Loading fs/cifs/cifs_unicode.c +0 −1 Original line number Diff line number Diff line Loading @@ -330,4 +330,3 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, ctoUTF16_out: return i; } fs/cifs/cifs_unicode.h +0 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,6 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen, const struct nls_table *codepage); extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen, const struct nls_table *cp, int mapChars); #endif /* Loading fs/cifs/cifsglob.h +10 −1 Original line number Diff line number Diff line Loading @@ -528,7 +528,7 @@ struct cifs_tcon { char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; char *password; /* for share-level security */ __u16 tid; /* The 2 byte tree id */ __u32 tid; /* The 4 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; #ifdef CONFIG_CIFS_STATS Loading Loading @@ -584,6 +584,15 @@ struct cifs_tcon { bool local_lease:1; /* check leases (only) on local system not remote */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool need_reconnect:1; /* connection reset, tid now invalid */ #ifdef CONFIG_CIFS_SMB2 bool print:1; /* set if connection to printer share */ bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */ __u32 capabilities; __u32 share_flags; __u32 maximal_access; __u32 vol_serial_number; __le64 vol_create_time; #endif /* CONFIG_CIFS_SMB2 */ #ifdef CONFIG_CIFS_FSCACHE u64 resource_id; /* server resource id */ struct fscache_cookie *fscache; /* cookie for share */ Loading fs/cifs/smb2ops.c +2 −0 Original line number Diff line number Diff line Loading @@ -172,6 +172,8 @@ struct smb_version_operations smb21_operations = { .negotiate = smb2_negotiate, .sess_setup = SMB2_sess_setup, .logoff = SMB2_logoff, .tree_connect = SMB2_tcon, .tree_disconnect = SMB2_tdis, }; struct smb_version_values smb21_values = { Loading fs/cifs/smb2pdu.c +157 −2 Original line number Diff line number Diff line Loading @@ -110,8 +110,8 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , hdr->SessionId = tcon->ses->Suid; /* BB check following DFS flags BB */ /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */ /* if (tcon->share_flags & SHI1005_FLAGS_DFS) hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */ if (tcon->share_flags & SHI1005_FLAGS_DFS) hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; /* BB how does SMB2 do case sensitive? */ /* if (tcon->nocase) hdr->Flags |= SMBFLG_CASELESS; */ Loading Loading @@ -549,3 +549,158 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) */ return rc; } static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) { /* cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[code]); */ } #define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, struct cifs_tcon *tcon, const struct nls_table *cp) { struct smb2_tree_connect_req *req; struct smb2_tree_connect_rsp *rsp = NULL; struct kvec iov[2]; int rc = 0; int resp_buftype; int unc_path_len; struct TCP_Server_Info *server; __le16 *unc_path = NULL; cFYI(1, "TCON"); if ((ses->server) && tree) server = ses->server; else return -EIO; if (tcon && tcon->bad_network_name) return -ENOENT; unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); if (unc_path == NULL) return -ENOMEM; unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp) + 1; unc_path_len *= 2; if (unc_path_len < 2) { kfree(unc_path); return -EINVAL; } rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); if (rc) { kfree(unc_path); return rc; } if (tcon == NULL) { /* since no tcon, smb2_init can not do this, so do here */ req->hdr.SessionId = ses->Suid; /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ } iov[0].iov_base = (char *)req; /* 4 for rfc1002 length field and 1 for pad */ iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; /* Testing shows that buffer offset must be at location of Buffer[0] */ req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req) - 1 /* pad */ - 4 /* do not count rfc1001 len field */); req->PathLength = cpu_to_le16(unc_path_len - 2); iov[1].iov_base = unc_path; iov[1].iov_len = unc_path_len; inc_rfc1001_len(req, unc_path_len - 1 /* pad */); rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0); rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base; if (rc != 0) { if (tcon) { cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE); tcon->need_reconnect = true; } goto tcon_error_exit; } if (rsp == NULL) { rc = -EIO; goto tcon_exit; } if (tcon == NULL) { ses->ipc_tid = rsp->hdr.TreeId; goto tcon_exit; } if (rsp->ShareType & SMB2_SHARE_TYPE_DISK) cFYI(1, "connection to disk share"); else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) { tcon->ipc = true; cFYI(1, "connection to pipe share"); } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) { tcon->print = true; cFYI(1, "connection to printer"); } else { cERROR(1, "unknown share type %d", rsp->ShareType); rc = -EOPNOTSUPP; goto tcon_error_exit; } tcon->share_flags = le32_to_cpu(rsp->ShareFlags); tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); tcon->tidStatus = CifsGood; tcon->need_reconnect = false; tcon->tid = rsp->hdr.TreeId; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) cERROR(1, "DFS capability contradicts DFS flag"); tcon_exit: free_rsp_buf(resp_buftype, rsp); kfree(unc_path); return rc; tcon_error_exit: if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { cERROR(1, "BAD_NETWORK_NAME: %s", tree); tcon->bad_network_name = true; } goto tcon_exit; } int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) { struct smb2_tree_disconnect_req *req; /* response is trivial */ int rc = 0; struct TCP_Server_Info *server; struct cifs_ses *ses = tcon->ses; cFYI(1, "Tree Disconnect"); if (ses && (ses->server)) server = ses->server; else return -EIO; if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) return 0; rc = small_smb2_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req); if (rc) return rc; rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0); if (rc) cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); return rc; } Loading
fs/cifs/cifs_unicode.c +0 −1 Original line number Diff line number Diff line Loading @@ -330,4 +330,3 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, ctoUTF16_out: return i; }
fs/cifs/cifs_unicode.h +0 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,6 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen, const struct nls_table *codepage); extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen, const struct nls_table *cp, int mapChars); #endif /* Loading
fs/cifs/cifsglob.h +10 −1 Original line number Diff line number Diff line Loading @@ -528,7 +528,7 @@ struct cifs_tcon { char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; char *password; /* for share-level security */ __u16 tid; /* The 2 byte tree id */ __u32 tid; /* The 4 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; #ifdef CONFIG_CIFS_STATS Loading Loading @@ -584,6 +584,15 @@ struct cifs_tcon { bool local_lease:1; /* check leases (only) on local system not remote */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool need_reconnect:1; /* connection reset, tid now invalid */ #ifdef CONFIG_CIFS_SMB2 bool print:1; /* set if connection to printer share */ bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */ __u32 capabilities; __u32 share_flags; __u32 maximal_access; __u32 vol_serial_number; __le64 vol_create_time; #endif /* CONFIG_CIFS_SMB2 */ #ifdef CONFIG_CIFS_FSCACHE u64 resource_id; /* server resource id */ struct fscache_cookie *fscache; /* cookie for share */ Loading
fs/cifs/smb2ops.c +2 −0 Original line number Diff line number Diff line Loading @@ -172,6 +172,8 @@ struct smb_version_operations smb21_operations = { .negotiate = smb2_negotiate, .sess_setup = SMB2_sess_setup, .logoff = SMB2_logoff, .tree_connect = SMB2_tcon, .tree_disconnect = SMB2_tdis, }; struct smb_version_values smb21_values = { Loading
fs/cifs/smb2pdu.c +157 −2 Original line number Diff line number Diff line Loading @@ -110,8 +110,8 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , hdr->SessionId = tcon->ses->Suid; /* BB check following DFS flags BB */ /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */ /* if (tcon->share_flags & SHI1005_FLAGS_DFS) hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */ if (tcon->share_flags & SHI1005_FLAGS_DFS) hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; /* BB how does SMB2 do case sensitive? */ /* if (tcon->nocase) hdr->Flags |= SMBFLG_CASELESS; */ Loading Loading @@ -549,3 +549,158 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) */ return rc; } static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) { /* cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[code]); */ } #define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, struct cifs_tcon *tcon, const struct nls_table *cp) { struct smb2_tree_connect_req *req; struct smb2_tree_connect_rsp *rsp = NULL; struct kvec iov[2]; int rc = 0; int resp_buftype; int unc_path_len; struct TCP_Server_Info *server; __le16 *unc_path = NULL; cFYI(1, "TCON"); if ((ses->server) && tree) server = ses->server; else return -EIO; if (tcon && tcon->bad_network_name) return -ENOENT; unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); if (unc_path == NULL) return -ENOMEM; unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp) + 1; unc_path_len *= 2; if (unc_path_len < 2) { kfree(unc_path); return -EINVAL; } rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); if (rc) { kfree(unc_path); return rc; } if (tcon == NULL) { /* since no tcon, smb2_init can not do this, so do here */ req->hdr.SessionId = ses->Suid; /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ } iov[0].iov_base = (char *)req; /* 4 for rfc1002 length field and 1 for pad */ iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; /* Testing shows that buffer offset must be at location of Buffer[0] */ req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req) - 1 /* pad */ - 4 /* do not count rfc1001 len field */); req->PathLength = cpu_to_le16(unc_path_len - 2); iov[1].iov_base = unc_path; iov[1].iov_len = unc_path_len; inc_rfc1001_len(req, unc_path_len - 1 /* pad */); rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0); rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base; if (rc != 0) { if (tcon) { cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE); tcon->need_reconnect = true; } goto tcon_error_exit; } if (rsp == NULL) { rc = -EIO; goto tcon_exit; } if (tcon == NULL) { ses->ipc_tid = rsp->hdr.TreeId; goto tcon_exit; } if (rsp->ShareType & SMB2_SHARE_TYPE_DISK) cFYI(1, "connection to disk share"); else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) { tcon->ipc = true; cFYI(1, "connection to pipe share"); } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) { tcon->print = true; cFYI(1, "connection to printer"); } else { cERROR(1, "unknown share type %d", rsp->ShareType); rc = -EOPNOTSUPP; goto tcon_error_exit; } tcon->share_flags = le32_to_cpu(rsp->ShareFlags); tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); tcon->tidStatus = CifsGood; tcon->need_reconnect = false; tcon->tid = rsp->hdr.TreeId; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) cERROR(1, "DFS capability contradicts DFS flag"); tcon_exit: free_rsp_buf(resp_buftype, rsp); kfree(unc_path); return rc; tcon_error_exit: if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { cERROR(1, "BAD_NETWORK_NAME: %s", tree); tcon->bad_network_name = true; } goto tcon_exit; } int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) { struct smb2_tree_disconnect_req *req; /* response is trivial */ int rc = 0; struct TCP_Server_Info *server; struct cifs_ses *ses = tcon->ses; cFYI(1, "Tree Disconnect"); if (ses && (ses->server)) server = ses->server; else return -EIO; if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) return 0; rc = small_smb2_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req); if (rc) return rc; rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0); if (rc) cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); return rc; }