Re: [PATCH] cifs: implementation id context as negotiate context

Shyam Prasad N
2026-03-09T16:37:29Z

On Mon, Mar 9, 2026 at 9:49 PM Ralph Boehme <slow@samba.org> wrote:
>
> Hi!
>
> I wonder which servers are expected to be implementing this? I suppose
> this protocol extension is not proposed without a server vendor
> interested in actually implementing it, otherwise the whole metrics
> story doesn't make sense.

Hi Ralph,

This is supposed to give the server an idea of what version of cifs.ko
the client is actually running.
This can be useful for servers like Azure SMB servers, where it is not
easy to explain client side behaviour without knowing what exact
version of the code is running on the client.

>
> *scratches head*
>
> Thanks!
> -slow
>
> On 3/4/26 1:27 PM, nspmangalore@gmail.com wrote:
> > From: Shyam Prasad N <sprasad@microsoft.com>
> >
> > MS-SMB2 does not allow any fields for the client to communicate
> > the client version details to the server. This change is a
> > proof-of-concept to add client details in a new negotiate context.
> >
> > Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
> > ---
> > fs/smb/client/smb2pdu.c | 78 +++++++++++++++++++++++++++++++++++++++++
> > fs/smb/common/smb2pdu.h | 32 +++++++++++++++++
> > 2 files changed, 110 insertions(+)
> >
> > diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
> > index ef655acf673df..9c89f6b4a6709 100644
> > --- a/fs/smb/client/smb2pdu.c
> > +++ b/fs/smb/client/smb2pdu.c
> > @@ -24,6 +24,7 @@
> > #include <linux/pagemap.h>
> > #include <linux/xattr.h>
> > #include <linux/netfs.h>
> > +#include <linux/utsname.h>
> > #include <trace/events/netfs.h>
> > #include "cifsglob.h"
> > #include "cifsproto.h"
> > @@ -45,6 +46,7 @@
> > #include "cached_dir.h"
> > #include "compress.h"
> > #include "fs_context.h"
> > +#include "cifsfs.h"
> >
> > /*
> > * The following table defines the expected "StructureSize" of SMB2 requests
> > @@ -724,6 +726,75 @@ build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
> > pneg_ctxt->Name[15] = 0x7C;
> > }
> >
> > +static unsigned int
> > +build_implementation_id_ctxt(struct smb2_implementation_id_context *pneg_ctxt)
> > +{
> > + struct nls_table *cp = load_nls_default();
> > + struct new_utsname *uts = utsname();
> > + const char *impl_domain = "kernel.org";
> > + const char *impl_name = "fs/smb/client";
> > + const char *os_name = "Linux";
> > + unsigned int data_len = 0;
> > + __u8 *data_ptr;
> > + int len;
> > +
> > + pneg_ctxt->ContextType = SMB2_IMPLEMENTATION_ID_CONTEXT_ID;
> > + data_ptr = pneg_ctxt->Data;
> > +
> > + /* ImplDomain */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, impl_domain,
> > + SMB2_IMPL_ID_MAX_DOMAIN_LEN, cp);
> > + pneg_ctxt->ImplDomainLength = cpu_to_le16(len * 2);
> > + data_ptr += len * 2;
> > + data_len += len * 2;
> > +
> > + /* ImplName */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, impl_name,
> > + SMB2_IMPL_ID_MAX_NAME_LEN, cp);
> > + pneg_ctxt->ImplNameLength = cpu_to_le16(len * 2);
> > + data_ptr += len * 2;
> > + data_len += len * 2;
> > +
> > + /* ImplVersion - CIFS_VERSION from cifsfs.h */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, CIFS_VERSION,
> > + SMB2_IMPL_ID_MAX_VERSION_LEN, cp);
> > + pneg_ctxt->ImplVersionLength = cpu_to_le16(len * 2);
> > + data_ptr += len * 2;
> > + data_len += len * 2;
> > +
> > + /* HostName - from utsname()->nodename */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, uts->nodename,
> > + SMB2_IMPL_ID_MAX_HOSTNAME_LEN, cp);
> > + pneg_ctxt->HostNameLength = cpu_to_le16(len * 2);
> > + data_ptr += len * 2;
> > + data_len += len * 2;
> > +
> > + /* OSName */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, os_name,
> > + SMB2_IMPL_ID_MAX_OS_NAME_LEN, cp);
> > + pneg_ctxt->OSNameLength = cpu_to_le16(len * 2);
> > + data_ptr += len * 2;
> > + data_len += len * 2;
> > +
> > + /* OSVersion - from utsname()->release */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, uts->release,
> > + SMB2_IMPL_ID_MAX_OS_VERSION_LEN, cp);
> > + pneg_ctxt->OSVersionLength = cpu_to_le16(len * 2);
> > + data_ptr += len * 2;
> > + data_len += len * 2;
> > +
> > + /* Arch - from utsname()->machine */
> > + len = cifs_strtoUTF16((__le16 *)data_ptr, uts->machine,
> > + SMB2_IMPL_ID_MAX_ARCH_LEN, cp);
> > + pneg_ctxt->ArchLength = cpu_to_le16(len * 2);
> > + data_len += len * 2;
> > +
> > + pneg_ctxt->Reserved2 = 0;
> > + pneg_ctxt->DataLength = cpu_to_le16(data_len + 14); /* 14 = 7 length fields * 2 bytes */
> > + /* Context size is DataLength + minimal smb2_neg_context, aligned to 8 */
> > + return ALIGN(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg_context), 8);
> > +}
> > +
> > static void
> > assemble_neg_contexts(struct smb2_negotiate_req *req,
> > struct TCP_Server_Info *server, unsigned int *total_len)
> > @@ -797,6 +868,13 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
> > neg_context_count++;
> > }
> >
> > + /* Add implementation ID context */
> > + ctxt_len = build_implementation_id_ctxt((struct smb2_implementation_id_context *)
> > + pneg_ctxt);
> > + *total_len += ctxt_len;
> > + pneg_ctxt += ctxt_len;
> > + neg_context_count++;
> > +
> > /* check for and add transport_capabilities and signing capabilities */
> > req->NegotiateContextCount = cpu_to_le16(neg_context_count);
> >
> > diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
> > index e482c86ceb00d..1ad7b57ce2952 100644
> > --- a/fs/smb/common/smb2pdu.h
> > +++ b/fs/smb/common/smb2pdu.h
> > @@ -457,6 +457,7 @@ struct smb2_tree_disconnect_rsp {
> > #define SMB2_TRANSPORT_CAPABILITIES cpu_to_le16(6)
> > #define SMB2_RDMA_TRANSFORM_CAPABILITIES cpu_to_le16(7)
> > #define SMB2_SIGNING_CAPABILITIES cpu_to_le16(8)
> > +#define SMB2_IMPLEMENTATION_ID_CONTEXT_ID cpu_to_le16(0xF100)
> > #define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100)
> >
> > struct smb2_neg_context {
> > @@ -596,6 +597,37 @@ struct smb2_signing_capabilities {
> > /* Followed by padding to 8 byte boundary (required by some servers) */
> > } __packed;
> >
> > +/*
> > + * For implementation ID context see MS-SMB2 2.2.3.1.8
> > + * Maximum string lengths per specification
> > + */
> > +#define SMB2_IMPL_ID_MAX_DOMAIN_LEN 128
> > +#define SMB2_IMPL_ID_MAX_NAME_LEN 260
> > +#define SMB2_IMPL_ID_MAX_VERSION_LEN 260
> > +#define SMB2_IMPL_ID_MAX_HOSTNAME_LEN 64
> > +#define SMB2_IMPL_ID_MAX_OS_NAME_LEN 64
> > +#define SMB2_IMPL_ID_MAX_OS_VERSION_LEN 64
> > +#define SMB2_IMPL_ID_MAX_ARCH_LEN 64
> > +
> > +struct smb2_implementation_id_context {
> > + __le16 ContextType; /* 9 */
> > + __le16 DataLength;
> > + __le32 Reserved;
> > + __le16 ImplDomainLength;
> > + __le16 ImplNameLength;
> > + __le16 ImplVersionLength;
> > + __le16 HostNameLength;
> > + __le16 OSNameLength;
> > + __le16 OSVersionLength;
> > + __le16 ArchLength;
> > + __le16 Reserved2;
> > + /* Followed by variable length UTF-16 strings:
> > + * ImplDomain, ImplName, ImplVersion, HostName,
> > + * OSName, OSVersion, Arch
> > + */
> > + __u8 Data[];
> > +} __packed;
> > +
> > #define POSIX_CTXT_DATA_LEN 16
> > struct smb2_posix_neg_context {
> > __le16 ContextType; /* 0x100 */
>

--
Regards,
Shyam