Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

CIFS: move DFS response parsing out of SMB1 code

since the DFS payload is not tied to the SMB version we can:
* isolate the DFS payload in its own struct, and include that struct in
packet structs
* move the function that parses the response to misc.c and make it work
on the new DFS payload struct (add payload size and utf16 flag as a
result).

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Acked-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <smfrench@gmail.com>

authored by

Aurelien Aptel and committed by
Steve French
4ecce920 61cfac6f

+125 -120
+10 -6
fs/cifs/cifspdu.h
··· 2086 2086 __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ 2087 2087 } __attribute__((packed)) REFERRAL3; 2088 2088 2089 - typedef struct smb_com_transaction_get_dfs_refer_rsp { 2090 - struct smb_hdr hdr; /* wct = 10 */ 2091 - struct trans2_resp t2; 2092 - __u16 ByteCount; 2093 - __u8 Pad; 2089 + struct get_dfs_referral_rsp { 2094 2090 __le16 PathConsumed; 2095 2091 __le16 NumberOfReferrals; 2096 2092 __le32 DFSFlags; 2097 2093 REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ 2098 2094 /* followed by the strings pointed to by the referral structures */ 2099 - } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP; 2095 + } __packed; 2096 + 2097 + typedef struct smb_com_transaction_get_dfs_refer_rsp { 2098 + struct smb_hdr hdr; /* wct = 10 */ 2099 + struct trans2_resp t2; 2100 + __u16 ByteCount; 2101 + __u8 Pad; 2102 + struct get_dfs_referral_rsp dfs_data; 2103 + } __packed TRANSACTION2_GET_DFS_REFER_RSP; 2100 2104 2101 2105 /* DFS Flags */ 2102 2106 #define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */
+5
fs/cifs/cifsproto.h
··· 284 284 const struct nls_table *nls_codepage, 285 285 unsigned int *num_referrals, 286 286 struct dfs_info3_param **referrals, int remap); 287 + extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, 288 + unsigned int *num_of_nodes, 289 + struct dfs_info3_param **target_nodes, 290 + const struct nls_table *nls_codepage, int remap, 291 + const char *searchName, bool is_unicode); 287 292 extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, 288 293 struct cifs_sb_info *cifs_sb, 289 294 struct smb_vol *vol);
+5 -114
fs/cifs/cifssmb.c
··· 4786 4786 return rc; 4787 4787 } 4788 4788 4789 - /* parses DFS refferal V3 structure 4790 - * caller is responsible for freeing target_nodes 4791 - * returns: 4792 - * on success - 0 4793 - * on failure - errno 4794 - */ 4795 - static int 4796 - parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, 4797 - unsigned int *num_of_nodes, 4798 - struct dfs_info3_param **target_nodes, 4799 - const struct nls_table *nls_codepage, int remap, 4800 - const char *searchName) 4801 - { 4802 - int i, rc = 0; 4803 - char *data_end; 4804 - bool is_unicode; 4805 - struct dfs_referral_level_3 *ref; 4806 - 4807 - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) 4808 - is_unicode = true; 4809 - else 4810 - is_unicode = false; 4811 - *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); 4812 - 4813 - if (*num_of_nodes < 1) { 4814 - cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", 4815 - *num_of_nodes); 4816 - rc = -EINVAL; 4817 - goto parse_DFS_referrals_exit; 4818 - } 4819 - 4820 - ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); 4821 - if (ref->VersionNumber != cpu_to_le16(3)) { 4822 - cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n", 4823 - le16_to_cpu(ref->VersionNumber)); 4824 - rc = -EINVAL; 4825 - goto parse_DFS_referrals_exit; 4826 - } 4827 - 4828 - /* get the upper boundary of the resp buffer */ 4829 - data_end = (char *)(&(pSMBr->PathConsumed)) + 4830 - le16_to_cpu(pSMBr->t2.DataCount); 4831 - 4832 - cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n", 4833 - *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags)); 4834 - 4835 - *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param), 4836 - GFP_KERNEL); 4837 - if (*target_nodes == NULL) { 4838 - rc = -ENOMEM; 4839 - goto parse_DFS_referrals_exit; 4840 - } 4841 - 4842 - /* collect necessary data from referrals */ 4843 - for (i = 0; i < *num_of_nodes; i++) { 4844 - char *temp; 4845 - int max_len; 4846 - struct dfs_info3_param *node = (*target_nodes)+i; 4847 - 4848 - node->flags = le32_to_cpu(pSMBr->DFSFlags); 4849 - if (is_unicode) { 4850 - __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, 4851 - GFP_KERNEL); 4852 - if (tmp == NULL) { 4853 - rc = -ENOMEM; 4854 - goto parse_DFS_referrals_exit; 4855 - } 4856 - cifsConvertToUTF16((__le16 *) tmp, searchName, 4857 - PATH_MAX, nls_codepage, remap); 4858 - node->path_consumed = cifs_utf16_bytes(tmp, 4859 - le16_to_cpu(pSMBr->PathConsumed), 4860 - nls_codepage); 4861 - kfree(tmp); 4862 - } else 4863 - node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); 4864 - 4865 - node->server_type = le16_to_cpu(ref->ServerType); 4866 - node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); 4867 - 4868 - /* copy DfsPath */ 4869 - temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); 4870 - max_len = data_end - temp; 4871 - node->path_name = cifs_strndup_from_utf16(temp, max_len, 4872 - is_unicode, nls_codepage); 4873 - if (!node->path_name) { 4874 - rc = -ENOMEM; 4875 - goto parse_DFS_referrals_exit; 4876 - } 4877 - 4878 - /* copy link target UNC */ 4879 - temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); 4880 - max_len = data_end - temp; 4881 - node->node_name = cifs_strndup_from_utf16(temp, max_len, 4882 - is_unicode, nls_codepage); 4883 - if (!node->node_name) { 4884 - rc = -ENOMEM; 4885 - goto parse_DFS_referrals_exit; 4886 - } 4887 - 4888 - ref++; 4889 - } 4890 - 4891 - parse_DFS_referrals_exit: 4892 - if (rc) { 4893 - free_dfs_info_array(*target_nodes, *num_of_nodes); 4894 - *target_nodes = NULL; 4895 - *num_of_nodes = 0; 4896 - } 4897 - return rc; 4898 - } 4899 - 4900 4789 int 4901 4790 CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, 4902 4791 const char *search_name, struct dfs_info3_param **target_nodes, ··· 4882 4993 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); 4883 4994 4884 4995 /* parse returned result into more usable form */ 4885 - rc = parse_DFS_referrals(pSMBr, num_of_nodes, 4886 - target_nodes, nls_codepage, remap, 4887 - search_name); 4996 + rc = parse_dfs_referrals(&pSMBr->dfs_data, 4997 + le16_to_cpu(pSMBr->t2.DataCount), 4998 + num_of_nodes, target_nodes, nls_codepage, 4999 + remap, search_name, 5000 + pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); 4888 5001 4889 5002 GetDFSRefExit: 4890 5003 cifs_buf_release(pSMB);
+105
fs/cifs/misc.c
··· 640 640 cifs_add_pending_open_locked(fid, tlink, open); 641 641 spin_unlock(&tlink_tcon(open->tlink)->open_file_lock); 642 642 } 643 + 644 + /* parses DFS refferal V3 structure 645 + * caller is responsible for freeing target_nodes 646 + * returns: 647 + * - on success - 0 648 + * - on failure - errno 649 + */ 650 + int 651 + parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, 652 + unsigned int *num_of_nodes, 653 + struct dfs_info3_param **target_nodes, 654 + const struct nls_table *nls_codepage, int remap, 655 + const char *searchName, bool is_unicode) 656 + { 657 + int i, rc = 0; 658 + char *data_end; 659 + struct dfs_referral_level_3 *ref; 660 + 661 + *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals); 662 + 663 + if (*num_of_nodes < 1) { 664 + cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", 665 + *num_of_nodes); 666 + rc = -EINVAL; 667 + goto parse_DFS_referrals_exit; 668 + } 669 + 670 + ref = (struct dfs_referral_level_3 *) &(rsp->referrals); 671 + if (ref->VersionNumber != cpu_to_le16(3)) { 672 + cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n", 673 + le16_to_cpu(ref->VersionNumber)); 674 + rc = -EINVAL; 675 + goto parse_DFS_referrals_exit; 676 + } 677 + 678 + /* get the upper boundary of the resp buffer */ 679 + data_end = (char *)rsp + rsp_size; 680 + 681 + cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n", 682 + *num_of_nodes, le32_to_cpu(rsp->DFSFlags)); 683 + 684 + *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param), 685 + GFP_KERNEL); 686 + if (*target_nodes == NULL) { 687 + rc = -ENOMEM; 688 + goto parse_DFS_referrals_exit; 689 + } 690 + 691 + /* collect necessary data from referrals */ 692 + for (i = 0; i < *num_of_nodes; i++) { 693 + char *temp; 694 + int max_len; 695 + struct dfs_info3_param *node = (*target_nodes)+i; 696 + 697 + node->flags = le32_to_cpu(rsp->DFSFlags); 698 + if (is_unicode) { 699 + __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, 700 + GFP_KERNEL); 701 + if (tmp == NULL) { 702 + rc = -ENOMEM; 703 + goto parse_DFS_referrals_exit; 704 + } 705 + cifsConvertToUTF16((__le16 *) tmp, searchName, 706 + PATH_MAX, nls_codepage, remap); 707 + node->path_consumed = cifs_utf16_bytes(tmp, 708 + le16_to_cpu(rsp->PathConsumed), 709 + nls_codepage); 710 + kfree(tmp); 711 + } else 712 + node->path_consumed = le16_to_cpu(rsp->PathConsumed); 713 + 714 + node->server_type = le16_to_cpu(ref->ServerType); 715 + node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); 716 + 717 + /* copy DfsPath */ 718 + temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); 719 + max_len = data_end - temp; 720 + node->path_name = cifs_strndup_from_utf16(temp, max_len, 721 + is_unicode, nls_codepage); 722 + if (!node->path_name) { 723 + rc = -ENOMEM; 724 + goto parse_DFS_referrals_exit; 725 + } 726 + 727 + /* copy link target UNC */ 728 + temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); 729 + max_len = data_end - temp; 730 + node->node_name = cifs_strndup_from_utf16(temp, max_len, 731 + is_unicode, nls_codepage); 732 + if (!node->node_name) { 733 + rc = -ENOMEM; 734 + goto parse_DFS_referrals_exit; 735 + } 736 + 737 + ref++; 738 + } 739 + 740 + parse_DFS_referrals_exit: 741 + if (rc) { 742 + free_dfs_info_array(*target_nodes, *num_of_nodes); 743 + *target_nodes = NULL; 744 + *num_of_nodes = 0; 745 + } 746 + return rc; 747 + }