Linux-CIFS Archive mirror
 help / color / mirror / Atom feed
From: Henrique Carvalho <henrique.carvalho@suse.com>
To: linux-cifs@vger.kernel.org
Cc: sfrench@samba.org, linkinjeon@kernel.org, metze@samba.org,
	pc@manguebit.com, ronniesahlberg@gmail.com,
	sprasad@microsoft.com, tom@talpey.com, bharathsm@microsoft.com,
	ematsumiya@suse.de,
	Henrique Carvalho <henrique.carvalho@suse.com>
Subject: [PATCH 03/11] smb: client: add QUIC mount and transport setup
Date: Tue, 28 Apr 2026 12:46:01 -0300	[thread overview]
Message-ID: <20260428154604.222551-6-henrique.carvalho@suse.com> (raw)
In-Reply-To: <20260428154604.222551-1-henrique.carvalho@suse.com>

Introduce new mount options used to drive SMB over QUIC: `quic` and
`mtls`. Introduce per-server state needed to drive the QUIC transport.
Introduce transport functions for smb quic tls handshake setup and
initial quic transport setup. Include SMB2_TRANSPORT_CAPABILITIES
negotiate context for QUIC.

Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com>
---
 fs/smb/client/cifsglob.h   |  19 +++-
 fs/smb/client/connect.c    | 184 +++++++++++++++++++++++++++++++++++--
 fs/smb/client/fs_context.c |  27 ++++++
 fs/smb/client/fs_context.h |   4 +
 fs/smb/client/smb2pdu.c    |  27 ++++++
 fs/smb/client/transport.c  |  40 ++++----
 6 files changed, 274 insertions(+), 27 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 58be72377c7d..f56d3732bfa8 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -35,6 +35,7 @@
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
 #define SMBD_IWARP_PORT 5445
+#define SMB_QUIC_PORT 443
 
 /*
  * The sizes of various internal tables and strings
@@ -759,8 +760,10 @@ struct TCP_Server_Info {
 	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
 	bool	sec_iakerb;		/* supports pass-through auth for Kerberos (krb5 proxy) */
 	bool	large_buf;		/* is current buffer large? */
-	int	ipproto; /* IPPROTO_TCP or IPOROTO_SMBDIRECT */
+	int	ipproto; /* IPPROTO_TCP, IPOROTO_SMBDIRECT or IPPROTO_QUIC */
 #define cifs_rdma_enabled(__server)	((__server)->ipproto == IPPROTO_SMBDIRECT)
+	/* point to the SMBD connection if RDMA is used instead of socket */
+	struct smbd_connection *smbd_conn;
 	struct delayed_work	echo; /* echo ping workqueue job */
 	char	*smallbuf;	/* pointer to current "small" buffer */
 	char	*bigbuf;	/* pointer to current "big" buffer */
@@ -832,6 +835,14 @@ struct TCP_Server_Info {
 	char *leaf_fullpath;
 	bool dfs_conn:1;
 	char dns_dom[CIFS_MAX_DOMAINNAME_LEN + 1];
+
+	struct {
+		bool need_smb_seal; /* if unset, smb encryption is disabled over QUIC
+				     * transport, and QUIC security (i.e. TLS 1.3) is
+				     * the one used
+				     */
+		bool mtls;
+	} quic_conn;
 };
 
 static inline bool is_smb1(const struct TCP_Server_Info *server)
@@ -855,6 +866,12 @@ static inline void cifs_server_unlock(struct TCP_Server_Info *server)
 	memalloc_nofs_restore(nofs_flag);
 }
 
