Re: [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel@xxxxxxxx>:
> 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@xxxxxxxx>
> ---
>  fs/cifs/cifspdu.h   |  16 ++++---
>  fs/cifs/cifsproto.h |   5 +++
>  fs/cifs/cifssmb.c   | 119 +++-------------------------------------------------
>  fs/cifs/misc.c      | 105 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 125 insertions(+), 120 deletions(-)
>
> diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
> index f5b8730..1ce733f 100644
> --- a/fs/cifs/cifspdu.h
> +++ b/fs/cifs/cifspdu.h
> @@ -2086,17 +2086,21 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */
>         __u8   ServiceSiteGuid[16];  /* MBZ, ignored */
>  } __attribute__((packed)) REFERRAL3;
>
> -typedef struct smb_com_transaction_get_dfs_refer_rsp {
> -       struct smb_hdr hdr;     /* wct = 10 */
> -       struct trans2_resp t2;
> -       __u16 ByteCount;
> -       __u8 Pad;
> +struct get_dfs_referral_rsp {
>         __le16 PathConsumed;
>         __le16 NumberOfReferrals;
>         __le32 DFSFlags;
>         REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */
>         /* followed by the strings pointed to by the referral structures */
> -} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP;
> +} __packed;
> +
> +typedef struct smb_com_transaction_get_dfs_refer_rsp {
> +       struct smb_hdr hdr;     /* wct = 10 */
> +       struct trans2_resp t2;
> +       __u16 ByteCount;
> +       __u8 Pad;
> +       struct get_dfs_referral_rsp dfs_data;
> +} __packed TRANSACTION2_GET_DFS_REFER_RSP;
>
>  /* DFS Flags */
>  #define DFSREF_REFERRAL_SERVER  0x00000001 /* all targets are DFS roots */
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 406d2c1..c097830 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -284,6 +284,11 @@ extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
>                         const struct nls_table *nls_codepage,
>                         unsigned int *num_referrals,
>                         struct dfs_info3_param **referrals, int remap);
> +extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
> +                              unsigned int *num_of_nodes,
> +                              struct dfs_info3_param **target_nodes,
> +                              const struct nls_table *nls_codepage, int remap,
> +                              const char *searchName, bool is_unicode);
>  extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
>                                  struct cifs_sb_info *cifs_sb,
>                                  struct smb_vol *vol);
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index f5099fb..5005c79 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -4786,117 +4786,6 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
>         return rc;
>  }
>
> -/* parses DFS refferal V3 structure
> - * caller is responsible for freeing target_nodes
> - * returns:
> - *     on success - 0
> - *     on failure - errno
> - */
> -static int
> -parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
> -               unsigned int *num_of_nodes,
> -               struct dfs_info3_param **target_nodes,
> -               const struct nls_table *nls_codepage, int remap,
> -               const char *searchName)
> -{
> -       int i, rc = 0;
> -       char *data_end;
> -       bool is_unicode;
> -       struct dfs_referral_level_3 *ref;
> -
> -       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
> -               is_unicode = true;
> -       else
> -               is_unicode = false;
> -       *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
> -
> -       if (*num_of_nodes < 1) {
> -               cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
> -                        *num_of_nodes);
> -               rc = -EINVAL;
> -               goto parse_DFS_referrals_exit;
> -       }
> -
> -       ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
> -       if (ref->VersionNumber != cpu_to_le16(3)) {
> -               cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
> -                        le16_to_cpu(ref->VersionNumber));
> -               rc = -EINVAL;
> -               goto parse_DFS_referrals_exit;
> -       }
> -
> -       /* get the upper boundary of the resp buffer */
> -       data_end = (char *)(&(pSMBr->PathConsumed)) +
> -                               le16_to_cpu(pSMBr->t2.DataCount);
> -
> -       cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
> -                *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
> -
> -       *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
> -                               GFP_KERNEL);
> -       if (*target_nodes == NULL) {
> -               rc = -ENOMEM;
> -               goto parse_DFS_referrals_exit;
> -       }
> -
> -       /* collect necessary data from referrals */
> -       for (i = 0; i < *num_of_nodes; i++) {
> -               char *temp;
> -               int max_len;
> -               struct dfs_info3_param *node = (*target_nodes)+i;
> -
> -               node->flags = le32_to_cpu(pSMBr->DFSFlags);
> -               if (is_unicode) {
> -                       __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
> -                                               GFP_KERNEL);
> -                       if (tmp == NULL) {
> -                               rc = -ENOMEM;
> -                               goto parse_DFS_referrals_exit;
> -                       }
> -                       cifsConvertToUTF16((__le16 *) tmp, searchName,
> -                                          PATH_MAX, nls_codepage, remap);
> -                       node->path_consumed = cifs_utf16_bytes(tmp,
> -                                       le16_to_cpu(pSMBr->PathConsumed),
> -                                       nls_codepage);
> -                       kfree(tmp);
> -               } else
> -                       node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
> -
> -               node->server_type = le16_to_cpu(ref->ServerType);
> -               node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
> -
> -               /* copy DfsPath */
> -               temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
> -               max_len = data_end - temp;
> -               node->path_name = cifs_strndup_from_utf16(temp, max_len,
> -                                               is_unicode, nls_codepage);
> -               if (!node->path_name) {
> -                       rc = -ENOMEM;
> -                       goto parse_DFS_referrals_exit;
> -               }
> -
> -               /* copy link target UNC */
> -               temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
> -               max_len = data_end - temp;
> -               node->node_name = cifs_strndup_from_utf16(temp, max_len,
> -                                               is_unicode, nls_codepage);
> -               if (!node->node_name) {
> -                       rc = -ENOMEM;
> -                       goto parse_DFS_referrals_exit;
> -               }
> -
> -               ref++;
> -       }
> -
> -parse_DFS_referrals_exit:
> -       if (rc) {
> -               free_dfs_info_array(*target_nodes, *num_of_nodes);
> -               *target_nodes = NULL;
> -               *num_of_nodes = 0;
> -       }
> -       return rc;
> -}
> -
>  int
>  CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
>                 const char *search_name, struct dfs_info3_param **target_nodes,
> @@ -4993,9 +4882,11 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
>                  get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
>
>         /* parse returned result into more usable form */
> -       rc = parse_DFS_referrals(pSMBr, num_of_nodes,
> -                                target_nodes, nls_codepage, remap,
> -                                search_name);
> +       rc = parse_dfs_referrals(&pSMBr->dfs_data,
> +                                le16_to_cpu(pSMBr->t2.DataCount),
> +                                num_of_nodes, target_nodes, nls_codepage,
> +                                remap, search_name,
> +                                pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
>
>  GetDFSRefExit:
>         cifs_buf_release(pSMB);
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index c672915..d3fb115 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -640,3 +640,108 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
>         cifs_add_pending_open_locked(fid, tlink, open);
>         spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
>  }
> +
> +/* parses DFS refferal V3 structure
> + * caller is responsible for freeing target_nodes
> + * returns:
> + * - on success - 0
> + * - on failure - errno
> + */
> +int
> +parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
> +                   unsigned int *num_of_nodes,
> +                   struct dfs_info3_param **target_nodes,
> +                   const struct nls_table *nls_codepage, int remap,
> +                   const char *searchName, bool is_unicode)
> +{
> +       int i, rc = 0;
> +       char *data_end;
> +       struct dfs_referral_level_3 *ref;
> +
> +       *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);
> +
> +       if (*num_of_nodes < 1) {
> +               cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
> +                        *num_of_nodes);
> +               rc = -EINVAL;
> +               goto parse_DFS_referrals_exit;
> +       }
> +
> +       ref = (struct dfs_referral_level_3 *) &(rsp->referrals);
> +       if (ref->VersionNumber != cpu_to_le16(3)) {
> +               cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
> +                        le16_to_cpu(ref->VersionNumber));
> +               rc = -EINVAL;
> +               goto parse_DFS_referrals_exit;
> +       }
> +
> +       /* get the upper boundary of the resp buffer */
> +       data_end = (char *)rsp + rsp_size;
> +
> +       cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
> +                *num_of_nodes, le32_to_cpu(rsp->DFSFlags));
> +
> +       *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
> +                               GFP_KERNEL);
> +       if (*target_nodes == NULL) {
> +               rc = -ENOMEM;
> +               goto parse_DFS_referrals_exit;
> +       }
> +
> +       /* collect necessary data from referrals */
> +       for (i = 0; i < *num_of_nodes; i++) {
> +               char *temp;
> +               int max_len;
> +               struct dfs_info3_param *node = (*target_nodes)+i;
> +
> +               node->flags = le32_to_cpu(rsp->DFSFlags);
> +               if (is_unicode) {
> +                       __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
> +                                               GFP_KERNEL);
> +                       if (tmp == NULL) {
> +                               rc = -ENOMEM;
> +                               goto parse_DFS_referrals_exit;
> +                       }
> +                       cifsConvertToUTF16((__le16 *) tmp, searchName,
> +                                          PATH_MAX, nls_codepage, remap);
> +                       node->path_consumed = cifs_utf16_bytes(tmp,
> +                                       le16_to_cpu(rsp->PathConsumed),
> +                                       nls_codepage);
> +                       kfree(tmp);
> +               } else
> +                       node->path_consumed = le16_to_cpu(rsp->PathConsumed);
> +
> +               node->server_type = le16_to_cpu(ref->ServerType);
> +               node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
> +
> +               /* copy DfsPath */
> +               temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
> +               max_len = data_end - temp;
> +               node->path_name = cifs_strndup_from_utf16(temp, max_len,
> +                                               is_unicode, nls_codepage);
> +               if (!node->path_name) {
> +                       rc = -ENOMEM;
> +                       goto parse_DFS_referrals_exit;
> +               }
> +
> +               /* copy link target UNC */
> +               temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
> +               max_len = data_end - temp;
> +               node->node_name = cifs_strndup_from_utf16(temp, max_len,
> +                                               is_unicode, nls_codepage);
> +               if (!node->node_name) {
> +                       rc = -ENOMEM;
> +                       goto parse_DFS_referrals_exit;
> +               }
> +
> +               ref++;
> +       }
> +
> +parse_DFS_referrals_exit:
> +       if (rc) {
> +               free_dfs_info_array(*target_nodes, *num_of_nodes);
> +               *target_nodes = NULL;
> +               *num_of_nodes = 0;
> +       }
> +       return rc;
> +}
> --
> 2.10.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Acked-by: Pavel Shilovsky <pshilov@xxxxxxxxxxxxx>

-- 
Best regards,
Pavel Shilovsky
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux