xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c (revision adee678425979226b2b55d1a0b39ce4c989382e9)
1 /*
2  * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. Please obtain a copy of the License at
10  * http://www.opensource.apple.com/apsl/ and read it before using this
11  * file.
12  *
13  * The Original Code and all software distributed under the License are
14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18  * Please see the License for the specific language governing rights and
19  * limitations under the License.
20  *
21  * @APPLE_LICENSE_HEADER_END@
22  */
23 
24 /*
25  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kmem.h>
31 #include <sys/proc.h>
32 #include <sys/lock.h>
33 #include <sys/socket.h>
34 #include <sys/uio.h>
35 #include <sys/random.h>
36 #include <sys/note.h>
37 #include <sys/errno.h>
38 #include <sys/cmn_err.h>
39 
40 #include <smb/ntaccess.h>
41 #include <smb/winioctl.h>
42 
43 #include <netsmb/smb_osdep.h>
44 
45 #include <netsmb/smb.h>
46 #include <netsmb/smb2.h>
47 #include <netsmb/smb_conn.h>
48 #include <netsmb/smb_subr.h>
49 #include <netsmb/smb_tran.h>
50 #include <netsmb/smb_rq.h>
51 #include <netsmb/smb2_rq.h>
52 
53 #define	NDIALECTS	1
54 static const uint16_t smb2_dialects[1] = {
55 	SMB2_DIALECT_0210
56 };
57 
58 /* Optional capabilities we advertise (none yet). */
59 uint32_t smb2_clnt_caps = 0;
60 
61 /* How many credits to ask for during ssn. setup. */
62 uint16_t smb2_ss_req_credits = 64;
63 
64 /*
65  * Default timeout values, all in seconds.
66  * Make these tunable (only via mdb for now).
67  */
68 int smb2_timo_notice = 15;
69 int smb2_timo_default = 30;
70 int smb2_timo_logon = 45;
71 int smb2_timo_open = 45;
72 int smb2_timo_read = 45;
73 int smb2_timo_write = 60;
74 int smb2_timo_append = 90;
75 
76 /*
77  * This is a special handler for the odd SMB1-to-SMB2 negotiate
78  * response, where an SMB1 request gets an SMB2 response.
79  *
80  * Unlike most parse functions here, this needs to parse both
81  * the SMB2 header and the nego. response body.  Note that
82  * the only "SMB2" dialect our SMB1 negotiate offered was
83  * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
84  * SMB2 dialect we should get is: SMB2_DIALECT_02ff
85  */
86 int
87 smb2_parse_smb1nego_resp(struct smb_rq *rqp)
88 {
89 	struct smb_vc *vcp = rqp->sr_vc;
90 	struct smb_sopt *sp = &vcp->vc_sopt;
91 	struct mdchain *mdp;
92 	uint16_t length = 0;
93 	int error;
94 
95 	/* Get pointer to response data */
96 	smb_rq_getreply(rqp, &mdp);
97 
98 	error = smb2_rq_parsehdr(rqp);
99 	if (error != 0)
100 		return (error);
101 
102 	/*
103 	 * Parse SMB 2/3 Negotiate Response
104 	 * We are already pointing to begining of Response data
105 	 */
106 
107 	/* Check structure size is 65 */
108 	md_get_uint16le(mdp, &length);
109 	if (length != 65)
110 		return (EBADRPC);
111 
112 	/* Get Security Mode */
113 	md_get_uint16le(mdp, &sp->sv2_security_mode);
114 
115 	/* Get Dialect. */
116 	error = md_get_uint16le(mdp, &sp->sv2_dialect);
117 	if (error != 0)
118 		return (error);
119 
120 	/* What dialect did we get? */
121 	if (sp->sv2_dialect != SMB2_DIALECT_02ff) {
122 		SMBERROR("Unknown dialect 0x%x\n", sp->sv2_dialect);
123 		return (EINVAL);
124 	}
125 	/* Set our (internal) SMB1 dialect also. */
126 	sp->sv_proto = SMB_DIALECT_SMB2_FF;
127 
128 	/*
129 	 * This request did not go through smb2_iod_addrq and
130 	 * smb2_iod_process() so the SMB2 message ID state is
131 	 * behind what we need it to be.  Fix that.
132 	 */
133 	vcp->vc2_next_message_id = 1;
134 	vcp->vc2_limit_message_id = 2;
135 
136 	/*
137 	 * Skip parsing the rest.  We'll get a normal
138 	 * SMB2 negotiate next and do negotiate then.
139 	 */
140 	return (0);
141 }
142 
143 int
144 smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
145 {
146 	smb_sopt_t *sp = &vcp->vc_sopt;
147 	smbioc_ssn_work_t *wk = &vcp->vc_work;
148 	struct smb_rq *rqp = NULL;
149 	struct mbchain *mbp = NULL;
150 	struct mdchain *mdp = NULL;
151 	uint16_t ndialects = NDIALECTS;
152 	boolean_t will_sign = B_FALSE;
153 	uint16_t length = 0;
154 	uint16_t security_mode;
155 	uint16_t sec_buf_off;
156 	uint16_t sec_buf_len;
157 	int err, i;
158 
159 	/*
160 	 * Compute security mode
161 	 */
162 	if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
163 		security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
164 	} else {
165 		security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
166 	}
167 
168 	err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
169 	if (err)
170 		return (err);
171 
172 	/*
173 	 * Build the SMB2 negotiate request.
174 	 */
175 	smb_rq_getrequest(rqp, &mbp);
176 	mb_put_uint16le(mbp, 36);		/* Struct Size */
177 	mb_put_uint16le(mbp, ndialects);	/* Dialect Count */
178 	mb_put_uint16le(mbp, security_mode);
179 	mb_put_uint16le(mbp, 0);		/*  Reserved */
180 	mb_put_uint32le(mbp, smb2_clnt_caps);
181 	mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
182 	mb_put_uint64le(mbp, 0);		/* Start Time */
183 	for (i = 0; i < ndialects; i++) {	/* Dialects */
184 		mb_put_uint16le(mbp, smb2_dialects[i]);
185 	}
186 
187 	/*
188 	 * Do the OTW call.
189 	 */
190 	err = smb2_rq_internal(rqp, smb2_timo_default);
191 	if (err) {
192 		goto errout;
193 	}
194 	/* Should only get status success. */
195 	if (rqp->sr_error != NT_STATUS_SUCCESS) {
196 		err = ENOTSUP;
197 		goto errout;
198 	}
199 
200 	/*
201 	 * Decode the negotiate response
202 	 */
203 	smb_rq_getreply(rqp, &mdp);
204 
205 	md_get_uint16le(mdp, &length);	/* Struct size */
206 	if (length != 65) {
207 		err = EBADRPC;
208 		goto errout;
209 	}
210 
211 	md_get_uint16le(mdp, &sp->sv2_security_mode);
212 	md_get_uint16le(mdp, &sp->sv2_dialect);
213 	md_get_uint16le(mdp, NULL);	/* reserved */
214 	md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
215 	md_get_uint32le(mdp, &sp->sv2_capabilities);
216 	md_get_uint32le(mdp, &sp->sv2_maxtransact);
217 	md_get_uint32le(mdp, &sp->sv2_maxread);
218 	md_get_uint32le(mdp, &sp->sv2_maxwrite);
219 	md_get_uint64le(mdp, NULL);	/* curr_time */
220 	md_get_uint64le(mdp, NULL);	/* boot_time */
221 
222 	/* Get Security Blob offset and length */
223 	md_get_uint16le(mdp, &sec_buf_off);
224 	err = md_get_uint16le(mdp, &sec_buf_len);
225 	if (err != 0)
226 		goto errout;
227 	md_get_uint32le(mdp, NULL);	/* reserved */
228 
229 	/*
230 	 * Security buffer offset is from the beginning of SMB 2 Header
231 	 * Calculate how much further we have to go to get to it.
232 	 * Current offset is: SMB2_HDRLEN + 64
233 	 */
234 	if (sec_buf_len != 0) {
235 		int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
236 		if (skip < 0) {
237 			err = EBADRPC;
238 			goto errout;
239 		}
240 		if (skip > 0) {
241 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
242 		}
243 
244 		/*
245 		 * Copy the security blob out to user space.
246 		 * Buffer addr,size in vc_auth_rbuf,rlen
247 		 */
248 		if (wk->wk_u_auth_rlen < sec_buf_len) {
249 			SMBSDEBUG("vc_auth_rbuf too small");
250 			/* Give caller required size. */
251 			wk->wk_u_auth_rlen = sec_buf_len;
252 			err = EMSGSIZE;
253 			goto errout;
254 		}
255 		wk->wk_u_auth_rlen = sec_buf_len;
256 		err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
257 				 sec_buf_len, MB_MUSER);
258 		if (err) {
259 			goto errout;
260 		}
261 	}
262 
263 	/*
264 	 * Decoded everything.  Now decisions.
265 	 */
266 
267 	/*
268 	 * Turn on signing if either Server or client requires it,
269 	 * except: anonymous sessions can't sign.
270 	 */
271 	if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
272 	    (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
273 		will_sign = B_TRUE;
274 	if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
275 		will_sign = B_FALSE;
276 	SMBSDEBUG("Security signatures: %d", (int)will_sign);
277 	if (will_sign)
278 		vcp->vc_flags |= SMBV_SIGNING;
279 
280 	/*
281 	 * ToDo - too many places are looking at sv_caps, so for now
282 	 * set the SMB1 capabilities too.  Later we should use the
283 	 * sv2_capabilities for SMB 2+.
284 	 */
285 	sp->sv_caps =  (SMB_CAP_UNICODE |
286 			SMB_CAP_LARGE_FILES |
287 			SMB_CAP_STATUS32 |
288 			SMB_CAP_LARGE_READX |
289 			SMB_CAP_LARGE_WRITEX |
290 			SMB_CAP_EXT_SECURITY);
291 	if (sp->sv2_capabilities & SMB2_CAP_DFS)
292 		sp->sv_caps |= SMB_CAP_DFS;
293 
294 	/*
295 	 * A few sanity checks on what we received,
296 	 * becuse we will send these in ssnsetup.
297 	 *
298 	 * Maximum outstanding requests (we care),
299 	 * and Max. VCs (we only use one).  Also,
300 	 * MaxBufferSize lower limit per spec.
301 	 */
302 	if (sp->sv2_maxread < 0x8000) {
303 		SMBSDEBUG("maxread too small\n");
304 		err = ENOTSUP;
305 		goto errout;
306 	}
307 	if (sp->sv2_maxwrite < 0x8000) {
308 		SMBSDEBUG("maxwrite too small\n");
309 		err = ENOTSUP;
310 		goto errout;
311 	}
312 	if (sp->sv2_maxtransact < 0x4000) {
313 		SMBSDEBUG("maxtransact too small\n");
314 		err = ENOTSUP;
315 		goto errout;
316 	}
317 
318 	/* Here too, fill SMB1 fields */
319 	vcp->vc_rxmax = sp->sv2_maxread;
320 	vcp->vc_wxmax = sp->sv2_maxwrite;
321 	vcp->vc_txmax = sp->sv2_maxtransact;
322 
323 	smb_rq_done(rqp);
324 	return (0);
325 
326 errout:
327 	smb_rq_done(rqp);
328 	if (err == 0)
329 		err = EBADRPC;
330 	return (err);
331 }
332 
333 int
334 smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
335 {
336 	// smb_sopt_t *sv = &vcp->vc_sopt;
337 	smbioc_ssn_work_t *wk = &vcp->vc_work;
338 	struct smb_rq *rqp = NULL;
339 	struct mbchain *mbp = NULL;
340 	struct mdchain *mdp = NULL;
341 	char *sb;
342 	int err, ret;
343 	uint16_t sblen;
344 	uint16_t length = 0;
345 	uint16_t session_flags;
346 	uint16_t sec_buf_off;
347 	uint16_t sec_buf_len;
348 	uint8_t security_mode;
349 
350 	/*
351 	 * Compute security mode
352 	 */
353 	if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
354 		security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
355 	} else {
356 		security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
357 	}
358 
359 	sb = wk->wk_u_auth_wbuf.lp_ptr;
360 	sblen = (uint16_t)wk->wk_u_auth_wlen;
361 
362 	err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
363 	if (err != 0) {
364 		ret = err;
365 		goto out;
366 	}
367 
368 	/*
369 	 * Always ask for some credits. The server usually will
370 	 * only grant these credits once we've authenticated.
371 	 */
372 	rqp->sr2_creditsrequested = smb2_ss_req_credits;
373 
374 	/*
375 	 * Build the SMB Session Setup request.
376 	 */
377 	smb_rq_getrequest(rqp, &mbp);
378 
379 	mb_put_uint16le(mbp, 25);	/* Struct size */
380 	mb_put_uint8(mbp, 0);		/* VcNumber */
381 	mb_put_uint8(mbp, security_mode);
382 	mb_put_uint32le(mbp, smb2_clnt_caps);	/* Capabilities */
383 	mb_put_uint32le(mbp, 0);	/* Channel - always 0 */
384 
385 	/*
386 	 * Security buffer offset and length.  Normally would use
387 	 * ptr = mb_reserve() and fill in later, but since only a
388 	 * small amount of fixed-size stuff follows (12 bytes)
389 	 * we can just compute the offset now.
390 	 */
391 	mb_put_uint16le(mbp, mbp->mb_count + 12);
392 	mb_put_uint16le(mbp, sblen);
393 	mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
394 	err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
395 	if (err != 0) {
396 		ret = err;
397 		goto out;
398 	}
399 
400 	/*
401 	 * Run the request.  The return value here should be the
402 	 * return from this function, unless we fail decoding.
403 	 * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
404 	 * the caller expects EINPROGRESS for that case.
405 	 */
406 	ret = smb2_rq_internal(rqp, smb2_timo_logon);
407 	if (ret != 0)
408 		goto out;
409 	switch (rqp->sr_error) {
410 	case NT_STATUS_SUCCESS:
411 		break;
412 	case NT_STATUS_MORE_PROCESSING_REQUIRED:
413 		/* Keep going, but return... */
414 		ret = EINPROGRESS;
415 		break;
416 	default:
417 		ret = EAUTH;
418 		goto out;
419 	}
420 
421 	/*
422 	 * After the first Session Setup Response,
423 	 * save the session ID.
424 	 */
425 	if (vcp->vc2_session_id == 0)
426 		vcp->vc2_session_id = rqp->sr2_rspsessionid;
427 
428 	/*
429 	 * Decode the session setup response
430 	 */
431 	smb_rq_getreply(rqp, &mdp);
432 
433 	md_get_uint16le(mdp, &length);	/* Struct size */
434 	if (length != 9) {
435 		ret = EBADRPC;
436 		goto out;
437 	}
438 
439 	md_get_uint16le(mdp, &session_flags);
440 	md_get_uint16le(mdp, &sec_buf_off);
441 	err = md_get_uint16le(mdp, &sec_buf_len);
442 	if (err != 0) {
443 		ret = err;
444 		goto out;
445 	}
446 
447 	/*
448 	 * Security buffer offset is from the beginning of SMB 2 Header
449 	 * Calculate how much further we have to go to get to it.
450 	 * Current offset is: SMB2_HDRLEN + 8
451 	 */
452 	if (sec_buf_len != 0) {
453 		int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
454 		if (skip < 0) {
455 			ret = EBADRPC;
456 			goto out;
457 		}
458 		if (skip > 0) {
459 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
460 		}
461 
462 		/*
463 		 * Copy the security blob out to user space.
464 		 * Buffer addr,size in vc_auth_rbuf,rlen
465 		 */
466 		if (wk->wk_u_auth_rlen < sec_buf_len) {
467 			SMBSDEBUG("vc_auth_rbuf too small");
468 			/* Give caller required size. */
469 			wk->wk_u_auth_rlen = sec_buf_len;
470 			ret = EMSGSIZE;
471 			goto out;
472 		}
473 		wk->wk_u_auth_rlen = sec_buf_len;
474 		err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
475 				 sec_buf_len, MB_MUSER);
476 		if (err != 0) {
477 			ret = err;
478 			goto out;
479 		}
480 	}
481 
482 out:
483 	if (err != 0 && err != EINPROGRESS) {
484 		/* Session ID no longer valid. */
485 		vcp->vc2_session_id = 0;
486 	}
487 	if (rqp)
488 		smb_rq_done(rqp);
489 
490 	return (ret);
491 }
492 
493 int
494 smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
495 {
496 	struct smb_rq *rqp;
497 	struct mbchain *mbp;
498 	int error;
499 
500 	if (vcp->vc2_session_id == 0)
501 		return (0);
502 
503 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
504 	if (error)
505 		return (error);
506 
507 	/*
508 	 * Fill in Logoff part
509 	 */
510 	smb_rq_getrequest(rqp, &mbp);
511 	mb_put_uint16le(mbp, 4);	/* Struct size */
512 	mb_put_uint16le(mbp, 0);	/* Reserved */
513 
514 	/*
515 	 * Run this with a relatively short timeout. (5 sec.)
516 	 * We don't really care about the result here.
517 	 * Also, don't reconnect for this, of course!
518 	 */
519 	rqp->sr_flags |= SMBR_NORECONNECT;
520 	error = smb2_rq_internal(rqp, 5);
521 	smb_rq_done(rqp);
522 	return (error);
523 }
524 
525 int
526 smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
527 {
528 	struct smb_vc *vcp;
529 	struct smb_rq *rqp = NULL;
530 	struct mbchain *mbp;
531 	struct mdchain *mdp;
532 	char *unc_name = NULL;
533 	int error, unc_len;
534 	uint16_t plen, *plenp;
535 	uint16_t options = 0;
536 	uint_t cnt0;
537 	uint32_t net_stype;
538 	uint16_t structure_size = 0;
539 	uint8_t smb2stype;
540 
541 	vcp = SSTOVC(ssp);
542 
543 	/*
544 	 * Make this a "VC-level" request, so it will have
545 	 * rqp->sr_share == NULL, and smb_iod_sendrq()
546 	 * will send it with TID = SMB_TID_UNKNOWN
547 	 *
548 	 * This also serves to bypass the wait for
549 	 * share state changes, which this call is
550 	 * trying to carry out.
551 	 */
552 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
553 	if (error)
554 		return (error);
555 
556 	/*
557 	 * Build the UNC name, i.e. "//server/share"
558 	 * but with backslashes of course.
559 	 * size math: three slashes, one null.
560 	 */
561 	unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
562 	unc_name = kmem_alloc(unc_len, KM_SLEEP);
563 	(void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
564 	    vcp->vc_srvname, ssp->ss_name);
565 	SMBSDEBUG("unc_name: \"%s\"", unc_name);
566 
567 	/*
568 	 * Build the request.
569 	 */
570 	mbp = &rqp->sr_rq;
571 
572 	mb_put_uint16le(mbp, 9);	/* Struct size */
573 	mb_put_uint16le(mbp, 0);	/* Reserved */
574 	mb_put_uint16le(mbp, 72);	/* Path Offset */
575 
576 	/*
577 	 * Fill in path length after we put the string, so we know
578 	 * the length after conversion from UTF-8 to UCS-2.
579 	 */
580 	plenp = mb_reserve(mbp, 2);
581 	cnt0 = mbp->mb_count;
582 
583 	/* UNC resource name (without the null) */
584 	error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
585 	    SMB_CS_NONE, NULL);
586 	if (error)
587 		goto out;
588 
589 	/* Now go back and fill in the path length. */
590 	plen = (uint16_t)(mbp->mb_count - cnt0);
591 	*plenp = htoles(plen);
592 
593 	/*
594 	 * Run the request.
595 	 *
596 	 * Using NOINTR_RECV because we don't want to risk
597 	 * missing a successful tree connect response,
598 	 * which would "leak" Tree IDs.
599 	 */
600 	rqp->sr_flags |= SMBR_NOINTR_RECV;
601 	error = smb2_rq_simple(rqp);
602 	SMBSDEBUG("%d\n", error);
603 	if (error) {
604 		/*
605 		 * If we get the server name wrong, i.e. due to
606 		 * mis-configured name services, this will be
607 		 * NT_STATUS_DUPLICATE_NAME.  Log this error.
608 		 */
609 		SMBERROR("(%s) failed, status=0x%x",
610 		    unc_name, rqp->sr_error);
611 		goto out;
612 	}
613 
614 	/*
615 	 * Parse the tree connect response
616 	 */
617 	smb_rq_getreply(rqp, &mdp);
618 
619 	/* Check structure size is 16 */
620 	md_get_uint16le(mdp, &structure_size);
621 	if (structure_size != 16) {
622 		error = EBADRPC;
623 		goto out;
624 	}
625 
626 	md_get_uint8(mdp, &smb2stype);
627 	md_get_uint8(mdp, NULL);	/* reserved */
628 	md_get_uint32le(mdp, &ssp->ss2_share_flags);
629 	md_get_uint32le(mdp, &ssp->ss2_share_caps);
630 	error = md_get_uint32le(mdp, NULL);	/* maxAccessRights */
631 	if (error)
632 		goto out;
633 
634 	/*
635 	 * Convert SMB2 share type to NetShareEnum share type
636 	 */
637 	switch (smb2stype) {
638 	case SMB2_SHARE_TYPE_DISK:
639 		net_stype = STYPE_DISKTREE;
640 		break;
641 	case SMB2_SHARE_TYPE_PIPE:
642 		net_stype = STYPE_IPC;
643 		break;
644 	case SMB2_SHARE_TYPE_PRINT:
645 		net_stype = STYPE_PRINTQ;
646 		break;
647 	default:
648 		net_stype = STYPE_UNKNOWN;
649 		break;
650 	}
651 	ssp->ss_type = net_stype;
652 
653 	/*
654 	 * Map SMB 2/3 capabilities to SMB 1 options,
655 	 * for common code that looks there.
656 	 */
657 	if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
658 		options |= SMB_SHARE_IS_IN_DFS;
659 
660 	/* Update share state */
661 	SMB_SS_LOCK(ssp);
662 	ssp->ss2_tree_id = rqp->sr2_rsptreeid;
663 	ssp->ss_vcgenid = vcp->vc_genid;
664 	ssp->ss_options = options;
665 	ssp->ss_flags |= SMBS_CONNECTED;
666 	SMB_SS_UNLOCK(ssp);
667 
668 out:
669 	if (unc_name)
670 		kmem_free(unc_name, unc_len);
671 	smb_rq_done(rqp);
672 	return (error);
673 }
674 
675 int
676 smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
677 {
678 	struct smb_vc *vcp;
679 	struct smb_rq *rqp;
680 	struct mbchain *mbp;
681 	int error;
682 
683 	if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
684 		return (0);
685 
686 	/*
687 	 * Build this as a "VC-level" request, so it will
688 	 * avoid testing the _GONE flag on the share,
689 	 * which has already been set at this point.
690 	 * Add the share pointer "by hand" below, so
691 	 * smb_iod_sendrq will plug in the TID.
692 	 */
693 	vcp = SSTOVC(ssp);
694 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
695 	if (error)
696 		return (error);
697 	rqp->sr_share = ssp; /* See "by hand" above. */
698 
699 	/*
700 	 * Fill in SMB2 Tree Disconnect part
701 	 */
702 	smb_rq_getrequest(rqp, &mbp);
703 	mb_put_uint16le(mbp, 4);	/* Struct size */
704 	mb_put_uint16le(mbp, 0);	/* Reserved */
705 
706 	/*
707 	 * Run this with a relatively short timeout. (5 sec.)
708 	 * We don't really care about the result here, but we
709 	 * do need to make sure we send this out, or we could
710 	 * "leak" active tree IDs on interrupt or timeout.
711 	 * The NOINTR_SEND flag makes this request immune to
712 	 * interrupt or timeout until the send is done.
713 	 * Also, don't reconnect for this, of course!
714 	 */
715 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
716 	error = smb2_rq_simple_timed(rqp, 5);
717 
718 	smb_rq_done(rqp);
719 
720 	/* Whether we get an error or not... */
721 	ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
722 
723 	return (error);
724 }
725 
726 /*
727  * Put the name, first skipping a leading slash.
728  */
729 static int
730 put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
731 {
732 	mblk_t *m;
733 
734 	if (name_mbp == NULL)
735 		return (0);
736 	m = name_mbp->mb_top;
737 	if (m == NULL)
738 		return (0);
739 
740 	/* Use a dup of the message to leave the passed one untouched. */
741 	m = dupmsg(m);
742 	if (m == NULL)
743 		return (ENOSR);
744 
745 	if (MBLKL(m) >= 2 &&
746 	    m->b_rptr[0] == '\\' &&
747 	    m->b_rptr[1] == '\0')
748 		m->b_rptr += 2;
749 
750 	return (mb_put_mbuf(mbp, m));
751 }
752 
753 /*
754  * Modern create/open of file or directory.
755  *
756  * The passed name is a full path relative to the share root.
757  * Callers prepare paths with a leading slash (backslash)
758  * because that's what SMB1 expected.  SMB2 does not allow the
759  * leading slash here.  To make life simpler for callers skip a
760  * leading slash here.  That allows callers use use common logic
761  * for building paths without needing to know if the connection
762  * is using SMB1 or SMB2 (just build paths with a leading slash).
763  */
764 int
765 smb2_smb_ntcreate(
766 	struct smb_share *ssp,
767 	struct mbchain	*name_mb,
768 	struct mbchain	*cctx_in,
769 	struct mdchain	*cctx_out,
770 	uint32_t cr_flags,	/* create flags */
771 	uint32_t req_acc,	/* requested access */
772 	uint32_t efa,		/* ext. file attrs (DOS attr +) */
773 	uint32_t share_acc,
774 	uint32_t open_disp,	/* open disposition */
775 	uint32_t createopt,	/* NTCREATEX_OPTIONS_ */
776 	uint32_t impersonate,	/* NTCREATEX_IMPERSONATION_... */
777 	struct smb_cred *scrp,
778 	smb2fid_t *fidp,	/* returned FID */
779 	uint32_t *cr_act_p,	/* optional create action */
780 	struct smbfattr *fap)	/* optional attributes */
781 {
782 	struct smbfattr fa;
783 	struct smb_rq *rqp;
784 	struct mbchain *mbp;
785 	struct mdchain *mdp;
786 	uint16_t *name_offp;
787 	uint16_t *name_lenp;
788 	uint32_t *cctx_offp;
789 	uint32_t *cctx_lenp;
790 	uint32_t rcc_off, rcc_len;
791 	smb2fid_t smb2_fid;
792 	uint64_t llongint;
793 	uint32_t longint, createact;
794 	uint_t off, len;
795 	int error;
796 	uint16_t StructSize = 57;	// [MS-SMB2]
797 
798 	bzero(&fa, sizeof (fa));
799 
800 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
801 	if (error)
802 		return (error);
803 
804 	/*
805 	 * Todo: Assemble creat contexts (if needed)
806 	 * into an mbchain.
807 	 */
808 
809 	/*
810 	 * Build the SMB 2/3 Create Request
811 	 */
812 	smb_rq_getrequest(rqp, &mbp);
813 	mb_put_uint16le(mbp, StructSize);
814 	mb_put_uint8(mbp, 0);				/* Security flags */
815 	mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE);	/* Oplock level */
816 	mb_put_uint32le(mbp, impersonate);		/* Impersonation Level */
817 	mb_put_uint64le(mbp, cr_flags);
818 	mb_put_uint64le(mbp, 0);			/* Reserved */
819 	mb_put_uint32le(mbp, req_acc);
820 	mb_put_uint32le(mbp, efa);			/* File attributes */
821 	mb_put_uint32le(mbp, share_acc);		/* Share access */
822 	mb_put_uint32le(mbp, open_disp);		/* Create disposition */
823 	mb_put_uint32le(mbp, createopt);		/* Create options */
824 
825 	name_offp = mb_reserve(mbp, 2);			/* Name offset */
826 	name_lenp = mb_reserve(mbp, 2);			/* Name len */
827 
828 	cctx_offp = mb_reserve(mbp, 4);			/* Context offset */
829 	cctx_lenp = mb_reserve(mbp, 4);			/* Context len */
830 
831 	/*
832 	 * Put the file name, which is provided in an mbchain.
833 	 * If there's a leading slash, skip it (see above).
834 	 */
835 	off = mbp->mb_count;
836 	*name_offp = htoles((uint16_t)off);
837 	error = put_name_skip_slash(mbp, name_mb);
838 	if (error)
839 		goto out;
840 	len = mbp->mb_count - off;
841 	*name_lenp = htoles((uint16_t)len);
842 
843 	/*
844 	 * Now the create contexts (if provided)
845 	 */
846 	if (cctx_in != NULL) {
847 		off = mbp->mb_count;
848 		*cctx_offp = htolel((uint32_t)off);
849 		mb_put_mbchain(mbp, cctx_in);
850 		len = mbp->mb_count - off;
851 		*cctx_lenp = htolel((uint32_t)len);
852 	} else {
853 		*cctx_offp = 0;
854 		*cctx_lenp = 0;
855 	}
856 
857 	/*
858 	 * If we didn't put any variable-sized data, we'll have
859 	 * put exactly 56 bytes of data, and we need to pad out
860 	 * this request to the 57 bytes StructSize indicated.
861 	 */
862 	if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
863 		mb_put_uint8(mbp, 0);
864 
865 	/*
866 	 * Don't want to risk missing a successful
867 	 * open response, or we could "leak" FIDs.
868 	 */
869 	rqp->sr_flags |= SMBR_NOINTR_RECV;
870 	error = smb2_rq_simple_timed(rqp, smb2_timo_open);
871 	if (error)
872 		goto out;
873 
874 	/*
875 	 * Parse SMB 2/3 Create Response
876 	 */
877 	smb_rq_getreply(rqp, &mdp);
878 
879 	/* Check structure size is 89 */
880 	error = md_get_uint16le(mdp, &StructSize);
881 	if (StructSize != 89) {
882 		error = EBADRPC;
883 		goto out;
884 	}
885 
886 	md_get_uint8(mdp, NULL);		/* oplock lvl granted */
887 	md_get_uint8(mdp, NULL);		/* mbz */
888 	md_get_uint32le(mdp, &createact);	/* create_action */
889 	md_get_uint64le(mdp, &llongint);	/* creation time */
890 	smb_time_NT2local(llongint, &fa.fa_createtime);
891 	md_get_uint64le(mdp, &llongint);	/* access time */
892 	smb_time_NT2local(llongint, &fa.fa_atime);
893 	md_get_uint64le(mdp, &llongint);	/* write time */
894 	smb_time_NT2local(llongint, &fa.fa_mtime);
895 	md_get_uint64le(mdp, &llongint);	/* change time */
896 	smb_time_NT2local(llongint, &fa.fa_ctime);
897 	md_get_uint64le(mdp, &llongint);	/* allocation size */
898 	fa.fa_allocsz = llongint;
899 	md_get_uint64le(mdp, &llongint);	/* EOF position */
900 	fa.fa_size = llongint;
901 	md_get_uint32le(mdp, &longint);		/* attributes */
902 	fa.fa_attr = longint;
903 	md_get_uint32le(mdp, NULL);		/* reserved */
904 
905 	/* Get SMB 2/3 File ID and create user fid to return */
906 	md_get_uint64le(mdp, &smb2_fid.fid_persistent);
907 	error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
908 	if (error)
909 		goto out;
910 
911 	/* Get Context Offset */
912 	error = md_get_uint32le(mdp, &rcc_off);
913 	if (error)
914 		goto out;
915 	/* Get Context Length */
916 	error = md_get_uint32le(mdp, &rcc_len);
917 	if (error)
918 		goto out;
919 
920 	/*
921 	 * If the caller wants the returned create contexts, parse.
922 	 * Context offset is from the beginning of SMB 2/3 Header
923 	 * Calculate how much further we have to go to get to it.
924 	 * Current offset is: SMB2_HDRLEN + 88
925 	 */
926 	if (rcc_len != 0) {
927 		int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
928 		if (skip < 0) {
929 			error = EBADRPC;
930 			goto out;
931 		}
932 		if (skip > 0) {
933 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
934 		}
935 		if (cctx_out != NULL) {
936 			mblk_t *m = NULL;
937 			error = md_get_mbuf(mdp, rcc_len, &m);
938 			if (error)
939 				goto out;
940 			md_initm(cctx_out, m);
941 		}
942 	}
943 
944 out:
945 	smb_rq_done(rqp);
946 	if (error)
947 		return (error);
948 
949 	*fidp = smb2_fid;
950 	if (cr_act_p)
951 		*cr_act_p = createact;
952 	if (fap)
953 		*fap = fa; /* struct copy */
954 
955 	return (0);
956 }
957 
958 int
959 smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
960 {
961 	struct smb_rq *rqp;
962 	struct mbchain *mbp;
963 	int error;
964 
965 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
966 	if (error)
967 		return (error);
968 
969 	/*
970 	 * Build the SMB 2/3 Close Request
971 	 */
972 	smb_rq_getrequest(rqp, &mbp);
973 	mb_put_uint16le(mbp, 24);		/* Struct size */
974 	mb_put_uint16le(mbp, 0);		/* Flags */
975 	mb_put_uint32le(mbp, 0);		/* Reserved */
976 
977 	mb_put_uint64le(mbp, fid->fid_persistent);
978 	mb_put_uint64le(mbp, fid->fid_volatile);
979 
980 	/* Make sure we send, but only if already connected */
981 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
982 	error = smb2_rq_simple(rqp);
983 	smb_rq_done(rqp);
984 	return (error);
985 }
986 
987 int
988 smb2_smb_ioctl(
989 	struct smb_share *ssp,
990 	smb2fid_t *fid,
991 	struct mbchain	*data_in,
992 	struct mdchain	*data_out,
993 	uint32_t *data_out_sz,	/* max / returned */
994 	uint32_t ctl_code,
995 	struct smb_cred *scrp)
996 {
997 	struct smb_rq *rqp;
998 	struct mbchain *mbp;
999 	struct mdchain *mdp;
1000 	uint32_t *data_in_offp;
1001 	uint32_t *data_in_lenp;
1002 	uint32_t data_out_off;
1003 	uint32_t data_out_len;
1004 	uint16_t length = 0;
1005 	uint_t off, len;
1006 	int error;
1007 
1008 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
1009 	if (error)
1010 		return (error);
1011 
1012 	/*
1013 	 * Build the SMB 2 IOCTL Request
1014 	 */
1015 	smb_rq_getrequest(rqp, &mbp);
1016 	mb_put_uint16le(mbp, 57);		/* Struct size */
1017 	mb_put_uint16le(mbp, 0);		/* Reserved */
1018 	mb_put_uint32le(mbp, ctl_code);
1019 
1020 	mb_put_uint64le(mbp, fid->fid_persistent);
1021 	mb_put_uint64le(mbp, fid->fid_volatile);
1022 
1023 	data_in_offp = mb_reserve(mbp, 4);
1024 	data_in_lenp = mb_reserve(mbp, 4);
1025 	mb_put_uint32le(mbp, 0);		/* Max input resp */
1026 
1027 	mb_put_uint32le(mbp, 0);		/* Output offset */
1028 	mb_put_uint32le(mbp, 0);		/* Output count */
1029 	mb_put_uint32le(mbp, *data_out_sz);
1030 
1031 	mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
1032 	mb_put_uint32le(mbp, 0);		/* Reserved2 */
1033 
1034 	/*
1035 	 * Now data_in (if provided)
1036 	 */
1037 	if (data_in != NULL) {
1038 		off = mbp->mb_count;
1039 		*data_in_offp = htolel((uint32_t)off);
1040 		mb_put_mbchain(mbp, data_in);
1041 		len = mbp->mb_count - off;
1042 		*data_in_lenp = htolel((uint32_t)len);
1043 	} else {
1044 		*data_in_offp = 0;
1045 		*data_in_lenp = 0;
1046 	}
1047 
1048 	/*
1049 	 * Run the request
1050 	 */
1051 	error = smb2_rq_simple_timed(rqp, smb2_timo_default);
1052 	if (error)
1053 		goto out;
1054 
1055 	/*
1056 	 * Parse SMB 2 Ioctl Response
1057 	 */
1058 	smb_rq_getreply(rqp, &mdp);
1059 
1060 	/* Check structure size is 49 */
1061 	md_get_uint16le(mdp, &length);
1062 	if (length != 49) {
1063 		error = EBADRPC;
1064 		goto out;
1065 	}
1066 	md_get_uint16le(mdp, NULL);	/* reserved */
1067 	md_get_uint32le(mdp, NULL);	/* Get CtlCode */
1068 	md_get_uint64le(mdp, NULL);	/* fid_persistent */
1069 	md_get_uint64le(mdp, NULL);	/* fid_volatile */
1070 	md_get_uint32le(mdp, NULL);	/* Get Input offset */
1071 	md_get_uint32le(mdp, NULL);	/* Get Input count */
1072 
1073 	error = md_get_uint32le(mdp, &data_out_off);
1074 	if (error)
1075 		goto out;
1076 	error = md_get_uint32le(mdp, &data_out_len);
1077 	if (error)
1078 		goto out;
1079 
1080 	md_get_uint32le(mdp, NULL);	/* Flags */
1081 	md_get_uint32le(mdp, NULL);	/* reserved */
1082 
1083 	/*
1084 	 * If the caller wants the ioctl output data, parse.
1085 	 * Current offset is: SMB2_HDRLEN + 48
1086 	 * Always return the received length.
1087 	 */
1088 	*data_out_sz = data_out_len;
1089 	if (data_out_len != 0) {
1090 		int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
1091 		if (skip < 0) {
1092 			error = EBADRPC;
1093 			goto out;
1094 		}
1095 		if (skip > 0) {
1096 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1097 		}
1098 		if (data_out != NULL) {
1099 			mblk_t *m = NULL;
1100 			error = md_get_mbuf(mdp, data_out_len, &m);
1101 			if (error)
1102 				goto out;
1103 			md_initm(data_out, m);
1104 		}
1105 	}
1106 
1107 out:
1108 	smb_rq_done(rqp);
1109 
1110 	return (error);
1111 }
1112 
1113 int
1114 smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
1115 	uio_t *uiop, smb_cred_t *scred, int timo)
1116 {
1117 	struct smb_share *ssp = FHTOSS(fhp);
1118 	struct smb_rq *rqp;
1119 	struct mbchain *mbp;
1120 	struct mdchain *mdp;
1121 	int error;
1122 	uint64_t off64 = uiop->uio_loffset;
1123 	uint32_t rlen;
1124 	uint16_t length = 0;
1125 	uint8_t data_offset;
1126 
1127 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
1128 	if (error)
1129 		return (error);
1130 
1131 	/*
1132 	 * Build the SMB 2 Read Request
1133 	 */
1134 	smb_rq_getrequest(rqp, &mbp);
1135 	mb_put_uint16le(mbp, 49);		/* Struct size */
1136 	mb_put_uint16le(mbp, 0);		/* Padding and Reserved */
1137 
1138 	mb_put_uint32le(mbp, *lenp);		/* Length of read */
1139 	mb_put_uint64le(mbp, off64);		/* Offset */
1140 
1141 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1142 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1143 
1144 	mb_put_uint32le(mbp, 1);	/* MinCount */
1145 					/* (only indicates blocking) */
1146 
1147 	mb_put_uint32le(mbp, 0);	/* Channel */
1148 	mb_put_uint32le(mbp, 0);	/* Remaining */
1149 	mb_put_uint32le(mbp, 0);	/* Channel offset/len */
1150 	mb_put_uint8(mbp, 0);		/* data "blob" (pad) */
1151 
1152 	if (timo == 0)
1153 		timo = smb2_timo_read;
1154 	error = smb2_rq_simple_timed(rqp, timo);
1155 	if (error)
1156 		goto out;
1157 
1158 	/*
1159 	 * Parse SMB 2 Read Response
1160 	 */
1161 	smb_rq_getreply(rqp, &mdp);
1162 
1163 	/* Check structure size is 17 */
1164 	md_get_uint16le(mdp, &length);
1165 	if (length != 17) {
1166 		error = EBADRPC;
1167 		goto out;
1168 	}
1169 	md_get_uint8(mdp, &data_offset);
1170 	md_get_uint8(mdp, NULL);		/* reserved */
1171 
1172 	/* Get Data Length read */
1173 	error = md_get_uint32le(mdp, &rlen);
1174 	if (error)
1175 		goto out;
1176 
1177 	md_get_uint32le(mdp, NULL);	/* Data Remaining (always 0) */
1178 	md_get_uint32le(mdp, NULL);	/* Get Reserved2 (always 0) */
1179 
1180 	/*
1181 	 * Data offset is from the beginning of SMB 2/3 Header
1182 	 * Calculate how much further we have to go to get to it.
1183 	 */
1184 	if (data_offset < (SMB2_HDRLEN + 16)) {
1185 		error = EBADRPC;
1186 		goto out;
1187 	}
1188 	if (data_offset > (SMB2_HDRLEN + 16)) {
1189 		int skip = data_offset - (SMB2_HDRLEN + 16);
1190 		md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1191 	}
1192 
1193 	/*
1194 	 * Get the data
1195 	 */
1196 	if (rlen == 0) {
1197 		*lenp = rlen;
1198 		goto out;
1199 	}
1200 	/* paranoid */
1201 	if (rlen > *lenp) {
1202 		SMBSDEBUG("bad server! rlen %d, len %d\n",
1203 		    rlen, *lenp);
1204 		rlen = *lenp;
1205 	}
1206 
1207 	error = md_get_uio(mdp, uiop, rlen);
1208 	if (error)
1209 		goto out;
1210 
1211 	/* Success */
1212 	*lenp = rlen;
1213 
1214 out:
1215 	smb_rq_done(rqp);
1216 	return (error);
1217 }
1218 
1219 int
1220 smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
1221 	uio_t *uiop, smb_cred_t *scred, int timo)
1222 {
1223 	struct smb_share *ssp = FHTOSS(fhp);
1224 	struct smb_rq *rqp;
1225 	struct mbchain *mbp;
1226 	struct mdchain *mdp;
1227 	int error;
1228 	uint64_t off64 = uiop->uio_loffset;
1229 	uint32_t rlen;
1230 	uint16_t data_offset;
1231 	uint16_t length = 0;
1232 
1233 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
1234 	if (error)
1235 		return (error);
1236 
1237 	/*
1238 	 * Build the SMB 2 Write Request
1239 	 */
1240 	smb_rq_getrequest(rqp, &mbp);
1241 	mb_put_uint16le(mbp, 49);		/* Struct size */
1242 	data_offset = SMB2_HDRLEN + 48;
1243 	mb_put_uint16le(mbp, data_offset);	/* Data Offset */
1244 	mb_put_uint32le(mbp, *lenp);		/* Length of write */
1245 	mb_put_uint64le(mbp, off64);		/* Offset */
1246 
1247 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1248 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1249 
1250 	mb_put_uint32le(mbp, 0);		/* Channel */
1251 	mb_put_uint32le(mbp, 0);		/* Remaining */
1252 	mb_put_uint32le(mbp, 0);		/* Channel offset/len */
1253 	mb_put_uint32le(mbp, 0);		/* Write flags */
1254 
1255 	error = mb_put_uio(mbp, uiop, *lenp);
1256 	if (error)
1257 		goto out;
1258 
1259 	if (timo == 0)
1260 		timo = smb2_timo_write;
1261 	error = smb2_rq_simple_timed(rqp, timo);
1262 	if (error)
1263 		goto out;
1264 
1265 	/*
1266 	 * Parse SMB 2/3 Write Response
1267 	 */
1268 	smb_rq_getreply(rqp, &mdp);
1269 
1270 	/* Check structure size is 17 */
1271 	md_get_uint16le(mdp, &length);
1272 	if (length != 17) {
1273 		error = EBADRPC;
1274 		goto out;
1275 	}
1276 
1277 	md_get_uint16le(mdp, NULL);    /* Get Reserved */
1278 
1279 	/* Get Data Length written */
1280 	error = md_get_uint32le(mdp, &rlen);
1281 	if (error)
1282 		goto out;
1283 
1284 	/* Get Data Remaining (always 0) */
1285 	md_get_uint32le(mdp, NULL);
1286 
1287 	/* Get Reserved2 (always 0) */
1288 	md_get_uint32le(mdp, NULL);
1289 
1290 	/* Success */
1291 	*lenp = rlen;
1292 
1293 out:
1294 	smb_rq_done(rqp);
1295 	return (error);
1296 }
1297 
1298 /*
1299  * Note: the IOD calls this, so this request must not wait for
1300  * connection state changes, etc. (uses smb2_rq_internal)
1301  */
1302 int
1303 smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1304 {
1305 	struct smb_rq *rqp;
1306 	struct mbchain *mbp;
1307 	int error;
1308 
1309 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
1310 	if (error)
1311 		return (error);
1312 
1313 	/*
1314 	 * Build the SMB 2 Echo Request
1315 	 */
1316 	smb_rq_getrequest(rqp, &mbp);
1317 	mb_put_uint16le(mbp, 4);		/* Struct size */
1318 	mb_put_uint16le(mbp, 0);		/* Reserved */
1319 
1320 	rqp->sr_flags |= SMBR_NORECONNECT;
1321 	error = smb2_rq_internal(rqp, timo);
1322 
1323 	smb_rq_done(rqp);
1324 	return (error);
1325 }
1326