+static inline bool
+cifs_quic_enabled(struct TCP_Server_Info *server)
+{
+	return server->ipproto == IPPROTO_QUIC;
+}
+
 struct cifs_credits {
 	unsigned int value;
 	unsigned int instance;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 33d619007905..bfe949b14db2 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -25,11 +25,14 @@
 #include <linux/namei.h>
 #include <linux/uuid.h>
 #include <linux/uaccess.h>
+#include <linux/quic.h>
 #include <asm/processor.h>
 #include <linux/inet.h>
 #include <linux/module.h>
 #include <keys/user-type.h>
 #include <net/ipv6.h>
+#include <net/handshake.h>
+#include <keys/asymmetric-type.h>
 #include <linux/parser.h>
 #include <linux/bvec.h>
 #include "cifsglob.h"
@@ -70,7 +73,11 @@ static void mchan_mount_work_fn(struct work_struct *work);
 
 static void smb_sock_release(struct TCP_Server_Info *server)
 {
-	sock_release(server->ssocket);
+	/* ->ssocket will be released by fput() */
+	if (cifs_quic_enabled(server) && server->ssocket->file)
+		fput(server->ssocket->file);
+	else if (server->ssocket)
+		sock_release(server->ssocket);
 	server->ssocket = NULL;
 }
 
@@ -1643,6 +1650,9 @@ static int match_server(struct TCP_Server_Info *server,
 	if (cifs_rdma_enabled(server) != ctx->rdma)
 		return 0;
 
+	if (cifs_quic_enabled(server) != ctx->quic)
+		return 0;
+
 	if (server->ignore_signature != ctx->ignore_signature)
 		return 0;
 
@@ -1784,7 +1794,10 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
 	tcp_ses->tcp_nodelay = ctx->sockopt_tcp_nodelay;
 	if (ctx->rdma)
 		tcp_ses->ipproto = IPPROTO_SMBDIRECT;
-	else
+	else if (ctx->quic) {
+		tcp_ses->ipproto = IPPROTO_QUIC;
+		tcp_ses->quic_conn.mtls = ctx->mtls;
+	} else
 		tcp_ses->ipproto = IPPROTO_TCP;
 
 	tcp_ses->in_flight = 0;
@@ -3304,6 +3317,145 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
 	return 0;
 }
 
+static void
+smb_tls_handshake_done(void *data, int status, key_serial_t peerid)
+{
+	struct smb_tls *smb_tls = (struct smb_tls *)data;
+
+	smb_tls->status = status;
+	smb_tls->peerid = peerid;
+
+	complete(&smb_tls->handshake_done);
+}
+
+static inline struct smb_tls *
+smb_tls_init(struct TCP_Server_Info *server)
+{
+	struct smb_tls *tls;
+
+	tls = kzalloc_obj(*tls, GFP_KERNEL);
+	if (!tls)
+		return ERR_PTR(-ENOMEM);
+
+	tls->status = 0;
+
+	tls->args.ta_sock = server->ssocket;
+	tls->args.ta_done = smb_tls_handshake_done;
+	tls->args.ta_data = tls;
+	tls->args.ta_peername = kstrdup(server->hostname, GFP_KERNEL); /* do I need kstrdup ? */
+	tls->args.ta_timeout_ms = SMB_TLS_TIMEOUT_MS;
+	tls->args.ta_keyring = TLS_NO_KEYRING;
+
+	init_completion(&tls->handshake_done);
+
+	return tls;
+}
+
+static void smb_tls_free(struct smb_tls **tls)
+{
+	kfree((*tls)->args.ta_peername);
+	kfree_sensitive(*tls);
+	*tls = NULL;
+}
+
+static inline void
+smb_tls_debug(int rc)
+{
+	switch (rc) {
+	case 0:
+		cifs_dbg(VFS, "smb tls: Handshake successful");
+		return;
+	case -ERESTARTSYS:
+		cifs_dbg(VFS, "smb tls: Handshake interrupted");
+		return;
+	case -ETIMEDOUT:
+		cifs_dbg(VFS, "smb tls: Handshake timed out");
+		return;
+	case -EINVAL:
+		cifs_dbg(VFS, "smb tls: Consumer provided an invalid argument");
+		return;
+	case -ENOKEY:
+		cifs_dbg(VFS, "smb tls: Missing authentication material");
+		return;
+	case -EIO:
+		cifs_dbg(VFS, "smb tls: An unexpected fault occurred");
+		return;
+	default:
+		cifs_dbg(VFS, "smb tls: Error: %d", -rc);
+		return;
+	}
+}
+
+static int
+smb_tls_handshake(struct TCP_Server_Info *server)
+{
+	int rc;
+	struct smb_tls *tls;
+
+	cifs_dbg(FYI, "smb tls: starting TLS handshake");
+
+	tls = smb_tls_init(server);
+	if (IS_ERR(tls))
+		return PTR_ERR(tls);
+
+	if (server->quic_conn.mtls)
+		rc = tls_client_hello_x509(&tls->args, GFP_KERNEL);
+	else
+		rc = tls_client_hello_anon(&tls->args, GFP_KERNEL);
+
+	if (rc < 0)
+		goto free;
+
+	rc = wait_for_completion_interruptible(&tls->handshake_done);
+	if (rc < 0)
+		tls_handshake_cancel(server->ssocket->sk);
+	else
+		rc = tls->status;
+
+free:
+	smb_tls_free(&tls);
+
+	smb_tls_debug(rc);
+
+	return rc;
+}
+
+static int
+smb_quic_tls(struct TCP_Server_Info *server)
+{
+	int rc;
+	size_t sinfolen;
+	struct quic_stream_info sinfo;
+	struct socket *socket = server->ssocket;
+
+	rc = smb_tls_handshake(server);
+	if (rc < 0)
+		return rc;
+
+	/* open a new stream after handshake, default to stream id == 0 */
+	sinfo.stream_id = -1;
+	sinfolen = sizeof(sinfo);
+	rc = quic_do_getsockopt(socket->sk, QUIC_SOCKOPT_STREAM_OPEN,
+				KERNEL_SOCKPTR(&sinfo), KERNEL_SOCKPTR(&sinfolen));
+
+	return rc;
+}
+
+static int
+smb_quic_prepare_socket(struct TCP_Server_Info *server)
+{
+	int flags = 0;
+	struct file *filp;
+	struct socket *socket = server->ssocket;
+
+	filp = sock_alloc_file(socket, flags, NULL);
+	if (IS_ERR(filp))
+		return PTR_ERR(filp);
+
+	return quic_do_setsockopt(socket->sk, QUIC_SOCKOPT_ALPN,
+				  KERNEL_SOCKPTR("smb"), 3);
+}
+
 static inline const char *
 get_protocol_name(struct TCP_Server_Info *server)
 {
@@ -3350,8 +3502,6 @@ generic_ip_connect(struct TCP_Server_Info *server)
 			 __func__, pname, &ipv4->sin_addr, ntohs(sport));
 	}
 
