All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: [PATCH 11/16] CIFS: Add session setup/logoff capability for SMB2
Date: Mon, 26 Mar 2012 13:21:38 +0400	[thread overview]
Message-ID: <1332753703-4315-12-git-send-email-piastry@etersoft.ru> (raw)
In-Reply-To: <1332753703-4315-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    3 +
 fs/cifs/connect.c   |   14 +++-
 fs/cifs/ntlmssp.h   |   10 +++
 fs/cifs/sess.c      |    6 +-
 fs/cifs/smb2misc.c  |    5 +
 fs/cifs/smb2pdu.c   |  225 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   37 +++++++++
 fs/cifs/smb2proto.h |    3 +
 8 files changed, 298 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 49f6a57..63eb795 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -450,6 +450,9 @@ struct cifs_ses {
 	struct session_key auth_key;
 	struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
 	bool need_reconnect:1; /* connection reset, uid now invalid */
+#ifdef CONFIG_CIFS_SMB2
+	__u16 session_flags;
+#endif /* CONFIG_CIFS_SMB2 */
 };
 /* no more than one of the following three session flags may be set */
 #define CIFS_SES_NT4 1
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c59d051..46c203f 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2427,7 +2427,12 @@ cifs_put_smb_ses(struct cifs_ses *ses)
 
 	if (ses->status == CifsGood) {
 		xid = GetXid();
-		CIFSSMBLogoff(xid, ses);
+#ifdef CONFIG_CIFS_SMB2
+		if (ses->server->is_smb2)
+			SMB2_logoff(xid, ses);
+		else
+#endif
+			CIFSSMBLogoff(xid, ses);
 		_FreeXid(xid);
 	}
 	sesInfoFree(ses);
@@ -4184,7 +4189,12 @@ int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
 	cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
 		 server->sec_mode, server->capabilities, server->timeAdj);
 
-	rc = CIFS_SessSetup(xid, ses, nls_info);
+#ifdef CONFIG_CIFS_SMB2
+	if (ses->server->is_smb2)
+		rc = SMB2_sess_setup(xid, ses, nls_info);
+	else
+#endif
+		rc = CIFS_SessSetup(xid, ses, nls_info);
 	if (rc) {
 		cERROR(1, "Send error in SessSetup = %d", rc);
 	} else {
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index 5d52e4a..848249f 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -126,3 +126,13 @@ typedef struct _AUTHENTICATE_MESSAGE {
 	   do not set the version is present flag */
 	char UserString[0];
 } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
+
+/*
+ * Size of the session key (crypto key encrypted with the password
+ */
+
+int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
+void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses);
+int build_ntlmssp_auth_blob(unsigned char *pbuffer, u16 *buflen,
+			struct cifs_ses *ses,
+			const struct nls_table *nls_cp);
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index f88fa4d..45b01bb 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -364,7 +364,7 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 	return rc;
 }
 
-static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
+int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 				    struct cifs_ses *ses)
 {
 	unsigned int tioffset; /* challenge message target info area */
@@ -415,7 +415,7 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 
 /* We do not malloc the blob, it is passed in pbuffer, because
    it is fixed size, and small, making this approach cleaner */
-static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
+void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
 					 struct cifs_ses *ses)
 {
 	NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
@@ -451,7 +451,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
 /* We do not malloc the blob, it is passed in pbuffer, because its
    maximum possible size is fixed and small, making this approach cleaner.
    This function returns the length of the data in the blob */
-static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
+int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 					u16 *buflen,
 				   struct cifs_ses *ses,
 				   const struct nls_table *nls_cp)
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 88918ac..4817fac 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -222,6 +222,11 @@ char *smb2_get_data_area_len(int *poff, int *plen, struct smb2_hdr *pSMB2)
 		    ((struct smb2_negotiate_rsp *)pSMB2)->SecurityBufferLength);
 		break;
 	case SMB2_SESSION_SETUP:
+		*poff = le16_to_cpu(
+		  ((struct smb2_sess_setup_rsp *)pSMB2)->SecurityBufferOffset);
+		*plen = le16_to_cpu(
+		  ((struct smb2_sess_setup_rsp *)pSMB2)->SecurityBufferLength);
+		break;
 	case SMB2_CREATE:
 	case SMB2_READ:
 	case SMB2_QUERY_INFO:
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 1a12e7f..28fbadc 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -383,3 +383,228 @@ neg_exit:
 	free_rsp_buf(resp_buftype, pSMB2r);
 	return rc;
 }
