xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c (revision 8329232e00f1048795bae53acb230316243aadb5)
1 /*
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
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.
19  *
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.
31  *
32  * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
33  */
34 
35 /*
36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
38  */
39 
40 /*
41  * various SMB requests. Most of the routines merely packs data into mbufs.
42  */
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/errno.h>
53 #include <sys/cmn_err.h>
54 
55 #include <netsmb/smb_osdep.h>
56 
57 #include <netsmb/smb.h>
58 #include <netsmb/smb_conn.h>
59 #include <netsmb/smb_rq.h>
60 #include <netsmb/smb_subr.h>
61 #include <netsmb/smb_tran.h>
62 
63 #define	STYPE_LEN	8	/* share type strings */
64 
65 /*
66  * Largest size to use with LARGE_READ/LARGE_WRITE.
67  * Specs say up to 64k data bytes, but Windows traffic
68  * uses 60k... no doubt for some good reason.
69  * (Probably to keep 4k block alignment.)
70  * XXX: Move to smb.h maybe?
71  */
72 #define	SMB_MAX_LARGE_RW_SIZE (60*1024)
73 
74 /*
75  * Default timeout values, all in seconds.
76  * Make these tunable (only via mdb for now).
77  */
78 int smb_timo_notice = 15;
79 int smb_timo_default = 30;	/* was SMB_DEFRQTIMO */
80 int smb_timo_open = 45;
81 int smb_timo_read = 45;
82 int smb_timo_write = 60;	/* was SMBWRTTIMO */
83 int smb_timo_append = 90;
84 
85 static int smb_smb_read(struct smb_share *ssp, uint16_t fid,
86 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
87 static int smb_smb_write(struct smb_share *ssp, uint16_t fid,
88 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
89 
90 static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
91 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
92 static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
93 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
94 
95 /*
96  * Get the string representation of a share "use" type,
97  * as needed for the "service" in tree connect.
98  */
99 static const char *
100 smb_share_typename(uint32_t stype)
101 {
102 	const char *p;
103 
104 	switch (stype) {
105 	case STYPE_DISKTREE:
106 		p = "A:";
107 		break;
108 	case STYPE_PRINTQ:
109 		p = "LPT1:";
110 		break;
111 	case STYPE_DEVICE:
112 		p = "COMM";
113 		break;
114 	case STYPE_IPC:
115 		p = "IPC";
116 		break;
117 	case STYPE_UNKNOWN:
118 	default:
119 		p = "?????";
120 		break;
121 	}
122 	return (p);
123 }
124 
125 /*
126  * Parse a share type name (inverse of above)
127  */
128 static uint32_t
129 smb_share_parsetype(char *name)
130 {
131 	int stype;
132 
133 	switch (*name) {
134 	case 'A':	/* A: */
135 		stype = STYPE_DISKTREE;
136 		break;
137 	case 'C':	/* COMM */
138 		stype = STYPE_DEVICE;
139 		break;
140 	case 'I':	/* IPC */
141 		stype = STYPE_IPC;
142 		break;
143 	case 'L':	/* LPT: */
144 		stype = STYPE_PRINTQ;
145 		break;
146 	default:
147 		stype = STYPE_UNKNOWN;
148 		break;
149 	}
150 	return (stype);
151 }
152 
153 int
154 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
155 {
156 	struct smb_vc *vcp;
157 	struct smb_rq *rqp = NULL;
158 	struct mbchain *mbp;
159 	struct mdchain *mdp;
160 	const char *tname;
161 	char *pbuf, *unc_name = NULL;
162 	int error, tlen, plen, unc_len;
163 	uint16_t bcnt, options;
164 	uint8_t wc;
165 	char stype_str[STYPE_LEN];
166 
167 	vcp = SSTOVC(ssp);
168 
169 	/*
170 	 * Make this a "VC-level" request, so it will have
171 	 * rqp->sr_share == NULL, and smb_iod_sendrq()
172 	 * will send it with TID = SMB_TID_UNKNOWN
173 	 *
174 	 * This also serves to bypass the wait for
175 	 * share state changes, which this call is
176 	 * trying to carry out.
177 	 */
178 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
179 	    scred, &rqp);
180 	if (error)
181 		return (error);
182 
183 	/*
184 	 * Build the UNC name, i.e. "//server/share"
185 	 * but with backslashes of course.
186 	 * size math: three slashes, one null.
187 	 */
188 	unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
189 	unc_name = kmem_alloc(unc_len, KM_SLEEP);
190 	(void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
191 	    vcp->vc_srvname, ssp->ss_name);
192 	SMBSDEBUG("unc_name: \"%s\"", unc_name);
193 
194 
195 	/*
196 	 * Share-level password (pre-computed in user-space)
197 	 * MS-SMB 2.2.6 says this should be null terminated,
198 	 * and the pw length includes the null.
199 	 */
200 	pbuf = ssp->ss_pass;
201 	plen = strlen(pbuf) + 1;
202 
203 	/*
204 	 * Build the request.
205 	 */
206 	mbp = &rqp->sr_rq;
207 	smb_rq_wstart(rqp);
208 	mb_put_uint8(mbp, 0xff);
209 	mb_put_uint8(mbp, 0);
210 	mb_put_uint16le(mbp, 0);
211 	mb_put_uint16le(mbp, 0);		/* Flags */
212 	mb_put_uint16le(mbp, plen);
213 	smb_rq_wend(rqp);
214 	smb_rq_bstart(rqp);
215 
216 	/* Tree connect password, if any */
217 	error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
218 	if (error)
219 		goto out;
220 
221 	/* UNC resource name */
222 	error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
223 	if (error)
224 		goto out;
225 
226 	/*
227 	 * Put the type string (always ASCII),
228 	 * including the null.
229 	 */
230 	tname = smb_share_typename(ssp->ss_use);
231 	tlen = strlen(tname) + 1;
232 	error = mb_put_mem(mbp, tname, tlen, MB_MSYSTEM);
233 	if (error)
234 		goto out;
235 
236 	smb_rq_bend(rqp);
237 
238 	/*
239 	 * Run the request.
240 	 *
241 	 * Using NOINTR_RECV because we don't want to risk
242 	 * missing a successful tree connect response,
243 	 * which would "leak" Tree IDs.
244 	 */
245 	rqp->sr_flags |= SMBR_NOINTR_RECV;
246 	error = smb_rq_simple(rqp);
247 	SMBSDEBUG("%d\n", error);
248 	if (error) {
249 		/*
250 		 * If we get the server name wrong, i.e. due to
251 		 * mis-configured name services, this will be
252 		 * NT_STATUS_DUPLICATE_NAME.  Log this error.
253 		 */
254 		SMBERROR("(%s) failed, status=0x%x",
255 		    unc_name, rqp->sr_error);
256 		goto out;
257 	}
258 
259 	/*
260 	 * Parse the TCON response
261 	 */
262 	smb_rq_getreply(rqp, &mdp);
263 	md_get_uint8(mdp, &wc);
264 	if (wc != 3 && wc != 7) {
265 		error = EBADRPC;
266 		goto out;
267 	}
268 	md_get_uint16le(mdp, NULL);		/* AndX cmd */
269 	md_get_uint16le(mdp, NULL);		/* AndX off */
270 	md_get_uint16le(mdp, &options);		/* option bits (DFS, search) */
271 	if (wc == 7) {
272 		md_get_uint32le(mdp, NULL);	/* MaximalShareAccessRights */
273 		md_get_uint32le(mdp, NULL);	/* GuestMaximalShareAcc... */
274 	}
275 	error = md_get_uint16le(mdp, &bcnt);	/* byte count */
276 	if (error)
277 		goto out;
278 
279 	/*
280 	 * Get the returned share type string, i.e. "IPC" or whatever.
281 	 * (See smb_share_typename, smb_share_parsetype).  If we get
282 	 * an error reading the type, just say STYPE_UNKNOWN.
283 	 */
284 	tlen = STYPE_LEN;
285 	bzero(stype_str, tlen--);
286 	if (tlen > bcnt)
287 		tlen = bcnt;
288 	md_get_mem(mdp, stype_str, tlen, MB_MSYSTEM);
289 	stype_str[tlen] = '\0';
290 	ssp->ss_type = smb_share_parsetype(stype_str);
291 
292 	/* Success! */
293 	SMB_SS_LOCK(ssp);
294 	ssp->ss_tid = rqp->sr_rptid;
295 	ssp->ss_vcgenid = vcp->vc_genid;
296 	ssp->ss_options = options;
297 	ssp->ss_flags |= SMBS_CONNECTED;
298 	SMB_SS_UNLOCK(ssp);
299 
300 out:
301 	if (unc_name)
302 		kmem_free(unc_name, unc_len);
303 	smb_rq_done(rqp);
304 	return (error);
305 }
306 
307 int
308 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
309 {
310 	struct smb_vc *vcp;
311 	struct smb_rq *rqp;
312 	int error;
313 
314 	if (ssp->ss_tid == SMB_TID_UNKNOWN)
315 		return (0);
316 
317 	/*
318 	 * Build this as a "VC-level" request, so it will
319 	 * avoid testing the _GONE flag on the share,
320 	 * which has already been set at this point.
321 	 * Add the share pointer "by hand" below, so
322 	 * smb_iod_sendrq will plug in the TID.
323 	 */
324 	vcp = SSTOVC(ssp);
325 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
326 	if (error)
327 		return (error);
328 	rqp->sr_share = ssp; /* by hand */
329 
330 	smb_rq_wstart(rqp);
331 	smb_rq_wend(rqp);
332 	smb_rq_bstart(rqp);
333 	smb_rq_bend(rqp);
334 
335 	/*
336 	 * Run this with a relatively short timeout. (5 sec.)
337 	 * We don't really care about the result here, but we
338 	 * do need to make sure we send this out, or we could
339 	 * "leak" active tree IDs on interrupt or timeout.
340 	 * The NOINTR_SEND flag makes this request immune to
341 	 * interrupt or timeout until the send is done.
342 	 * Also, don't reconnect for this, of course!
343 	 */
344 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
345 	error = smb_rq_simple_timed(rqp, 5);
346 	SMBSDEBUG("%d\n", error);
347 	smb_rq_done(rqp);
348 	ssp->ss_tid = SMB_TID_UNKNOWN;
349 	return (error);
350 }
351 
352 /*
353  * Modern create/open of file or directory.
354  */
355 int
356 smb_smb_ntcreate(
357 	struct smb_share *ssp,
358 	struct mbchain	*name_mb,
359 	uint32_t cr_flags,	/* create flags */
360 	uint32_t req_acc,	/* requested access */
361 	uint32_t efa,		/* ext. file attrs (DOS attr +) */
362 	uint32_t share_acc,
363 	uint32_t open_disp,	/* open disposition */
364 	uint32_t createopt,	/* NTCREATEX_OPTIONS_ */
365 	uint32_t impersonate,	/* NTCREATEX_IMPERSONATION_... */
366 	struct smb_cred *scrp,
367 	uint16_t *fidp,		/* returned FID */
368 	uint32_t *cr_act_p,	/* optional create action */
369 	struct smbfattr *fap)	/* optional attributes */
370 {
371 	struct smb_rq rq, *rqp = &rq;
372 	struct smb_vc *vcp = SSTOVC(ssp);
373 	struct mbchain *mbp;
374 	struct mdchain *mdp;
375 	struct smbfattr fa;
376 	uint64_t llongint;
377 	uint32_t longint, createact;
378 	uint16_t fid;
379 	uint8_t wc;
380 	int error;
381 
382 	bzero(&fa, sizeof (fa));
383 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
384 	if (error)
385 		return (error);
386 	smb_rq_getrequest(rqp, &mbp);
387 
388 	/* Word parameters */
389 	smb_rq_wstart(rqp);
390 	mb_put_uint8(mbp, 0xff);	/* secondary command */
391 	mb_put_uint8(mbp, 0);		/* MBZ */
392 	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
393 	mb_put_uint8(mbp, 0);		/* MBZ */
394 	mb_put_uint16le(mbp, name_mb->mb_count);
395 	mb_put_uint32le(mbp, cr_flags);	/* NTCREATEX_FLAGS_* */
396 	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
397 	mb_put_uint32le(mbp, req_acc);
398 	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
399 	mb_put_uint32le(mbp, efa);
400 	mb_put_uint32le(mbp, share_acc);
401 	mb_put_uint32le(mbp, open_disp);
402 	mb_put_uint32le(mbp, createopt);
403 	mb_put_uint32le(mbp, impersonate);
404 	mb_put_uint8(mbp, 0);   /* security flags (?) */
405 	smb_rq_wend(rqp);
406 
407 	/*
408 	 * Byte parameters: Just the path name, aligned.
409 	 * Note: mb_put_mbuf consumes mb_top, so clear it.
410 	 */
411 	smb_rq_bstart(rqp);
412 	if (SMB_UNICODE_STRINGS(vcp))
413 		mb_put_padbyte(mbp);
414 	mb_put_mbuf(mbp, name_mb->mb_top);
415 	bzero(name_mb, sizeof (*name_mb));
416 	smb_rq_bend(rqp);
417 
418 	/*
419 	 * Don't want to risk missing a successful
420 	 * open response, or we could "leak" FIDs.
421 	 */
422 	rqp->sr_flags |= SMBR_NOINTR_RECV;
423 	error = smb_rq_simple_timed(rqp, smb_timo_open);
424 	if (error)
425 		goto done;
426 	smb_rq_getreply(rqp, &mdp);
427 	/*
428 	 * spec says 26 for word count, but 34 words are defined
429 	 * and observed from win2000
430 	 */
431 	error = md_get_uint8(mdp, &wc);
432 	if (error)
433 		goto done;
434 	if (wc != 26 && wc < 34) {
435 		error = EBADRPC;
436 		goto done;
437 	}
438 	md_get_uint8(mdp, NULL);		/* secondary cmd */
439 	md_get_uint8(mdp, NULL);		/* mbz */
440 	md_get_uint16le(mdp, NULL);		/* andxoffset */
441 	md_get_uint8(mdp, NULL);		/* oplock lvl granted */
442 	md_get_uint16le(mdp, &fid);		/* file ID */
443 	md_get_uint32le(mdp, &createact);	/* create_action */
444 
445 	md_get_uint64le(mdp, &llongint);	/* creation time */
446 	smb_time_NT2local(llongint, &fa.fa_createtime);
447 	md_get_uint64le(mdp, &llongint);	/* access time */
448 	smb_time_NT2local(llongint, &fa.fa_atime);
449 	md_get_uint64le(mdp, &llongint);	/* write time */
450 	smb_time_NT2local(llongint, &fa.fa_mtime);
451 	md_get_uint64le(mdp, &llongint);	/* change time */
452 	smb_time_NT2local(llongint, &fa.fa_ctime);
453 
454 	md_get_uint32le(mdp, &longint);		/* attributes */
455 	fa.fa_attr = longint;
456 	md_get_uint64le(mdp, &llongint);	/* allocation size */
457 	fa.fa_allocsz = llongint;
458 	md_get_uint64le(mdp, &llongint);	/* EOF position */
459 	fa.fa_size = llongint;
460 
461 	error = md_get_uint16le(mdp, NULL);	/* file type */
462 	/* other stuff we don't care about */
463 
464 done:
465 	smb_rq_done(rqp);
466 	if (error)
467 		return (error);
468 
469 	*fidp = fid;
470 	if (cr_act_p)
471 		*cr_act_p = createact;
472 	if (fap)
473 		*fap = fa; /* struct copy */
474 
475 	return (0);
476 }
477 
478 int
479 smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
480 	struct smb_cred *scrp)
481 {
482 	struct smb_rq rq, *rqp = &rq;
483 	struct mbchain *mbp;
484 	long time;
485 	int error;
486 
487 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
488 	if (error)
489 		return (error);
490 	smb_rq_getrequest(rqp, &mbp);
491 	smb_rq_wstart(rqp);
492 	mb_put_uint16le(mbp, fid);
493 	if (mtime) {
494 		int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
495 		smb_time_local2server(mtime, sv_tz, &time);
496 	} else {
497 		time = 0;
498 	}
499 	mb_put_uint32le(mbp, time);
500 	smb_rq_wend(rqp);
501 	smb_rq_bstart(rqp);
502 	smb_rq_bend(rqp);
503 
504 	/* Make sure we send, but only if already connected */
505 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
506 	error = smb_rq_simple(rqp);
507 	smb_rq_done(rqp);
508 	return (error);
509 }
510 
511 int
512 smb_smb_open_prjob(
513 	struct smb_share *ssp,
514 	char	*title,
515 	uint16_t setuplen,
516 	uint16_t mode,
517 	struct smb_cred *scrp,
518 	uint16_t *fidp)
519 {
520 	struct smb_rq rq, *rqp = &rq;
521 	struct smb_vc *vcp = SSTOVC(ssp);
522 	struct mbchain *mbp;
523 	struct mdchain *mdp;
524 	uint16_t fid;
525 	uint8_t wc;
526 	int error;
527 
528 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN_PRINT_FILE, scrp);
529 	if (error)
530 		return (error);
531 	smb_rq_getrequest(rqp, &mbp);
532 
533 	/* Word parameters */
534 	smb_rq_wstart(rqp);
535 	mb_put_uint16le(mbp, setuplen);
536 	mb_put_uint16le(mbp, mode);
537 	smb_rq_wend(rqp);
538 
539 	/*
540 	 * Byte parameters: Just the title
541 	 */
542 	smb_rq_bstart(rqp);
543 	mb_put_uint8(mbp, SMB_DT_ASCII);
544 	error = smb_put_dstring(mbp, vcp, title, SMB_CS_NONE);
545 	smb_rq_bend(rqp);
546 	if (error)
547 		goto done;
548 
549 	/*
550 	 * Don't want to risk missing a successful
551 	 * open response, or we could "leak" FIDs.
552 	 */
553 	rqp->sr_flags |= SMBR_NOINTR_RECV;
554 	error = smb_rq_simple_timed(rqp, smb_timo_open);
555 	if (error)
556 		goto done;
557 
558 	smb_rq_getreply(rqp, &mdp);
559 	error = md_get_uint8(mdp, &wc);
560 	if (error || wc < 1) {
561 		error = EBADRPC;
562 		goto done;
563 	}
564 	error = md_get_uint16le(mdp, &fid);
565 
566 done:
567 	smb_rq_done(rqp);
568 	if (error)
569 		return (error);
570 
571 	*fidp = fid;
572 	return (0);
573 }
574 
575 /*
576  * Like smb_smb_close, but for print shares.
577  */
578 int
579 smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
580 	struct smb_cred *scrp)
581 {
582 	struct smb_rq rq, *rqp = &rq;
583 	struct mbchain *mbp;
584 	int error;
585 
586 	error = smb_rq_init(rqp, SSTOCP(ssp),
587 	    SMB_COM_CLOSE_PRINT_FILE, scrp);
588 	if (error)
589 		return (error);
590 	smb_rq_getrequest(rqp, &mbp);
591 	smb_rq_wstart(rqp);
592 	mb_put_uint16le(mbp, fid);
593 	smb_rq_wend(rqp);
594 	smb_rq_bstart(rqp);
595 	smb_rq_bend(rqp);
596 
597 	/* Make sure we send but only if already connected */
598 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
599 	error = smb_rq_simple(rqp);
600 	smb_rq_done(rqp);
601 	return (error);
602 }
603 
604 /*
605  * Common function for read/write with UIO.
606  * Called by netsmb smb_usr_rw,
607  *  smbfs_readvnode, smbfs_writevnode
608  */
609 int
610 smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
611 	uio_t *uiop, smb_cred_t *scred, int timo)
612 {
613 	struct smb_vc *vcp = SSTOVC(ssp);
614 	ssize_t  save_resid;
615 	uint32_t len, rlen, maxlen;
616 	int error = 0;
617 	int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
618 	    uio_t *, smb_cred_t *, int);
619 
620 	/*
621 	 * Determine which function to use,
622 	 * and the transfer size per call.
623 	 */
624 	if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
625 		/*
626 		 * Using NT LM 0.12, so readx, writex.
627 		 * Make sure we can represent the offset.
628 		 */
629 		if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
630 		    (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
631 			return (EFBIG);
632 
633 		if (rw == UIO_READ) {
634 			iofun = smb_smb_readx;
635 			if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
636 				maxlen = SMB_MAX_LARGE_RW_SIZE;
637 			else
638 				maxlen = vcp->vc_rxmax;
639 		} else { /* UIO_WRITE */
640 			iofun = smb_smb_writex;
641 			if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
642 				maxlen = SMB_MAX_LARGE_RW_SIZE;
643 			else
644 				maxlen = vcp->vc_wxmax;
645 		}
646 	} else {
647 		/*
648 		 * Using the old SMB_READ and SMB_WRITE so
649 		 * we're limited to 32-bit offsets, etc.
650 		 * XXX: Someday, punt the old dialects.
651 		 */
652 		if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
653 			return (EFBIG);
654 
655 		if (rw == UIO_READ) {
656 			iofun = smb_smb_read;
657 			maxlen = vcp->vc_rxmax;
658 		} else { /* UIO_WRITE */
659 			iofun = smb_smb_write;
660 			maxlen = vcp->vc_wxmax;
661 		}
662 	}
663 
664 	save_resid = uiop->uio_resid;
665 	while (uiop->uio_resid > 0) {
666 		/* Lint: uio_resid may be 64-bits */
667 		rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
668 		error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
669 
670 		/*
671 		 * Note: the iofun called uio_update, so
672 		 * not doing that here as one might expect.
673 		 *
674 		 * Quit the loop either on error, or if we
675 		 * transferred less then requested.
676 		 */
677 		if (error || (rlen < len))
678 			break;
679 
680 		timo = 0; /* only first I/O should wait */
681 	}
682 	if (error && (save_resid != uiop->uio_resid)) {
683 		/*
684 		 * Stopped on an error after having
685 		 * successfully transferred data.
686 		 * Suppress this error.
687 		 */
688 		SMBSDEBUG("error %d suppressed\n", error);
689 		error = 0;
690 	}
691 
692 	return (error);
693 }
694 
695 static int
696 smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
697 	uio_t *uiop, smb_cred_t *scred, int timo)
698 {
699 	struct smb_rq *rqp;
700 	struct mbchain *mbp;
701 	struct mdchain *mdp;
702 	int error;
703 	uint32_t offlo, offhi, rlen;
704 	uint16_t lenhi, lenlo, off, doff;
705 	uint8_t wc;
706 
707 	lenhi = (uint16_t)(*lenp >> 16);
708 	lenlo = (uint16_t)*lenp;
709 	offhi = (uint32_t)(uiop->uio_loffset >> 32);
710 	offlo = (uint32_t)uiop->uio_loffset;
711 
712 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
713 	if (error)
714 		return (error);
715 	smb_rq_getrequest(rqp, &mbp);
716 	smb_rq_wstart(rqp);
717 	mb_put_uint8(mbp, 0xff);	/* no secondary command */
718 	mb_put_uint8(mbp, 0);		/* MBZ */
719 	mb_put_uint16le(mbp, 0);	/* offset to secondary */
720 	mb_put_uint16le(mbp, fid);
721 	mb_put_uint32le(mbp, offlo);	/* offset (low part) */
722 	mb_put_uint16le(mbp, lenlo);	/* MaxCount */
723 	mb_put_uint16le(mbp, 1);	/* MinCount */
724 					/* (only indicates blocking) */
725 	mb_put_uint32le(mbp, lenhi);	/* MaxCountHigh */
726 	mb_put_uint16le(mbp, lenlo);	/* Remaining ("obsolete") */
727 	mb_put_uint32le(mbp, offhi);	/* offset (high part) */
728 	smb_rq_wend(rqp);
729 	smb_rq_bstart(rqp);
730 	smb_rq_bend(rqp);
731 
732 	if (timo == 0)
733 		timo = smb_timo_read;
734 	error = smb_rq_simple_timed(rqp, timo);
735 	if (error)
736 		goto out;
737 
738 	smb_rq_getreply(rqp, &mdp);
739 	error = md_get_uint8(mdp, &wc);
740 	if (error)
741 		goto out;
742 	if (wc != 12) {
743 		error = EBADRPC;
744 		goto out;
745 	}
746 	md_get_uint8(mdp, NULL);
747 	md_get_uint8(mdp, NULL);
748 	md_get_uint16le(mdp, NULL);
749 	md_get_uint16le(mdp, NULL);
750 	md_get_uint16le(mdp, NULL);	/* data compaction mode */
751 	md_get_uint16le(mdp, NULL);
752 	md_get_uint16le(mdp, &lenlo);	/* data len ret. */
753 	md_get_uint16le(mdp, &doff);	/* data offset */
754 	md_get_uint16le(mdp, &lenhi);
755 	rlen = (lenhi << 16) | lenlo;
756 	md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
757 	error = md_get_uint16le(mdp, NULL);	/* ByteCount */
758 	if (error)
759 		goto out;
760 	/*
761 	 * Does the data offset indicate padding?
762 	 * The current offset is a constant, found
763 	 * by counting the md_get_ calls above.
764 	 */
765 	off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */
766 	if (doff > off)	/* pad byte(s)? */
767 		md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
768 	if (rlen == 0) {
769 		*lenp = rlen;
770 		goto out;
771 	}
772 	/* paranoid */
773 	if (rlen > *lenp) {
774 		SMBSDEBUG("bad server! rlen %d, len %d\n",
775 		    rlen, *lenp);
776 		rlen = *lenp;
777 	}
778 	error = md_get_uio(mdp, uiop, rlen);
779 	if (error)
780 		goto out;
781 
782 	/* Success */
783 	*lenp = rlen;
784 
785 out:
786 	smb_rq_done(rqp);
787 	return (error);
788 }
789 
790 static int
791 smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
792 	uio_t *uiop, smb_cred_t *scred, int timo)
793 {
794 	struct smb_rq *rqp;
795 	struct mbchain *mbp;
796 	struct mdchain *mdp;
797 	int error;
798 	uint32_t offlo, offhi, rlen;
799 	uint16_t lenhi, lenlo;
800 	uint8_t wc;
801 
802 	lenhi = (uint16_t)(*lenp >> 16);
803 	lenlo = (uint16_t)*lenp;
804 	offhi = (uint32_t)(uiop->uio_loffset >> 32);
805 	offlo = (uint32_t)uiop->uio_loffset;
806 
807 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
808 	if (error)
809 		return (error);
810 	smb_rq_getrequest(rqp, &mbp);
811 	smb_rq_wstart(rqp);
812 	mb_put_uint8(mbp, 0xff);	/* no secondary command */
813 	mb_put_uint8(mbp, 0);		/* MBZ */
814 	mb_put_uint16le(mbp, 0);	/* offset to secondary */
815 	mb_put_uint16le(mbp, fid);
816 	mb_put_uint32le(mbp, offlo);	/* offset (low part) */
817 	mb_put_uint32le(mbp, 0);	/* MBZ (timeout) */
818 	mb_put_uint16le(mbp, 0);	/* !write-thru */
819 	mb_put_uint16le(mbp, 0);
820 	mb_put_uint16le(mbp, lenhi);
821 	mb_put_uint16le(mbp, lenlo);
822 	mb_put_uint16le(mbp, 64);	/* data offset from header start */
823 	mb_put_uint32le(mbp, offhi);	/* offset (high part) */
824 	smb_rq_wend(rqp);
825 	smb_rq_bstart(rqp);
826 
827 	mb_put_uint8(mbp, 0);	/* pad byte */
828 	error = mb_put_uio(mbp, uiop, *lenp);
829 	if (error)
830 		goto out;
831 	smb_rq_bend(rqp);
832 	if (timo == 0)
833 		timo = smb_timo_write;
834 	error = smb_rq_simple_timed(rqp, timo);
835 	if (error)
836 		goto out;
837 	smb_rq_getreply(rqp, &mdp);
838 	error = md_get_uint8(mdp, &wc);
839 	if (error)
840 		goto out;
841 	if (wc != 6) {
842 		error = EBADRPC;
843 		goto out;
844 	}
845 	md_get_uint8(mdp, NULL);	/* andx cmd */
846 	md_get_uint8(mdp, NULL);	/* reserved */
847 	md_get_uint16le(mdp, NULL);	/* andx offset */
848 	md_get_uint16le(mdp, &lenlo);	/* data len ret. */
849 	md_get_uint16le(mdp, NULL);	/* remaining */
850 	error = md_get_uint16le(mdp, &lenhi);
851 	if (error)
852 		goto out;
853 
854 	/* Success */
855 	rlen = (lenhi << 16) | lenlo;
856 	*lenp = rlen;
857 
858 out:
859 	smb_rq_done(rqp);
860 	return (error);
861 }
862 
863 static int
864 smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
865 	uio_t *uiop, smb_cred_t *scred, int timo)
866 {
867 	struct smb_rq *rqp;
868 	struct mbchain *mbp;
869 	struct mdchain *mdp;
870 	int error;
871 	uint32_t off32;
872 	uint16_t bc, cnt, dlen, rcnt, todo;
873 	uint8_t wc;
874 
875 	ASSERT(uiop->uio_loffset <= UINT32_MAX);
876 	off32 = (uint32_t)uiop->uio_loffset;
877 	ASSERT(*lenp <= UINT16_MAX);
878 	cnt = (uint16_t)*lenp;
879 	/* This next is an "estimate" of planned reads. */
880 	todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
881 
882 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
883 	if (error)
884 		return (error);
885 	smb_rq_getrequest(rqp, &mbp);
886 	smb_rq_wstart(rqp);
887 	mb_put_uint16le(mbp, fid);
888 	mb_put_uint16le(mbp, cnt);
889 	mb_put_uint32le(mbp, off32);
890 	mb_put_uint16le(mbp, todo);
891 	smb_rq_wend(rqp);
892 	smb_rq_bstart(rqp);
893 	smb_rq_bend(rqp);
894 
895 	if (timo == 0)
896 		timo = smb_timo_read;
897 	error = smb_rq_simple_timed(rqp, timo);
898 	if (error)
899 		goto out;
900 	smb_rq_getreply(rqp, &mdp);
901 	error = md_get_uint8(mdp, &wc);
902 	if (error)
903 		goto out;
904 	if (wc != 5) {
905 		error = EBADRPC;
906 		goto out;
907 	}
908 	md_get_uint16le(mdp, &rcnt);		/* ret. count */
909 	md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);  /* res. */
910 	md_get_uint16le(mdp, &bc);		/* byte count */
911 	md_get_uint8(mdp, NULL);		/* buffer format */
912 	error = md_get_uint16le(mdp, &dlen);	/* data len */
913 	if (error)
914 		goto out;
915 	if (dlen < rcnt) {
916 		SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
917 		    (int)dlen, (int)rcnt);
918 		rcnt = dlen;
919 	}
920 	if (rcnt == 0) {
921 		*lenp = 0;
922 		goto out;
923 	}
924 	/* paranoid */
925 	if (rcnt > cnt) {
926 		SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
927 		    (int)rcnt, (int)cnt);
928 		rcnt = cnt;
929 	}
930 	error = md_get_uio(mdp, uiop, (int)rcnt);
931 	if (error)
932 		goto out;
933 
934 	/* success */
935 	*lenp = (int)rcnt;
936 
937 out:
938 	smb_rq_done(rqp);
939 	return (error);
940 }
941 
942 static int
943 smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
944 	uio_t *uiop, smb_cred_t *scred, int timo)
945 {
946 	struct smb_rq *rqp;
947 	struct mbchain *mbp;
948 	struct mdchain *mdp;
949 	int error;
950 	uint32_t off32;
951 	uint16_t cnt, rcnt, todo;
952 	uint8_t wc;
953 
954 	ASSERT(uiop->uio_loffset <= UINT32_MAX);
955 	off32 = (uint32_t)uiop->uio_loffset;
956 	ASSERT(*lenp <= UINT16_MAX);
957 	cnt = (uint16_t)*lenp;
958 	/* This next is an "estimate" of planned writes. */
959 	todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
960 
961 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
962 	if (error)
963 		return (error);
964 	smb_rq_getrequest(rqp, &mbp);
965 	smb_rq_wstart(rqp);
966 	mb_put_uint16le(mbp, fid);
967 	mb_put_uint16le(mbp, cnt);
968 	mb_put_uint32le(mbp, off32);
969 	mb_put_uint16le(mbp, todo);
970 	smb_rq_wend(rqp);
971 	smb_rq_bstart(rqp);
972 	mb_put_uint8(mbp, SMB_DT_DATA);
973 	mb_put_uint16le(mbp, cnt);
974 
975 	error = mb_put_uio(mbp, uiop, *lenp);
976 	if (error)
977 		goto out;
978 	smb_rq_bend(rqp);
979 	if (timo == 0)
980 		timo = smb_timo_write;
981 	error = smb_rq_simple_timed(rqp, timo);
982 	if (error)
983 		goto out;
984 	smb_rq_getreply(rqp, &mdp);
985 	error = md_get_uint8(mdp, &wc);
986 	if (error)
987 		goto out;
988 	if (wc != 1) {
989 		error = EBADRPC;
990 		goto out;
991 	}
992 	error = md_get_uint16le(mdp, &rcnt);
993 	if (error)
994 		goto out;
995 	*lenp = rcnt;
996 
997 out:
998 	smb_rq_done(rqp);
999 	return (error);
1000 }
1001 
1002 
1003 static u_int32_t	smbechoes = 0;
1004 
1005 int
1006 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1007 {
1008 	struct smb_rq *rqp;
1009 	struct mbchain *mbp;
1010 	int error;
1011 
1012 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
1013 	if (error)
1014 		return (error);
1015 	mbp = &rqp->sr_rq;
1016 	smb_rq_wstart(rqp);
1017 	mb_put_uint16le(mbp, 1); /* echo count */
1018 	smb_rq_wend(rqp);
1019 	smb_rq_bstart(rqp);
1020 	mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
1021 	smb_rq_bend(rqp);
1022 	/*
1023 	 * Note: the IOD calls this, so
1024 	 * this request must not wait for
1025 	 * connection state changes, etc.
1026 	 */
1027 	rqp->sr_flags |= SMBR_NORECONNECT;
1028 	error = smb_rq_simple_timed(rqp, timo);
1029 	SMBSDEBUG("%d\n", error);
1030 	smb_rq_done(rqp);
1031 	return (error);
1032 }
1033