-	smb_sock_release(server);
-
 	{
 		struct net *net = cifs_net_ns(server);
 		struct sock *sk;
@@ -3380,8 +3530,8 @@ generic_ip_connect(struct TCP_Server_Info *server)
 
 	rc = bind_socket(server);
 	if (rc < 0) {
-		cifs_dbg(FYI, "Error %d bind_socket() %s\n", rc, pname);
-		goto close_socket;
+		cifs_dbg(VFS, "Error %d bind_socket() %s\n", rc, pname);
+		return rc;
 	}
 
 	/*
@@ -3406,10 +3556,16 @@ generic_ip_connect(struct TCP_Server_Info *server)
 	if (cifs_rdma_enabled(server)) {
 		rc = smbd_prepare_socket(server, ntohs(sport));
 		if (rc < 0) {
-			cifs_dbg(FYI, "Error %d from smbd_prepare_socket(port=%u)\n",
+			cifs_dbg(VFS, "Error %d from smbd_prepare_socket(port=%u)\n",
 				 rc, ntohs(sport));
 			goto close_socket;
 		}
+	} else if (cifs_quic_enabled(server)) {
+		rc = smb_quic_prepare_socket(server);
+		if (rc < 0) {
+			cifs_dbg(VFS, "Error %d from smb_quic_prepare_socket()\n", rc);
+			goto close_socket;
+		}
 	}
 
 	cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n",
@@ -3426,9 +3582,18 @@ generic_ip_connect(struct TCP_Server_Info *server)
 	if (server->noblockcnt && rc == -EINPROGRESS)
 		rc = 0;
 	if (rc < 0) {
-		cifs_dbg(FYI, "Error %d connecting with %s to server\n", rc, pname);
+		cifs_dbg(VFS, "Error %d connecting with %s to server\n", rc, pname);
 		goto close_socket;
 	}
+
+	if (cifs_quic_enabled(server)) {
+		rc = smb_quic_tls(server);
+		if (rc < 0) {
+			cifs_dbg(VFS, "Error %d from smb_quic_tls()\n", rc);
+			goto close_socket;
+		}
+	}
+
 	trace_smb3_connect_done(server->hostname, server->conn_id, &server->dstaddr);
 
 	/*
@@ -3467,6 +3632,9 @@ ip_connect(struct TCP_Server_Info *server)
 	if (cifs_rdma_enabled(server)) {
 		port1 = SMBD_IWARP_PORT;
 		port2 = CIFS_PORT;
+	} else if (cifs_quic_enabled(server)) {
+		port1 = SMB_QUIC_PORT;
+		port2 = 0;
 	}
 
 	if (server->dstaddr.ss_family == AF_INET6)
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 54090739535f..3a0c66cf3c2c 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -127,6 +127,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
 	fsparam_flag("nosparse", Opt_nosparse),
 	fsparam_flag("domainauto", Opt_domainauto),
 	fsparam_flag("rdma", Opt_rdma),
+	fsparam_flag("quic", Opt_quic),
 	fsparam_flag("modesid", Opt_modesid),
 	fsparam_flag("modefromsid", Opt_modesid),
 	fsparam_flag("rootfs", Opt_rootfs),
@@ -135,6 +136,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
 	fsparam_flag_no("nativesocket", Opt_nativesocket),
 	fsparam_flag_no("unicode", Opt_unicode),
 	fsparam_flag_no("nbsessinit", Opt_nbsessinit),
+	fsparam_flag("mtls", Opt_mtls),
 
 	/* Mount options which take uid or gid */
 	fsparam_uid("backupuid", Opt_backupuid),
@@ -840,6 +842,19 @@ static int smb3_fs_context_validate(struct fs_context *fc)
 		return -EOPNOTSUPP;
 	}
 