+
+int
+SMB2_sess_setup(unsigned int xid, struct cifs_ses *ses,
+		const struct nls_table *nls_cp)
+{
+	struct smb2_sess_setup_req *pSMB2;
+	struct smb2_sess_setup_rsp *pSMB2r = NULL;
+	struct kvec iov[2];
+	int rc = 0;
+	int resp_buftype;
+	__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
+	struct TCP_Server_Info *server;
+	unsigned int sec_flags;
+	u8 temp = 0;
+	u16 blob_length = 0;
+	char *security_blob;
+	char *ntlmssp_blob = NULL;
+	bool use_spnego = false; /* else use raw ntlmssp */
+
+	cFYI(1, "Session Setup");
+
+	if (ses->server)
+		server = ses->server;
+	else {
+		rc = -EIO;
+		return rc;
+	}
+
+	/* if memory allocation is successful, caller of this function
+	 * frees it.
+	 */
+	ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
+	if (!ses->ntlmssp)
+		return -ENOMEM;
+
+	ses->server->secType = RawNTLMSSP;
+
+ssetup_ntlmssp_authenticate:
+	if (phase == NtLmChallenge)
+		phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
+
+	rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &pSMB2);
+	if (rc)
+		return rc;
+
+	/* if any of auth flags (ie not sign or seal) are overriden use them */
+	if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+		sec_flags = ses->overrideSecFlg;  /* BB FIXME fix sign flags?*/
+	else /* if override flags set only sign/seal OR them with global auth */
+		sec_flags = global_secflags | ses->overrideSecFlg;
+
+	cFYI(1, "sec_flags 0x%x", sec_flags);
+
+	pSMB2->hdr.SessionId = 0; /* First session, not a reauthenticate */
+	pSMB2->VcNumber = 0; /* MBZ */
+	/* to enable echos and oplocks */
+	pSMB2->hdr.CreditRequest = cpu_to_le16(3);
+
+	/* only one of SMB2 signing flags may be set in SMB2 request */
+	if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
+		temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+	else if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
+		temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+	else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
+		temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
+
+	pSMB2->SecurityMode = temp;
+
+	/* We only support the DFS cap (others are currently undefined) */
+	pSMB2->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS
+						& ses->server->capabilities);
+	pSMB2->Channel = 0; /* MBZ */
+	iov[0].iov_base = (char *)pSMB2;
+	iov[0].iov_len = be32_to_cpu(pSMB2->hdr.smb2_buf_length)
+					+ 4 /* rfc1001 len */ - 1 /* pad */;
+	if (phase == NtLmNegotiate) {
+		ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
+					GFP_KERNEL);
+		if (ntlmssp_blob == NULL) {
+			rc = -ENOMEM;
+			goto ssetup_exit;
+		}
+
+		build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
+		if (use_spnego) {
+			/* blob_length = build_spnego_ntlmssp_blob(
+					&security_blob,
+					sizeof(struct _NEGOTIATE_MESSAGE),
+					ntlmssp_blob); */
+			/* BB eventually need to add this */
+			cERROR(1, "spnego not supported for SMB2 yet");
+			rc = -EOPNOTSUPP;
+			kfree(ntlmssp_blob);
+			goto ssetup_exit;
+		} else {
+			blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
+			/* with raw NTLMSSP we don't encapsulate in SPNEGO */
+			security_blob = ntlmssp_blob;
+		}
+	} else if (phase == NtLmAuthenticate) {
+		pSMB2->hdr.SessionId = ses->Suid;
+		ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
+					GFP_KERNEL);
+		if (ntlmssp_blob == NULL) {
+			cERROR(1, "failed to malloc ntlmssp blob");
+			rc = -ENOMEM;
+			goto ssetup_exit;
+		}
+		rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length,
+					ses, nls_cp);
+		if (rc) {
+			cFYI(1, "build_ntlmssp_auth_blob failed %d", rc);
+			goto ssetup_exit; /* BB double check error handling */
+		}
+		if (use_spnego) {
+			/* blob_length = build_spnego_ntlmssp_blob(
+							&security_blob,
+							blob_length,
+							ntlmssp_blob); */
+			cERROR(1, "spnego not supported for SMB2 yet");
+			rc = -EOPNOTSUPP;
+			kfree(ntlmssp_blob);
+			goto ssetup_exit;
+		} else {
+			security_blob = ntlmssp_blob;
+		}
+	} else {
+		cERROR(1, "illegal ntlmssp phase");
+		rc = -EIO;
+		goto ssetup_exit;
+	}
+
+	/* Testing shows that buffer offset must be at location of Buffer[0] */
+	pSMB2->SecurityBufferOffset = cpu_to_le16(
+			sizeof(struct smb2_sess_setup_req) - 1 /* pad */
+			- 4 /* rfc1001 len */);
+	pSMB2->SecurityBufferLength = cpu_to_le16(blob_length);
+	iov[1].iov_base = security_blob;
+	iov[1].iov_len = blob_length;
+
+	pSMB2->hdr.smb2_buf_length =
+		cpu_to_be32(be32_to_cpu(pSMB2->hdr.smb2_buf_length)
+			    - 1 /* pad */ + blob_length);
+
+	/* BB add code to build os and lm fields */
+
+	rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
+
+	kfree(security_blob);
+	pSMB2r = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
+	if (pSMB2r->hdr.Status ==
+			cpu_to_le32(STATUS_MORE_PROCESSING_REQUIRED)) {
+		if (phase != NtLmNegotiate) {
+			cERROR(1, "Unexpected more processing error");
+			goto ssetup_exit;
+		}
+		if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
+			le16_to_cpu(pSMB2r->SecurityBufferOffset)) {
+			cERROR(1, "Invalid security buffer offset %d",
+				    le16_to_cpu(pSMB2r->SecurityBufferOffset));
+			rc = -EIO;
+			goto ssetup_exit;
+		}
+
+		/* NTLMSSP Negotiate sent now processing challenge (response) */
+		phase = NtLmChallenge; /* process ntlmssp challenge */
+		rc = 0; /* MORE_PROCESSING is not an error here but expected */
+		ses->Suid = pSMB2r->hdr.SessionId;
+		rc = decode_ntlmssp_challenge(pSMB2r->Buffer,
+				le16_to_cpu(pSMB2r->SecurityBufferLength), ses);
+	}
+
+	/* BB eventually add code for SPNEGO decoding of NtlmChallenge blob,
+	   but at least the raw NTLMSSP case works */
+
+	/*
+	 * No tcon so can't do
+	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
+	 */
+	if (rc != 0)
+		goto ssetup_exit;
+
+	if (pSMB2r == NULL) {
+		rc = -EIO;
+		goto ssetup_exit;
+	}
+
+	ses->session_flags = le16_to_cpu(pSMB2r->SessionFlags);
+ssetup_exit:
+	free_rsp_buf(resp_buftype, pSMB2r);
+
+	/* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
+	if ((phase == NtLmChallenge) && (rc == 0))
+		goto ssetup_ntlmssp_authenticate;
+	return rc;
+}
+
+int
+SMB2_logoff(const int xid, struct cifs_ses *ses)
+{
+	struct smb2_logoff_req *pSMB2; /* response is also trivial struct */
+	int rc = 0;
+	struct TCP_Server_Info *server;
+
+	cFYI(1, "disconnect session %p", ses);
+
+	if (ses && (ses->server))
+		server = ses->server;
+	else
+		return -EIO;
+
+	rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &pSMB2);
+	if (rc)
+		return rc;
+
+	 /* since no tcon, smb2_init can not do this, so do here */
+	pSMB2->hdr.SessionId = ses->Suid;
+
+	rc = SendReceiveNoRsp(xid, ses, (char *) &pSMB2->hdr, 0);
+	/*
+	 * No tcon so can't do
+	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
+	 */
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 65be640..3886266 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -181,4 +181,41 @@ struct smb2_negotiate_rsp {
 	__u8   Buffer[1];	/* variable length GSS security buffer */
 } __packed;
 
