1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22*dc20a302Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27da6c28aaSamw 28da6c28aaSamw #include <sys/syslog.h> 29da6c28aaSamw #include <smbsrv/smb_incl.h> 30da6c28aaSamw #include <smbsrv/smb_fsops.h> 31da6c28aaSamw 32da6c28aaSamw 33da6c28aaSamw typedef struct smb_read_param { 34da6c28aaSamw uint64_t r_offset; 35da6c28aaSamw uint16_t r_count; 36da6c28aaSamw uint16_t r_mincnt; 37da6c28aaSamw } smb_read_param_t; 38da6c28aaSamw 39da6c28aaSamw 40da6c28aaSamw int smb_common_read(struct smb_request *sr, smb_read_param_t *param); 41da6c28aaSamw 42da6c28aaSamw 43da6c28aaSamw /* 44da6c28aaSamw * Read bytes from a file or named pipe (SMB Core). 45da6c28aaSamw * 46da6c28aaSamw * The requested count specifies the number of bytes desired. Offset 47da6c28aaSamw * is limited to 32 bits, so this client request is inappropriate for 48da6c28aaSamw * files with 64 bit offsets. 49da6c28aaSamw * 50da6c28aaSamw * On return, count is the number of bytes actually being returned, which 51da6c28aaSamw * may be less than the count requested only if a read specifies bytes 52da6c28aaSamw * beyond the current file size. In this case only the bytes that exist 53da6c28aaSamw * are returned. A read completely beyond the end of file results in a 54da6c28aaSamw * response of length zero. This is the only circumstance when a zero 55da6c28aaSamw * length response is generated. A count returned which is less than the 56da6c28aaSamw * count requested is the end of file indicator. 57da6c28aaSamw */ 58da6c28aaSamw int 59da6c28aaSamw smb_com_read(struct smb_request *sr) 60da6c28aaSamw { 61da6c28aaSamw smb_read_param_t param; 62da6c28aaSamw uint32_t off_low; 63da6c28aaSamw uint16_t remcnt; 64da6c28aaSamw int rc; 65da6c28aaSamw 66da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 67da6c28aaSamw ¶m.r_count, &off_low, &remcnt); 68da6c28aaSamw if (rc != 0) { 69da6c28aaSamw smbsr_decode_error(sr); 70da6c28aaSamw /* NOTREACHED */ 71da6c28aaSamw } 72da6c28aaSamw 73da6c28aaSamw param.r_offset = (uint64_t)off_low; 74da6c28aaSamw param.r_mincnt = 0; 75da6c28aaSamw 76da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 77da6c28aaSamw if (sr->fid_ofile == NULL) { 78*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 79da6c28aaSamw /* NOTREACHED */ 80da6c28aaSamw } 81da6c28aaSamw 82da6c28aaSamw if ((rc = smb_common_read(sr, ¶m)) != 0) { 83*dc20a302Sas200622 smbsr_errno(sr, rc); 84da6c28aaSamw /* NOTREACHED */ 85da6c28aaSamw } 86da6c28aaSamw 87da6c28aaSamw smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 88da6c28aaSamw 5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data); 89da6c28aaSamw 90da6c28aaSamw return (SDRC_NORMAL_REPLY); 91da6c28aaSamw } 92da6c28aaSamw 93da6c28aaSamw /* 94da6c28aaSamw * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/ 95da6c28aaSamw * SmbLockAndWrite sub-dialect is only valid on disk files: reject any 96da6c28aaSamw * attempt to use it on non-disk shares. 97da6c28aaSamw * 98da6c28aaSamw * The requested count specifies the number of bytes desired. Offset 99da6c28aaSamw * specifies the offset in the file of the first byte to be locked then 100da6c28aaSamw * read. Note that offset is limited to 32 bits, so this client request 101da6c28aaSamw * is inappropriate for files with 64 bit offsets. 102da6c28aaSamw * 103da6c28aaSamw * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted 104da6c28aaSamw * immediately an error should be returned to the client. If an error 105da6c28aaSamw * occurs on the lock, the bytes should not be read. 106da6c28aaSamw * 107da6c28aaSamw * On return, count is the number of bytes actually being returned, which 108da6c28aaSamw * may be less than the count requested only if a read specifies bytes 109da6c28aaSamw * beyond the current file size. In this case only the bytes that exist 110da6c28aaSamw * are returned. A read completely beyond the end of file results in a 111da6c28aaSamw * response of length zero. This is the only circumstance when a zero 112da6c28aaSamw * length response is generated. A count returned which is less than the 113da6c28aaSamw * count requested is the end of file indicator. 114da6c28aaSamw */ 115da6c28aaSamw int 116da6c28aaSamw smb_com_lock_and_read(struct smb_request *sr) 117da6c28aaSamw { 118da6c28aaSamw smb_read_param_t param; 119da6c28aaSamw uint16_t remcnt; 120da6c28aaSamw uint32_t off_low; 121da6c28aaSamw DWORD result; 122da6c28aaSamw int rc; 123da6c28aaSamw 124da6c28aaSamw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 125*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 126da6c28aaSamw /* NOTREACHED */ 127da6c28aaSamw } 128da6c28aaSamw 129da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 130da6c28aaSamw ¶m.r_count, &off_low, &remcnt); 131da6c28aaSamw if (rc != 0) { 132da6c28aaSamw smbsr_decode_error(sr); 133da6c28aaSamw /* NOTREACHED */ 134da6c28aaSamw } 135da6c28aaSamw 136da6c28aaSamw param.r_offset = (uint64_t)off_low; 137da6c28aaSamw param.r_mincnt = 0; 138da6c28aaSamw 139da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 140da6c28aaSamw if (sr->fid_ofile == NULL) { 141*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 142da6c28aaSamw /* NOTREACHED */ 143da6c28aaSamw } 144da6c28aaSamw 145da6c28aaSamw result = smb_lock_range(sr, sr->fid_ofile, param.r_offset, 14655bf511dSas200622 (uint64_t)param.r_count, UINT_MAX, SMB_LOCK_TYPE_READWRITE); 147da6c28aaSamw if (result != NT_STATUS_SUCCESS) { 148*dc20a302Sas200622 smb_lock_range_error(sr, result); 149da6c28aaSamw } 150da6c28aaSamw 151da6c28aaSamw if ((rc = smb_common_read(sr, ¶m)) != 0) { 152*dc20a302Sas200622 smbsr_errno(sr, rc); 153da6c28aaSamw /* NOTREACHED */ 154da6c28aaSamw } 155da6c28aaSamw 156da6c28aaSamw smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 157da6c28aaSamw 5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data); 158da6c28aaSamw 159da6c28aaSamw return (SDRC_NORMAL_REPLY); 160da6c28aaSamw } 161da6c28aaSamw 162da6c28aaSamw /* 163da6c28aaSamw * The SMB_COM_READ_RAW protocol is a negotiated option introduced in 164da6c28aaSamw * SMB Core Plus to maximize performance when reading a large block 165da6c28aaSamw * of data from a server. This request was extended in LM 0.12 to 166da6c28aaSamw * support 64-bit offsets; the server can indicate support by setting 167da6c28aaSamw * CAP_LARGE_FILES in the negotiated capabilities. 168da6c28aaSamw * 169da6c28aaSamw * The client must guarantee that there is (and will be) no other request 170da6c28aaSamw * to the server for the duration of the SMB_COM_READ_RAW, since the 171da6c28aaSamw * server response has no header or trailer. To help ensure that there 172da6c28aaSamw * are no interruptions, we block all I/O for the session during read raw. 173da6c28aaSamw * 174da6c28aaSamw * If this is the first SMB request received since we sent an oplock break 175da6c28aaSamw * to this client, we don't know if it's safe to send the raw data because 176da6c28aaSamw * the requests may have crossed on the wire and the client may have 177da6c28aaSamw * interpreted the oplock break as part of the raw data. To avoid problems, 178da6c28aaSamw * we send a zero length session packet, which will force the client to 179da6c28aaSamw * retry the read. 180da6c28aaSamw * 181da6c28aaSamw * Read errors are handled by sending a zero length response. 182da6c28aaSamw */ 183da6c28aaSamw int 184da6c28aaSamw smb_com_read_raw(struct smb_request *sr) 185da6c28aaSamw { 186da6c28aaSamw smb_read_param_t param; 187da6c28aaSamw smb_node_t *node; 188da6c28aaSamw uint32_t off_low; 189da6c28aaSamw uint32_t off_high; 190da6c28aaSamw uint32_t timeout; 191da6c28aaSamw int rc; 192da6c28aaSamw 193da6c28aaSamw switch (sr->session->s_state) { 194da6c28aaSamw case SMB_SESSION_STATE_NEGOTIATED: 195da6c28aaSamw if (sr->smb_wct == 8) { 196da6c28aaSamw rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid, 197da6c28aaSamw &off_low, ¶m.r_count, ¶m.r_mincnt, 198da6c28aaSamw &timeout); 199da6c28aaSamw param.r_offset = (uint64_t)off_low; 200da6c28aaSamw } else { 201da6c28aaSamw rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid, 202da6c28aaSamw &off_low, ¶m.r_count, ¶m.r_mincnt, &timeout, 203da6c28aaSamw &off_high); 204da6c28aaSamw param.r_offset = ((uint64_t)off_high << 32) | off_low; 205da6c28aaSamw } 206da6c28aaSamw 207da6c28aaSamw if (rc != 0) { 208da6c28aaSamw smbsr_decode_error(sr); 209da6c28aaSamw /* NOTREACHED */ 210da6c28aaSamw } 211da6c28aaSamw 212da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, 213da6c28aaSamw sr->smb_fid); 214da6c28aaSamw if (sr->fid_ofile == NULL) { 215*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 216da6c28aaSamw ERRDOS, ERRbadfid); 217da6c28aaSamw /* NOTREACHED */ 218da6c28aaSamw } 219da6c28aaSamw 220da6c28aaSamw rc = smb_common_read(sr, ¶m); 221da6c28aaSamw /* 222da6c28aaSamw * XXX Do we need to handle errors here? What if we have an 223da6c28aaSamw * access error (either permissions or range lock violations? 224da6c28aaSamw */ 225da6c28aaSamw if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { 226da6c28aaSamw node = sr->fid_ofile->f_node; 227da6c28aaSamw if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) { 228da6c28aaSamw rc = EAGAIN; 229da6c28aaSamw } 230da6c28aaSamw } 231da6c28aaSamw 232da6c28aaSamw if (rc != 0) { 233da6c28aaSamw (void) smb_session_send(sr->session, 0, NULL); 234da6c28aaSamw m_freem(sr->raw_data.chain); 235da6c28aaSamw sr->raw_data.chain = 0; 236da6c28aaSamw } else { 237da6c28aaSamw (void) smb_session_send(sr->session, 0, &sr->raw_data); 238da6c28aaSamw } 239da6c28aaSamw return (SDRC_NO_REPLY); 240da6c28aaSamw 241da6c28aaSamw case SMB_SESSION_STATE_OPLOCK_BREAKING: 242da6c28aaSamw (void) smb_session_send(sr->session, 0, NULL); 243da6c28aaSamw sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; 244da6c28aaSamw return (SDRC_NO_REPLY); 245da6c28aaSamw 246da6c28aaSamw case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: 247da6c28aaSamw ASSERT(0); 248da6c28aaSamw return (SDRC_DROP_VC); 249da6c28aaSamw 250da6c28aaSamw case SMB_SESSION_STATE_TERMINATED: 251da6c28aaSamw ASSERT(0); 252da6c28aaSamw return (SDRC_NO_REPLY); 253da6c28aaSamw 254da6c28aaSamw case SMB_SESSION_STATE_DISCONNECTED: 255da6c28aaSamw return (SDRC_NO_REPLY); 256da6c28aaSamw 257da6c28aaSamw case SMB_SESSION_STATE_CONNECTED: 258da6c28aaSamw case SMB_SESSION_STATE_ESTABLISHED: 259da6c28aaSamw default: 260da6c28aaSamw ASSERT(0); 261da6c28aaSamw return (SDRC_DROP_VC); 262da6c28aaSamw } 263da6c28aaSamw } 264da6c28aaSamw 265da6c28aaSamw /* 266da6c28aaSamw * Read bytes from a file (SMB Core). This request was extended in 267da6c28aaSamw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 268da6c28aaSamw * 12 and including additional offset information. 269da6c28aaSamw */ 270da6c28aaSamw int 271da6c28aaSamw smb_com_read_andx(struct smb_request *sr) 272da6c28aaSamw { 273da6c28aaSamw smb_read_param_t param; 274da6c28aaSamw uint32_t off_low; 275da6c28aaSamw uint32_t off_high; 276da6c28aaSamw uint16_t remcnt; 277da6c28aaSamw uint16_t offset2; 278da6c28aaSamw uint8_t secondary; 279da6c28aaSamw int rc; 280da6c28aaSamw 281da6c28aaSamw if (sr->smb_wct == 12) { 282da6c28aaSamw rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary, 283da6c28aaSamw &sr->smb_fid, &off_low, ¶m.r_count, &remcnt, &off_high); 284da6c28aaSamw 285da6c28aaSamw param.r_offset = ((uint64_t)off_high << 32) | off_low; 286da6c28aaSamw } else { 287da6c28aaSamw rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary, 288da6c28aaSamw &sr->smb_fid, &off_low, ¶m.r_count, &remcnt); 289da6c28aaSamw 290da6c28aaSamw param.r_offset = (uint64_t)off_low; 291da6c28aaSamw } 292da6c28aaSamw 293da6c28aaSamw if (rc != 0) { 294da6c28aaSamw smbsr_decode_error(sr); 295da6c28aaSamw /* NOTREACHED */ 296da6c28aaSamw } 297da6c28aaSamw 298da6c28aaSamw param.r_mincnt = 0; 299da6c28aaSamw 300da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 301da6c28aaSamw if (sr->fid_ofile == NULL) { 302*dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 303da6c28aaSamw /* NOTREACHED */ 304da6c28aaSamw } 305da6c28aaSamw 306da6c28aaSamw if ((rc = smb_common_read(sr, ¶m)) != 0) { 307*dc20a302Sas200622 smbsr_errno(sr, rc); 308da6c28aaSamw /* NOTREACHED */ 309da6c28aaSamw } 310da6c28aaSamw 311da6c28aaSamw /* 312da6c28aaSamw * Ensure that the next response offset is zero 313da6c28aaSamw * if there is no secondary command. 314da6c28aaSamw */ 315da6c28aaSamw offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59; 316da6c28aaSamw 317da6c28aaSamw /* 318da6c28aaSamw * The STYPE_IPC response format is different. 319da6c28aaSamw * The unknown value (2) may be to indicate that it 320da6c28aaSamw * is a follow-up to an earlier RPC transaction. 321da6c28aaSamw */ 322da6c28aaSamw if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 323da6c28aaSamw smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC", 324da6c28aaSamw 12, /* wct */ 325da6c28aaSamw secondary, /* Secondary andx command */ 326da6c28aaSamw offset2, /* offset to next */ 327da6c28aaSamw 0, /* must be 0 */ 328da6c28aaSamw param.r_count, /* data byte count */ 329da6c28aaSamw 60, /* Offset from start to data */ 330da6c28aaSamw VAR_BCC, /* BCC marker */ 331da6c28aaSamw 0x02, /* unknown */ 332da6c28aaSamw &sr->raw_data); 333da6c28aaSamw } else { 334da6c28aaSamw smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC", 335da6c28aaSamw 12, /* wct */ 336da6c28aaSamw secondary, /* Secondary andx command */ 337da6c28aaSamw offset2, /* offset to next */ 338da6c28aaSamw -1, /* must be -1 */ 339da6c28aaSamw param.r_count, /* data byte count */ 340da6c28aaSamw 59, /* Offset from start to data */ 341da6c28aaSamw VAR_BCC, /* BCC marker */ 342da6c28aaSamw &sr->raw_data); 343da6c28aaSamw } 344da6c28aaSamw 345da6c28aaSamw return (SDRC_NORMAL_REPLY); 346da6c28aaSamw } 347da6c28aaSamw 348da6c28aaSamw /* 349da6c28aaSamw * Common function for reading files or IPC/MSRPC named pipes. All 350da6c28aaSamw * protocol read functions should lookup the fid before calling this 351da6c28aaSamw * function. We can't move the fid lookup here because lock-and-read 352da6c28aaSamw * requires the fid to do locking before attempting the read. 353da6c28aaSamw * 354da6c28aaSamw * Returns errno values. 355da6c28aaSamw */ 356da6c28aaSamw int 357da6c28aaSamw smb_common_read(struct smb_request *sr, smb_read_param_t *param) 358da6c28aaSamw { 359da6c28aaSamw smb_ofile_t *ofile = sr->fid_ofile; 360da6c28aaSamw smb_node_t *node; 361da6c28aaSamw struct vardata_block *vdb; 362da6c28aaSamw struct mbuf *top; 363da6c28aaSamw int rc; 364da6c28aaSamw 365da6c28aaSamw vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP); 366da6c28aaSamw vdb->tag = 0; 367da6c28aaSamw vdb->uio.uio_iov = &vdb->iovec[0]; 368da6c28aaSamw vdb->uio.uio_iovcnt = MAX_IOVEC; 369da6c28aaSamw vdb->uio.uio_resid = param->r_count; 37055bf511dSas200622 vdb->uio.uio_loffset = (offset_t)param->r_offset; 371da6c28aaSamw vdb->uio.uio_segflg = UIO_SYSSPACE; 372da6c28aaSamw 373da6c28aaSamw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 374da6c28aaSamw case STYPE_DISKTREE: 375da6c28aaSamw node = ofile->f_node; 376da6c28aaSamw 377da6c28aaSamw if (node->attr.sa_vattr.va_type != VDIR) { 378da6c28aaSamw rc = smb_lock_range_access(sr, node, param->r_offset, 379*dc20a302Sas200622 param->r_count, B_FALSE); 380da6c28aaSamw if (rc != NT_STATUS_SUCCESS) { 381da6c28aaSamw rc = ERANGE; 382da6c28aaSamw break; 383da6c28aaSamw } 384da6c28aaSamw } 385da6c28aaSamw 386da6c28aaSamw (void) smb_sync_fsattr(sr, sr->user_cr, node); 387da6c28aaSamw 388da6c28aaSamw sr->raw_data.max_bytes = vdb->uio.uio_resid; 389da6c28aaSamw top = smb_mbuf_allocate(&vdb->uio); 390da6c28aaSamw 391da6c28aaSamw rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio, 392da6c28aaSamw &node->attr); 393da6c28aaSamw 394da6c28aaSamw sr->raw_data.max_bytes -= vdb->uio.uio_resid; 395da6c28aaSamw smb_mbuf_trim(top, sr->raw_data.max_bytes); 396da6c28aaSamw MBC_ATTACH_MBUF(&sr->raw_data, top); 397da6c28aaSamw break; 398da6c28aaSamw 399da6c28aaSamw case STYPE_IPC: 400da6c28aaSamw rc = smb_rpc_read(sr, &vdb->uio); 401da6c28aaSamw break; 402da6c28aaSamw 403da6c28aaSamw default: 404da6c28aaSamw rc = EACCES; 405da6c28aaSamw break; 406da6c28aaSamw } 407da6c28aaSamw 408da6c28aaSamw param->r_count -= vdb->uio.uio_resid; 409da6c28aaSamw kmem_free(vdb, sizeof (struct vardata_block)); 410da6c28aaSamw 411da6c28aaSamw if (rc != 0) 412da6c28aaSamw return (rc); 413da6c28aaSamw 414da6c28aaSamw if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) { 415da6c28aaSamw /* 416da6c28aaSamw * mincnt is only used by read-raw and is typically 417da6c28aaSamw * zero. If mincnt is greater than zero and the 418da6c28aaSamw * number of bytes read is less than mincnt, tell 419da6c28aaSamw * the client that we read nothing. 420da6c28aaSamw */ 421da6c28aaSamw param->r_count = 0; 422da6c28aaSamw } 423da6c28aaSamw 424da6c28aaSamw param->r_offset += param->r_count; 425da6c28aaSamw mutex_enter(&sr->fid_ofile->f_mutex); 426da6c28aaSamw ofile->f_seek_pos = param->r_offset; 427da6c28aaSamw mutex_exit(&sr->fid_ofile->f_mutex); 428da6c28aaSamw return (rc); 429da6c28aaSamw } 430da6c28aaSamw 431da6c28aaSamw /* 432da6c28aaSamw * The Read Block Multiplexed protocol is used to maximize performance 433da6c28aaSamw * when reading a large block of data from server to client while still 434da6c28aaSamw * allowing other operations to take place between the client and server 435da6c28aaSamw * in parallel. 436da6c28aaSamw * 437da6c28aaSamw * The mpx sub protocol is not supported because we support only 438da6c28aaSamw * connection oriented transports and NT supports SMB_COM_READ_MPX 439da6c28aaSamw * only over connectionless transports. 440da6c28aaSamw */ 441da6c28aaSamw /*ARGSUSED*/ 442da6c28aaSamw int 443da6c28aaSamw smb_com_read_mpx(struct smb_request *sr) 444da6c28aaSamw { 445da6c28aaSamw return (SDRC_UNIMPLEMENTED); 446da6c28aaSamw } 447da6c28aaSamw 448da6c28aaSamw /*ARGSUSED*/ 449da6c28aaSamw int 450da6c28aaSamw smb_com_read_mpx_secondary(struct smb_request *sr) 451da6c28aaSamw { 452da6c28aaSamw return (SDRC_UNIMPLEMENTED); 453da6c28aaSamw } 454