Home | History | Annotate | Download | only in smbsrv
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * SMB: write_raw
     28  * 5.27       WRITE_RAW: Write Raw Bytes
     29  *
     30  * The Write Block Raw protocol is used to maximize the performance of
     31  * writing a large block of data from the client to the server.  The Write
     32  * Block Raw command's scope includes files, Named Pipes, and spooled
     33  * output (can be used in place COM_WRITE_PRINT_FILE ).
     34  *
     35  *  Client Request              Description
     36  *  ==========================  =========================================
     37  *
     38  *  UCHAR WordCount;            Count of parameter words = 12
     39  *  USHORT Fid;                 File handle
     40  *  USHORT Count;               Total bytes, including this buffer
     41  *  USHORT Reserved;
     42  *  ULONG Offset;               Offset in file to begin write
     43  *  ULONG Timeout;
     44  *  USHORT WriteMode;           Write mode:
     45  *                              bit 0 - complete write to disk and send
     46  *                              final result response
     47  *                              bit 1 - return Remaining (pipe/dev)
     48  *                              (see WriteAndX for #defines)
     49  *  ULONG Reserved2;
     50  *  USHORT DataLength;          Number of data bytes this buffer
     51  *  USHORT DataOffset;          Offset (from header start) to data
     52  *  USHORT ByteCount;           Count of data bytes
     53  *  UCHAR Pad[];                Pad to SHORT or LONG
     54  *  UCHAR Data[];               Data (# = DataLength)
     55  *
     56  *  First Server Response          Description
     57  *  ============================== =====================================
     58  *
     59  *  UCHAR WordCount;               Count of parameter words = 1
     60  *  USHORT Remaining;              Bytes remaining to be read if pipe
     61  *  USHORT ByteCount;              Count of data bytes = 0
     62  *
     63  *  Final Server Response              Description
     64  *  ================================== =================================
     65  *
     66  *  UCHAR Command (in SMB header)      SMB_COM_WRITE_COMPLETE
     67  *
     68  *  UCHAR WordCount;                   Count of parameter words = 1
     69  *  USHORT Count;                      Total number of bytes written
     70  *  USHORT ByteCount;                  Count of data bytes = 0
     71  *
     72  * The first response format will be that of the final server response in
     73  * the case where the server gets an error while writing the data sent
     74  * along with the request.  Thus Count is the number of bytes which did get
     75  * written any time an error is returned.  If an error occurs after the
     76  * first response has been sent allowing the client to send the remaining
     77  * data, the final response should not be sent unless write through is set.
     78  * Rather the server should return this "write behind" error on the next
     79  * access to the Fid.
     80  *
     81  * The client must guarantee that there is (and will be) no other request
     82  * on the connection for the duration of this request.  The server will
     83  * reserve enough resources to receive the data and respond with a response
     84  * SMB as defined above.  The client then sends the raw data in one send.
     85  * Thus the server is able to receive up to 65,535 bytes of data directly
     86  * into the server buffer.  The amount of data transferred is expected to
     87  * be larger than the negotiated buffer size for this protocol.
     88  *
     89  * The reason that no other requests can be active on the connection for
     90  * the duration of the request is that if other receives are present on the
     91  * connection, there is normally no way to guarantee that the data will be
     92  * received into the correct server buffer, rather the data may fill one
     93  * (or more) of the other buffers.  Also if the client is sending other
     94  * requests on the connection, a request may land in the buffer that the
     95  * server has allocated for the this SMB's data.
     96  *
     97  * Whether or not SMB_COM_WRITE_RAW is supported is returned in the
     98  * response to SMB_COM_NEGOTIATE.  SMB_COM_WRITE_RAW is not supported for
     99  * connectionless clients.
    100  *
    101  * When write through is not specified ((WriteMode & 01) == 0) this SMB is
    102  * assumed to be a form of write behind.  The transport layer guarantees
    103  * delivery of all secondary requests from the client.  Thus no "got the
    104  * data you sent" SMB is needed.  If an error should occur at the server
    105  * end, all bytes must be received and thrown away.  If an error occurs
    106  * while writing data to disk such as disk full, the next access of the
    107  * file handle (another write, close, read, etc.) will return the fact that
    108  * the error occurred.
    109  *
    110  * If write through is specified ((WriteMode & 01) != 0), the server will
    111  * receive the data, write it to disk and then send a final response
    112  * indicating the result of the write.  The total number of bytes written
    113  * is also returned in this response in the Count field.
    114  *
    115  * The flow for the SMB_COM_WRITE_RAW SMB is:
    116  *
    117  * client -----> SMB_COM_WRITE_RAW request (optional data) >-------> server
    118  * client <------------------< OK send (more) data <---------------- server
    119  * client  ----------------------> raw data >----------------------> server
    120  * client  <---< data on disk or error (write through only) <------- server
    121  *
    122  * This protocol is set up such that the SMB_COM_WRITE_RAW request may also
    123  * carry data.  This is an optimization in that up to the server's buffer
    124  * size (MaxCount from SMB_COM_NEGOTIATE response), minus the size of the
    125  * SMB_COM_WRITE_RAW SMB request, may be sent along with the request.  Thus
    126  * if the server is busy and unable to support the raw write of the
    127  * remaining data, the data sent along with the request has been delivered
    128  * and need not be sent again.  The server will write any data sent in the
    129  * request (and wait for it to be on the disk or device if write through is
    130  * set), prior to sending the response.
    131  *
    132  * The specific responses error class ERRSRV, error codes ERRusempx and
    133  * ERRusestd, indicate that the server is temporarily out of the resources
    134  *
    135  * needed to support the raw write of the remaining data, but that any data
    136  * sent along with the request has been successfully written.  The client
    137  * should then write the remaining data using a different type of SMB write
    138  * request, or delay and retry using SMB_COM_WRITE_RAW.  If a write error
    139  * occurs writing the initial data, it will be returned and the write raw
    140  * request is implicitly denied.
    141  *
    142  * The return field Remaining is returned for named pipes only.  It is used
    143  * to return the number of bytes currently available in the pipe.  This
    144  * information can then be used by the client to know when a subsequent
    145  * (non blocking) read of the pipe may return some data.  Of course when
    146  * the read request is actually received by the server there may be more or
    147  * less actual data in the pipe (more data has been written to the pipe /
    148  * device or another reader drained it).  If the information is currently
    149  * not available or the request is NOT for a pipe or the server does not
    150  * support this feature, a -1 value should be returned.
    151  *
    152  * If the negotiated dialect is NT LM 0.12 or later, and the response to
    153  * the SMB_COM_NEGOTIATE SMB has CAP_LARGE_FILES set in the Capabilities
    154  * field, an additional request format is allowed which accommodates very
    155  * large files having 64 bit offsets:
    156  *
    157  *  Client Request                     Description
    158  *  ================================== =================================
    159  *   UCHAR WordCount;                   Count of parameter words = 14
    160  *   USHORT Fid;                       File handle
    161  *   USHORT Count;                     Total bytes, including this
    162  *                                      buffer
    163  *   USHORT Reserved;
    164  *   ULONG Offset;                     Offset in file to begin write
    165  *   ULONG Timeout;
    166  *   USHORT WriteMode;                 Write mode:
    167  *                                      bit 0 - complete write to disk
    168  *                                      and send final result response
    169  *                                      bit 1 - return Remaining
    170  *                                      (pipe/dev)
    171  *   ULONG Reserved2;
    172  *   USHORT DataLength;                Number of data bytes this buffer
    173  *   USHORT DataOffset;                Offset (from header start) to
    174  *                                      data
    175  *   ULONG OffsetHigh;                 Upper 32 bits of offset
    176  *   USHORT ByteCount;                  Count of data bytes
    177  *   UCHAR Pad[];                       Pad to SHORT or LONG
    178  *   UCHAR Data[];                     Data (# = DataLength)
    179  *
    180  * In this case the final offset in the file is formed by combining
    181  * OffsetHigh and Offset, the resulting offset must not be negative.
    182  */
    183 
    184 #include <sys/sdt.h>
    185 #include <smbsrv/smb_kproto.h>
    186 #include <smbsrv/smb_fsops.h>
    187 #include <smbsrv/netbios.h>
    188 
    189 extern uint32_t smb_keep_alive;
    190 
    191 static int smb_write_raw_helper(smb_request_t *, struct uio *, int,
    192     offset_t *, uint32_t *);
    193 static int smb_transfer_write_raw_data(smb_request_t *, uint16_t);
    194 
    195 #define	WR_MODE_WR_THRU	1
    196 
    197 smb_sdrc_t
    198 smb_pre_write_raw(smb_request_t *sr)
    199 {
    200 	int rc = 0;
    201 
    202 	DTRACE_SMB_2(op__WriteRaw__start, smb_request_t *, sr,
    203 	    smb_rw_param_t *, sr->arg.rw);
    204 
    205 	smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
    206 
    207 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    208 }
    209 
    210 void
    211 smb_post_write_raw(smb_request_t *sr)
    212 {
    213 	DTRACE_SMB_2(op__WriteRaw__done, smb_request_t *, sr,
    214 	    smb_rw_param_t *, sr->arg.rw);
    215 
    216 	smb_rwx_rwexit(&sr->session->s_lock);
    217 }
    218 
    219 smb_sdrc_t
    220 smb_com_write_raw(struct smb_request *sr)
    221 {
    222 	int			rc = 0;
    223 	int			session_send_rc = 0;
    224 	unsigned short		addl_xfer_count;
    225 	unsigned short		count;
    226 	unsigned short		write_mode, data_offset, data_length;
    227 	offset_t		off;
    228 	uint32_t		off_low, off_high, timeout;
    229 	uint32_t		lcount = 0;
    230 	uint32_t		addl_lcount = 0;
    231 	struct uio		uio;
    232 	iovec_t			iovec;
    233 	int			stability;
    234 	struct mbuf_chain	reply;
    235 	smb_node_t		*fnode;
    236 	smb_error_t		err;
    237 
    238 	if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE)
    239 		return (SDRC_DROP_VC);
    240 
    241 	if (sr->smb_wct == 12) {
    242 		off_high = 0;
    243 		rc = smbsr_decode_vwv(sr, "ww2.llw4.ww", &sr->smb_fid, &count,
    244 		    &off_low, &timeout, &write_mode, &data_length,
    245 		    &data_offset);
    246 		data_offset -= 59;
    247 	} else {
    248 		rc = smbsr_decode_vwv(sr, "ww2.llw4.wwl", &sr->smb_fid, &count,
    249 		    &off_low, &timeout, &write_mode, &data_length,
    250 		    &data_offset, &off_high);
    251 		data_offset -= 63;
    252 	}
    253 
    254 	if (rc != 0)
    255 		return (SDRC_ERROR);
    256 
    257 	off = ((offset_t)off_high << 32) | off_low;
    258 	addl_xfer_count = count - data_length;
    259 
    260 	smbsr_lookup_file(sr);
    261 	if (sr->fid_ofile == NULL) {
    262 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
    263 		return (SDRC_ERROR);
    264 	}
    265 
    266 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
    267 
    268 	fnode = sr->fid_ofile->f_node;
    269 	stability = ((write_mode & WR_MODE_WR_THRU) ||
    270 	    (fnode->flags & NODE_FLAGS_WRITE_THROUGH)) ? FSYNC : 0;
    271 
    272 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
    273 		/*
    274 		 * See comments in smb_write.c
    275 		 */
    276 		if (!smb_node_is_dir(fnode)) {
    277 			rc = smb_lock_range_access(sr, fnode, off,
    278 			    count, B_TRUE);
    279 			if (rc != NT_STATUS_SUCCESS) {
    280 				smbsr_error(sr, rc, ERRSRV, ERRaccess);
    281 				return (SDRC_ERROR);
    282 			}
    283 		}
    284 	}
    285 
    286 	/*
    287 	 * Make sure any raw write data that is supposed to be
    288 	 * contained in this SMB is actually present.
    289 	 */
    290 	if (sr->smb_data.chain_offset + data_offset + data_length >
    291 	    sr->smb_data.max_bytes) {
    292 		/* Error handling code will wake up the session daemon */
    293 		return (SDRC_ERROR);
    294 	}
    295 
    296 	/*
    297 	 * Init uio (resid will get filled in later)
    298 	 */
    299 	uio.uio_iov = &iovec;
    300 	uio.uio_iovcnt = 1;
    301 	uio.uio_segflg = UIO_SYSSPACE;
    302 	uio.uio_loffset = off;
    303 
    304 	/*
    305 	 * Send response if there is additional data to transfer.  This
    306 	 * will prompt the client to send the remaining data.
    307 	 */
    308 	if (addl_xfer_count != 0) {
    309 		MBC_INIT(&reply, MLEN);
    310 		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT "bww",
    311 		    sr->first_smb_com,
    312 		    sr->smb_rcls,
    313 		    sr->smb_reh,
    314 		    sr->smb_err,
    315 		    sr->smb_flg | SMB_FLAGS_REPLY,
    316 		    sr->smb_flg2,
    317 		    sr->smb_pid_high,
    318 		    sr->smb_sig,
    319 		    sr->smb_tid,
    320 		    sr->smb_pid,
    321 		    sr->smb_uid,
    322 		    sr->smb_mid, 1, -1, 0);
    323 
    324 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
    325 			smb_sign_reply(sr, &reply);
    326 
    327 		session_send_rc = smb_session_send(sr->session, 0, &reply);
    328 
    329 		/*
    330 		 * If the session response failed we're not going to
    331 		 * return an error just yet -- we can still write the
    332 		 * data we received along with the SMB even if the
    333 		 * response failed.  If it failed, we need to force the
    334 		 * stability level to "write-through".
    335 		 */
    336 		stability = (session_send_rc == 0) ? stability : FSYNC;
    337 	}
    338 
    339 	/*
    340 	 * While the response is in flight (and the data begins to arrive)
    341 	 * write out the first data segment.  Start by setting up the
    342 	 * iovec list for the first transfer.
    343 	 */
    344 	iovec.iov_base = sr->smb_data.chain->m_data +
    345 	    sr->smb_data.chain_offset + data_offset;
    346 	iovec.iov_len = data_length;
    347 	uio.uio_resid = data_length;
    348 
    349 	/*
    350 	 * smb_write_raw_helper will call smb_opipe_write or
    351 	 * smb_fsop_write as appropriate, and update the other f_node fields.
    352 	 * It's possible that data_length may be 0 for this transfer but
    353 	 * we still want to process it since it will update the file state
    354 	 * (seek position, file size (possibly), etc).
    355 	 */
    356 	rc = smb_write_raw_helper(sr, &uio, stability, &off, &lcount);
    357 
    358 	/*
    359 	 * If our initial session response failed then we're done.  Return
    360 	 * failure.  The client will know we wrote some of the data because
    361 	 * of the transfer count (count - lcount) in the response.
    362 	 */
    363 	if (session_send_rc != 0) {
    364 		sr->smb_rcls = ERRSRV;
    365 		sr->smb_err  = ERRusestd;
    366 		goto write_raw_transfer_failed;
    367 	}
    368 
    369 	/*
    370 	 * If we have more data to read then go get it
    371 	 */
    372 	if (addl_xfer_count) {
    373 		/*
    374 		 * This is the only place where a worker thread should
    375 		 * directly read from the session socket.  If the data
    376 		 * is read successfully then the buffer (sr->sr_raw_data_buf)
    377 		 * will need to be freed after the data is written.
    378 		 */
    379 		if (smb_transfer_write_raw_data(sr, addl_xfer_count) != 0) {
    380 			/*
    381 			 * Raw data transfer failed
    382 			 */
    383 			goto write_raw_transfer_failed;
    384 		}
    385 
    386 		/*
    387 		 * Fill in next iov entry
    388 		 */
    389 		iovec.iov_base = sr->sr_raw_data_buf;
    390 		iovec.iov_len = addl_xfer_count;
    391 		uio.uio_resid = addl_xfer_count;
    392 	}
    393 
    394 	/*
    395 	 * Wake up session daemon since we now have all of our data and
    396 	 * it's safe for the session daemon to resume processing SMB's.
    397 	 */
    398 	sr->session->s_write_raw_status = 0;
    399 	sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
    400 
    401 	/*
    402 	 * If we didn't write all the data from the first segment then
    403 	 * there's not much point in continuing (we still wanted to
    404 	 * read any additional data above since we don't necessarily
    405 	 * want to drop the connection and we need to read through
    406 	 * to the next SMB).
    407 	 */
    408 	if ((rc != 0) || (lcount != data_length)) {
    409 		goto notify_write_raw_complete;
    410 	}
    411 
    412 	/*
    413 	 * Write any additional data
    414 	 */
    415 	if (addl_xfer_count) {
    416 		rc = smb_write_raw_helper(sr, &uio, stability, &off,
    417 		    &addl_lcount);
    418 	}
    419 
    420 	/*
    421 	 * If we were called in "Write-behind" mode ((write_mode & 1) == 0)
    422 	 * and the transfer was successful then we don't need to send
    423 	 * any further response.  If we were called in "Write-Through" mode
    424 	 * ((write_mode & 1) == 1) or if the transfer failed we need to
    425 	 * send a completion notification.  The "count" value will indicate
    426 	 * whether the transfer was successful.
    427 	 */
    428 	if ((rc != 0) || (write_mode & WR_MODE_WR_THRU) ||
    429 	    (lcount + addl_lcount != count)) {
    430 		goto notify_write_raw_complete;
    431 	}
    432 
    433 	/*
    434 	 * Free raw write buffer (allocated in smb_transfer_write_raw_data)
    435 	 */
    436 	kmem_free(sr->sr_raw_data_buf, sr->sr_raw_data_length);
    437 
    438 	(void) smb_session_send(sr->session, SESSION_KEEP_ALIVE, NULL);
    439 	return (SDRC_NO_REPLY);
    440 
    441 write_raw_transfer_failed:
    442 	/*
    443 	 * Raw data transfer failed, wake up session
    444 	 * daemon
    445 	 */
    446 	sr->session->s_write_raw_status = 20;
    447 	sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
    448 
    449 notify_write_raw_complete:
    450 	/*
    451 	 * If we had an error fill in the appropriate error code
    452 	 */
    453 	if (rc != 0) {
    454 		smbsr_map_errno(rc, &err);
    455 		smbsr_set_error(sr, &err);
    456 	}
    457 
    458 	/*
    459 	 * Free raw write buffer if present (from smb_transfer_write_raw_data)
    460 	 */
    461 	if (sr->sr_raw_data_buf != NULL) {
    462 		kmem_free(sr->sr_raw_data_buf, sr->sr_raw_data_length);
    463 	}
    464 	/* Write complete notification */
    465 	sr->first_smb_com = SMB_COM_WRITE_COMPLETE;
    466 	rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
    467 	    count - (lcount + addl_lcount), 0);
    468 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    469 }
    470 
    471 
    472 
    473 /*
    474  * smb_write_raw_helper
    475  *
    476  * This function will call smb_opipe_write or smb_fsop_write
    477  * as appropriate, and update the other f_node fields.
    478  * It's possible that data_length may be 0 for this transfer but
    479  * we still want process it since it will update the file state
    480  * (seek position, file size (possibly), etc).
    481  *
    482  * Returns 0 for success, non-zero for failure
    483  */
    484 static int
    485 smb_write_raw_helper(struct smb_request *sr, struct uio *uiop,
    486     int stability, offset_t *offp, uint32_t *lcountp)
    487 {
    488 	smb_node_t *fnode;
    489 	int rc = 0;
    490 
    491 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
    492 		*lcountp = uiop->uio_resid;
    493 
    494 		if ((rc = smb_opipe_write(sr, uiop)) != 0)
    495 			*lcountp = 0;
    496 	} else {
    497 		fnode = sr->fid_ofile->f_node;
    498 		rc = smb_fsop_write(sr, sr->user_cr, fnode,
    499 		    uiop, lcountp, stability);
    500 
    501 		if (rc == 0)
    502 			smb_ofile_set_write_time_pending(sr->fid_ofile);
    503 	}
    504 
    505 	*offp += *lcountp;
    506 	mutex_enter(&sr->fid_ofile->f_mutex);
    507 	sr->fid_ofile->f_seek_pos = *offp;
    508 	mutex_exit(&sr->fid_ofile->f_mutex);
    509 
    510 	return (rc);
    511 }
    512 
    513 
    514 /*
    515  * smb_handle_write_raw
    516  *
    517  * Called from smb_session_daemon() when the SMB command is SMB_COM_WRITE_RAW.
    518  * Dispatches the command to the worker thread and waits until the worker
    519  * has completed processing the command.
    520  *
    521  * Returns 0 for success, non-zero for failure
    522  */
    523 int
    524 smb_handle_write_raw(smb_session_t *session, smb_request_t *sr)
    525 {
    526 	int	drop_reason = 0;
    527 
    528 	/*
    529 	 * Set flag to indicate that we are waiting for raw data.  The
    530 	 * worker thread will actually retrieve the raw data directly
    531 	 * from the socket.  This should be the only case when a worker
    532 	 * thread reads from the session socket.  When the data is read
    533 	 * the worker will clear the flag.
    534 	 */
    535 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
    536 	switch (session->s_state) {
    537 	case SMB_SESSION_STATE_NEGOTIATED:
    538 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
    539 		session->s_state = SMB_SESSION_STATE_WRITE_RAW_ACTIVE;
    540 		smb_rwx_rwexit(&session->s_lock);
    541 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
    542 		(void) taskq_dispatch(session->s_server->sv_thread_pool,
    543 		    smb_session_worker, sr, TQ_SLEEP);
    544 		smb_rwx_rwenter(&session->s_lock, RW_READER);
    545 		while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
    546 			(void) smb_rwx_rwwait(&session->s_lock, -1);
    547 		}
    548 		drop_reason = session->s_write_raw_status;
    549 		break;
    550 	default:
    551 		drop_reason = 21;
    552 		break;
    553 	}
    554 	smb_rwx_rwexit(&session->s_lock);
    555 	return (drop_reason);
    556 }
    557 
    558 /*
    559  * smb_transfer_write_raw_data
    560  *
    561  * Handles the second transfer phase of SMB_COM_WRITE_RAW.  smb_com_write_raw()
    562  * will process the parameters and data from the SMB and send the initial
    563  * SMB response.  This function reads the remaining data from the socket
    564  * as it arrives from the client.
    565  *
    566  * Clients may send KEEP_ALIVE messages (when using NBT) between the first
    567  * and second parts of write raw requests.  The only session transport
    568  * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE.
    569  *
    570  * Returns 0 for success, non-zero for failure
    571  */
    572 int
    573 smb_transfer_write_raw_data(smb_request_t *sr, uint16_t addl_xfer_count)
    574 {
    575 	smb_session_t *session = sr->session;
    576 	smb_xprt_t hdr;
    577 	uint8_t *data_buf;
    578 
    579 	do {
    580 		if (smb_session_xprt_gethdr(session, &hdr) != 0)
    581 			return (-1);
    582 
    583 		if ((hdr.xh_type == SESSION_MESSAGE) ||
    584 		    (hdr.xh_type == SESSION_KEEP_ALIVE)) {
    585 			session->keep_alive = smb_keep_alive;
    586 		} else {
    587 			return (-1);
    588 		}
    589 	} while (hdr.xh_type == SESSION_KEEP_ALIVE);
    590 
    591 	if (hdr.xh_length < addl_xfer_count) {
    592 		/*
    593 		 * Less data than we were expecting.
    594 		 */
    595 		return (-1);
    596 	}
    597 
    598 	data_buf = kmem_alloc(hdr.xh_length, KM_SLEEP);
    599 
    600 	if (smb_sorecv(session->sock, data_buf, hdr.xh_length) != 0) {
    601 		kmem_free(data_buf, hdr.xh_length);
    602 		sr->sr_raw_data_buf = NULL;
    603 		sr->sr_raw_data_length = 0;
    604 		return (-1);
    605 	}
    606 
    607 	sr->sr_raw_data_buf = data_buf;
    608 	sr->sr_raw_data_length = hdr.xh_length;
    609 	return (0);
    610 }
    611