+struct smb2_sess_setup_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 25 */
+	__u8   VcNumber;
+	__u8   SecurityMode;
+	__le32 Capabilities;
+	__le32 Channel;
+	__le16 SecurityBufferOffset;
+	__le16 SecurityBufferLength;
+	__le64 PreviousSessionId;
+	__u8   Buffer[1];	/* variable length GSS security buffer */
+} __packed;
+
+/* Currently defined SessionFlags */
+#define SMB2_SESSION_FLAG_IS_GUEST	0x0001
+#define SMB2_SESSION_FLAG_IS_NULL	0x0002
+struct smb2_sess_setup_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 9 */
+	__le16 SessionFlags;
+	__le16 SecurityBufferOffset;
+	__le16 SecurityBufferLength;
+	__u8   Buffer[1];	/* variable length GSS security buffer */
+} __packed;
+
+struct smb2_logoff_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;	/* Must be 4 */
+	__le16 Reserved;
+} __packed;
+
+struct smb2_logoff_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;	/* Must be 4 */
+	__le16 Reserved;
+} __packed;
+
 #endif				/* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index bc283ff..ec12d6e 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -48,5 +48,8 @@ extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
  *  are contained within these calls
  */
 extern int SMB2_negotiate(unsigned int xid, struct cifs_ses *ses);
