Skip to content

Commit fe856be

Browse files
aaptelsmfrench
authored andcommitted
CIFS: parse and store info on iface queries
Signed-off-by: Aurelien Aptel <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent b6f0dd5 commit fe856be

File tree

1 file changed

+155
-15
lines changed

1 file changed

+155
-15
lines changed

fs/cifs/smb2ops.c

Lines changed: 155 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -294,34 +294,176 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
294294
return rsize;
295295
}
296296

297-
#ifdef CONFIG_CIFS_STATS2
297+
298+
static int
299+
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
300+
size_t buf_len,
301+
struct cifs_server_iface **iface_list,
302+
size_t *iface_count)
303+
{
304+
struct network_interface_info_ioctl_rsp *p;
305+
struct sockaddr_in *addr4;
306+
struct sockaddr_in6 *addr6;
307+
struct iface_info_ipv4 *p4;
308+
struct iface_info_ipv6 *p6;
309+
struct cifs_server_iface *info;
310+
ssize_t bytes_left;
311+
size_t next = 0;
312+
int nb_iface = 0;
313+
int rc = 0;
314+
315+
*iface_list = NULL;
316+
*iface_count = 0;
317+
318+
/*
319+
* Fist pass: count and sanity check
320+
*/
321+
322+
bytes_left = buf_len;
323+
p = buf;
324+
while (bytes_left >= sizeof(*p)) {
325+
nb_iface++;
326+
next = le32_to_cpu(p->Next);
327+
if (!next) {
328+
bytes_left -= sizeof(*p);
329+
break;
330+
}
331+
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
332+
bytes_left -= next;
333+
}
334+
335+
if (!nb_iface) {
336+
cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
337+
rc = -EINVAL;
338+
goto out;
339+
}
340+
341+
if (bytes_left || p->Next)
342+
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
343+
344+
345+
/*
346+
* Second pass: extract info to internal structure
347+
*/
348+
349+
*iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);
350+
if (!*iface_list) {
351+
rc = -ENOMEM;
352+
goto out;
353+
}
354+
355+
info = *iface_list;
356+
bytes_left = buf_len;
357+
p = buf;
358+
while (bytes_left >= sizeof(*p)) {
359+
info->speed = le64_to_cpu(p->LinkSpeed);
360+
info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE);
361+
info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE);
362+
363+
cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count);
364+
cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
365+
cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
366+
le32_to_cpu(p->Capability));
367+
368+
switch (p->Family) {
369+
/*
370+
* The kernel and wire socket structures have the same
371+
* layout and use network byte order but make the
372+
* conversion explicit in case either one changes.
373+
*/
374+
case INTERNETWORK:
375+
addr4 = (struct sockaddr_in *)&info->sockaddr;
376+
p4 = (struct iface_info_ipv4 *)p->Buffer;
377+
addr4->sin_family = AF_INET;
378+
memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
379+
380+
/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
381+
addr4->sin_port = cpu_to_be16(CIFS_PORT);
382+
383+
cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
384+
&addr4->sin_addr);
385+
break;
386+
case INTERNETWORKV6:
387+
addr6 = (struct sockaddr_in6 *)&info->sockaddr;
388+
p6 = (struct iface_info_ipv6 *)p->Buffer;
389+
addr6->sin6_family = AF_INET6;
390+
memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
391+
392+
/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
393+
addr6->sin6_flowinfo = 0;
394+
addr6->sin6_scope_id = 0;
395+
addr6->sin6_port = cpu_to_be16(CIFS_PORT);
396+
397+
cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
398+
&addr6->sin6_addr);
399+
break;
400+
default:
401+
cifs_dbg(VFS,
402+
"%s: skipping unsupported socket family\n",
403+
__func__);
404+
goto next_iface;
405+
}
406+
407+
(*iface_count)++;
408+
info++;
409+
next_iface:
410+
next = le32_to_cpu(p->Next);
411+
if (!next)
412+
break;
413+
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
414+
bytes_left -= next;
415+
}
416+
417+
if (!*iface_count) {
418+
rc = -EINVAL;
419+
goto out;
420+
}
421+
422+
out:
423+
if (rc) {
424+
kfree(*iface_list);
425+
*iface_count = 0;
426+
*iface_list = NULL;
427+
}
428+
return rc;
429+
}
430+
431+
298432
static int
299433
SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
300434
{
301435
int rc;
302436
unsigned int ret_data_len = 0;
303-
struct network_interface_info_ioctl_rsp *out_buf;
437+
struct network_interface_info_ioctl_rsp *out_buf = NULL;
438+
struct cifs_server_iface *iface_list;
439+
size_t iface_count;
440+
struct cifs_ses *ses = tcon->ses;
304441

305442
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
306443
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
307444
NULL /* no data input */, 0 /* no data input */,
308445
(char **)&out_buf, &ret_data_len);
309-
if (rc != 0)
446+
if (rc != 0) {
310447
cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
311-
else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) {
312-
cifs_dbg(VFS, "server returned bad net interface info buf\n");
313-
rc = -EINVAL;
314-
} else {
315-
/* Dump info on first interface */
316-
cifs_dbg(FYI, "Adapter Capability 0x%x\t",
317-
le32_to_cpu(out_buf->Capability));
318-
cifs_dbg(FYI, "Link Speed %lld\n",
319-
le64_to_cpu(out_buf->LinkSpeed));
448+
goto out;
320449
}
450+
451+
rc = parse_server_interfaces(out_buf, ret_data_len,
452+
&iface_list, &iface_count);
453+
if (rc)
454+
goto out;
455+
456+
spin_lock(&ses->iface_lock);
457+
kfree(ses->iface_list);
458+
ses->iface_list = iface_list;
459+
ses->iface_count = iface_count;
460+
ses->iface_last_update = jiffies;
461+
spin_unlock(&ses->iface_lock);
462+
463+
out:
321464
kfree(out_buf);
322465
return rc;
323466
}
324-
#endif /* STATS2 */
325467

326468
void
327469
smb2_cached_lease_break(struct work_struct *work)
@@ -399,9 +541,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
399541
if (rc)
400542
return;
401543

402-
#ifdef CONFIG_CIFS_STATS2
403544
SMB3_request_interfaces(xid, tcon);
404-
#endif /* STATS2 */
405545

406546
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
407547
FS_ATTRIBUTE_INFORMATION);

0 commit comments

Comments
 (0)