15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
22*12890SJoyce.McIntosh@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw */
245331Samw
2510966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
265331Samw #include <smbsrv/smb_fsops.h>
275331Samw
28*12890SJoyce.McIntosh@Sun.COM /*
29*12890SJoyce.McIntosh@Sun.COM * There may be oplock break requests waiting to be sent after
30*12890SJoyce.McIntosh@Sun.COM * a read raw request completes.
31*12890SJoyce.McIntosh@Sun.COM */
32*12890SJoyce.McIntosh@Sun.COM #define SMB_OPLOCK_BREAKS_PENDING(sr) \
33*12890SJoyce.McIntosh@Sun.COM !list_is_empty(&(sr)->session->s_oplock_brkreqs)
345331Samw
358934SJose.Borrego@Sun.COM /*
368934SJose.Borrego@Sun.COM * The maximum number of bytes to return from SMB Core
378934SJose.Borrego@Sun.COM * SmbRead or SmbLockAndRead.
388934SJose.Borrego@Sun.COM */
398934SJose.Borrego@Sun.COM #define SMB_CORE_READ_MAX 4432
408934SJose.Borrego@Sun.COM
418934SJose.Borrego@Sun.COM /*
428934SJose.Borrego@Sun.COM * The limit in bytes for SmbReadX.
438934SJose.Borrego@Sun.COM */
448934SJose.Borrego@Sun.COM #define SMB_READX_MAX 0x10000
458934SJose.Borrego@Sun.COM
466139Sjb150015 int smb_common_read(smb_request_t *, smb_rw_param_t *);
475331Samw
485331Samw /*
495331Samw * Read bytes from a file or named pipe (SMB Core).
505331Samw *
515331Samw * The requested count specifies the number of bytes desired. Offset
525331Samw * is limited to 32 bits, so this client request is inappropriate for
535331Samw * files with 64 bit offsets.
545331Samw *
555331Samw * On return, count is the number of bytes actually being returned, which
565331Samw * may be less than the count requested only if a read specifies bytes
575331Samw * beyond the current file size. In this case only the bytes that exist
585331Samw * are returned. A read completely beyond the end of file results in a
595331Samw * response of length zero. This is the only circumstance when a zero
605331Samw * length response is generated. A count returned which is less than the
615331Samw * count requested is the end of file indicator.
625331Samw */
636030Sjb150015 smb_sdrc_t
smb_pre_read(smb_request_t * sr)646139Sjb150015 smb_pre_read(smb_request_t *sr)
655331Samw {
666139Sjb150015 smb_rw_param_t *param;
675331Samw uint32_t off_low;
688934SJose.Borrego@Sun.COM uint16_t count;
695331Samw uint16_t remcnt;
705331Samw int rc;
715331Samw
726139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
736139Sjb150015 sr->arg.rw = param;
746139Sjb150015
755331Samw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
768934SJose.Borrego@Sun.COM &count, &off_low, &remcnt);
776139Sjb150015
786139Sjb150015 param->rw_offset = (uint64_t)off_low;
798934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count;
806139Sjb150015 param->rw_mincnt = 0;
816139Sjb150015
826139Sjb150015 DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
836139Sjb150015 smb_rw_param_t *, param);
846139Sjb150015
856139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
866139Sjb150015 }
875331Samw
886139Sjb150015 void
smb_post_read(smb_request_t * sr)896139Sjb150015 smb_post_read(smb_request_t *sr)
906139Sjb150015 {
916139Sjb150015 DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
926139Sjb150015 smb_rw_param_t *, sr->arg.rw);
936139Sjb150015
946139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
956139Sjb150015 }
966139Sjb150015
976139Sjb150015 smb_sdrc_t
smb_com_read(smb_request_t * sr)986139Sjb150015 smb_com_read(smb_request_t *sr)
996139Sjb150015 {
1006139Sjb150015 smb_rw_param_t *param = sr->arg.rw;
1018934SJose.Borrego@Sun.COM uint16_t count;
1026139Sjb150015 int rc;
1035331Samw
1048934SJose.Borrego@Sun.COM smbsr_lookup_file(sr);
1055331Samw if (sr->fid_ofile == NULL) {
1065772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1076139Sjb150015 return (SDRC_ERROR);
1085331Samw }
1095331Samw
1107961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
1117961SNatalie.Li@Sun.COM
1128934SJose.Borrego@Sun.COM if (param->rw_count > SMB_CORE_READ_MAX)
1138934SJose.Borrego@Sun.COM param->rw_count = SMB_CORE_READ_MAX;
1148934SJose.Borrego@Sun.COM
1156139Sjb150015 if ((rc = smb_common_read(sr, param)) != 0) {
1165772Sas200622 smbsr_errno(sr, rc);
1176139Sjb150015 return (SDRC_ERROR);
1185331Samw }
1195331Samw
1208934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count;
1216030Sjb150015 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
1228934SJose.Borrego@Sun.COM 5, count, VAR_BCC, 0x01, count, &sr->raw_data);
1235331Samw
1246139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1255331Samw }
1265331Samw
1275331Samw /*
1285331Samw * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/
1295331Samw * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
1305331Samw * attempt to use it on non-disk shares.
1315331Samw *
1325331Samw * The requested count specifies the number of bytes desired. Offset
1335331Samw * specifies the offset in the file of the first byte to be locked then
1345331Samw * read. Note that offset is limited to 32 bits, so this client request
1355331Samw * is inappropriate for files with 64 bit offsets.
1365331Samw *
1375331Samw * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
1385331Samw * immediately an error should be returned to the client. If an error
1395331Samw * occurs on the lock, the bytes should not be read.
1405331Samw *
1415331Samw * On return, count is the number of bytes actually being returned, which
1425331Samw * may be less than the count requested only if a read specifies bytes
1435331Samw * beyond the current file size. In this case only the bytes that exist
1445331Samw * are returned. A read completely beyond the end of file results in a
1455331Samw * response of length zero. This is the only circumstance when a zero
1465331Samw * length response is generated. A count returned which is less than the
1475331Samw * count requested is the end of file indicator.
1485331Samw */
1496030Sjb150015 smb_sdrc_t
smb_pre_lock_and_read(smb_request_t * sr)1506139Sjb150015 smb_pre_lock_and_read(smb_request_t *sr)
1515331Samw {
1526139Sjb150015 smb_rw_param_t *param;
1538934SJose.Borrego@Sun.COM uint32_t off_low;
1548934SJose.Borrego@Sun.COM uint16_t count;
1555331Samw uint16_t remcnt;
1566139Sjb150015 int rc;
1576139Sjb150015
1586139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
1596139Sjb150015 sr->arg.rw = param;
1606139Sjb150015
1616139Sjb150015 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
1628934SJose.Borrego@Sun.COM &count, &off_low, &remcnt);
1636139Sjb150015
1646139Sjb150015 param->rw_offset = (uint64_t)off_low;
1658934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count;
1666139Sjb150015 param->rw_mincnt = 0;
1676139Sjb150015
1686139Sjb150015 DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
1696139Sjb150015 smb_rw_param_t *, param);
1706139Sjb150015
1716139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1726139Sjb150015 }
1736139Sjb150015
1746139Sjb150015 void
smb_post_lock_and_read(smb_request_t * sr)1756139Sjb150015 smb_post_lock_and_read(smb_request_t *sr)
1766139Sjb150015 {
1776139Sjb150015 DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
1786139Sjb150015 smb_rw_param_t *, sr->arg.rw);
1796139Sjb150015
1806139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
1816139Sjb150015 }
1826139Sjb150015
1836139Sjb150015 smb_sdrc_t
smb_com_lock_and_read(smb_request_t * sr)1846139Sjb150015 smb_com_lock_and_read(smb_request_t *sr)
1856139Sjb150015 {
1866139Sjb150015 smb_rw_param_t *param = sr->arg.rw;
1876139Sjb150015 DWORD status;
1888934SJose.Borrego@Sun.COM uint16_t count;
1895331Samw int rc;
1905331Samw
1915331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
1925772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
1936139Sjb150015 return (SDRC_ERROR);
1945331Samw }
1955331Samw
1968934SJose.Borrego@Sun.COM smbsr_lookup_file(sr);
1975331Samw if (sr->fid_ofile == NULL) {
1985772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1996139Sjb150015 return (SDRC_ERROR);
2005331Samw }
2015331Samw
2027961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
2037961SNatalie.Li@Sun.COM
2046432Sas200622 status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
2058934SJose.Borrego@Sun.COM 0, SMB_LOCK_TYPE_READWRITE);
2068934SJose.Borrego@Sun.COM
2076139Sjb150015 if (status != NT_STATUS_SUCCESS) {
2086139Sjb150015 smb_lock_range_error(sr, status);
2096139Sjb150015 return (SDRC_ERROR);
2105331Samw }
2115331Samw
2128934SJose.Borrego@Sun.COM if (param->rw_count > SMB_CORE_READ_MAX)
2138934SJose.Borrego@Sun.COM param->rw_count = SMB_CORE_READ_MAX;
2148934SJose.Borrego@Sun.COM
2156139Sjb150015 if ((rc = smb_common_read(sr, param)) != 0) {
2165772Sas200622 smbsr_errno(sr, rc);
2176139Sjb150015 return (SDRC_ERROR);
2185331Samw }
2195331Samw
2208934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count;
2216030Sjb150015 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
2228934SJose.Borrego@Sun.COM 5, count, VAR_BCC, 0x1, count, &sr->raw_data);
2235331Samw
2246139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2255331Samw }
2265331Samw
2275331Samw /*
2285331Samw * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
2295331Samw * SMB Core Plus to maximize performance when reading a large block
2305331Samw * of data from a server. This request was extended in LM 0.12 to
2315331Samw * support 64-bit offsets; the server can indicate support by setting
2325331Samw * CAP_LARGE_FILES in the negotiated capabilities.
2335331Samw *
2345331Samw * The client must guarantee that there is (and will be) no other request
2355331Samw * to the server for the duration of the SMB_COM_READ_RAW, since the
2365331Samw * server response has no header or trailer. To help ensure that there
2375331Samw * are no interruptions, we block all I/O for the session during read raw.
2385331Samw *
2395331Samw * If this is the first SMB request received since we sent an oplock break
2405331Samw * to this client, we don't know if it's safe to send the raw data because
2415331Samw * the requests may have crossed on the wire and the client may have
2425331Samw * interpreted the oplock break as part of the raw data. To avoid problems,
2435331Samw * we send a zero length session packet, which will force the client to
2445331Samw * retry the read.
2455331Samw *
2468934SJose.Borrego@Sun.COM * Do not return errors from SmbReadRaw.
2475331Samw * Read errors are handled by sending a zero length response.
2485331Samw */
2496030Sjb150015 smb_sdrc_t
smb_pre_read_raw(smb_request_t * sr)2506139Sjb150015 smb_pre_read_raw(smb_request_t *sr)
2515331Samw {
2526139Sjb150015 smb_rw_param_t *param;
2536139Sjb150015 uint32_t off_low;
2546139Sjb150015 uint32_t off_high;
2556139Sjb150015 uint32_t timeout;
2568934SJose.Borrego@Sun.COM uint16_t count;
2576139Sjb150015 int rc;
2586139Sjb150015
2596139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
2606139Sjb150015 sr->arg.rw = param;
2616139Sjb150015
2626139Sjb150015 if (sr->smb_wct == 8) {
2636139Sjb150015 rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
2648934SJose.Borrego@Sun.COM &off_low, &count, ¶m->rw_mincnt, &timeout);
2658934SJose.Borrego@Sun.COM if (rc == 0) {
2668934SJose.Borrego@Sun.COM param->rw_offset = (uint64_t)off_low;
2678934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count;
2688934SJose.Borrego@Sun.COM }
2696139Sjb150015 } else {
2706139Sjb150015 rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
2718934SJose.Borrego@Sun.COM &off_low, &count, ¶m->rw_mincnt, &timeout, &off_high);
2728934SJose.Borrego@Sun.COM if (rc == 0) {
2738934SJose.Borrego@Sun.COM param->rw_offset = ((uint64_t)off_high << 32) | off_low;
2748934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count;
2758934SJose.Borrego@Sun.COM }
2766139Sjb150015 }
2776139Sjb150015
2786139Sjb150015 DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
2796139Sjb150015 smb_rw_param_t *, param);
2806139Sjb150015
2819343SAfshin.Ardakani@Sun.COM smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
2828934SJose.Borrego@Sun.COM return (SDRC_SUCCESS);
2836139Sjb150015 }
2846139Sjb150015
2856139Sjb150015 void
smb_post_read_raw(smb_request_t * sr)2866139Sjb150015 smb_post_read_raw(smb_request_t *sr)
2876139Sjb150015 {
2888934SJose.Borrego@Sun.COM mbuf_chain_t *mbc;
2898934SJose.Borrego@Sun.COM
2908934SJose.Borrego@Sun.COM if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
291*12890SJoyce.McIntosh@Sun.COM if (SMB_OPLOCK_BREAKS_PENDING(sr)) {
292*12890SJoyce.McIntosh@Sun.COM sr->session->s_state =
293*12890SJoyce.McIntosh@Sun.COM SMB_SESSION_STATE_OPLOCK_BREAKING;
294*12890SJoyce.McIntosh@Sun.COM } else {
295*12890SJoyce.McIntosh@Sun.COM sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
296*12890SJoyce.McIntosh@Sun.COM }
2978934SJose.Borrego@Sun.COM
2988934SJose.Borrego@Sun.COM while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
2998934SJose.Borrego@Sun.COM NULL) {
3008934SJose.Borrego@Sun.COM SMB_MBC_VALID(mbc);
3018934SJose.Borrego@Sun.COM list_remove(&sr->session->s_oplock_brkreqs, mbc);
3028934SJose.Borrego@Sun.COM (void) smb_session_send(sr->session, 0, mbc);
3038934SJose.Borrego@Sun.COM smb_mbc_free(mbc);
3048934SJose.Borrego@Sun.COM }
3058934SJose.Borrego@Sun.COM }
3068934SJose.Borrego@Sun.COM
3076139Sjb150015 DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
3086139Sjb150015 smb_rw_param_t *, sr->arg.rw);
3096139Sjb150015
3109343SAfshin.Ardakani@Sun.COM smb_rwx_rwexit(&sr->session->s_lock);
3116139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
3126139Sjb150015 }
3136139Sjb150015
3146139Sjb150015 smb_sdrc_t
smb_com_read_raw(smb_request_t * sr)3156139Sjb150015 smb_com_read_raw(smb_request_t *sr)
3166139Sjb150015 {
3176139Sjb150015 smb_rw_param_t *param = sr->arg.rw;
3185331Samw
319*12890SJoyce.McIntosh@Sun.COM if (!smb_raw_mode)
320*12890SJoyce.McIntosh@Sun.COM return (SDRC_DROP_VC);
321*12890SJoyce.McIntosh@Sun.COM
3225331Samw switch (sr->session->s_state) {
3235331Samw case SMB_SESSION_STATE_NEGOTIATED:
3248934SJose.Borrego@Sun.COM sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
3256139Sjb150015 break;
3265331Samw
3275331Samw case SMB_SESSION_STATE_OPLOCK_BREAKING:
3285331Samw (void) smb_session_send(sr->session, 0, NULL);
3295331Samw return (SDRC_NO_REPLY);
3305331Samw
3315331Samw case SMB_SESSION_STATE_TERMINATED:
3325331Samw case SMB_SESSION_STATE_DISCONNECTED:
3335331Samw return (SDRC_NO_REPLY);
3345331Samw
3358934SJose.Borrego@Sun.COM case SMB_SESSION_STATE_READ_RAW_ACTIVE:
3368934SJose.Borrego@Sun.COM sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
3378934SJose.Borrego@Sun.COM return (SDRC_DROP_VC);
3388934SJose.Borrego@Sun.COM
3396139Sjb150015 case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
3405331Samw case SMB_SESSION_STATE_CONNECTED:
3415331Samw case SMB_SESSION_STATE_ESTABLISHED:
3425331Samw default:
3435331Samw return (SDRC_DROP_VC);
3445331Samw }
3456139Sjb150015
3468934SJose.Borrego@Sun.COM smbsr_lookup_file(sr);
3476139Sjb150015 if (sr->fid_ofile == NULL) {
3488934SJose.Borrego@Sun.COM (void) smb_session_send(sr->session, 0, NULL);
3498934SJose.Borrego@Sun.COM return (SDRC_NO_REPLY);
3506139Sjb150015 }
3516139Sjb150015
3527961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
3537961SNatalie.Li@Sun.COM
3548934SJose.Borrego@Sun.COM if (param->rw_mincnt > param->rw_count)
3558934SJose.Borrego@Sun.COM param->rw_mincnt = 0;
3566139Sjb150015
357*12890SJoyce.McIntosh@Sun.COM if ((smb_common_read(sr, param) != 0) ||
358*12890SJoyce.McIntosh@Sun.COM (SMB_OPLOCK_BREAKS_PENDING(sr))) {
3596139Sjb150015 (void) smb_session_send(sr->session, 0, NULL);
3606139Sjb150015 m_freem(sr->raw_data.chain);
3618934SJose.Borrego@Sun.COM sr->raw_data.chain = NULL;
3626139Sjb150015 } else {
3636139Sjb150015 (void) smb_session_send(sr->session, 0, &sr->raw_data);
3646139Sjb150015 }
3656139Sjb150015
3666139Sjb150015 return (SDRC_NO_REPLY);
3675331Samw }
3685331Samw
3695331Samw /*
3705331Samw * Read bytes from a file (SMB Core). This request was extended in
3715331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
3725331Samw * 12 and including additional offset information.
3738934SJose.Borrego@Sun.COM *
3748934SJose.Borrego@Sun.COM * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
3758934SJose.Borrego@Sun.COM * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
3768934SJose.Borrego@Sun.COM * than the negotiated buffer size. If maxcnt_high is 0xFF, it must
3778934SJose.Borrego@Sun.COM * be ignored. Otherwise, maxcnt_high represents the upper 16 bits
3788934SJose.Borrego@Sun.COM * of rw_count.
3795331Samw */
3806030Sjb150015 smb_sdrc_t
smb_pre_read_andx(smb_request_t * sr)3816139Sjb150015 smb_pre_read_andx(smb_request_t *sr)
3825331Samw {
3836139Sjb150015 smb_rw_param_t *param;
3845331Samw uint32_t off_low;
3855331Samw uint32_t off_high;
3868934SJose.Borrego@Sun.COM uint32_t maxcnt_high;
3878934SJose.Borrego@Sun.COM uint16_t maxcnt_low;
3888934SJose.Borrego@Sun.COM uint16_t mincnt;
3895331Samw uint16_t remcnt;
3905331Samw int rc;
3915331Samw
3926139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
3936139Sjb150015 sr->arg.rw = param;
3946139Sjb150015
3955331Samw if (sr->smb_wct == 12) {
3968934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", ¶m->rw_andx,
3978934SJose.Borrego@Sun.COM &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
3988934SJose.Borrego@Sun.COM &remcnt, &off_high);
3998934SJose.Borrego@Sun.COM
4008934SJose.Borrego@Sun.COM param->rw_offset = ((uint64_t)off_high << 32) |
4018934SJose.Borrego@Sun.COM (uint64_t)off_low;
4025331Samw
4038934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)maxcnt_low;
4048938Samw@Sun.COM
4058938Samw@Sun.COM if ((sr->session->capabilities & CAP_LARGE_READX) &&
4068938Samw@Sun.COM (maxcnt_high < 0xFF))
4078934SJose.Borrego@Sun.COM param->rw_count |= maxcnt_high << 16;
4085331Samw } else {
4098934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "b3.wlwwlw", ¶m->rw_andx,
4108934SJose.Borrego@Sun.COM &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
4118934SJose.Borrego@Sun.COM &remcnt);
4125331Samw
4136139Sjb150015 param->rw_offset = (uint64_t)off_low;
4148934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)maxcnt_low;
4155331Samw }
4165331Samw
4176139Sjb150015 param->rw_mincnt = 0;
4186139Sjb150015
4196139Sjb150015 DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
4206139Sjb150015 smb_rw_param_t *, param);
4216139Sjb150015
4226139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
4236139Sjb150015 }
4245331Samw
4256139Sjb150015 void
smb_post_read_andx(smb_request_t * sr)4266139Sjb150015 smb_post_read_andx(smb_request_t *sr)
4276139Sjb150015 {
4286139Sjb150015 DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
4296139Sjb150015 smb_rw_param_t *, sr->arg.rw);
4306139Sjb150015
4316139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
4326139Sjb150015 }
4336139Sjb150015
4346139Sjb150015 smb_sdrc_t
smb_com_read_andx(smb_request_t * sr)4356139Sjb150015 smb_com_read_andx(smb_request_t *sr)
4366139Sjb150015 {
4376139Sjb150015 smb_rw_param_t *param = sr->arg.rw;
4388934SJose.Borrego@Sun.COM uint16_t datalen_high;
4398934SJose.Borrego@Sun.COM uint16_t datalen_low;
4408934SJose.Borrego@Sun.COM uint16_t data_offset;
4416139Sjb150015 uint16_t offset2;
4426139Sjb150015 int rc;
4435331Samw
4448934SJose.Borrego@Sun.COM smbsr_lookup_file(sr);
4455331Samw if (sr->fid_ofile == NULL) {
4465772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
4476139Sjb150015 return (SDRC_ERROR);
4485331Samw }
4495331Samw
4507961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
4517961SNatalie.Li@Sun.COM
4528934SJose.Borrego@Sun.COM if (param->rw_count >= SMB_READX_MAX)
4538934SJose.Borrego@Sun.COM param->rw_count = 0;
4548934SJose.Borrego@Sun.COM
4556139Sjb150015 if ((rc = smb_common_read(sr, param)) != 0) {
4565772Sas200622 smbsr_errno(sr, rc);
4576139Sjb150015 return (SDRC_ERROR);
4585331Samw }
4595331Samw
4608934SJose.Borrego@Sun.COM datalen_low = param->rw_count & 0xFFFF;
4618934SJose.Borrego@Sun.COM datalen_high = (param->rw_count >> 16) & 0xFF;
4625331Samw
4635331Samw /*
4648934SJose.Borrego@Sun.COM * If this is a secondary command, the data offset
4658934SJose.Borrego@Sun.COM * includes the previous wct + sizeof(wct).
4665331Samw */
4678934SJose.Borrego@Sun.COM data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
4688934SJose.Borrego@Sun.COM
4695331Samw if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
4708934SJose.Borrego@Sun.COM data_offset += 60;
4718934SJose.Borrego@Sun.COM offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
4728934SJose.Borrego@Sun.COM
4738934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
4745331Samw 12, /* wct */
4758934SJose.Borrego@Sun.COM param->rw_andx, /* secondary andx command */
4768934SJose.Borrego@Sun.COM offset2, /* offset to next command */
4778934SJose.Borrego@Sun.COM 0, /* set to 0 for named pipes */
4788934SJose.Borrego@Sun.COM datalen_low, /* data byte count */
4798934SJose.Borrego@Sun.COM data_offset, /* offset from start to data */
4808934SJose.Borrego@Sun.COM datalen_high, /* data byte count */
4815331Samw VAR_BCC, /* BCC marker */
4828934SJose.Borrego@Sun.COM 0x00, /* padding */
4835331Samw &sr->raw_data);
4845331Samw } else {
4858934SJose.Borrego@Sun.COM data_offset += 59;
4868934SJose.Borrego@Sun.COM offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
4878934SJose.Borrego@Sun.COM
4888934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
4895331Samw 12, /* wct */
4908934SJose.Borrego@Sun.COM param->rw_andx, /* secondary andx command */
4918934SJose.Borrego@Sun.COM offset2, /* offset to next command */
4928934SJose.Borrego@Sun.COM -1, /* must be -1 for regular files */
4938934SJose.Borrego@Sun.COM datalen_low, /* data byte count */
4948934SJose.Borrego@Sun.COM data_offset, /* offset from start to data */
4958934SJose.Borrego@Sun.COM datalen_high, /* data byte count */
4965331Samw VAR_BCC, /* BCC marker */
4975331Samw &sr->raw_data);
4985331Samw }
4995331Samw
5006139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
5015331Samw }
5025331Samw
5035331Samw /*
5045331Samw * Common function for reading files or IPC/MSRPC named pipes. All
5055331Samw * protocol read functions should lookup the fid before calling this
5065331Samw * function. We can't move the fid lookup here because lock-and-read
5075331Samw * requires the fid to do locking before attempting the read.
5085331Samw *
509*12890SJoyce.McIntosh@Sun.COM * Reading from a file should break oplocks on the file to LEVEL_II.
510*12890SJoyce.McIntosh@Sun.COM * A call to smb_oplock_break(SMB_OPLOCK_BREAK_TO_LEVEL_II) is not
511*12890SJoyce.McIntosh@Sun.COM * required as it is a no-op. If there's anything greater than a
512*12890SJoyce.McIntosh@Sun.COM * LEVEL_II oplock on the file, the oplock MUST be owned by the ofile
513*12890SJoyce.McIntosh@Sun.COM * on which the read is occuring and therefore would not be broken.
514*12890SJoyce.McIntosh@Sun.COM *
5155331Samw * Returns errno values.
5165331Samw */
5175331Samw int
smb_common_read(smb_request_t * sr,smb_rw_param_t * param)5186139Sjb150015 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
5195331Samw {
5205331Samw smb_ofile_t *ofile = sr->fid_ofile;
5215331Samw smb_node_t *node;
5226139Sjb150015 smb_vdb_t *vdb = ¶m->rw_vdb;
5235331Samw struct mbuf *top;
5245331Samw int rc;
5255331Samw
5268934SJose.Borrego@Sun.COM vdb->vdb_tag = 0;
5278934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
5288934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
5298934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_resid = param->rw_count;
5308934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
5318934SJose.Borrego@Sun.COM vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
53211447Samw@Sun.COM vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
5335331Samw
5345331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) {
5355331Samw case STYPE_DISKTREE:
5365331Samw node = ofile->f_node;
5375331Samw
53810001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) {
5396139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset,
5406139Sjb150015 param->rw_count, B_FALSE);
5415331Samw if (rc != NT_STATUS_SUCCESS) {
5425331Samw rc = ERANGE;
5435331Samw break;
5445331Samw }
5455331Samw }
5465331Samw
5478934SJose.Borrego@Sun.COM if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
54811963SAfshin.Ardakani@Sun.COM !(sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) {
5498934SJose.Borrego@Sun.COM /*
55011963SAfshin.Ardakani@Sun.COM * SMB_FLAGS2_READ_IF_EXECUTE: permit execute-only
55111963SAfshin.Ardakani@Sun.COM * reads.
5528934SJose.Borrego@Sun.COM *
5538934SJose.Borrego@Sun.COM * Reject request if the file has been opened
55411963SAfshin.Ardakani@Sun.COM * execute-only and SMB_FLAGS2_READ_IF_EXECUTE is not
55511963SAfshin.Ardakani@Sun.COM * set.
5568934SJose.Borrego@Sun.COM */
5578934SJose.Borrego@Sun.COM rc = EACCES;
5588934SJose.Borrego@Sun.COM break;
5598934SJose.Borrego@Sun.COM }
5608934SJose.Borrego@Sun.COM
5618934SJose.Borrego@Sun.COM sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
5628934SJose.Borrego@Sun.COM top = smb_mbuf_allocate(&vdb->vdb_uio);
5635331Samw
56410001SJoyce.McIntosh@Sun.COM rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio);
5655331Samw
5668934SJose.Borrego@Sun.COM sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
5675331Samw smb_mbuf_trim(top, sr->raw_data.max_bytes);
5685331Samw MBC_ATTACH_MBUF(&sr->raw_data, top);
5695331Samw break;
5705331Samw
5715331Samw case STYPE_IPC:
5728934SJose.Borrego@Sun.COM rc = smb_opipe_read(sr, &vdb->vdb_uio);
5735331Samw break;
5745331Samw
5755331Samw default:
5765331Samw rc = EACCES;
5775331Samw break;
5785331Samw }
5795331Samw
5808934SJose.Borrego@Sun.COM param->rw_count -= vdb->vdb_uio.uio_resid;
5815331Samw
5825331Samw if (rc != 0)
5835331Samw return (rc);
5845331Samw
5856139Sjb150015 if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
5865331Samw /*
5875331Samw * mincnt is only used by read-raw and is typically
5885331Samw * zero. If mincnt is greater than zero and the
5895331Samw * number of bytes read is less than mincnt, tell
5905331Samw * the client that we read nothing.
5915331Samw */
5926139Sjb150015 param->rw_count = 0;
5935331Samw }
5945331Samw
5956139Sjb150015 param->rw_offset += param->rw_count;
5965331Samw mutex_enter(&sr->fid_ofile->f_mutex);
5976139Sjb150015 ofile->f_seek_pos = param->rw_offset;
5985331Samw mutex_exit(&sr->fid_ofile->f_mutex);
5995331Samw return (rc);
6005331Samw }
601