+	if (ctx->rdma && ctx->quic) {
+		cifs_errorf(fc, "SMB Direct and QUIC transport are mutually exclusive\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (ctx->quic) {
+		pr_err("%x", ctx->vals->protocol_id);
+		if (ctx->vals->protocol_id < SMB311_PROT_ID) {
+			cifs_errorf(fc, "SMB over QUIC requires Version >=3.1.1\n");
+			return -EOPNOTSUPP;
+		}
+	}
+
 #ifndef CONFIG_KEYS
 	/* Muliuser mounts require CONFIG_KEYS support */
 	if (ctx->multiuser) {
@@ -1011,6 +1026,7 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
 		cifs_errorf(fc, "can not change nbsessinit during remount\n");
 		return -EINVAL;
 	}
+	/* XXX(QUIC): support remount ? */
 
 	return 0;
 }
@@ -1871,6 +1887,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
 	case Opt_rdma:
 		ctx->rdma = true;
 		break;
+	case Opt_quic:
+#if !IS_ENABLED(CONFIG_IP_QUIC)
+		cifs_dbg(VFS, "CONFIG_IP_QUIC is not enabled\n");
+		goto cifs_parse_mount_err;
+#endif
+		ctx->quic = true;
+		break;
 	case Opt_reparse:
 		if (parse_reparse_flavor(fc, param->string, ctx))
 			goto cifs_parse_mount_err;
@@ -1896,7 +1919,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
 		ctx->symlinkroot = param->string;
 		param->string = NULL;
 		break;
+	case Opt_mtls:
+		ctx->mtls = true;
+		break;
 	}
