8592 ZFS channel programs - rollback
[unleashed.git] / usr / src / uts / common / fs / smbclnt / netsmb / smb_smb.c
blob6016f5061adf033d4a04b02805fb3858264527d3
1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
30 * SUCH DAMAGE.
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>
45 #include <sys/kmem.h>
46 #include <sys/proc.h>
47 #include <sys/lock.h>
48 #include <sys/socket.h>
49 #include <sys/uio.h>
50 #include <sys/random.h>
51 #include <sys/note.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.
98 static const char *
99 smb_share_typename(uint32_t stype)
101 const char *p;
103 switch (stype) {
104 case STYPE_DISKTREE:
105 p = "A:";
106 break;
107 case STYPE_PRINTQ:
108 p = "LPT1:";
109 break;
110 case STYPE_DEVICE:
111 p = "COMM";
112 break;
113 case STYPE_IPC:
114 p = "IPC";
115 break;
116 case STYPE_UNKNOWN:
117 default:
118 p = "?????";
119 break;
121 return (p);
125 * Parse a share type name (inverse of above)
127 static uint32_t
128 smb_share_parsetype(char *name)
130 int stype;
132 switch (*name) {
133 case 'A': /* A: */
134 stype = STYPE_DISKTREE;
135 break;
136 case 'C': /* COMM */
137 stype = STYPE_DEVICE;
138 break;
139 case 'I': /* IPC */
140 stype = STYPE_IPC;
141 break;
142 case 'L': /* LPT: */
143 stype = STYPE_PRINTQ;
144 break;
145 default:
146 stype = STYPE_UNKNOWN;
147 break;
149 return (stype);
153 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
155 struct smb_vc *vcp;
156 struct smb_rq *rqp = NULL;
157 struct mbchain *mbp;
158 struct mdchain *mdp;
159 const char *tname;
160 char *pbuf, *unc_name = NULL;
161 int error, tlen, plen, unc_len;
162 uint16_t bcnt, options;
163 uint8_t wc;
164 char stype_str[STYPE_LEN];
166 vcp = SSTOVC(ssp);
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,
178 scred, &rqp);
179 if (error)
180 return (error);
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.
199 pbuf = ssp->ss_pass;
200 plen = strlen(pbuf) + 1;
203 * Build the request.
205 mbp = &rqp->sr_rq;
206 smb_rq_wstart(rqp);
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);
212 smb_rq_wend(rqp);
213 smb_rq_bstart(rqp);
215 /* Tree connect password, if any */
216 error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
217 if (error)
218 goto out;
220 /* UNC resource name */
221 error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
222 if (error)
223 goto out;
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);
232 if (error)
233 goto out;
235 smb_rq_bend(rqp);
238 * Run the request.
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);
247 if (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);
255 goto out;
259 * Parse the TCON response
261 smb_rq_getreply(rqp, &mdp);
262 md_get_uint8(mdp, &wc);
263 if (wc != 3 && wc != 7) {
264 error = EBADRPC;
265 goto out;
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) */
270 if (wc == 7) {
271 md_get_uint32le(mdp, NULL); /* MaximalShareAccessRights */
272 md_get_uint32le(mdp, NULL); /* GuestMaximalShareAcc... */
274 error = md_get_uint16le(mdp, &bcnt); /* byte count */
275 if (error)
276 goto out;
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.
283 tlen = STYPE_LEN;
284 bzero(stype_str, tlen--);
285 if (tlen > bcnt)
286 tlen = bcnt;
287 md_get_mem(mdp, stype_str, tlen, MB_MSYSTEM);
288 stype_str[tlen] = '\0';
289 ssp->ss_type = smb_share_parsetype(stype_str);
291 /* Success! */
292 SMB_SS_LOCK(ssp);
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;
297 SMB_SS_UNLOCK(ssp);
299 out:
300 if (unc_name)
301 kmem_free(unc_name, unc_len);
302 smb_rq_done(rqp);
303 return (error);
307 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
309 struct smb_vc *vcp;
310 struct smb_rq *rqp;
311 int error;
313 if (ssp->ss_tid == SMB_TID_UNKNOWN)
314 return (0);
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.
323 vcp = SSTOVC(ssp);
324 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
325 if (error)
326 return (error);
327 rqp->sr_share = ssp; /* by hand */
329 smb_rq_wstart(rqp);
330 smb_rq_wend(rqp);
331 smb_rq_bstart(rqp);
332 smb_rq_bend(rqp);
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);
346 smb_rq_done(rqp);
347 ssp->ss_tid = SMB_TID_UNKNOWN;
348 return (error);
352 * Modern create/open of file or directory.
355 smb_smb_ntcreate(
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 +) */
361 uint32_t share_acc,
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);
372 struct mbchain *mbp;
373 struct mdchain *mdp;
374 struct smbfattr fa;
375 uint64_t llongint;
376 uint32_t longint, createact;
377 uint16_t fid;
378 uint8_t wc;
379 int error;
381 bzero(&fa, sizeof (fa));
382 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
383 if (error)
384 return (error);
385 smb_rq_getrequest(rqp, &mbp);
387 /* Word parameters */
388 smb_rq_wstart(rqp);
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 (?) */
404 smb_rq_wend(rqp);
407 * Byte parameters: Just the path name, aligned.
408 * Note: mb_put_mbuf consumes mb_top, so clear it.
410 smb_rq_bstart(rqp);
411 if (SMB_UNICODE_STRINGS(vcp))
412 mb_put_padbyte(mbp);
413 mb_put_mbuf(mbp, name_mb->mb_top);
414 bzero(name_mb, sizeof (*name_mb));
415 smb_rq_bend(rqp);
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);
423 if (error)
424 goto done;
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);
431 if (error)
432 goto done;
433 if (wc != 26 && wc < 34) {
434 error = EBADRPC;
435 goto done;
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 */
463 done:
464 smb_rq_done(rqp);
465 if (error)
466 return (error);
468 *fidp = fid;
469 if (cr_act_p)
470 *cr_act_p = createact;
471 if (fap)
472 *fap = fa; /* struct copy */
474 return (0);
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;
482 struct mbchain *mbp;
483 long time;
484 int error;
486 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
487 if (error)
488 return (error);
489 smb_rq_getrequest(rqp, &mbp);
490 smb_rq_wstart(rqp);
491 mb_put_uint16le(mbp, fid);
492 if (mtime) {
493 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
494 smb_time_local2server(mtime, sv_tz, &time);
495 } else {
496 time = 0;
498 mb_put_uint32le(mbp, time);
499 smb_rq_wend(rqp);
500 smb_rq_bstart(rqp);
501 smb_rq_bend(rqp);
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);
506 smb_rq_done(rqp);
507 return (error);
511 smb_smb_open_prjob(
512 struct smb_share *ssp,
513 char *title,
514 uint16_t setuplen,
515 uint16_t mode,
516 struct smb_cred *scrp,
517 uint16_t *fidp)
519 struct smb_rq rq, *rqp = &rq;
520 struct smb_vc *vcp = SSTOVC(ssp);
521 struct mbchain *mbp;
522 struct mdchain *mdp;
523 uint16_t fid;
524 uint8_t wc;
525 int error;
527 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN_PRINT_FILE, scrp);
528 if (error)
529 return (error);
530 smb_rq_getrequest(rqp, &mbp);
532 /* Word parameters */
533 smb_rq_wstart(rqp);
534 mb_put_uint16le(mbp, setuplen);
535 mb_put_uint16le(mbp, mode);
536 smb_rq_wend(rqp);
539 * Byte parameters: Just the title
541 smb_rq_bstart(rqp);
542 mb_put_uint8(mbp, SMB_DT_ASCII);
543 error = smb_put_dstring(mbp, vcp, title, SMB_CS_NONE);
544 smb_rq_bend(rqp);
545 if (error)
546 goto done;
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);
554 if (error)
555 goto done;
557 smb_rq_getreply(rqp, &mdp);
558 error = md_get_uint8(mdp, &wc);
559 if (error || wc < 1) {
560 error = EBADRPC;
561 goto done;
563 error = md_get_uint16le(mdp, &fid);
565 done:
566 smb_rq_done(rqp);
567 if (error)
568 return (error);
570 *fidp = fid;
571 return (0);
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;
582 struct mbchain *mbp;
583 int error;
585 error = smb_rq_init(rqp, SSTOCP(ssp),
586 SMB_COM_CLOSE_PRINT_FILE, scrp);
587 if (error)
588 return (error);
589 smb_rq_getrequest(rqp, &mbp);
590 smb_rq_wstart(rqp);
591 mb_put_uint16le(mbp, fid);
592 smb_rq_wend(rqp);
593 smb_rq_bstart(rqp);
594 smb_rq_bend(rqp);
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);
599 smb_rq_done(rqp);
600 return (error);
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);
613 ssize_t save_resid;
614 uint32_t len, rlen, maxlen;
615 int error = 0;
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)
630 return (EFBIG);
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;
636 else
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;
642 else
643 maxlen = vcp->vc_wxmax;
645 } else {
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)
652 return (EFBIG);
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))
677 break;
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);
688 error = 0;
691 return (error);
694 static int
695 smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
696 uio_t *uiop, smb_cred_t *scred, int timo)
698 struct smb_rq *rqp;
699 struct mbchain *mbp;
700 struct mdchain *mdp;
701 int error;
702 uint32_t offlo, offhi, rlen;
703 uint16_t lenhi, lenlo, off, doff;
704 uint8_t wc;
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);
712 if (error)
713 return (error);
714 smb_rq_getrequest(rqp, &mbp);
715 smb_rq_wstart(rqp);
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) */
727 smb_rq_wend(rqp);
728 smb_rq_bstart(rqp);
729 smb_rq_bend(rqp);
731 if (timo == 0)
732 timo = smb_timo_read;
733 error = smb_rq_simple_timed(rqp, timo);
734 if (error)
735 goto out;
737 smb_rq_getreply(rqp, &mdp);
738 error = md_get_uint8(mdp, &wc);
739 if (error)
740 goto out;
741 if (wc != 12) {
742 error = EBADRPC;
743 goto out;
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 */
757 if (error)
758 goto out;
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);
767 if (rlen == 0) {
768 *lenp = rlen;
769 goto out;
771 /* paranoid */
772 if (rlen > *lenp) {
773 SMBSDEBUG("bad server! rlen %d, len %d\n",
774 rlen, *lenp);
775 rlen = *lenp;
777 error = md_get_uio(mdp, uiop, rlen);
778 if (error)
779 goto out;
781 /* Success */
782 *lenp = rlen;
784 out:
785 smb_rq_done(rqp);
786 return (error);
789 static int
790 smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
791 uio_t *uiop, smb_cred_t *scred, int timo)
793 struct smb_rq *rqp;
794 struct mbchain *mbp;
795 struct mdchain *mdp;
796 int error;
797 uint32_t offlo, offhi, rlen;
798 uint16_t lenhi, lenlo;
799 uint8_t wc;
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);
807 if (error)
808 return (error);
809 smb_rq_getrequest(rqp, &mbp);
810 smb_rq_wstart(rqp);
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) */
823 smb_rq_wend(rqp);
824 smb_rq_bstart(rqp);
826 mb_put_uint8(mbp, 0); /* pad byte */
827 error = mb_put_uio(mbp, uiop, *lenp);
828 if (error)
829 goto out;
830 smb_rq_bend(rqp);
831 if (timo == 0)
832 timo = smb_timo_write;
833 error = smb_rq_simple_timed(rqp, timo);
834 if (error)
835 goto out;
836 smb_rq_getreply(rqp, &mdp);
837 error = md_get_uint8(mdp, &wc);
838 if (error)
839 goto out;
840 if (wc != 6) {
841 error = EBADRPC;
842 goto out;
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);
850 if (error)
851 goto out;
853 /* Success */
854 rlen = (lenhi << 16) | lenlo;
855 *lenp = rlen;
857 out:
858 smb_rq_done(rqp);
859 return (error);
862 static int
863 smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
864 uio_t *uiop, smb_cred_t *scred, int timo)
866 struct smb_rq *rqp;
867 struct mbchain *mbp;
868 struct mdchain *mdp;
869 int error;
870 uint32_t off32;
871 uint16_t bc, cnt, dlen, rcnt, todo;
872 uint8_t wc;
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);
882 if (error)
883 return (error);
884 smb_rq_getrequest(rqp, &mbp);
885 smb_rq_wstart(rqp);
886 mb_put_uint16le(mbp, fid);
887 mb_put_uint16le(mbp, cnt);
888 mb_put_uint32le(mbp, off32);
889 mb_put_uint16le(mbp, todo);
890 smb_rq_wend(rqp);
891 smb_rq_bstart(rqp);
892 smb_rq_bend(rqp);
894 if (timo == 0)
895 timo = smb_timo_read;
896 error = smb_rq_simple_timed(rqp, timo);
897 if (error)
898 goto out;
899 smb_rq_getreply(rqp, &mdp);
900 error = md_get_uint8(mdp, &wc);
901 if (error)
902 goto out;
903 if (wc != 5) {
904 error = EBADRPC;
905 goto out;
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 */
912 if (error)
913 goto out;
914 if (dlen < rcnt) {
915 SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
916 (int)dlen, (int)rcnt);
917 rcnt = dlen;
919 if (rcnt == 0) {
920 *lenp = 0;
921 goto out;
923 /* paranoid */
924 if (rcnt > cnt) {
925 SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
926 (int)rcnt, (int)cnt);
927 rcnt = cnt;
929 error = md_get_uio(mdp, uiop, (int)rcnt);
930 if (error)
931 goto out;
933 /* success */
934 *lenp = (int)rcnt;
936 out:
937 smb_rq_done(rqp);
938 return (error);
941 static int
942 smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
943 uio_t *uiop, smb_cred_t *scred, int timo)
945 struct smb_rq *rqp;
946 struct mbchain *mbp;
947 struct mdchain *mdp;
948 int error;
949 uint32_t off32;
950 uint16_t cnt, rcnt, todo;
951 uint8_t wc;
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);
961 if (error)
962 return (error);
963 smb_rq_getrequest(rqp, &mbp);
964 smb_rq_wstart(rqp);
965 mb_put_uint16le(mbp, fid);
966 mb_put_uint16le(mbp, cnt);
967 mb_put_uint32le(mbp, off32);
968 mb_put_uint16le(mbp, todo);
969 smb_rq_wend(rqp);
970 smb_rq_bstart(rqp);
971 mb_put_uint8(mbp, SMB_DT_DATA);
972 mb_put_uint16le(mbp, cnt);
974 error = mb_put_uio(mbp, uiop, *lenp);
975 if (error)
976 goto out;
977 smb_rq_bend(rqp);
978 if (timo == 0)
979 timo = smb_timo_write;
980 error = smb_rq_simple_timed(rqp, timo);
981 if (error)
982 goto out;
983 smb_rq_getreply(rqp, &mdp);
984 error = md_get_uint8(mdp, &wc);
985 if (error)
986 goto out;
987 if (wc != 1) {
988 error = EBADRPC;
989 goto out;
991 error = md_get_uint16le(mdp, &rcnt);
992 if (error)
993 goto out;
994 *lenp = rcnt;
996 out:
997 smb_rq_done(rqp);
998 return (error);
1002 static u_int32_t smbechoes = 0;
1005 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1007 struct smb_rq *rqp;
1008 struct mbchain *mbp;
1009 int error;
1011 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
1012 if (error)
1013 return (error);
1014 mbp = &rqp->sr_rq;
1015 smb_rq_wstart(rqp);
1016 mb_put_uint16le(mbp, 1); /* echo count */
1017 smb_rq_wend(rqp);
1018 smb_rq_bstart(rqp);
1019 mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
1020 smb_rq_bend(rqp);
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);
1029 smb_rq_done(rqp);
1030 return (error);