aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2011-12-27 07:04:00 -0500
committerPavel Shilovsky <pshilovsky@samba.org>2012-07-24 13:54:58 -0400
commitfaaf946a7d5b79194358437150f34ab4c66bfe21 (patch)
tree1bf4b4cab6abc39443a63e90cac771f9aaad0f52 /fs/cifs
parent5478f9ba9a34d660eb3227dcd16314689c51f946 (diff)
CIFS: Add tree connect/disconnect capability for SMB2
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifs_unicode.c1
-rw-r--r--fs/cifs/cifs_unicode.h1
-rw-r--r--fs/cifs/cifsglob.h11
-rw-r--r--fs/cifs/smb2ops.c2
-rw-r--r--fs/cifs/smb2pdu.c159
-rw-r--r--fs/cifs/smb2pdu.h57
-rw-r--r--fs/cifs/smb2proto.h4
7 files changed, 230 insertions, 5 deletions
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index fbb9da951843..97c1d4210869 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -330,4 +330,3 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
330ctoUTF16_out: 330ctoUTF16_out:
331 return i; 331 return i;
332} 332}
333
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
index a513a546700b..a44c6eb8a4d7 100644
--- a/fs/cifs/cifs_unicode.h
+++ b/fs/cifs/cifs_unicode.h
@@ -84,7 +84,6 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen,
84 const struct nls_table *codepage); 84 const struct nls_table *codepage);
85extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen, 85extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen,
86 const struct nls_table *cp, int mapChars); 86 const struct nls_table *cp, int mapChars);
87
88#endif 87#endif
89 88
90/* 89/*
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0d78bc410cb3..ef4e0a0bc826 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -528,7 +528,7 @@ struct cifs_tcon {
528 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ 528 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
529 char *nativeFileSystem; 529 char *nativeFileSystem;
530 char *password; /* for share-level security */ 530 char *password; /* for share-level security */
531 __u16 tid; /* The 2 byte tree id */ 531 __u32 tid; /* The 4 byte tree id */
532 __u16 Flags; /* optional support bits */ 532 __u16 Flags; /* optional support bits */
533 enum statusEnum tidStatus; 533 enum statusEnum tidStatus;
534#ifdef CONFIG_CIFS_STATS 534#ifdef CONFIG_CIFS_STATS
@@ -584,6 +584,15 @@ struct cifs_tcon {
584 bool local_lease:1; /* check leases (only) on local system not remote */ 584 bool local_lease:1; /* check leases (only) on local system not remote */
585 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ 585 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
586 bool need_reconnect:1; /* connection reset, tid now invalid */ 586 bool need_reconnect:1; /* connection reset, tid now invalid */
587#ifdef CONFIG_CIFS_SMB2
588 bool print:1; /* set if connection to printer share */
589 bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
590 __u32 capabilities;
591 __u32 share_flags;
592 __u32 maximal_access;
593 __u32 vol_serial_number;
594 __le64 vol_create_time;
595#endif /* CONFIG_CIFS_SMB2 */
587#ifdef CONFIG_CIFS_FSCACHE 596#ifdef CONFIG_CIFS_FSCACHE
588 u64 resource_id; /* server resource id */ 597 u64 resource_id; /* server resource id */
589 struct fscache_cookie *fscache; /* cookie for share */ 598 struct fscache_cookie *fscache; /* cookie for share */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0057861ce19d..0e33ca32abf9 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -172,6 +172,8 @@ struct smb_version_operations smb21_operations = {
172 .negotiate = smb2_negotiate, 172 .negotiate = smb2_negotiate,
173 .sess_setup = SMB2_sess_setup, 173 .sess_setup = SMB2_sess_setup,
174 .logoff = SMB2_logoff, 174 .logoff = SMB2_logoff,
175 .tree_connect = SMB2_tcon,
176 .tree_disconnect = SMB2_tdis,
175}; 177};
176 178
177struct smb_version_values smb21_values = { 179struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 2165f0d15963..1bf037ec5a9d 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -110,8 +110,8 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
110 hdr->SessionId = tcon->ses->Suid; 110 hdr->SessionId = tcon->ses->Suid;
111 /* BB check following DFS flags BB */ 111 /* BB check following DFS flags BB */
112 /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */ 112 /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */
113 /* if (tcon->share_flags & SHI1005_FLAGS_DFS) 113 if (tcon->share_flags & SHI1005_FLAGS_DFS)
114 hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */ 114 hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS;
115 /* BB how does SMB2 do case sensitive? */ 115 /* BB how does SMB2 do case sensitive? */
116 /* if (tcon->nocase) 116 /* if (tcon->nocase)
117 hdr->Flags |= SMBFLG_CASELESS; */ 117 hdr->Flags |= SMBFLG_CASELESS; */
@@ -549,3 +549,158 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
549 */ 549 */
550 return rc; 550 return rc;
551} 551}
552
553static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code)
554{
555 /* cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[code]); */
556}
557
558#define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */)
559
560int
561SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
562 struct cifs_tcon *tcon, const struct nls_table *cp)
563{
564 struct smb2_tree_connect_req *req;
565 struct smb2_tree_connect_rsp *rsp = NULL;
566 struct kvec iov[2];
567 int rc = 0;
568 int resp_buftype;
569 int unc_path_len;
570 struct TCP_Server_Info *server;
571 __le16 *unc_path = NULL;
572
573 cFYI(1, "TCON");
574
575 if ((ses->server) && tree)
576 server = ses->server;
577 else
578 return -EIO;
579
580 if (tcon && tcon->bad_network_name)
581 return -ENOENT;
582
583 unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
584 if (unc_path == NULL)
585 return -ENOMEM;
586
587 unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp) + 1;
588 unc_path_len *= 2;
589 if (unc_path_len < 2) {
590 kfree(unc_path);
591 return -EINVAL;
592 }
593
594 rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req);
595 if (rc) {
596 kfree(unc_path);
597 return rc;
598 }
599
600 if (tcon == NULL) {
601 /* since no tcon, smb2_init can not do this, so do here */
602 req->hdr.SessionId = ses->Suid;
603 /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
604 req->hdr.Flags |= SMB2_FLAGS_SIGNED; */
605 }
606
607 iov[0].iov_base = (char *)req;
608 /* 4 for rfc1002 length field and 1 for pad */
609 iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
610
611 /* Testing shows that buffer offset must be at location of Buffer[0] */
612 req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req)
613 - 1 /* pad */ - 4 /* do not count rfc1001 len field */);
614 req->PathLength = cpu_to_le16(unc_path_len - 2);
615 iov[1].iov_base = unc_path;
616 iov[1].iov_len = unc_path_len;
617
618 inc_rfc1001_len(req, unc_path_len - 1 /* pad */);
619
620 rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
621 rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base;
622
623 if (rc != 0) {
624 if (tcon) {
625 cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE);
626 tcon->need_reconnect = true;
627 }
628 goto tcon_error_exit;
629 }
630
631 if (rsp == NULL) {
632 rc = -EIO;
633 goto tcon_exit;
634 }
635
636 if (tcon == NULL) {
637 ses->ipc_tid = rsp->hdr.TreeId;
638 goto tcon_exit;
639 }
640
641 if (rsp->ShareType & SMB2_SHARE_TYPE_DISK)
642 cFYI(1, "connection to disk share");
643 else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) {
644 tcon->ipc = true;
645 cFYI(1, "connection to pipe share");
646 } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) {
647 tcon->print = true;
648 cFYI(1, "connection to printer");
649 } else {
650 cERROR(1, "unknown share type %d", rsp->ShareType);
651 rc = -EOPNOTSUPP;
652 goto tcon_error_exit;
653 }
654
655 tcon->share_flags = le32_to_cpu(rsp->ShareFlags);
656 tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
657 tcon->tidStatus = CifsGood;
658 tcon->need_reconnect = false;
659 tcon->tid = rsp->hdr.TreeId;
660 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
661
662 if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
663 ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
664 cERROR(1, "DFS capability contradicts DFS flag");
665
666tcon_exit:
667 free_rsp_buf(resp_buftype, rsp);
668 kfree(unc_path);
669 return rc;
670
671tcon_error_exit:
672 if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
673 cERROR(1, "BAD_NETWORK_NAME: %s", tree);
674 tcon->bad_network_name = true;
675 }
676 goto tcon_exit;
677}
678
679int
680SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
681{
682 struct smb2_tree_disconnect_req *req; /* response is trivial */
683 int rc = 0;
684 struct TCP_Server_Info *server;
685 struct cifs_ses *ses = tcon->ses;
686
687 cFYI(1, "Tree Disconnect");
688
689 if (ses && (ses->server))
690 server = ses->server;
691 else
692 return -EIO;
693
694 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
695 return 0;
696
697 rc = small_smb2_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req);
698 if (rc)
699 return rc;
700
701 rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0);
702 if (rc)
703 cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
704
705 return rc;
706}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 26af68b2955a..aa77bf3a7a69 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -224,4 +224,61 @@ struct smb2_logoff_rsp {
224 __le16 Reserved; 224 __le16 Reserved;
225} __packed; 225} __packed;
226 226
227struct smb2_tree_connect_req {
228 struct smb2_hdr hdr;
229 __le16 StructureSize; /* Must be 9 */
230 __le16 Reserved;
231 __le16 PathOffset;
232 __le16 PathLength;
233 __u8 Buffer[1]; /* variable length */
234} __packed;
235
236struct smb2_tree_connect_rsp {
237 struct smb2_hdr hdr;
238 __le16 StructureSize; /* Must be 16 */
239 __u8 ShareType; /* see below */
240 __u8 Reserved;
241 __le32 ShareFlags; /* see below */
242 __le32 Capabilities; /* see below */
243 __le32 MaximalAccess;
244} __packed;
245
246/* Possible ShareType values */
247#define SMB2_SHARE_TYPE_DISK 0x01
248#define SMB2_SHARE_TYPE_PIPE 0x02
249#define SMB2_SHARE_TYPE_PRINT 0x03
250
251/*
252 * Possible ShareFlags - exactly one and only one of the first 4 caching flags
253 * must be set (any of the remaining, SHI1005, flags may be set individually
254 * or in combination.
255 */
256#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000
257#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010
258#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020
259#define SMB2_SHAREFLAG_NO_CACHING 0x00000030
260#define SHI1005_FLAGS_DFS 0x00000001
261#define SHI1005_FLAGS_DFS_ROOT 0x00000002
262#define SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS 0x00000100
263#define SHI1005_FLAGS_FORCE_SHARED_DELETE 0x00000200
264#define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING 0x00000400
265#define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x00000800
266#define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK 0x00001000
267#define SHI1005_FLAGS_ENABLE_HASH 0x00002000
268
269/* Possible share capabilities */
270#define SMB2_SHARE_CAP_DFS cpu_to_le32(0x00000008)
271
272struct smb2_tree_disconnect_req {
273 struct smb2_hdr hdr;
274 __le16 StructureSize; /* Must be 4 */
275 __le16 Reserved;
276} __packed;
277
278struct smb2_tree_disconnect_rsp {
279 struct smb2_hdr hdr;
280 __le16 StructureSize; /* Must be 4 */
281 __le16 Reserved;
282} __packed;
283
227#endif /* _SMB2PDU_H */ 284#endif /* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 9364fbcb90c6..bc7299349dbf 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -50,5 +50,9 @@ extern int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses);
50extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, 50extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
51 const struct nls_table *nls_cp); 51 const struct nls_table *nls_cp);
52extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); 52extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses);
53extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
54 const char *tree, struct cifs_tcon *tcon,
55 const struct nls_table *);
56extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
53 57
54#endif /* _SMB2PROTO_H */ 58#endif /* _SMB2PROTO_H */