+extern int SMB2_sess_setup(unsigned int xid, struct cifs_ses *ses,
+			   const struct nls_table *nls_cp);
+extern int SMB2_logoff(const int xid, struct cifs_ses *ses);
 
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

  parent reply	other threads:[~2012-03-26  9:21 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-26  9:21 [PATCH 00/16] Get SMB2 mount work Pavel Shilovsky
     [not found] ` <1332753703-4315-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-26  9:21   ` [PATCH 01/16] CIFS: Introduce SMB2 Kconfig option Pavel Shilovsky
     [not found]     ` <1332753703-4315-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 12:25       ` Jeff Layton
2012-03-26  9:21   ` [PATCH 02/16] CIFS: Introduce SMB2 mounts as vers=2 Pavel Shilovsky
     [not found]     ` <1332753703-4315-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 12:31       ` Jeff Layton
     [not found]         ` <20120506083103.605e3dae-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-06 12:37           ` Jeff Layton
2012-03-26  9:21   ` [PATCH 03/16] CIFS: Check for SMB2 vs CIFS in find_tcp_session Pavel Shilovsky
     [not found]     ` <1332753703-4315-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 14:01       ` Jeff Layton
     [not found]         ` <20120506100129.0b2f626b-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-07  3:32           ` Steve French
     [not found]             ` <CAH2r5mvX4pfxR4B9TXYcSDOTn3cY0d+Be50zwZ+NhceDOR6vxQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 11:36               ` Jeff Layton
     [not found]                 ` <20120507073636.1d10a9ae-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-07 12:52                   ` Steve French
     [not found]                     ` <CAH2r5mt7hxvaCzaUU0n96p9SVQ6Sso5p6JaYg0gwm6QA0SgHeg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 13:32                       ` Jeff Layton
     [not found]                         ` <20120507093233.04d13b0d-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-07 13:34                           ` Steve French
     [not found]                             ` <CAH2r5msg8C8WMk_+4WYss_109EWec8v2R=vcH4BGmsGtb2tUQw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 13:36                               ` Steve French
     [not found]                                 ` <CAH2r5msOqC=jgX7m6GfKs_S7oMaxzC5rh+0_-ZGLYrVOJri=Vg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 13:51                                   ` Jeff Layton
2012-05-11 17:21           ` Jeff Layton
2012-03-26  9:21   ` [PATCH 04/16] CIFS: Add SMB2 status codes Pavel Shilovsky
     [not found]     ` <1332753703-4315-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 14:10       ` Jeff Layton
2012-03-26  9:21   ` [PATCH 06/16] CIFS: Make transport routines work with SMB2 Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 07/16] CIFS: Add SMB2 credits support Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 08/16] CIFS: Make demultiplex_thread work with SMB2 code Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 09/16] CIFS: Respect SMB2 max hdr size for cifs_request kmem_cache Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 10/16] CIFS: Add capability to send SMB2 negotiate message Pavel Shilovsky
2012-03-26  9:21   ` Pavel Shilovsky [this message]
2012-03-26  9:21   ` [PATCH 12/16] CIFS: Add tree connect/disconnect capability for SMB2 Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 13/16] CIFS: Process reconnects for SMB2 shares Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 14/16] CIFS: Add SMB2 support for is_path_accessible Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 15/16] CIFS: Query SMB2 inode info Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 16/16] CIFS: Get SMB2 mount work Pavel Shilovsky

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=1332753703-4315-12-git-send-email-piastry@etersoft.ru \
    --to=piastry-7qunaywfiewox3rin2dayq@public.gmane.org \
    --cc=linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.