1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_READ
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 #include <smbsrv/smb_fsops.h>
  22 
  23 smb_sdrc_t
  24 smb2_read(smb_request_t *sr)
  25 {
  26         smb_ofile_t *of = NULL;
  27         smb_vdb_t *vdb = NULL;
  28         struct mbuf *m = NULL;
  29         uint16_t StructSize;
  30         uint8_t Padding;
  31         uint8_t DataOff;
  32         uint32_t Length;
  33         uint64_t Offset;
  34         smb2fid_t smb2fid;
  35         uint32_t MinCount;
  36         uint32_t Channel;
  37         uint32_t Remaining;
  38         uint16_t ChanInfoOffset;
  39         uint16_t ChanInfoLength;
  40         uint32_t XferCount;
  41         uint32_t status;
  42         int rc = 0;
  43 
  44         /*
  45          * SMB2 Read request
  46          */
  47         rc = smb_mbc_decodef(
  48             &sr->smb_data,
  49             "wb.lqqqlllww",
  50             &StructSize,            /* w */
  51             &Padding,                       /* b. */
  52             &Length,                        /* l */
  53             &Offset,                        /* q */
  54             &smb2fid.persistent,    /* q */
  55             &smb2fid.temporal,              /* q */
  56             &MinCount,                      /* l */
  57             &Channel,                       /* l */
  58             &Remaining,                     /* l */
  59             &ChanInfoOffset,                /* w */
  60             &ChanInfoLength);               /* w */
  61         if (rc)
  62                 return (SDRC_ERROR);
  63         if (StructSize != 49)
  64                 return (SDRC_ERROR);
  65 
  66         status = smb2sr_lookup_fid(sr, &smb2fid);
  67         if (status) {
  68                 smb2sr_put_error(sr, status);
  69                 return (SDRC_SUCCESS);
  70         }
  71         of = sr->fid_ofile;
  72 
  73         if (Length > smb2_max_rwsize) {
  74                 smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
  75                 return (SDRC_SUCCESS);
  76         }
  77         if (MinCount > Length)
  78                 MinCount = Length;
  79 
  80         /* This is automatically free'd. */
  81         vdb = smb_srm_zalloc(sr, sizeof (*vdb));
  82         vdb->vdb_tag = 0;
  83         vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
  84         vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
  85         vdb->vdb_uio.uio_resid = Length;
  86         vdb->vdb_uio.uio_loffset = (offset_t)Offset;
  87         vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
  88         vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
  89 
  90         sr->raw_data.max_bytes = Length;
  91         m = smb_mbuf_allocate(&vdb->vdb_uio);
  92 
  93         switch (of->f_tree->t_res_type & STYPE_MASK) {
  94         case STYPE_DISKTREE:
  95                 if (!smb_node_is_dir(of->f_node)) {
  96                         /* Check for conflicting locks. */
  97                         rc = smb_lock_range_access(sr, of->f_node,
  98                             Offset, Length, B_FALSE);
  99                         if (rc) {
 100                                 rc = ERANGE;
 101                                 break;
 102                         }
 103                 }
 104                 rc = smb_fsop_read(sr, of->f_cr, of->f_node, &vdb->vdb_uio);
 105                 break;
 106         case STYPE_IPC:
 107                 rc = smb_opipe_read(sr, &vdb->vdb_uio);
 108                 break;
 109         default:
 110         case STYPE_PRINTQ:
 111                 rc = EACCES;
 112                 break;
 113         }
 114 
 115         /* How much data we moved. */
 116         XferCount = Length - vdb->vdb_uio.uio_resid;
 117 
 118         sr->raw_data.max_bytes = XferCount;
 119         smb_mbuf_trim(m, XferCount);
 120         MBC_ATTACH_MBUF(&sr->raw_data, m);
 121 
 122         /*
 123          * Checking the error return _after_ dealing with
 124          * the returned data so that if m was allocated,
 125          * it will be free'd via sr->raw_data cleanup.
 126          */
 127         if (rc) {
 128                 smb2sr_put_errno(sr, rc);
 129                 return (SDRC_SUCCESS);
 130         }
 131 
 132         /*
 133          * SMB2 Read reply
 134          */
 135         DataOff = SMB2_HDR_SIZE + 16;
 136         rc = smb_mbc_encodef(
 137             &sr->reply,
 138             "wb.lllC",
 139             17, /* StructSize */        /* w */
 140             DataOff,                    /* b. */
 141             XferCount,                  /* l */
 142             0, /* DataRemaining */      /* l */
 143             0, /* reserved */           /* l */
 144             &sr->raw_data);              /* C */
 145         if (rc)
 146                 return (SDRC_ERROR);
 147 
 148         mutex_enter(&of->f_mutex);
 149         of->f_seek_pos = Offset + XferCount;
 150         mutex_exit(&of->f_mutex);
 151 
 152         return (SDRC_SUCCESS);
 153 }