+
 	/* case Opt_ignore: - is ignored as expected ... */
 
 	if (ctx->multiuser && ctx->upcall_target == UPTARGET_MOUNT) {
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 0b64fcb5d302..e9b85c1c1937 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -143,6 +143,7 @@ enum cifs_param {
 	Opt_tcp_nodelay,
 	Opt_domainauto,
 	Opt_rdma,
+	Opt_quic,
 	Opt_modesid,
 	Opt_rootfs,
 	Opt_multichannel,
@@ -199,6 +200,7 @@ enum cifs_param {
 	Opt_nativesocket,
 	Opt_symlink,
 	Opt_symlinkroot,
+	Opt_mtls,
 
 	/* Mount options to be ignored */
 	Opt_ignore,
@@ -293,6 +295,8 @@ struct smb3_fs_context {
 	bool resilient:1; /* noresilient not required since not fored for CA */
 	bool domainauto:1;
 	bool rdma:1;
+	bool quic:1;
+	bool mtls:1;
 	bool multichannel:1;
 	bool multichannel_specified:1; /* true if user specified multichannel or nomultichannel */
 	bool max_channels_specified:1; /* true if user specified max_channels */
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index bac88a612d5d..848f9137f01d 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -732,6 +732,16 @@ build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
 	return smb2_neg_context_len(pneg_ctxt);
 }
 
+static unsigned int
+build_transport_ctxt(struct smb2_transport_capabilities_context *pneg_ctxt)
+{
+	pneg_ctxt->ContextType = SMB2_TRANSPORT_CAPABILITIES;
+	pneg_ctxt->DataLength = cpu_to_le16(sizeof(struct smb2_transport_capabilities_context) -
+					    sizeof(struct smb2_neg_context));
+	pneg_ctxt->Flags = cpu_to_le32(SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY);
+	return smb2_neg_context_len(pneg_ctxt);
+}
+
 struct neg_ctx {
 	char *pos;
 	unsigned int len;
@@ -801,6 +811,11 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
 	if (enable_negotiate_signing)
 		add_context(&nc, build_signing_ctxt((struct smb2_signing_capabilities *)nc.pos));
 
+	if (cifs_quic_enabled(server) && server->quic_conn.need_smb_seal)
+		add_context(&nc,
+			    build_transport_ctxt(
+				    (struct smb2_transport_capabilities_context *)nc.pos));
+
 	/* check for and add transport_capabilities and signing capabilities */
 	req->NegotiateContextCount = cpu_to_le16(nc.cnt);
 
@@ -945,6 +960,15 @@ static void decode_signing_ctx(struct TCP_Server_Info *server,
 		     server->signing_algorithm);
 }
 
+static void
+decode_transport_ctx(struct TCP_Server_Info *server,
+		     struct smb2_transport_capabilities_context *pctxt)
+{
+	if (pctxt->Flags == cpu_to_le32(SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY))
+		server->quic_conn.need_smb_seal = false;
+	else
+		server->quic_conn.need_smb_seal = true;
+}
 
 static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
 				     struct TCP_Server_Info *server,
@@ -997,6 +1021,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
 		else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES)
 			decode_signing_ctx(server,
 				(struct smb2_signing_capabilities *)pctx);
+		else if (pctx->ContextType == SMB2_TRANSPORT_CAPABILITIES)
+			decode_transport_ctx(server,
+				(struct smb2_transport_capabilities_context *)pctx);
 		else
 			cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
 				le16_to_cpu(pctx->ContextType));
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index e64becee928f..46a67c7eba54 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -23,6 +23,7 @@
 #include <linux/sched/signal.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/task_work.h>
+#include <linux/quic.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
@@ -148,10 +149,12 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
 
 	*sent = 0;
 
-	if (server->noblocksnd)
-		smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
-	else
-		smb_msg->msg_flags = MSG_NOSIGNAL;
+	if (cifs_quic_enabled(server)) {
+		if (server->noblocksnd)
+			smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
+		else
+			smb_msg->msg_flags = MSG_NOSIGNAL;
+	}
 
 	while (msg_data_left(smb_msg)) {
 		/*
@@ -270,7 +273,8 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 
 	rc = 0;
 	/* cork the socket */
-	tcp_sock_set_cork(ssocket->sk, true);
+	if (!cifs_quic_enabled(server))
+		tcp_sock_set_cork(ssocket->sk, true);
 
 	for (j = 0; j < num_rqst; j++)
 		send_length += smb_rqst_len(server, &rqst[j]);
@@ -287,19 +291,17 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	sigprocmask(SIG_BLOCK, &mask, &oldmask);
 
 	/* Generate a rfc1002 marker */
-	{
-		struct kvec hiov = {
-			.iov_base = &rfc1002_marker,
-			.iov_len  = 4
-		};
-		iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
-		rc = smb_send_kvec(server, &smb_msg, &sent);
-		if (rc < 0)
-			goto unmask;
+	struct kvec hiov = {
+		.iov_base = &rfc1002_marker,
+		.iov_len  = 4
+	};
+	iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
+	rc = smb_send_kvec(server, &smb_msg, &sent);
+	if (rc < 0)
+		goto unmask;
 
-		total_len += sent;
-		send_length += 4;
-	}
+	total_len += sent;
+	send_length += 4;
 
 	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length);
 
@@ -350,7 +352,9 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	}
 
 	/* uncork it */
-	tcp_sock_set_cork(ssocket->sk, false);
+
+	if (!cifs_quic_enabled(server))
+		tcp_sock_set_cork(ssocket->sk, false);
 
 	if ((total_len > 0) && (total_len != send_length)) {
 		cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
-- 
2.53.0


      parent reply	other threads:[~2026-04-28 15:46 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-28 15:45 [PATCH 00/11] smb: implement SMB over QUIC Henrique Carvalho
2026-04-28 15:45 ` [PATCH 01/11] smb: client: refactor negotiate context assembly Henrique Carvalho
2026-04-28 15:45 ` [PATCH 01/11] smb: common: add smb_tls struct shared by client and server Henrique Carvalho
2026-04-28 15:45 ` [PATCH 02/11] smb: client: prepare connect path for QUIC transport Henrique Carvalho
2026-04-28 15:46 ` [PATCH 02/11] smb: client: refactor negotiate context assembly Henrique Carvalho
2026-04-28 15:46 ` Henrique Carvalho [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260428154604.222551-6-henrique.carvalho@suse.com \
    --to=henrique.carvalho@suse.com \
    --cc=bharathsm@microsoft.com \
    --cc=ematsumiya@suse.de \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=metze@samba.org \
    --cc=pc@manguebit.com \
    --cc=ronniesahlberg@gmail.com \
    --cc=sfrench@samba.org \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).