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