2 * Copyright (c) 2000-2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
36 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
37 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
41 * various SMB requests. Most of the routines merely packs data into mbufs.
43 #include <sys/param.h>
44 #include <sys/systm.h>
48 #include <sys/socket.h>
50 #include <sys/random.h>
52 #include <sys/cmn_err.h>
54 #include <netsmb/smb_osdep.h>
56 #include <netsmb/smb.h>
57 #include <netsmb/smb_conn.h>
58 #include <netsmb/smb_rq.h>
59 #include <netsmb/smb_subr.h>
60 #include <netsmb/smb_tran.h>
62 #define STYPE_LEN 8 /* share type strings */
65 * Largest size to use with LARGE_READ/LARGE_WRITE.
66 * Specs say up to 64k data bytes, but Windows traffic
67 * uses 60k... no doubt for some good reason.
68 * (Probably to keep 4k block alignment.)
69 * XXX: Move to smb.h maybe?
71 #define SMB_MAX_LARGE_RW_SIZE (60*1024)
74 * Default timeout values, all in seconds.
75 * Make these tunable (only via mdb for now).
77 int smb_timo_notice
= 15;
78 int smb_timo_default
= 30; /* was SMB_DEFRQTIMO */
79 int smb_timo_open
= 45;
80 int smb_timo_read
= 45;
81 int smb_timo_write
= 60; /* was SMBWRTTIMO */
82 int smb_timo_append
= 90;
84 static int smb_smb_read(struct smb_share
*ssp
, uint16_t fid
,
85 uint32_t *lenp
, uio_t
*uiop
, smb_cred_t
*scred
, int timo
);
86 static int smb_smb_write(struct smb_share
*ssp
, uint16_t fid
,
87 uint32_t *lenp
, uio_t
*uiop
, smb_cred_t
*scred
, int timo
);
89 static int smb_smb_readx(struct smb_share
*ssp
, uint16_t fid
,
90 uint32_t *lenp
, uio_t
*uiop
, smb_cred_t
*scred
, int timo
);
91 static int smb_smb_writex(struct smb_share
*ssp
, uint16_t fid
,
92 uint32_t *lenp
, uio_t
*uiop
, smb_cred_t
*scred
, int timo
);
95 * Get the string representation of a share "use" type,
96 * as needed for the "service" in tree connect.
99 smb_share_typename(uint32_t stype
)
125 * Parse a share type name (inverse of above)
128 smb_share_parsetype(char *name
)
134 stype
= STYPE_DISKTREE
;
137 stype
= STYPE_DEVICE
;
143 stype
= STYPE_PRINTQ
;
146 stype
= STYPE_UNKNOWN
;
153 smb_smb_treeconnect(struct smb_share
*ssp
, struct smb_cred
*scred
)
156 struct smb_rq
*rqp
= NULL
;
160 char *pbuf
, *unc_name
= NULL
;
161 int error
, tlen
, plen
, unc_len
;
162 uint16_t bcnt
, options
;
164 char stype_str
[STYPE_LEN
];
169 * Make this a "VC-level" request, so it will have
170 * rqp->sr_share == NULL, and smb_iod_sendrq()
171 * will send it with TID = SMB_TID_UNKNOWN
173 * This also serves to bypass the wait for
174 * share state changes, which this call is
175 * trying to carry out.
177 error
= smb_rq_alloc(VCTOCP(vcp
), SMB_COM_TREE_CONNECT_ANDX
,
183 * Build the UNC name, i.e. "//server/share"
184 * but with backslashes of course.
185 * size math: three slashes, one null.
187 unc_len
= 4 + strlen(vcp
->vc_srvname
) + strlen(ssp
->ss_name
);
188 unc_name
= kmem_alloc(unc_len
, KM_SLEEP
);
189 (void) snprintf(unc_name
, unc_len
, "\\\\%s\\%s",
190 vcp
->vc_srvname
, ssp
->ss_name
);
191 SMBSDEBUG("unc_name: \"%s\"", unc_name
);
195 * Share-level password (pre-computed in user-space)
196 * MS-SMB 2.2.6 says this should be null terminated,
197 * and the pw length includes the null.
200 plen
= strlen(pbuf
) + 1;
207 mb_put_uint8(mbp
, 0xff);
208 mb_put_uint8(mbp
, 0);
209 mb_put_uint16le(mbp
, 0);
210 mb_put_uint16le(mbp
, 0); /* Flags */
211 mb_put_uint16le(mbp
, plen
);
215 /* Tree connect password, if any */
216 error
= mb_put_mem(mbp
, pbuf
, plen
, MB_MSYSTEM
);
220 /* UNC resource name */
221 error
= smb_put_dstring(mbp
, vcp
, unc_name
, SMB_CS_NONE
);
226 * Put the type string (always ASCII),
227 * including the null.
229 tname
= smb_share_typename(ssp
->ss_use
);
230 tlen
= strlen(tname
) + 1;
231 error
= mb_put_mem(mbp
, tname
, tlen
, MB_MSYSTEM
);
240 * Using NOINTR_RECV because we don't want to risk
241 * missing a successful tree connect response,
242 * which would "leak" Tree IDs.
244 rqp
->sr_flags
|= SMBR_NOINTR_RECV
;
245 error
= smb_rq_simple(rqp
);
246 SMBSDEBUG("%d\n", error
);
249 * If we get the server name wrong, i.e. due to
250 * mis-configured name services, this will be
251 * NT_STATUS_DUPLICATE_NAME. Log this error.
253 SMBERROR("(%s) failed, status=0x%x",
254 unc_name
, rqp
->sr_error
);
259 * Parse the TCON response
261 smb_rq_getreply(rqp
, &mdp
);
262 md_get_uint8(mdp
, &wc
);
263 if (wc
!= 3 && wc
!= 7) {
267 md_get_uint16le(mdp
, NULL
); /* AndX cmd */
268 md_get_uint16le(mdp
, NULL
); /* AndX off */
269 md_get_uint16le(mdp
, &options
); /* option bits (DFS, search) */
271 md_get_uint32le(mdp
, NULL
); /* MaximalShareAccessRights */
272 md_get_uint32le(mdp
, NULL
); /* GuestMaximalShareAcc... */
274 error
= md_get_uint16le(mdp
, &bcnt
); /* byte count */
279 * Get the returned share type string, i.e. "IPC" or whatever.
280 * (See smb_share_typename, smb_share_parsetype). If we get
281 * an error reading the type, just say STYPE_UNKNOWN.
284 bzero(stype_str
, tlen
--);
287 md_get_mem(mdp
, stype_str
, tlen
, MB_MSYSTEM
);
288 stype_str
[tlen
] = '\0';
289 ssp
->ss_type
= smb_share_parsetype(stype_str
);
293 ssp
->ss_tid
= rqp
->sr_rptid
;
294 ssp
->ss_vcgenid
= vcp
->vc_genid
;
295 ssp
->ss_options
= options
;
296 ssp
->ss_flags
|= SMBS_CONNECTED
;
301 kmem_free(unc_name
, unc_len
);
307 smb_smb_treedisconnect(struct smb_share
*ssp
, struct smb_cred
*scred
)
313 if (ssp
->ss_tid
== SMB_TID_UNKNOWN
)
317 * Build this as a "VC-level" request, so it will
318 * avoid testing the _GONE flag on the share,
319 * which has already been set at this point.
320 * Add the share pointer "by hand" below, so
321 * smb_iod_sendrq will plug in the TID.
324 error
= smb_rq_alloc(VCTOCP(vcp
), SMB_COM_TREE_DISCONNECT
, scred
, &rqp
);
327 rqp
->sr_share
= ssp
; /* by hand */
335 * Run this with a relatively short timeout. (5 sec.)
336 * We don't really care about the result here, but we
337 * do need to make sure we send this out, or we could
338 * "leak" active tree IDs on interrupt or timeout.
339 * The NOINTR_SEND flag makes this request immune to
340 * interrupt or timeout until the send is done.
341 * Also, don't reconnect for this, of course!
343 rqp
->sr_flags
|= (SMBR_NOINTR_SEND
| SMBR_NORECONNECT
);
344 error
= smb_rq_simple_timed(rqp
, 5);
345 SMBSDEBUG("%d\n", error
);
347 ssp
->ss_tid
= SMB_TID_UNKNOWN
;
352 * Modern create/open of file or directory.
356 struct smb_share
*ssp
,
357 struct mbchain
*name_mb
,
358 uint32_t cr_flags
, /* create flags */
359 uint32_t req_acc
, /* requested access */
360 uint32_t efa
, /* ext. file attrs (DOS attr +) */
362 uint32_t open_disp
, /* open disposition */
363 uint32_t createopt
, /* NTCREATEX_OPTIONS_ */
364 uint32_t impersonate
, /* NTCREATEX_IMPERSONATION_... */
365 struct smb_cred
*scrp
,
366 uint16_t *fidp
, /* returned FID */
367 uint32_t *cr_act_p
, /* optional create action */
368 struct smbfattr
*fap
) /* optional attributes */
370 struct smb_rq rq
, *rqp
= &rq
;
371 struct smb_vc
*vcp
= SSTOVC(ssp
);
376 uint32_t longint
, createact
;
381 bzero(&fa
, sizeof (fa
));
382 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_NT_CREATE_ANDX
, scrp
);
385 smb_rq_getrequest(rqp
, &mbp
);
387 /* Word parameters */
389 mb_put_uint8(mbp
, 0xff); /* secondary command */
390 mb_put_uint8(mbp
, 0); /* MBZ */
391 mb_put_uint16le(mbp
, 0); /* offset to next command (none) */
392 mb_put_uint8(mbp
, 0); /* MBZ */
393 mb_put_uint16le(mbp
, name_mb
->mb_count
);
394 mb_put_uint32le(mbp
, cr_flags
); /* NTCREATEX_FLAGS_* */
395 mb_put_uint32le(mbp
, 0); /* FID - basis for path if not root */
396 mb_put_uint32le(mbp
, req_acc
);
397 mb_put_uint64le(mbp
, 0); /* "initial allocation size" */
398 mb_put_uint32le(mbp
, efa
);
399 mb_put_uint32le(mbp
, share_acc
);
400 mb_put_uint32le(mbp
, open_disp
);
401 mb_put_uint32le(mbp
, createopt
);
402 mb_put_uint32le(mbp
, impersonate
);
403 mb_put_uint8(mbp
, 0); /* security flags (?) */
407 * Byte parameters: Just the path name, aligned.
408 * Note: mb_put_mbuf consumes mb_top, so clear it.
411 if (SMB_UNICODE_STRINGS(vcp
))
413 mb_put_mbuf(mbp
, name_mb
->mb_top
);
414 bzero(name_mb
, sizeof (*name_mb
));
418 * Don't want to risk missing a successful
419 * open response, or we could "leak" FIDs.
421 rqp
->sr_flags
|= SMBR_NOINTR_RECV
;
422 error
= smb_rq_simple_timed(rqp
, smb_timo_open
);
425 smb_rq_getreply(rqp
, &mdp
);
427 * spec says 26 for word count, but 34 words are defined
428 * and observed from win2000
430 error
= md_get_uint8(mdp
, &wc
);
433 if (wc
!= 26 && wc
< 34) {
437 md_get_uint8(mdp
, NULL
); /* secondary cmd */
438 md_get_uint8(mdp
, NULL
); /* mbz */
439 md_get_uint16le(mdp
, NULL
); /* andxoffset */
440 md_get_uint8(mdp
, NULL
); /* oplock lvl granted */
441 md_get_uint16le(mdp
, &fid
); /* file ID */
442 md_get_uint32le(mdp
, &createact
); /* create_action */
444 md_get_uint64le(mdp
, &llongint
); /* creation time */
445 smb_time_NT2local(llongint
, &fa
.fa_createtime
);
446 md_get_uint64le(mdp
, &llongint
); /* access time */
447 smb_time_NT2local(llongint
, &fa
.fa_atime
);
448 md_get_uint64le(mdp
, &llongint
); /* write time */
449 smb_time_NT2local(llongint
, &fa
.fa_mtime
);
450 md_get_uint64le(mdp
, &llongint
); /* change time */
451 smb_time_NT2local(llongint
, &fa
.fa_ctime
);
453 md_get_uint32le(mdp
, &longint
); /* attributes */
454 fa
.fa_attr
= longint
;
455 md_get_uint64le(mdp
, &llongint
); /* allocation size */
456 fa
.fa_allocsz
= llongint
;
457 md_get_uint64le(mdp
, &llongint
); /* EOF position */
458 fa
.fa_size
= llongint
;
460 error
= md_get_uint16le(mdp
, NULL
); /* file type */
461 /* other stuff we don't care about */
470 *cr_act_p
= createact
;
472 *fap
= fa
; /* struct copy */
478 smb_smb_close(struct smb_share
*ssp
, uint16_t fid
, struct timespec
*mtime
,
479 struct smb_cred
*scrp
)
481 struct smb_rq rq
, *rqp
= &rq
;
486 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_CLOSE
, scrp
);
489 smb_rq_getrequest(rqp
, &mbp
);
491 mb_put_uint16le(mbp
, fid
);
493 int sv_tz
= SSTOVC(ssp
)->vc_sopt
.sv_tz
;
494 smb_time_local2server(mtime
, sv_tz
, &time
);
498 mb_put_uint32le(mbp
, time
);
503 /* Make sure we send, but only if already connected */
504 rqp
->sr_flags
|= (SMBR_NOINTR_SEND
| SMBR_NORECONNECT
);
505 error
= smb_rq_simple(rqp
);
512 struct smb_share
*ssp
,
516 struct smb_cred
*scrp
,
519 struct smb_rq rq
, *rqp
= &rq
;
520 struct smb_vc
*vcp
= SSTOVC(ssp
);
527 error
= smb_rq_init(rqp
, SSTOCP(ssp
), SMB_COM_OPEN_PRINT_FILE
, scrp
);
530 smb_rq_getrequest(rqp
, &mbp
);
532 /* Word parameters */
534 mb_put_uint16le(mbp
, setuplen
);
535 mb_put_uint16le(mbp
, mode
);
539 * Byte parameters: Just the title
542 mb_put_uint8(mbp
, SMB_DT_ASCII
);
543 error
= smb_put_dstring(mbp
, vcp
, title
, SMB_CS_NONE
);
549 * Don't want to risk missing a successful
550 * open response, or we could "leak" FIDs.
552 rqp
->sr_flags
|= SMBR_NOINTR_RECV
;
553 error
= smb_rq_simple_timed(rqp
, smb_timo_open
);
557 smb_rq_getreply(rqp
, &mdp
);
558 error
= md_get_uint8(mdp
, &wc
);
559 if (error
|| wc
< 1) {
563 error
= md_get_uint16le(mdp
, &fid
);
575 * Like smb_smb_close, but for print shares.
578 smb_smb_close_prjob(struct smb_share
*ssp
, uint16_t fid
,
579 struct smb_cred
*scrp
)
581 struct smb_rq rq
, *rqp
= &rq
;
585 error
= smb_rq_init(rqp
, SSTOCP(ssp
),
586 SMB_COM_CLOSE_PRINT_FILE
, scrp
);
589 smb_rq_getrequest(rqp
, &mbp
);
591 mb_put_uint16le(mbp
, fid
);
596 /* Make sure we send but only if already connected */
597 rqp
->sr_flags
|= (SMBR_NOINTR_SEND
| SMBR_NORECONNECT
);
598 error
= smb_rq_simple(rqp
);
604 * Common function for read/write with UIO.
605 * Called by netsmb smb_usr_rw,
606 * smbfs_readvnode, smbfs_writevnode
609 smb_rwuio(struct smb_share
*ssp
, uint16_t fid
, uio_rw_t rw
,
610 uio_t
*uiop
, smb_cred_t
*scred
, int timo
)
612 struct smb_vc
*vcp
= SSTOVC(ssp
);
614 uint32_t len
, rlen
, maxlen
;
616 int (*iofun
)(struct smb_share
*, uint16_t, uint32_t *,
617 uio_t
*, smb_cred_t
*, int);
620 * Determine which function to use,
621 * and the transfer size per call.
623 if (SMB_DIALECT(vcp
) >= SMB_DIALECT_NTLM0_12
) {
625 * Using NT LM 0.12, so readx, writex.
626 * Make sure we can represent the offset.
628 if ((vcp
->vc_sopt
.sv_caps
& SMB_CAP_LARGE_FILES
) == 0 &&
629 (uiop
->uio_loffset
+ uiop
->uio_resid
) > UINT32_MAX
)
632 if (rw
== UIO_READ
) {
633 iofun
= smb_smb_readx
;
634 if (vcp
->vc_sopt
.sv_caps
& SMB_CAP_LARGE_READX
)
635 maxlen
= SMB_MAX_LARGE_RW_SIZE
;
637 maxlen
= vcp
->vc_rxmax
;
638 } else { /* UIO_WRITE */
639 iofun
= smb_smb_writex
;
640 if (vcp
->vc_sopt
.sv_caps
& SMB_CAP_LARGE_WRITEX
)
641 maxlen
= SMB_MAX_LARGE_RW_SIZE
;
643 maxlen
= vcp
->vc_wxmax
;
647 * Using the old SMB_READ and SMB_WRITE so
648 * we're limited to 32-bit offsets, etc.
649 * XXX: Someday, punt the old dialects.
651 if ((uiop
->uio_loffset
+ uiop
->uio_resid
) > UINT32_MAX
)
654 if (rw
== UIO_READ
) {
655 iofun
= smb_smb_read
;
656 maxlen
= vcp
->vc_rxmax
;
657 } else { /* UIO_WRITE */
658 iofun
= smb_smb_write
;
659 maxlen
= vcp
->vc_wxmax
;
663 save_resid
= uiop
->uio_resid
;
664 while (uiop
->uio_resid
> 0) {
665 /* Lint: uio_resid may be 64-bits */
666 rlen
= len
= (uint32_t)min(maxlen
, uiop
->uio_resid
);
667 error
= (*iofun
)(ssp
, fid
, &rlen
, uiop
, scred
, timo
);
670 * Note: the iofun called uio_update, so
671 * not doing that here as one might expect.
673 * Quit the loop either on error, or if we
674 * transferred less then requested.
676 if (error
|| (rlen
< len
))
679 timo
= 0; /* only first I/O should wait */
681 if (error
&& (save_resid
!= uiop
->uio_resid
)) {
683 * Stopped on an error after having
684 * successfully transferred data.
685 * Suppress this error.
687 SMBSDEBUG("error %d suppressed\n", error
);
695 smb_smb_readx(struct smb_share
*ssp
, uint16_t fid
, uint32_t *lenp
,
696 uio_t
*uiop
, smb_cred_t
*scred
, int timo
)
702 uint32_t offlo
, offhi
, rlen
;
703 uint16_t lenhi
, lenlo
, off
, doff
;
706 lenhi
= (uint16_t)(*lenp
>> 16);
707 lenlo
= (uint16_t)*lenp
;
708 offhi
= (uint32_t)(uiop
->uio_loffset
>> 32);
709 offlo
= (uint32_t)uiop
->uio_loffset
;
711 error
= smb_rq_alloc(SSTOCP(ssp
), SMB_COM_READ_ANDX
, scred
, &rqp
);
714 smb_rq_getrequest(rqp
, &mbp
);
716 mb_put_uint8(mbp
, 0xff); /* no secondary command */
717 mb_put_uint8(mbp
, 0); /* MBZ */
718 mb_put_uint16le(mbp
, 0); /* offset to secondary */
719 mb_put_uint16le(mbp
, fid
);
720 mb_put_uint32le(mbp
, offlo
); /* offset (low part) */
721 mb_put_uint16le(mbp
, lenlo
); /* MaxCount */
722 mb_put_uint16le(mbp
, 1); /* MinCount */
723 /* (only indicates blocking) */
724 mb_put_uint32le(mbp
, lenhi
); /* MaxCountHigh */
725 mb_put_uint16le(mbp
, lenlo
); /* Remaining ("obsolete") */
726 mb_put_uint32le(mbp
, offhi
); /* offset (high part) */
732 timo
= smb_timo_read
;
733 error
= smb_rq_simple_timed(rqp
, timo
);
737 smb_rq_getreply(rqp
, &mdp
);
738 error
= md_get_uint8(mdp
, &wc
);
745 md_get_uint8(mdp
, NULL
);
746 md_get_uint8(mdp
, NULL
);
747 md_get_uint16le(mdp
, NULL
);
748 md_get_uint16le(mdp
, NULL
);
749 md_get_uint16le(mdp
, NULL
); /* data compaction mode */
750 md_get_uint16le(mdp
, NULL
);
751 md_get_uint16le(mdp
, &lenlo
); /* data len ret. */
752 md_get_uint16le(mdp
, &doff
); /* data offset */
753 md_get_uint16le(mdp
, &lenhi
);
754 rlen
= (lenhi
<< 16) | lenlo
;
755 md_get_mem(mdp
, NULL
, 4 * 2, MB_MSYSTEM
);
756 error
= md_get_uint16le(mdp
, NULL
); /* ByteCount */
760 * Does the data offset indicate padding?
761 * The current offset is a constant, found
762 * by counting the md_get_ calls above.
764 off
= SMB_HDRLEN
+ 3 + (12 * 2); /* =59 */
765 if (doff
> off
) /* pad byte(s)? */
766 md_get_mem(mdp
, NULL
, doff
- off
, MB_MSYSTEM
);
773 SMBSDEBUG("bad server! rlen %d, len %d\n",
777 error
= md_get_uio(mdp
, uiop
, rlen
);
790 smb_smb_writex(struct smb_share
*ssp
, uint16_t fid
, uint32_t *lenp
,
791 uio_t
*uiop
, smb_cred_t
*scred
, int timo
)
797 uint32_t offlo
, offhi
, rlen
;
798 uint16_t lenhi
, lenlo
;
801 lenhi
= (uint16_t)(*lenp
>> 16);
802 lenlo
= (uint16_t)*lenp
;
803 offhi
= (uint32_t)(uiop
->uio_loffset
>> 32);
804 offlo
= (uint32_t)uiop
->uio_loffset
;
806 error
= smb_rq_alloc(SSTOCP(ssp
), SMB_COM_WRITE_ANDX
, scred
, &rqp
);
809 smb_rq_getrequest(rqp
, &mbp
);
811 mb_put_uint8(mbp
, 0xff); /* no secondary command */
812 mb_put_uint8(mbp
, 0); /* MBZ */
813 mb_put_uint16le(mbp
, 0); /* offset to secondary */
814 mb_put_uint16le(mbp
, fid
);
815 mb_put_uint32le(mbp
, offlo
); /* offset (low part) */
816 mb_put_uint32le(mbp
, 0); /* MBZ (timeout) */
817 mb_put_uint16le(mbp
, 0); /* !write-thru */
818 mb_put_uint16le(mbp
, 0);
819 mb_put_uint16le(mbp
, lenhi
);
820 mb_put_uint16le(mbp
, lenlo
);
821 mb_put_uint16le(mbp
, 64); /* data offset from header start */
822 mb_put_uint32le(mbp
, offhi
); /* offset (high part) */
826 mb_put_uint8(mbp
, 0); /* pad byte */
827 error
= mb_put_uio(mbp
, uiop
, *lenp
);
832 timo
= smb_timo_write
;
833 error
= smb_rq_simple_timed(rqp
, timo
);
836 smb_rq_getreply(rqp
, &mdp
);
837 error
= md_get_uint8(mdp
, &wc
);
844 md_get_uint8(mdp
, NULL
); /* andx cmd */
845 md_get_uint8(mdp
, NULL
); /* reserved */
846 md_get_uint16le(mdp
, NULL
); /* andx offset */
847 md_get_uint16le(mdp
, &lenlo
); /* data len ret. */
848 md_get_uint16le(mdp
, NULL
); /* remaining */
849 error
= md_get_uint16le(mdp
, &lenhi
);
854 rlen
= (lenhi
<< 16) | lenlo
;
863 smb_smb_read(struct smb_share
*ssp
, uint16_t fid
, uint32_t *lenp
,
864 uio_t
*uiop
, smb_cred_t
*scred
, int timo
)
871 uint16_t bc
, cnt
, dlen
, rcnt
, todo
;
874 ASSERT(uiop
->uio_loffset
<= UINT32_MAX
);
875 off32
= (uint32_t)uiop
->uio_loffset
;
876 ASSERT(*lenp
<= UINT16_MAX
);
877 cnt
= (uint16_t)*lenp
;
878 /* This next is an "estimate" of planned reads. */
879 todo
= (uint16_t)min(uiop
->uio_resid
, UINT16_MAX
);
881 error
= smb_rq_alloc(SSTOCP(ssp
), SMB_COM_READ
, scred
, &rqp
);
884 smb_rq_getrequest(rqp
, &mbp
);
886 mb_put_uint16le(mbp
, fid
);
887 mb_put_uint16le(mbp
, cnt
);
888 mb_put_uint32le(mbp
, off32
);
889 mb_put_uint16le(mbp
, todo
);
895 timo
= smb_timo_read
;
896 error
= smb_rq_simple_timed(rqp
, timo
);
899 smb_rq_getreply(rqp
, &mdp
);
900 error
= md_get_uint8(mdp
, &wc
);
907 md_get_uint16le(mdp
, &rcnt
); /* ret. count */
908 md_get_mem(mdp
, NULL
, 4 * 2, MB_MSYSTEM
); /* res. */
909 md_get_uint16le(mdp
, &bc
); /* byte count */
910 md_get_uint8(mdp
, NULL
); /* buffer format */
911 error
= md_get_uint16le(mdp
, &dlen
); /* data len */
915 SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
916 (int)dlen
, (int)rcnt
);
925 SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
926 (int)rcnt
, (int)cnt
);
929 error
= md_get_uio(mdp
, uiop
, (int)rcnt
);
942 smb_smb_write(struct smb_share
*ssp
, uint16_t fid
, uint32_t *lenp
,
943 uio_t
*uiop
, smb_cred_t
*scred
, int timo
)
950 uint16_t cnt
, rcnt
, todo
;
953 ASSERT(uiop
->uio_loffset
<= UINT32_MAX
);
954 off32
= (uint32_t)uiop
->uio_loffset
;
955 ASSERT(*lenp
<= UINT16_MAX
);
956 cnt
= (uint16_t)*lenp
;
957 /* This next is an "estimate" of planned writes. */
958 todo
= (uint16_t)min(uiop
->uio_resid
, UINT16_MAX
);
960 error
= smb_rq_alloc(SSTOCP(ssp
), SMB_COM_WRITE
, scred
, &rqp
);
963 smb_rq_getrequest(rqp
, &mbp
);
965 mb_put_uint16le(mbp
, fid
);
966 mb_put_uint16le(mbp
, cnt
);
967 mb_put_uint32le(mbp
, off32
);
968 mb_put_uint16le(mbp
, todo
);
971 mb_put_uint8(mbp
, SMB_DT_DATA
);
972 mb_put_uint16le(mbp
, cnt
);
974 error
= mb_put_uio(mbp
, uiop
, *lenp
);
979 timo
= smb_timo_write
;
980 error
= smb_rq_simple_timed(rqp
, timo
);
983 smb_rq_getreply(rqp
, &mdp
);
984 error
= md_get_uint8(mdp
, &wc
);
991 error
= md_get_uint16le(mdp
, &rcnt
);
1002 static u_int32_t smbechoes
= 0;
1005 smb_smb_echo(struct smb_vc
*vcp
, struct smb_cred
*scred
, int timo
)
1008 struct mbchain
*mbp
;
1011 error
= smb_rq_alloc(VCTOCP(vcp
), SMB_COM_ECHO
, scred
, &rqp
);
1016 mb_put_uint16le(mbp
, 1); /* echo count */
1019 mb_put_uint32le(mbp
, atomic_inc_32_nv(&smbechoes
));
1022 * Note: the IOD calls this, so
1023 * this request must not wait for
1024 * connection state changes, etc.
1026 rqp
->sr_flags
|= SMBR_NORECONNECT
;
1027 error
= smb_rq_simple_timed(rqp
, timo
);
1028 SMBSDEBUG("%d\n", error
);