14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001, Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smb_rq.c,v 1.29 2005/02/11 01:44:17 lindak Exp $
334bff34e3Sthurlow  */
349c9af259SGordon Ross 
354bff34e3Sthurlow /*
36148c5f43SAlan Wright  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37*adee6784SGordon Ross  * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
3840c0e231SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
394bff34e3Sthurlow  */
404bff34e3Sthurlow 
414bff34e3Sthurlow #include <sys/param.h>
424bff34e3Sthurlow #include <sys/systm.h>
4302d09e03SGordon Ross #include <sys/time.h>
444bff34e3Sthurlow #include <sys/kmem.h>
454bff34e3Sthurlow #include <sys/proc.h>
464bff34e3Sthurlow #include <sys/lock.h>
474bff34e3Sthurlow #include <sys/socket.h>
484bff34e3Sthurlow #include <sys/mount.h>
49613a2f6bSGordon Ross #include <sys/sunddi.h>
504bff34e3Sthurlow #include <sys/cmn_err.h>
514bff34e3Sthurlow #include <sys/sdt.h>
524bff34e3Sthurlow 
534bff34e3Sthurlow #include <netsmb/smb_osdep.h>
544bff34e3Sthurlow 
554bff34e3Sthurlow #include <netsmb/smb.h>
56*adee6784SGordon Ross #include <netsmb/smb2.h>
574bff34e3Sthurlow #include <netsmb/smb_conn.h>
584bff34e3Sthurlow #include <netsmb/smb_subr.h>
594bff34e3Sthurlow #include <netsmb/smb_tran.h>
604bff34e3Sthurlow #include <netsmb/smb_rq.h>
61*adee6784SGordon Ross #include <netsmb/smb2_rq.h>
624bff34e3Sthurlow 
63613a2f6bSGordon Ross /*
64613a2f6bSGordon Ross  * How long to wait before restarting a request (after reconnect)
65613a2f6bSGordon Ross  */
66613a2f6bSGordon Ross #define	SMB_RCNDELAY		2	/* seconds */
67613a2f6bSGordon Ross 
68613a2f6bSGordon Ross /*
69613a2f6bSGordon Ross  * leave this zero - we can't ssecond guess server side effects of
70613a2f6bSGordon Ross  * duplicate ops, this isn't nfs!
71613a2f6bSGordon Ross  */
72613a2f6bSGordon Ross #define	SMBMAXRESTARTS		0
73613a2f6bSGordon Ross 
74613a2f6bSGordon Ross 
754bff34e3Sthurlow static int  smb_rq_reply(struct smb_rq *rqp);
76*adee6784SGordon Ross static int  smb_rq_parsehdr(struct smb_rq *rqp);
774bff34e3Sthurlow static int  smb_rq_enqueue(struct smb_rq *rqp);
784bff34e3Sthurlow static int  smb_rq_new(struct smb_rq *rqp, uchar_t cmd);
794bff34e3Sthurlow static int  smb_t2_reply(struct smb_t2rq *t2p);
804bff34e3Sthurlow static int  smb_nt_reply(struct smb_ntrq *ntp);
814bff34e3Sthurlow 
824bff34e3Sthurlow 
83613a2f6bSGordon Ross /*
84613a2f6bSGordon Ross  * Done with a request object.  Free its contents.
85613a2f6bSGordon Ross  * If it was allocated (SMBR_ALLOCED) free it too.
86613a2f6bSGordon Ross  * Some of these are stack locals, not allocated.
87613a2f6bSGordon Ross  *
88613a2f6bSGordon Ross  * No locks here - this is the last ref.
89613a2f6bSGordon Ross  */
90613a2f6bSGordon Ross void
smb_rq_done(struct smb_rq * rqp)91613a2f6bSGordon Ross smb_rq_done(struct smb_rq *rqp)
92613a2f6bSGordon Ross {
93613a2f6bSGordon Ross 
94613a2f6bSGordon Ross 	/*
95613a2f6bSGordon Ross 	 * No smb_vc_rele() here - see smb_rq_init()
96613a2f6bSGordon Ross 	 */
97613a2f6bSGordon Ross 	mb_done(&rqp->sr_rq);
98613a2f6bSGordon Ross 	md_done(&rqp->sr_rp);
99613a2f6bSGordon Ross 	mutex_destroy(&rqp->sr_lock);
100613a2f6bSGordon Ross 	cv_destroy(&rqp->sr_cond);
101613a2f6bSGordon Ross 	if (rqp->sr_flags & SMBR_ALLOCED)
102613a2f6bSGordon Ross 		kmem_free(rqp, sizeof (*rqp));
103613a2f6bSGordon Ross }
1044bff34e3Sthurlow 
1054bff34e3Sthurlow int
smb_rq_alloc(struct smb_connobj * layer,uchar_t cmd,struct smb_cred * scred,struct smb_rq ** rqpp)1064bff34e3Sthurlow smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, struct smb_cred *scred,
1074bff34e3Sthurlow 	struct smb_rq **rqpp)
1084bff34e3Sthurlow {
1094bff34e3Sthurlow 	struct smb_rq *rqp;
1104bff34e3Sthurlow 	int error;
1114bff34e3Sthurlow 
1124bff34e3Sthurlow 	rqp = (struct smb_rq *)kmem_alloc(sizeof (struct smb_rq), KM_SLEEP);
1134bff34e3Sthurlow 	if (rqp == NULL)
1144bff34e3Sthurlow 		return (ENOMEM);
1154bff34e3Sthurlow 	error = smb_rq_init(rqp, layer, cmd, scred);
1164bff34e3Sthurlow 	if (error) {
1174bff34e3Sthurlow 		smb_rq_done(rqp);
1184bff34e3Sthurlow 		return (error);
1194bff34e3Sthurlow 	}
1204bff34e3Sthurlow 	rqp->sr_flags |= SMBR_ALLOCED;
1214bff34e3Sthurlow 	*rqpp = rqp;
1224bff34e3Sthurlow 	return (0);
1234bff34e3Sthurlow }
1244bff34e3Sthurlow 
1254bff34e3Sthurlow int
smb_rq_init(struct smb_rq * rqp,struct smb_connobj * co,uchar_t cmd,struct smb_cred * scred)126613a2f6bSGordon Ross smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd,
1274bff34e3Sthurlow 	struct smb_cred *scred)
1284bff34e3Sthurlow {
1294bff34e3Sthurlow 	int error;
1304bff34e3Sthurlow 
1314bff34e3Sthurlow 	bzero(rqp, sizeof (*rqp));
1324bff34e3Sthurlow 	mutex_init(&rqp->sr_lock, NULL,  MUTEX_DRIVER, NULL);
1334bff34e3Sthurlow 	cv_init(&rqp->sr_cond, NULL, CV_DEFAULT, NULL);
1344bff34e3Sthurlow 
135613a2f6bSGordon Ross 	error = smb_rq_getenv(co, &rqp->sr_vc, &rqp->sr_share);
1364bff34e3Sthurlow 	if (error)
1374bff34e3Sthurlow 		return (error);
1384bff34e3Sthurlow 
139613a2f6bSGordon Ross 	/*
140613a2f6bSGordon Ross 	 * We copied a VC pointer (vcp) into rqp->sr_vc,
141613a2f6bSGordon Ross 	 * but we do NOT do a smb_vc_hold here.  Instead,
142613a2f6bSGordon Ross 	 * the caller is responsible for the hold on the
143613a2f6bSGordon Ross 	 * share or the VC as needed.  For smbfs callers,
144613a2f6bSGordon Ross 	 * the hold is on the share, via the smbfs mount.
145613a2f6bSGordon Ross 	 * For nsmb ioctl callers, the hold is done when
146613a2f6bSGordon Ross 	 * the driver handle gets VC or share references.
147613a2f6bSGordon Ross 	 * This design avoids frequent hold/rele activity
148613a2f6bSGordon Ross 	 * when creating and completing requests.
149613a2f6bSGordon Ross 	 */
150613a2f6bSGordon Ross 
1514bff34e3Sthurlow 	rqp->sr_rexmit = SMBMAXRESTARTS;
152613a2f6bSGordon Ross 	rqp->sr_cred = scred;	/* Note: ref hold done by caller. */
1534bff34e3Sthurlow 	error = smb_rq_new(rqp, cmd);
154613a2f6bSGordon Ross 
1554bff34e3Sthurlow 	return (error);
1564bff34e3Sthurlow }
1574bff34e3Sthurlow 
1584bff34e3Sthurlow static int
smb_rq_new(struct smb_rq * rqp,uchar_t cmd)1594bff34e3Sthurlow smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
1604bff34e3Sthurlow {
1614bff34e3Sthurlow 	struct mbchain *mbp = &rqp->sr_rq;
162613a2f6bSGordon Ross 	struct smb_vc *vcp = rqp->sr_vc;
1634bff34e3Sthurlow 	int error;
1644bff34e3Sthurlow 
1654bff34e3Sthurlow 	ASSERT(rqp != NULL);
166613a2f6bSGordon Ross 
1674bff34e3Sthurlow 	rqp->sr_sendcnt = 0;
168613a2f6bSGordon Ross 
1694bff34e3Sthurlow 	mb_done(mbp);
1704bff34e3Sthurlow 	md_done(&rqp->sr_rp);
1714bff34e3Sthurlow 	error = mb_init(mbp);
1724bff34e3Sthurlow 	if (error)
1734bff34e3Sthurlow 		return (error);
174613a2f6bSGordon Ross 
175*adee6784SGordon Ross 	if (vcp->vc_flags & SMBV_SMB2) {
176*adee6784SGordon Ross 		/*
177*adee6784SGordon Ross 		 * SMB2 request initialization
178*adee6784SGordon Ross 		 */
179*adee6784SGordon Ross 		rqp->sr2_command = cmd;
180*adee6784SGordon Ross 		rqp->sr2_creditcharge = 1;
181*adee6784SGordon Ross 		rqp->sr2_creditsrequested = 1;
182*adee6784SGordon Ross 		rqp->sr_pid = 0xFEFF;	/* Made up, just like Windows */
183*adee6784SGordon Ross 		rqp->sr2_rqflags = 0;
184*adee6784SGordon Ross 		if ((vcp->vc_flags & SMBV_SIGNING) != 0 &&
185*adee6784SGordon Ross 		    vcp->vc_mackey != NULL) {
186*adee6784SGordon Ross 			rqp->sr2_rqflags |= SMB2_FLAGS_SIGNED;
187*adee6784SGordon Ross 		}
188613a2f6bSGordon Ross 
189*adee6784SGordon Ross 		/*
190*adee6784SGordon Ross 		 * The SMB2 header is filled in later by
191*adee6784SGordon Ross 		 * smb2_rq_fillhdr (see smb2_rq.c)
192*adee6784SGordon Ross 		 * Just reserve space here.
193*adee6784SGordon Ross 		 */
194*adee6784SGordon Ross 		mb_put_mem(mbp, NULL, SMB2_HDRLEN, MB_MZERO);
195*adee6784SGordon Ross 	} else {
196*adee6784SGordon Ross 		/*
197*adee6784SGordon Ross 		 * SMB1 request initialization
198*adee6784SGordon Ross 		 */
199*adee6784SGordon Ross 		rqp->sr_cmd = cmd;
200*adee6784SGordon Ross 		rqp->sr_pid = (uint32_t)ddi_get_pid();
201*adee6784SGordon Ross 		rqp->sr_rqflags  = vcp->vc_hflags;
202*adee6784SGordon Ross 		rqp->sr_rqflags2 = vcp->vc_hflags2;
203*adee6784SGordon Ross 
204*adee6784SGordon Ross 		/*
205*adee6784SGordon Ross 		 * The SMB header is filled in later by
206*adee6784SGordon Ross 		 * smb_rq_fillhdr (see below)
207*adee6784SGordon Ross 		 * Just reserve space here.
208*adee6784SGordon Ross 		 */
209*adee6784SGordon Ross 		mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
210*adee6784SGordon Ross 	}
211613a2f6bSGordon Ross 
2124bff34e3Sthurlow 	return (0);
2134bff34e3Sthurlow }
2144bff34e3Sthurlow 
215613a2f6bSGordon Ross /*
216613a2f6bSGordon Ross  * Given a request with it's body already composed,
217613a2f6bSGordon Ross  * rewind to the start and fill in the SMB header.
218*adee6784SGordon Ross  * This is called when the request is enqueued,
219613a2f6bSGordon Ross  * so we have the final MID, seq num. etc.
220613a2f6bSGordon Ross  */
2214bff34e3Sthurlow void
smb_rq_fillhdr(struct smb_rq * rqp)222613a2f6bSGordon Ross smb_rq_fillhdr(struct smb_rq *rqp)
2234bff34e3Sthurlow {
224613a2f6bSGordon Ross 	struct mbchain mbtmp, *mbp = &mbtmp;
225613a2f6bSGordon Ross 	mblk_t *m;
226613a2f6bSGordon Ross 
227613a2f6bSGordon Ross 	/*
228613a2f6bSGordon Ross 	 * Fill in the SMB header using a dup of the first mblk,
229613a2f6bSGordon Ross 	 * which points at the same data but has its own wptr,
230613a2f6bSGordon Ross 	 * so we can rewind without trashing the message.
231613a2f6bSGordon Ross 	 */
232613a2f6bSGordon Ross 	m = dupb(rqp->sr_rq.mb_top);
233613a2f6bSGordon Ross 	m->b_wptr = m->b_rptr;	/* rewind */
234613a2f6bSGordon Ross 	mb_initm(mbp, m);
235613a2f6bSGordon Ross 
236613a2f6bSGordon Ross 	mb_put_mem(mbp, SMB_SIGNATURE, 4, MB_MSYSTEM);
237613a2f6bSGordon Ross 	mb_put_uint8(mbp, rqp->sr_cmd);
238613a2f6bSGordon Ross 	mb_put_uint32le(mbp, 0);	/* status */
239613a2f6bSGordon Ross 	mb_put_uint8(mbp, rqp->sr_rqflags);
240613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->sr_rqflags2);
241613a2f6bSGordon Ross 	mb_put_uint16le(mbp, 0);	/* pid-high */
242613a2f6bSGordon Ross 	mb_put_mem(mbp, NULL, 8, MB_MZERO);	/* MAC sig. (later) */
243613a2f6bSGordon Ross 	mb_put_uint16le(mbp, 0);	/* reserved */
244613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->sr_rqtid);
245*adee6784SGordon Ross 	mb_put_uint16le(mbp, (uint16_t)rqp->sr_pid);
246613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->sr_rquid);
247613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->sr_mid);
248613a2f6bSGordon Ross 
249613a2f6bSGordon Ross 	/* This will free the mblk from dupb. */
250613a2f6bSGordon Ross 	mb_done(mbp);
251613a2f6bSGordon Ross }
252613a2f6bSGordon Ross 
253613a2f6bSGordon Ross int
smb_rq_simple(struct smb_rq * rqp)254613a2f6bSGordon Ross smb_rq_simple(struct smb_rq *rqp)
255613a2f6bSGordon Ross {
256613a2f6bSGordon Ross 	return (smb_rq_simple_timed(rqp, smb_timo_default));
2574bff34e3Sthurlow }
2584bff34e3Sthurlow 
2594bff34e3Sthurlow /*
2604bff34e3Sthurlow  * Simple request-reply exchange
2614bff34e3Sthurlow  */
2624bff34e3Sthurlow int
smb_rq_simple_timed(struct smb_rq * rqp,int timeout)2634bff34e3Sthurlow smb_rq_simple_timed(struct smb_rq *rqp, int timeout)
2644bff34e3Sthurlow {
2654bff34e3Sthurlow 	int error = EINVAL;
2664bff34e3Sthurlow 
2674bff34e3Sthurlow 	for (; ; ) {
2684bff34e3Sthurlow 		/*
2694bff34e3Sthurlow 		 * Don't send any new requests if force unmount is underway.
2704bff34e3Sthurlow 		 * This check was moved into smb_rq_enqueue.
2714bff34e3Sthurlow 		 */
2724bff34e3Sthurlow 		rqp->sr_flags &= ~SMBR_RESTART;
2734bff34e3Sthurlow 		rqp->sr_timo = timeout;	/* in seconds */
2744bff34e3Sthurlow 		rqp->sr_state = SMBRQ_NOTSENT;
2754bff34e3Sthurlow 		error = smb_rq_enqueue(rqp);
2764bff34e3Sthurlow 		if (error) {
2774bff34e3Sthurlow 			break;
2784bff34e3Sthurlow 		}
2794bff34e3Sthurlow 		error = smb_rq_reply(rqp);
2804bff34e3Sthurlow 		if (!error)
2814bff34e3Sthurlow 			break;
2824bff34e3Sthurlow 		if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) !=
2834bff34e3Sthurlow 		    SMBR_RESTART)
2844bff34e3Sthurlow 			break;
2854bff34e3Sthurlow 		if (rqp->sr_rexmit <= 0)
2864bff34e3Sthurlow 			break;
2874bff34e3Sthurlow 		SMBRQ_LOCK(rqp);
288613a2f6bSGordon Ross 		if (rqp->sr_share) {
28902d09e03SGordon Ross 			(void) cv_reltimedwait(&rqp->sr_cond, &(rqp)->sr_lock,
29002d09e03SGordon Ross 			    SEC_TO_TICK(SMB_RCNDELAY), TR_CLOCK_TICK);
2914bff34e3Sthurlow 
2924bff34e3Sthurlow 		} else {
29302d09e03SGordon Ross 			delay(SEC_TO_TICK(SMB_RCNDELAY));
2944bff34e3Sthurlow 		}
2954bff34e3Sthurlow 		SMBRQ_UNLOCK(rqp);
2964bff34e3Sthurlow 		rqp->sr_rexmit--;
2974bff34e3Sthurlow 	}
2984bff34e3Sthurlow 	return (error);
2994bff34e3Sthurlow }
3004bff34e3Sthurlow 
3014bff34e3Sthurlow 
3024bff34e3Sthurlow static int
smb_rq_enqueue(struct smb_rq * rqp)3034bff34e3Sthurlow smb_rq_enqueue(struct smb_rq *rqp)
3044bff34e3Sthurlow {
3054bff34e3Sthurlow 	struct smb_vc *vcp = rqp->sr_vc;
3064bff34e3Sthurlow 	struct smb_share *ssp = rqp->sr_share;
3074bff34e3Sthurlow 	int error = 0;
3084bff34e3Sthurlow 
309*adee6784SGordon Ross 	ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
310*adee6784SGordon Ross 
3114bff34e3Sthurlow 	/*
312613a2f6bSGordon Ross 	 * Normal requests may initiate a reconnect,
313613a2f6bSGordon Ross 	 * and/or wait for state changes to finish.
314613a2f6bSGordon Ross 	 * Some requests set the NORECONNECT flag
315613a2f6bSGordon Ross 	 * to avoid all that (i.e. tree discon)
3164bff34e3Sthurlow 	 */
317613a2f6bSGordon Ross 	if (rqp->sr_flags & SMBR_NORECONNECT) {
318613a2f6bSGordon Ross 		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
319613a2f6bSGordon Ross 			SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
320613a2f6bSGordon Ross 			return (ENOTCONN);
321613a2f6bSGordon Ross 		}
322613a2f6bSGordon Ross 		if (ssp != NULL &&
323613a2f6bSGordon Ross 		    ((ssp->ss_flags & SMBS_CONNECTED) == 0))
324613a2f6bSGordon Ross 			return (ENOTCONN);
325613a2f6bSGordon Ross 		goto ok_out;
3264bff34e3Sthurlow 	}
3274bff34e3Sthurlow 
3284bff34e3Sthurlow 	/*
329613a2f6bSGordon Ross 	 * If we're not connected, initiate a reconnect
330613a2f6bSGordon Ross 	 * and/or wait for an existing one to finish.
3314bff34e3Sthurlow 	 */
3324bff34e3Sthurlow 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
333613a2f6bSGordon Ross 		error = smb_iod_reconnect(vcp);
334613a2f6bSGordon Ross 		if (error != 0)
335613a2f6bSGordon Ross 			return (error);
3364bff34e3Sthurlow 	}
3374bff34e3Sthurlow 
3384bff34e3Sthurlow 	/*
339613a2f6bSGordon Ross 	 * If this request has a "share" object
340613a2f6bSGordon Ross 	 * that needs a tree connect, do it now.
3414bff34e3Sthurlow 	 */
342613a2f6bSGordon Ross 	if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
343613a2f6bSGordon Ross 		error = smb_share_tcon(ssp, rqp->sr_cred);
344613a2f6bSGordon Ross 		if (error)
345613a2f6bSGordon Ross 			return (error);
3464bff34e3Sthurlow 	}
3474bff34e3Sthurlow 
348613a2f6bSGordon Ross 	/*
349613a2f6bSGordon Ross 	 * We now know what UID + TID to use.
350613a2f6bSGordon Ross 	 * Store them in the request.
351613a2f6bSGordon Ross 	 */
352613a2f6bSGordon Ross ok_out:
353613a2f6bSGordon Ross 	rqp->sr_rquid = vcp->vc_smbuid;
354613a2f6bSGordon Ross 	rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN;
355*adee6784SGordon Ross 	error = smb1_iod_addrq(rqp);
3564bff34e3Sthurlow 
3574bff34e3Sthurlow 	return (error);
3584bff34e3Sthurlow }
3594bff34e3Sthurlow 
36040c0e231SGordon Ross /*
361*adee6784SGordon Ross  * Used by the IOD thread during connection setup,
362*adee6784SGordon Ross  * and for smb_echo after network timeouts.  Note that
363*adee6784SGordon Ross  * unlike smb_rq_simple, callers must check sr_error.
36440c0e231SGordon Ross  */
36540c0e231SGordon Ross int
smb_rq_internal(struct smb_rq * rqp,int timeout)36640c0e231SGordon Ross smb_rq_internal(struct smb_rq *rqp, int timeout)
36740c0e231SGordon Ross {
36840c0e231SGordon Ross 	struct smb_vc *vcp = rqp->sr_vc;
369*adee6784SGordon Ross 	int error;
370*adee6784SGordon Ross 
371*adee6784SGordon Ross 	ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
37240c0e231SGordon Ross 
37340c0e231SGordon Ross 	rqp->sr_flags &= ~SMBR_RESTART;
37440c0e231SGordon Ross 	rqp->sr_timo = timeout;	/* in seconds */
37540c0e231SGordon Ross 	rqp->sr_state = SMBRQ_NOTSENT;
37640c0e231SGordon Ross 
37740c0e231SGordon Ross 	/*
378*adee6784SGordon Ross 	 * In-line smb_rq_enqueue(rqp) here, as we don't want it
379*adee6784SGordon Ross 	 * trying to reconnect etc. for an internal request.
38040c0e231SGordon Ross 	 */
38140c0e231SGordon Ross 	rqp->sr_rquid = vcp->vc_smbuid;
38240c0e231SGordon Ross 	rqp->sr_rqtid = SMB_TID_UNKNOWN;
383*adee6784SGordon Ross 	rqp->sr_flags |= SMBR_INTERNAL;
384*adee6784SGordon Ross 	error = smb1_iod_addrq(rqp);
385*adee6784SGordon Ross 	if (error != 0)
386*adee6784SGordon Ross 		return (error);
38740c0e231SGordon Ross 
388*adee6784SGordon Ross 	/*
389*adee6784SGordon Ross 	 * In-line a variant of smb_rq_reply(rqp) here as we may
390*adee6784SGordon Ross 	 * need to do custom parsing for SMB1-to-SMB2 negotiate.
391*adee6784SGordon Ross 	 */
392*adee6784SGordon Ross 	if (rqp->sr_timo == SMBNOREPLYWAIT) {
393*adee6784SGordon Ross 		smb_iod_removerq(rqp);
394*adee6784SGordon Ross 		return (0);
395*adee6784SGordon Ross 	}
39640c0e231SGordon Ross 
397*adee6784SGordon Ross 	error = smb_iod_waitrq_int(rqp);
398*adee6784SGordon Ross 	if (error)
399*adee6784SGordon Ross 		return (error);
400*adee6784SGordon Ross 
401*adee6784SGordon Ross 	/*
402*adee6784SGordon Ross 	 * If the request was signed, validate the
403*adee6784SGordon Ross 	 * signature on the response.
404*adee6784SGordon Ross 	 */
405*adee6784SGordon Ross 	if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
406*adee6784SGordon Ross 		error = smb_rq_verify(rqp);
407*adee6784SGordon Ross 		if (error)
408*adee6784SGordon Ross 			return (error);
409*adee6784SGordon Ross 	}
410*adee6784SGordon Ross 
411*adee6784SGordon Ross 	/*
412*adee6784SGordon Ross 	 * Parse the SMB header.
413*adee6784SGordon Ross 	 */
414*adee6784SGordon Ross 	error = smb_rq_parsehdr(rqp);
415*adee6784SGordon Ross 
416*adee6784SGordon Ross 	/*
417*adee6784SGordon Ross 	 * Skip the error translation smb_rq_reply does.
418*adee6784SGordon Ross 	 * Callers of this expect "raw" NT status.
419*adee6784SGordon Ross 	 */
420*adee6784SGordon Ross 
421*adee6784SGordon Ross 	return (error);
42240c0e231SGordon Ross }
42340c0e231SGordon Ross 
4244bff34e3Sthurlow /*
4254bff34e3Sthurlow  * Mark location of the word count, which is filled in later by
4264bff34e3Sthurlow  * smb_rw_wend().  Also initialize the counter that it uses
4274bff34e3Sthurlow  * to figure out what value to fill in.
4284bff34e3Sthurlow  *
4294bff34e3Sthurlow  * Note that the word count happens to be 8-bit.
4304bff34e3Sthurlow  */
4314bff34e3Sthurlow void
smb_rq_wstart(struct smb_rq * rqp)4324bff34e3Sthurlow smb_rq_wstart(struct smb_rq *rqp)
4334bff34e3Sthurlow {
4344bff34e3Sthurlow 	rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof (uint8_t));
4354bff34e3Sthurlow 	rqp->sr_rq.mb_count = 0;
4364bff34e3Sthurlow }
4374bff34e3Sthurlow 
4384bff34e3Sthurlow void
smb_rq_wend(struct smb_rq * rqp)4394bff34e3Sthurlow smb_rq_wend(struct smb_rq *rqp)
4404bff34e3Sthurlow {
4414bff34e3Sthurlow 	uint_t wcnt;
4424bff34e3Sthurlow 
4434bff34e3Sthurlow 	if (rqp->sr_wcount == NULL) {
4444bff34e3Sthurlow 		SMBSDEBUG("no wcount\n");
4454bff34e3Sthurlow 		return;
4464bff34e3Sthurlow 	}
4474bff34e3Sthurlow 	wcnt = rqp->sr_rq.mb_count;
4484bff34e3Sthurlow 	if (wcnt > 0x1ff)
4494bff34e3Sthurlow 		SMBSDEBUG("word count too large (%d)\n", wcnt);
4504bff34e3Sthurlow 	if (wcnt & 1)
4514bff34e3Sthurlow 		SMBSDEBUG("odd word count\n");
4524bff34e3Sthurlow 	/* Fill in the word count (8-bits) */
4534bff34e3Sthurlow 	*rqp->sr_wcount = (wcnt >> 1);
4544bff34e3Sthurlow }
4554bff34e3Sthurlow 
4564bff34e3Sthurlow /*
4574bff34e3Sthurlow  * Mark location of the byte count, which is filled in later by
4584bff34e3Sthurlow  * smb_rw_bend().  Also initialize the counter that it uses
4594bff34e3Sthurlow  * to figure out what value to fill in.
4604bff34e3Sthurlow  *
4614bff34e3Sthurlow  * Note that the byte count happens to be 16-bit.
4624bff34e3Sthurlow  */
4634bff34e3Sthurlow void
smb_rq_bstart(struct smb_rq * rqp)4644bff34e3Sthurlow smb_rq_bstart(struct smb_rq *rqp)
4654bff34e3Sthurlow {
4664bff34e3Sthurlow 	rqp->sr_bcount = mb_reserve(&rqp->sr_rq, sizeof (uint16_t));
4674bff34e3Sthurlow 	rqp->sr_rq.mb_count = 0;
4684bff34e3Sthurlow }
4694bff34e3Sthurlow 
4704bff34e3Sthurlow void
smb_rq_bend(struct smb_rq * rqp)4714bff34e3Sthurlow smb_rq_bend(struct smb_rq *rqp)
4724bff34e3Sthurlow {
4734bff34e3Sthurlow 	uint_t bcnt;
4744bff34e3Sthurlow 
4754bff34e3Sthurlow 	if (rqp->sr_bcount == NULL) {
4764bff34e3Sthurlow 		SMBSDEBUG("no bcount\n");
4774bff34e3Sthurlow 		return;
4784bff34e3Sthurlow 	}
4794bff34e3Sthurlow 	bcnt = rqp->sr_rq.mb_count;
4804bff34e3Sthurlow 	if (bcnt > 0xffff)
4814bff34e3Sthurlow 		SMBSDEBUG("byte count too large (%d)\n", bcnt);
4824bff34e3Sthurlow 	/*
4834bff34e3Sthurlow 	 * Fill in the byte count (16-bits)
4844bff34e3Sthurlow 	 * The pointer is char * type due to
4854bff34e3Sthurlow 	 * typical off-by-one alignment.
4864bff34e3Sthurlow 	 */
4874bff34e3Sthurlow 	rqp->sr_bcount[0] = bcnt & 0xFF;
4884bff34e3Sthurlow 	rqp->sr_bcount[1] = (bcnt >> 8);
4894bff34e3Sthurlow }
4904bff34e3Sthurlow 
4914bff34e3Sthurlow int
smb_rq_getenv(struct smb_connobj * co,struct smb_vc ** vcpp,struct smb_share ** sspp)4924bff34e3Sthurlow smb_rq_getenv(struct smb_connobj *co,
4934bff34e3Sthurlow 	struct smb_vc **vcpp, struct smb_share **sspp)
4944bff34e3Sthurlow {
4954bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
4964bff34e3Sthurlow 	struct smb_share *ssp = NULL;
497613a2f6bSGordon Ross 	int error = EINVAL;
4984bff34e3Sthurlow 
4994bff34e3Sthurlow 	if (co->co_flags & SMBO_GONE) {
5004bff34e3Sthurlow 		SMBSDEBUG("zombie CO\n");
5014bff34e3Sthurlow 		error = EINVAL;
5024bff34e3Sthurlow 		goto out;
5034bff34e3Sthurlow 	}
5044bff34e3Sthurlow 
5054bff34e3Sthurlow 	switch (co->co_level) {
506613a2f6bSGordon Ross 	case SMBL_SHARE:
507613a2f6bSGordon Ross 		ssp = CPTOSS(co);
508613a2f6bSGordon Ross 		if ((co->co_flags & SMBO_GONE) ||
509613a2f6bSGordon Ross 		    co->co_parent == NULL) {
510613a2f6bSGordon Ross 			SMBSDEBUG("zombie share %s\n", ssp->ss_name);
511613a2f6bSGordon Ross 			break;
512613a2f6bSGordon Ross 		}
513613a2f6bSGordon Ross 		/* instead of recursion... */
514613a2f6bSGordon Ross 		co = co->co_parent;
515613a2f6bSGordon Ross 		/* FALLTHROUGH */
5164bff34e3Sthurlow 	case SMBL_VC:
5174bff34e3Sthurlow 		vcp = CPTOVC(co);
518613a2f6bSGordon Ross 		if ((co->co_flags & SMBO_GONE) ||
519613a2f6bSGordon Ross 		    co->co_parent == NULL) {
5204bff34e3Sthurlow 			SMBSDEBUG("zombie VC %s\n", vcp->vc_srvname);
5214bff34e3Sthurlow 			break;
5224bff34e3Sthurlow 		}
523613a2f6bSGordon Ross 		error = 0;
5244bff34e3Sthurlow 		break;
5254bff34e3Sthurlow 
5264bff34e3Sthurlow 	default:
5274bff34e3Sthurlow 		SMBSDEBUG("invalid level %d passed\n", co->co_level);
5284bff34e3Sthurlow 	}
5294bff34e3Sthurlow 
5304bff34e3Sthurlow out:
5314bff34e3Sthurlow 	if (!error) {
5324bff34e3Sthurlow 		if (vcpp)
5334bff34e3Sthurlow 			*vcpp = vcp;
5344bff34e3Sthurlow 		if (sspp)
5354bff34e3Sthurlow 			*sspp = ssp;
5364bff34e3Sthurlow 	}
5374bff34e3Sthurlow 
5384bff34e3Sthurlow 	return (error);
5394bff34e3Sthurlow }
5404bff34e3Sthurlow 
5414bff34e3Sthurlow /*
542*adee6784SGordon Ross  * Wait for a reply to this request, then parse it.
5434bff34e3Sthurlow  */
5444bff34e3Sthurlow static int
smb_rq_reply(struct smb_rq * rqp)5454bff34e3Sthurlow smb_rq_reply(struct smb_rq *rqp)
5464bff34e3Sthurlow {
547*adee6784SGordon Ross 	int error;
5484bff34e3Sthurlow 
54902d09e03SGordon Ross 	if (rqp->sr_timo == SMBNOREPLYWAIT) {
55002d09e03SGordon Ross 		smb_iod_removerq(rqp);
55102d09e03SGordon Ross 		return (0);
55202d09e03SGordon Ross 	}
5534bff34e3Sthurlow 
5544bff34e3Sthurlow 	error = smb_iod_waitrq(rqp);
5554bff34e3Sthurlow 	if (error)
5564bff34e3Sthurlow 		return (error);
5579c9af259SGordon Ross 
5589c9af259SGordon Ross 	/*
5599c9af259SGordon Ross 	 * If the request was signed, validate the
5609c9af259SGordon Ross 	 * signature on the response.
5619c9af259SGordon Ross 	 */
5629c9af259SGordon Ross 	if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
5639c9af259SGordon Ross 		error = smb_rq_verify(rqp);
5649c9af259SGordon Ross 		if (error)
5659c9af259SGordon Ross 			return (error);
5669c9af259SGordon Ross 	}
5679c9af259SGordon Ross 
5689c9af259SGordon Ross 	/*
5699c9af259SGordon Ross 	 * Parse the SMB header
5709c9af259SGordon Ross 	 */
571*adee6784SGordon Ross 	error = smb_rq_parsehdr(rqp);
572*adee6784SGordon Ross 	if (error != 0)
5734bff34e3Sthurlow 		return (error);
57440c0e231SGordon Ross 
57540c0e231SGordon Ross 	if (rqp->sr_error != 0) {
57640c0e231SGordon Ross 		if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
577*adee6784SGordon Ross 			error = smb_maperr32(rqp->sr_error);
57840c0e231SGordon Ross 		} else {
57940c0e231SGordon Ross 			uint8_t errClass = rqp->sr_error & 0xff;
58040c0e231SGordon Ross 			uint16_t errCode = rqp->sr_error >> 16;
58140c0e231SGordon Ross 			/* Convert to NT status */
58240c0e231SGordon Ross 			rqp->sr_error = smb_doserr2status(errClass, errCode);
583*adee6784SGordon Ross 			error = smb_maperror(errClass, errCode);
58440c0e231SGordon Ross 		}
58540c0e231SGordon Ross 	}
58640c0e231SGordon Ross 
587*adee6784SGordon Ross 	if (error != 0) {
5884bff34e3Sthurlow 		/*
5894bff34e3Sthurlow 		 * Do a special check for STATUS_BUFFER_OVERFLOW;
5904bff34e3Sthurlow 		 * it's not an error.
5914bff34e3Sthurlow 		 */
5924bff34e3Sthurlow 		if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) {
5934bff34e3Sthurlow 			/*
5944bff34e3Sthurlow 			 * Don't report it as an error to our caller;
5954bff34e3Sthurlow 			 * they can look at rqp->sr_error if they
5964bff34e3Sthurlow 			 * need to know whether we got a
5974bff34e3Sthurlow 			 * STATUS_BUFFER_OVERFLOW.
5984bff34e3Sthurlow 			 */
59940c0e231SGordon Ross 			rqp->sr_flags |= SMBR_MOREDATA;
600*adee6784SGordon Ross 			error = 0;
60140c0e231SGordon Ross 		}
6024bff34e3Sthurlow 	} else {
6034bff34e3Sthurlow 		rqp->sr_flags &= ~SMBR_MOREDATA;
60440c0e231SGordon Ross 	}
6054bff34e3Sthurlow 
606*adee6784SGordon Ross 	return (error);
607*adee6784SGordon Ross }
608*adee6784SGordon Ross 
609*adee6784SGordon Ross /*
610*adee6784SGordon Ross  * Parse the SMB header
611*adee6784SGordon Ross  */
612*adee6784SGordon Ross static int
smb_rq_parsehdr(struct smb_rq * rqp)613*adee6784SGordon Ross smb_rq_parsehdr(struct smb_rq *rqp)
614*adee6784SGordon Ross {
615*adee6784SGordon Ross 	struct mdchain mdp_save;
616*adee6784SGordon Ross 	struct mdchain *mdp = &rqp->sr_rp;
617*adee6784SGordon Ross 	u_int8_t tb, sig[4];
618*adee6784SGordon Ross 	int error;
6194bff34e3Sthurlow 
620*adee6784SGordon Ross 	/*
621*adee6784SGordon Ross 	 * Parse the signature.  The reader already checked that
622*adee6784SGordon Ross 	 * the signature is valid.  Here we just have to check
623*adee6784SGordon Ross 	 * for SMB1-to-SMB2 negotiate.  Caller handles an EPROTO
624*adee6784SGordon Ross 	 * as a signal that we got an SMB2 reply.  If we return
625*adee6784SGordon Ross 	 * EPROTO, rewind the mdchain back where it was.
626*adee6784SGordon Ross 	 */
627*adee6784SGordon Ross 	mdp_save = *mdp;
628*adee6784SGordon Ross 	error = md_get_mem(mdp, sig, 4, MB_MSYSTEM);
629*adee6784SGordon Ross 	if (error)
630*adee6784SGordon Ross 		return (error);
631*adee6784SGordon Ross 	if (sig[0] != SMB_HDR_V1) {
632*adee6784SGordon Ross 		if (rqp->sr_cmd == SMB_COM_NEGOTIATE) {
633*adee6784SGordon Ross 			*mdp = mdp_save;
634*adee6784SGordon Ross 			return (EPROTO);
635*adee6784SGordon Ross 		}
636*adee6784SGordon Ross 		return (EBADRPC);
637*adee6784SGordon Ross 	}
638*adee6784SGordon Ross 
639*adee6784SGordon Ross 	/* Check cmd */
640*adee6784SGordon Ross 	error = md_get_uint8(mdp, &tb);
641*adee6784SGordon Ross 	if (tb != rqp->sr_cmd)
642*adee6784SGordon Ross 		return (EBADRPC);
643*adee6784SGordon Ross 
644*adee6784SGordon Ross 	md_get_uint32le(mdp, &rqp->sr_error);
645*adee6784SGordon Ross 	md_get_uint8(mdp, &rqp->sr_rpflags);
646*adee6784SGordon Ross 	md_get_uint16le(mdp, &rqp->sr_rpflags2);
647*adee6784SGordon Ross 
648*adee6784SGordon Ross 	/* Skip: pid-high(2), MAC sig(8), reserved(2) */
649*adee6784SGordon Ross 	md_get_mem(mdp, NULL, 12, MB_MSYSTEM);
650*adee6784SGordon Ross 
651*adee6784SGordon Ross 	md_get_uint16le(mdp, &rqp->sr_rptid);
652*adee6784SGordon Ross 	md_get_uint16le(mdp, &rqp->sr_rppid);
653*adee6784SGordon Ross 	md_get_uint16le(mdp, &rqp->sr_rpuid);
6544bff34e3Sthurlow 	error = md_get_uint16le(mdp, &rqp->sr_rpmid);
6554bff34e3Sthurlow 
656*adee6784SGordon Ross 	return (error);
6574bff34e3Sthurlow }
6584bff34e3Sthurlow 
6594bff34e3Sthurlow 
6604bff34e3Sthurlow #define	ALIGN4(a)	(((a) + 3) & ~3)
6614bff34e3Sthurlow 
6624bff34e3Sthurlow /*
6634bff34e3Sthurlow  * TRANS2 request implementation
6644bff34e3Sthurlow  * TRANS implementation is in the "t2" routines
6654bff34e3Sthurlow  * NT_TRANSACTION implementation is the separate "nt" stuff
6664bff34e3Sthurlow  */
6674bff34e3Sthurlow int
smb_t2_alloc(struct smb_connobj * layer,ushort_t setup,struct smb_cred * scred,struct smb_t2rq ** t2pp)6684bff34e3Sthurlow smb_t2_alloc(struct smb_connobj *layer, ushort_t setup, struct smb_cred *scred,
6694bff34e3Sthurlow 	struct smb_t2rq **t2pp)
6704bff34e3Sthurlow {
6714bff34e3Sthurlow 	struct smb_t2rq *t2p;
6724bff34e3Sthurlow 	int error;
6734bff34e3Sthurlow 
6744bff34e3Sthurlow 	t2p = (struct smb_t2rq *)kmem_alloc(sizeof (*t2p), KM_SLEEP);
6754bff34e3Sthurlow 	if (t2p == NULL)
6764bff34e3Sthurlow 		return (ENOMEM);
6774bff34e3Sthurlow 	error = smb_t2_init(t2p, layer, &setup, 1, scred);
6784bff34e3Sthurlow 	t2p->t2_flags |= SMBT2_ALLOCED;
6794bff34e3Sthurlow 	if (error) {
6804bff34e3Sthurlow 		smb_t2_done(t2p);
6814bff34e3Sthurlow 		return (error);
6824bff34e3Sthurlow 	}
6834bff34e3Sthurlow 	*t2pp = t2p;
6844bff34e3Sthurlow 	return (0);
6854bff34e3Sthurlow }
6864bff34e3Sthurlow 
6874bff34e3Sthurlow int
smb_nt_alloc(struct smb_connobj * layer,ushort_t fn,struct smb_cred * scred,struct smb_ntrq ** ntpp)6884bff34e3Sthurlow smb_nt_alloc(struct smb_connobj *layer, ushort_t fn, struct smb_cred *scred,
6894bff34e3Sthurlow 	struct smb_ntrq **ntpp)
6904bff34e3Sthurlow {
6914bff34e3Sthurlow 	struct smb_ntrq *ntp;
6924bff34e3Sthurlow 	int error;
6934bff34e3Sthurlow 
6944bff34e3Sthurlow 	ntp = (struct smb_ntrq *)kmem_alloc(sizeof (*ntp), KM_SLEEP);
6954bff34e3Sthurlow 	if (ntp == NULL)
6964bff34e3Sthurlow 		return (ENOMEM);
6974bff34e3Sthurlow 	error = smb_nt_init(ntp, layer, fn, scred);
6984bff34e3Sthurlow 	mutex_init(&ntp->nt_lock, NULL, MUTEX_DRIVER, NULL);
6994bff34e3Sthurlow 	cv_init(&ntp->nt_cond, NULL, CV_DEFAULT, NULL);
7004bff34e3Sthurlow 	ntp->nt_flags |= SMBT2_ALLOCED;
7014bff34e3Sthurlow 	if (error) {
7024bff34e3Sthurlow 		smb_nt_done(ntp);
7034bff34e3Sthurlow 		return (error);
7044bff34e3Sthurlow 	}
7054bff34e3Sthurlow 	*ntpp = ntp;
7064bff34e3Sthurlow 	return (0);
7074bff34e3Sthurlow }
7084bff34e3Sthurlow 
7094bff34e3Sthurlow int
smb_t2_init(struct smb_t2rq * t2p,struct smb_connobj * source,ushort_t * setup,int setupcnt,struct smb_cred * scred)7104bff34e3Sthurlow smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, ushort_t *setup,
7114bff34e3Sthurlow 	int setupcnt, struct smb_cred *scred)
7124bff34e3Sthurlow {
7134bff34e3Sthurlow 	int i;
7144bff34e3Sthurlow 	int error;
7154bff34e3Sthurlow 
7164bff34e3Sthurlow 	bzero(t2p, sizeof (*t2p));
717613a2f6bSGordon Ross 	mutex_init(&t2p->t2_lock, NULL, MUTEX_DRIVER, NULL);
718613a2f6bSGordon Ross 	cv_init(&t2p->t2_cond, NULL, CV_DEFAULT, NULL);
719613a2f6bSGordon Ross 
7204bff34e3Sthurlow 	t2p->t2_source = source;
7214bff34e3Sthurlow 	t2p->t2_setupcount = (u_int16_t)setupcnt;
7224bff34e3Sthurlow 	t2p->t2_setupdata = t2p->t2_setup;
7234bff34e3Sthurlow 	for (i = 0; i < setupcnt; i++)
7244bff34e3Sthurlow 		t2p->t2_setup[i] = setup[i];
7254bff34e3Sthurlow 	t2p->t2_fid = 0xffff;
7264bff34e3Sthurlow 	t2p->t2_cred = scred;
7274bff34e3Sthurlow 	t2p->t2_share = (source->co_level == SMBL_SHARE ?
7284bff34e3Sthurlow 	    CPTOSS(source) : NULL); /* for smb up/down */
7294bff34e3Sthurlow 	error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
7304bff34e3Sthurlow 	if (error)
7314bff34e3Sthurlow 		return (error);
7324bff34e3Sthurlow 	return (0);
7334bff34e3Sthurlow }
7344bff34e3Sthurlow 
7354bff34e3Sthurlow int
smb_nt_init(struct smb_ntrq * ntp,struct smb_connobj * source,ushort_t fn,struct smb_cred * scred)7364bff34e3Sthurlow smb_nt_init(struct smb_ntrq *ntp, struct smb_connobj *source, ushort_t fn,
7374bff34e3Sthurlow 	struct smb_cred *scred)
7384bff34e3Sthurlow {
7394bff34e3Sthurlow 	int error;
7404bff34e3Sthurlow 
7414bff34e3Sthurlow 	bzero(ntp, sizeof (*ntp));
7424bff34e3Sthurlow 	ntp->nt_source = source;
7434bff34e3Sthurlow 	ntp->nt_function = fn;
7444bff34e3Sthurlow 	ntp->nt_cred = scred;
7454bff34e3Sthurlow 	ntp->nt_share = (source->co_level == SMBL_SHARE ?
7464bff34e3Sthurlow 	    CPTOSS(source) : NULL); /* for smb up/down */
7474bff34e3Sthurlow 	error = smb_rq_getenv(source, &ntp->nt_vc, NULL);
7484bff34e3Sthurlow 	if (error)
7494bff34e3Sthurlow 		return (error);
7504bff34e3Sthurlow 	return (0);
7514bff34e3Sthurlow }
7524bff34e3Sthurlow 
7534bff34e3Sthurlow void
smb_t2_done(struct smb_t2rq * t2p)7544bff34e3Sthurlow smb_t2_done(struct smb_t2rq *t2p)
7554bff34e3Sthurlow {
7564bff34e3Sthurlow 	mb_done(&t2p->t2_tparam);
7574bff34e3Sthurlow 	mb_done(&t2p->t2_tdata);
7584bff34e3Sthurlow 	md_done(&t2p->t2_rparam);
7594bff34e3Sthurlow 	md_done(&t2p->t2_rdata);
7604bff34e3Sthurlow 	mutex_destroy(&t2p->t2_lock);
7614bff34e3Sthurlow 	cv_destroy(&t2p->t2_cond);
7624bff34e3Sthurlow 	if (t2p->t2_flags & SMBT2_ALLOCED)
7634bff34e3Sthurlow 		kmem_free(t2p, sizeof (*t2p));
7644bff34e3Sthurlow }
7654bff34e3Sthurlow 
7664bff34e3Sthurlow void
smb_nt_done(struct smb_ntrq * ntp)7674bff34e3Sthurlow smb_nt_done(struct smb_ntrq *ntp)
7684bff34e3Sthurlow {
7694bff34e3Sthurlow 	mb_done(&ntp->nt_tsetup);
7704bff34e3Sthurlow 	mb_done(&ntp->nt_tparam);
7714bff34e3Sthurlow 	mb_done(&ntp->nt_tdata);
7724bff34e3Sthurlow 	md_done(&ntp->nt_rparam);
7734bff34e3Sthurlow 	md_done(&ntp->nt_rdata);
7744bff34e3Sthurlow 	cv_destroy(&ntp->nt_cond);
7754bff34e3Sthurlow 	mutex_destroy(&ntp->nt_lock);
7764bff34e3Sthurlow 	if (ntp->nt_flags & SMBT2_ALLOCED)
7774bff34e3Sthurlow 		kmem_free(ntp, sizeof (*ntp));
7784bff34e3Sthurlow }
7794bff34e3Sthurlow 
7804bff34e3Sthurlow /*
7814bff34e3Sthurlow  * Extract data [offset,count] from mtop and add to mdp.
7824bff34e3Sthurlow  */
7834bff34e3Sthurlow static int
smb_t2_placedata(mblk_t * mtop,u_int16_t offset,u_int16_t count,struct mdchain * mdp)7844bff34e3Sthurlow smb_t2_placedata(mblk_t *mtop, u_int16_t offset, u_int16_t count,
7854bff34e3Sthurlow 	struct mdchain *mdp)
7864bff34e3Sthurlow {
7874bff34e3Sthurlow 	mblk_t *n;
7884bff34e3Sthurlow 
7894bff34e3Sthurlow 	n = m_copym(mtop, offset, count, M_WAITOK);
7904bff34e3Sthurlow 	if (n == NULL)
7914bff34e3Sthurlow 		return (EBADRPC);
7924bff34e3Sthurlow 
7934bff34e3Sthurlow 	if (mdp->md_top == NULL) {
7944bff34e3Sthurlow 		md_initm(mdp, n);
7954bff34e3Sthurlow 	} else
7964bff34e3Sthurlow 		m_cat(mdp->md_top, n);
7974bff34e3Sthurlow 
7984bff34e3Sthurlow 	return (0);
7994bff34e3Sthurlow }
8004bff34e3Sthurlow 
8014bff34e3Sthurlow static int
smb_t2_reply(struct smb_t2rq * t2p)8024bff34e3Sthurlow smb_t2_reply(struct smb_t2rq *t2p)
8034bff34e3Sthurlow {
8044bff34e3Sthurlow 	struct mdchain *mdp;
8054bff34e3Sthurlow 	struct smb_rq *rqp = t2p->t2_rq;
8064bff34e3Sthurlow 	int error, error2, totpgot, totdgot;
8074bff34e3Sthurlow 	u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
8084bff34e3Sthurlow 	u_int16_t tmp, bc, dcount;
8094bff34e3Sthurlow 	u_int8_t wc;
8104bff34e3Sthurlow 
8114bff34e3Sthurlow 	t2p->t2_flags &= ~SMBT2_MOREDATA;
8124bff34e3Sthurlow 
8134bff34e3Sthurlow 	error = smb_rq_reply(rqp);
8144bff34e3Sthurlow 	if (rqp->sr_flags & SMBR_MOREDATA)
8154bff34e3Sthurlow 		t2p->t2_flags |= SMBT2_MOREDATA;
8164bff34e3Sthurlow 	t2p->t2_sr_errclass = rqp->sr_errclass;
8174bff34e3Sthurlow 	t2p->t2_sr_serror = rqp->sr_serror;
8184bff34e3Sthurlow 	t2p->t2_sr_error = rqp->sr_error;
8194bff34e3Sthurlow 	t2p->t2_sr_rpflags2 = rqp->sr_rpflags2;
8204bff34e3Sthurlow 	if (error && !(rqp->sr_flags & SMBR_MOREDATA))
8214bff34e3Sthurlow 		return (error);
8224bff34e3Sthurlow 	/*
8234bff34e3Sthurlow 	 * Now we have to get all subseqent responses, if any.
8244bff34e3Sthurlow 	 * The CIFS specification says that they can be misordered,
8254bff34e3Sthurlow 	 * which is weird.
8264bff34e3Sthurlow 	 * TODO: timo
8274bff34e3Sthurlow 	 */
8284bff34e3Sthurlow 	totpgot = totdgot = 0;
8294bff34e3Sthurlow 	totpcount = totdcount = 0xffff;
8304bff34e3Sthurlow 	mdp = &rqp->sr_rp;
8314bff34e3Sthurlow 	for (;;) {
8324bff34e3Sthurlow 		DTRACE_PROBE2(smb_trans_reply,
8334bff34e3Sthurlow 		    (smb_rq_t *), rqp, (mblk_t *), mdp->md_top);
8344bff34e3Sthurlow 		m_dumpm(mdp->md_top);
8354bff34e3Sthurlow 
8364bff34e3Sthurlow 		if ((error2 = md_get_uint8(mdp, &wc)) != 0)
8374bff34e3Sthurlow 			break;
8384bff34e3Sthurlow 		if (wc < 10) {
8394bff34e3Sthurlow 			error2 = ENOENT;
8404bff34e3Sthurlow 			break;
8414bff34e3Sthurlow 		}
8424bff34e3Sthurlow 		if ((error2 = md_get_uint16le(mdp, &tmp)) != 0)
8434bff34e3Sthurlow 			break;
8444bff34e3Sthurlow 		if (totpcount > tmp)
8454bff34e3Sthurlow 			totpcount = tmp;
8464bff34e3Sthurlow 		if ((error2 = md_get_uint16le(mdp, &tmp)) != 0)
8474bff34e3Sthurlow 			break;
8484bff34e3Sthurlow 		if (totdcount > tmp)
8494bff34e3Sthurlow 			totdcount = tmp;
8504bff34e3Sthurlow 		if ((error2 = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
8514bff34e3Sthurlow 		    (error2 = md_get_uint16le(mdp, &pcount)) != 0 ||
8524bff34e3Sthurlow 		    (error2 = md_get_uint16le(mdp, &poff)) != 0 ||
8534bff34e3Sthurlow 		    (error2 = md_get_uint16le(mdp, &pdisp)) != 0)
8544bff34e3Sthurlow 			break;
8554bff34e3Sthurlow 		if (pcount != 0 && pdisp != totpgot) {
8564bff34e3Sthurlow 			SMBSDEBUG("Can't handle misordered parameters %d:%d\n",
8574bff34e3Sthurlow 			    pdisp, totpgot);
8584bff34e3Sthurlow 			error2 = EINVAL;
8594bff34e3Sthurlow 			break;
8604bff34e3Sthurlow 		}
8614bff34e3Sthurlow 		if ((error2 = md_get_uint16le(mdp, &dcount)) != 0 ||
8624bff34e3Sthurlow 		    (error2 = md_get_uint16le(mdp, &doff)) != 0 ||
8634bff34e3Sthurlow 		    (error2 = md_get_uint16le(mdp, &ddisp)) != 0)
8644bff34e3Sthurlow 			break;
8654bff34e3Sthurlow 		if (dcount != 0 && ddisp != totdgot) {
8664bff34e3Sthurlow 			SMBSDEBUG("Can't handle misordered data: dcount %d\n",
8674bff34e3Sthurlow 			    dcount);
8684bff34e3Sthurlow 			error2 = EINVAL;
8694bff34e3Sthurlow 			break;
8704bff34e3Sthurlow 		}
8714bff34e3Sthurlow 
8724bff34e3Sthurlow 		/* XXX: Skip setup words?  We don't save them? */
8734bff34e3Sthurlow 		md_get_uint8(mdp, &wc);  /* SetupCount */
8744bff34e3Sthurlow 		md_get_uint8(mdp, NULL); /* Reserved2 */
8754bff34e3Sthurlow 		tmp = wc;
8764bff34e3Sthurlow 		while (tmp--)
877613a2f6bSGordon Ross 			md_get_uint16le(mdp, NULL);
8784bff34e3Sthurlow 
8794bff34e3Sthurlow 		if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
8804bff34e3Sthurlow 			break;
8814bff34e3Sthurlow 
8824bff34e3Sthurlow 		/*
8834bff34e3Sthurlow 		 * There are pad bytes here, and the poff value
8844bff34e3Sthurlow 		 * indicates where the next data are found.
8854bff34e3Sthurlow 		 * No need to guess at the padding size.
8864bff34e3Sthurlow 		 */
8874bff34e3Sthurlow 		if (pcount) {
8884bff34e3Sthurlow 			error2 = smb_t2_placedata(mdp->md_top, poff,
8894bff34e3Sthurlow 			    pcount, &t2p->t2_rparam);
8904bff34e3Sthurlow 			if (error2)
8914bff34e3Sthurlow 				break;
8924bff34e3Sthurlow 		}
8934bff34e3Sthurlow 		totpgot += pcount;
8944bff34e3Sthurlow 
8954bff34e3Sthurlow 		if (dcount) {
8964bff34e3Sthurlow 			error2 = smb_t2_placedata(mdp->md_top, doff,
8974bff34e3Sthurlow 			    dcount, &t2p->t2_rdata);
8984bff34e3Sthurlow 			if (error2)
8994bff34e3Sthurlow 				break;
9004bff34e3Sthurlow 		}
9014bff34e3Sthurlow 		totdgot += dcount;
9024bff34e3Sthurlow 
9034bff34e3Sthurlow 		if (totpgot >= totpcount && totdgot >= totdcount) {
9044bff34e3Sthurlow 			error2 = 0;
9054bff34e3Sthurlow 			t2p->t2_flags |= SMBT2_ALLRECV;
9064bff34e3Sthurlow 			break;
9074bff34e3Sthurlow 		}
9084bff34e3Sthurlow 		/*
9094bff34e3Sthurlow 		 * We're done with this reply, look for the next one.
9104bff34e3Sthurlow 		 */
9114bff34e3Sthurlow 		SMBRQ_LOCK(rqp);
9124bff34e3Sthurlow 		md_next_record(&rqp->sr_rp);
9134bff34e3Sthurlow 		SMBRQ_UNLOCK(rqp);
9144bff34e3Sthurlow 		error2 = smb_rq_reply(rqp);
9154bff34e3Sthurlow 		if (rqp->sr_flags & SMBR_MOREDATA)
9164bff34e3Sthurlow 			t2p->t2_flags |= SMBT2_MOREDATA;
9174bff34e3Sthurlow 		if (!error2)
9184bff34e3Sthurlow 			continue;
9194bff34e3Sthurlow 		t2p->t2_sr_errclass = rqp->sr_errclass;
9204bff34e3Sthurlow 		t2p->t2_sr_serror = rqp->sr_serror;
9214bff34e3Sthurlow 		t2p->t2_sr_error = rqp->sr_error;
9224bff34e3Sthurlow 		t2p->t2_sr_rpflags2 = rqp->sr_rpflags2;
9234bff34e3Sthurlow 		error = error2;
9244bff34e3Sthurlow 		if (!(rqp->sr_flags & SMBR_MOREDATA))
9254bff34e3Sthurlow 			break;
9264bff34e3Sthurlow 	}
9274bff34e3Sthurlow 	return (error ? error : error2);
9284bff34e3Sthurlow }
9294bff34e3Sthurlow 
9304bff34e3Sthurlow static int
smb_nt_reply(struct smb_ntrq * ntp)9314bff34e3Sthurlow smb_nt_reply(struct smb_ntrq *ntp)
9324bff34e3Sthurlow {
9334bff34e3Sthurlow 	struct mdchain *mdp;
9344bff34e3Sthurlow 	struct smb_rq *rqp = ntp->nt_rq;
9354bff34e3Sthurlow 	int error, error2;
9364bff34e3Sthurlow 	u_int32_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
9374bff34e3Sthurlow 	u_int32_t tmp, dcount, totpgot, totdgot;
9384bff34e3Sthurlow 	u_int16_t bc;
9394bff34e3Sthurlow 	u_int8_t wc;
9404bff34e3Sthurlow 
9414bff34e3Sthurlow 	ntp->nt_flags &= ~SMBT2_MOREDATA;
9424bff34e3Sthurlow 
9434bff34e3Sthurlow 	error = smb_rq_reply(rqp);
9444bff34e3Sthurlow 	if (rqp->sr_flags & SMBR_MOREDATA)
9454bff34e3Sthurlow 		ntp->nt_flags |= SMBT2_MOREDATA;
9464bff34e3Sthurlow 	ntp->nt_sr_error = rqp->sr_error;
9474bff34e3Sthurlow 	ntp->nt_sr_rpflags2 = rqp->sr_rpflags2;
9484bff34e3Sthurlow 	if (error && !(rqp->sr_flags & SMBR_MOREDATA))
9494bff34e3Sthurlow 		return (error);
9504bff34e3Sthurlow 	/*
9514bff34e3Sthurlow 	 * Now we have to get all subseqent responses. The CIFS specification
9524bff34e3Sthurlow 	 * says that they can be misordered which is weird.
9534bff34e3Sthurlow 	 * TODO: timo
9544bff34e3Sthurlow 	 */
9554bff34e3Sthurlow 	totpgot = totdgot = 0;
9564bff34e3Sthurlow 	totpcount = totdcount = 0xffffffff;
9574bff34e3Sthurlow 	mdp = &rqp->sr_rp;
9584bff34e3Sthurlow 	for (;;) {
9594bff34e3Sthurlow 		DTRACE_PROBE2(smb_trans_reply,
9604bff34e3Sthurlow 		    (smb_rq_t *), rqp, (mblk_t *), mdp->md_top);
9614bff34e3Sthurlow 		m_dumpm(mdp->md_top);
9624bff34e3Sthurlow 
9634bff34e3Sthurlow 		if ((error2 = md_get_uint8(mdp, &wc)) != 0)
9644bff34e3Sthurlow 			break;
9654bff34e3Sthurlow 		if (wc < 18) {
9664bff34e3Sthurlow 			error2 = ENOENT;
9674bff34e3Sthurlow 			break;
9684bff34e3Sthurlow 		}
9694bff34e3Sthurlow 		md_get_mem(mdp, NULL, 3, MB_MSYSTEM); /* reserved */
9704bff34e3Sthurlow 		if ((error2 = md_get_uint32le(mdp, &tmp)) != 0)
9714bff34e3Sthurlow 			break;
9724bff34e3Sthurlow 		if (totpcount > tmp)
9734bff34e3Sthurlow 			totpcount = tmp;
9744bff34e3Sthurlow 		if ((error2 = md_get_uint32le(mdp, &tmp)) != 0)
9754bff34e3Sthurlow 			break;
9764bff34e3Sthurlow 		if (totdcount > tmp)
9774bff34e3Sthurlow 			totdcount = tmp;
9784bff34e3Sthurlow 		if ((error2 = md_get_uint32le(mdp, &pcount)) != 0 ||
9794bff34e3Sthurlow 		    (error2 = md_get_uint32le(mdp, &poff)) != 0 ||
9804bff34e3Sthurlow 		    (error2 = md_get_uint32le(mdp, &pdisp)) != 0)
9814bff34e3Sthurlow 			break;
9824bff34e3Sthurlow 		if (pcount != 0 && pdisp != totpgot) {
9834bff34e3Sthurlow 			SMBSDEBUG("Can't handle misordered parameters %d:%d\n",
9844bff34e3Sthurlow 			    pdisp, totpgot);
9854bff34e3Sthurlow 			error2 = EINVAL;
9864bff34e3Sthurlow 			break;
9874bff34e3Sthurlow 		}
9884bff34e3Sthurlow 		if ((error2 = md_get_uint32le(mdp, &dcount)) != 0 ||
9894bff34e3Sthurlow 		    (error2 = md_get_uint32le(mdp, &doff)) != 0 ||
9904bff34e3Sthurlow 		    (error2 = md_get_uint32le(mdp, &ddisp)) != 0)
9914bff34e3Sthurlow 			break;
9924bff34e3Sthurlow 		if (dcount != 0 && ddisp != totdgot) {
9934bff34e3Sthurlow 			SMBSDEBUG("Can't handle misordered data: dcount %d\n",
9944bff34e3Sthurlow 			    dcount);
9954bff34e3Sthurlow 			error2 = EINVAL;
9964bff34e3Sthurlow 			break;
9974bff34e3Sthurlow 		}
9984bff34e3Sthurlow 
9994bff34e3Sthurlow 		/* XXX: Skip setup words?  We don't save them? */
10004bff34e3Sthurlow 		md_get_uint8(mdp, &wc);  /* SetupCount */
10014bff34e3Sthurlow 		tmp = wc;
10024bff34e3Sthurlow 		while (tmp--)
1003613a2f6bSGordon Ross 			md_get_uint16le(mdp, NULL);
10044bff34e3Sthurlow 
10054bff34e3Sthurlow 		if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
10064bff34e3Sthurlow 			break;
10074bff34e3Sthurlow 
10084bff34e3Sthurlow 		/*
10094bff34e3Sthurlow 		 * There are pad bytes here, and the poff value
10104bff34e3Sthurlow 		 * indicates where the next data are found.
10114bff34e3Sthurlow 		 * No need to guess at the padding size.
10124bff34e3Sthurlow 		 */
10134bff34e3Sthurlow 		if (pcount) {
10144bff34e3Sthurlow 			error2 = smb_t2_placedata(mdp->md_top, poff, pcount,
10154bff34e3Sthurlow 			    &ntp->nt_rparam);
10164bff34e3Sthurlow 			if (error2)
10174bff34e3Sthurlow 				break;
10184bff34e3Sthurlow 		}
10194bff34e3Sthurlow 		totpgot += pcount;
10204bff34e3Sthurlow 
10214bff34e3Sthurlow 		if (dcount) {
10224bff34e3Sthurlow 			error2 = smb_t2_placedata(mdp->md_top, doff, dcount,
10234bff34e3Sthurlow 			    &ntp->nt_rdata);
10244bff34e3Sthurlow 			if (error2)
10254bff34e3Sthurlow 				break;
10264bff34e3Sthurlow 		}
10274bff34e3Sthurlow 		totdgot += dcount;
10284bff34e3Sthurlow 
10294bff34e3Sthurlow 		if (totpgot >= totpcount && totdgot >= totdcount) {
10304bff34e3Sthurlow 			error2 = 0;
10314bff34e3Sthurlow 			ntp->nt_flags |= SMBT2_ALLRECV;
10324bff34e3Sthurlow 			break;
10334bff34e3Sthurlow 		}
10344bff34e3Sthurlow 		/*
10354bff34e3Sthurlow 		 * We're done with this reply, look for the next one.
10364bff34e3Sthurlow 		 */
10374bff34e3Sthurlow 		SMBRQ_LOCK(rqp);
10384bff34e3Sthurlow 		md_next_record(&rqp->sr_rp);
10394bff34e3Sthurlow 		SMBRQ_UNLOCK(rqp);
10404bff34e3Sthurlow 		error2 = smb_rq_reply(rqp);
10414bff34e3Sthurlow 		if (rqp->sr_flags & SMBR_MOREDATA)
10424bff34e3Sthurlow 			ntp->nt_flags |= SMBT2_MOREDATA;
10434bff34e3Sthurlow 		if (!error2)
10444bff34e3Sthurlow 			continue;
10454bff34e3Sthurlow 		ntp->nt_sr_error = rqp->sr_error;
10464bff34e3Sthurlow 		ntp->nt_sr_rpflags2 = rqp->sr_rpflags2;
10474bff34e3Sthurlow 		error = error2;
10484bff34e3Sthurlow 		if (!(rqp->sr_flags & SMBR_MOREDATA))
10494bff34e3Sthurlow 			break;
10504bff34e3Sthurlow 	}
10514bff34e3Sthurlow 	return (error ? error : error2);
10524bff34e3Sthurlow }
10534bff34e3Sthurlow 
10544bff34e3Sthurlow /*
10554bff34e3Sthurlow  * Perform a full round of TRANS2 request
10564bff34e3Sthurlow  */
10574bff34e3Sthurlow static int
smb_t2_request_int(struct smb_t2rq * t2p)10584bff34e3Sthurlow smb_t2_request_int(struct smb_t2rq *t2p)
10594bff34e3Sthurlow {
10604bff34e3Sthurlow 	struct smb_vc *vcp = t2p->t2_vc;
10614bff34e3Sthurlow 	struct smb_cred *scred = t2p->t2_cred;
10624bff34e3Sthurlow 	struct mbchain *mbp;
10634bff34e3Sthurlow 	struct mdchain *mdp, mbparam, mbdata;
10644bff34e3Sthurlow 	mblk_t *m;
10654bff34e3Sthurlow 	struct smb_rq *rqp;
10664bff34e3Sthurlow 	int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
10679c9af259SGordon Ross 	int error, doff, poff, txdcount, txpcount, nmlen, nmsize;
10684bff34e3Sthurlow 
10694bff34e3Sthurlow 	m = t2p->t2_tparam.mb_top;
10704bff34e3Sthurlow 	if (m) {
10714bff34e3Sthurlow 		md_initm(&mbparam, m);	/* do not free it! */
10724bff34e3Sthurlow 		totpcount = m_fixhdr(m);
10734bff34e3Sthurlow 		if (totpcount > 0xffff)		/* maxvalue for ushort_t */
10744bff34e3Sthurlow 			return (EINVAL);
10754bff34e3Sthurlow 	} else
10764bff34e3Sthurlow 		totpcount = 0;
10774bff34e3Sthurlow 	m = t2p->t2_tdata.mb_top;
10784bff34e3Sthurlow 	if (m) {
10794bff34e3Sthurlow 		md_initm(&mbdata, m);	/* do not free it! */
108002d09e03SGordon Ross 		totdcount = m_fixhdr(m);
10814bff34e3Sthurlow 		if (totdcount > 0xffff)
10824bff34e3Sthurlow 			return (EINVAL);
10834bff34e3Sthurlow 	} else
10844bff34e3Sthurlow 		totdcount = 0;
10854bff34e3Sthurlow 	leftdcount = totdcount;
10864bff34e3Sthurlow 	leftpcount = totpcount;
10874bff34e3Sthurlow 	txmax = vcp->vc_txmax;
10889c9af259SGordon Ross 	error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
10894bff34e3Sthurlow 	    SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
10904bff34e3Sthurlow 	if (error)
10914bff34e3Sthurlow 		return (error);
10924bff34e3Sthurlow 	rqp->sr_timo = smb_timo_default;
10934bff34e3Sthurlow 	rqp->sr_flags |= SMBR_MULTIPACKET;
10944bff34e3Sthurlow 	t2p->t2_rq = rqp;
10954bff34e3Sthurlow 	mbp = &rqp->sr_rq;
10964bff34e3Sthurlow 	smb_rq_wstart(rqp);
10974bff34e3Sthurlow 	mb_put_uint16le(mbp, totpcount);
10984bff34e3Sthurlow 	mb_put_uint16le(mbp, totdcount);
10994bff34e3Sthurlow 	mb_put_uint16le(mbp, t2p->t2_maxpcount);
11004bff34e3Sthurlow 	mb_put_uint16le(mbp, t2p->t2_maxdcount);
11014bff34e3Sthurlow 	mb_put_uint8(mbp, t2p->t2_maxscount);
11024bff34e3Sthurlow 	mb_put_uint8(mbp, 0);			/* reserved */
11034bff34e3Sthurlow 	mb_put_uint16le(mbp, 0);			/* flags */
11044bff34e3Sthurlow 	mb_put_uint32le(mbp, 0);			/* Timeout */
11054bff34e3Sthurlow 	mb_put_uint16le(mbp, 0);			/* reserved 2 */
11064bff34e3Sthurlow 	len = mb_fixhdr(mbp);
11074bff34e3Sthurlow 
11084bff34e3Sthurlow 	/*
11099c9af259SGordon Ross 	 * Now we know the size of the trans overhead stuff:
11109c9af259SGordon Ross 	 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + nmsize),
11119c9af259SGordon Ross 	 * where nmsize is the OTW size of the name, including
11129c9af259SGordon Ross 	 * the unicode null terminator and any alignment.
11139c9af259SGordon Ross 	 * Use this to decide which parts (and how much)
11149c9af259SGordon Ross 	 * can go into this request: params, data
11154bff34e3Sthurlow 	 */
11169c9af259SGordon Ross 	nmlen = t2p->t_name ? t2p->t_name_len : 0;
11179c9af259SGordon Ross 	nmsize = nmlen + 1; /* null term. */
11189c9af259SGordon Ross 	if (SMB_UNICODE_STRINGS(vcp)) {
11199c9af259SGordon Ross 		nmsize *= 2;
11209c9af259SGordon Ross 		/* we know put_dmem will need to align */
11219c9af259SGordon Ross 		nmsize += 1;
11229c9af259SGordon Ross 	}
11239c9af259SGordon Ross 	len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmsize);
11244bff34e3Sthurlow 	if (len + leftpcount > txmax) {
11254bff34e3Sthurlow 		txpcount = min(leftpcount, txmax - len);
11264bff34e3Sthurlow 		poff = len;
11274bff34e3Sthurlow 		txdcount = 0;
11284bff34e3Sthurlow 		doff = 0;
11294bff34e3Sthurlow 	} else {
11304bff34e3Sthurlow 		txpcount = leftpcount;
11314bff34e3Sthurlow 		poff = txpcount ? len : 0;
11324bff34e3Sthurlow 		/*
11334bff34e3Sthurlow 		 * Other client traffic seems to "ALIGN2" here.  The extra
11344bff34e3Sthurlow 		 * 2 byte pad we use has no observed downside and may be
11354bff34e3Sthurlow 		 * required for some old servers(?)
11364bff34e3Sthurlow 		 */
11374bff34e3Sthurlow 		len = ALIGN4(len + txpcount);
11384bff34e3Sthurlow 		txdcount = min(leftdcount, txmax - len);
11394bff34e3Sthurlow 		doff = txdcount ? len : 0;
11404bff34e3Sthurlow 	}
11414bff34e3Sthurlow 	leftpcount -= txpcount;
11424bff34e3Sthurlow 	leftdcount -= txdcount;
11434bff34e3Sthurlow 	mb_put_uint16le(mbp, txpcount);
11444bff34e3Sthurlow 	mb_put_uint16le(mbp, poff);
11454bff34e3Sthurlow 	mb_put_uint16le(mbp, txdcount);
11464bff34e3Sthurlow 	mb_put_uint16le(mbp, doff);
11474bff34e3Sthurlow 	mb_put_uint8(mbp, t2p->t2_setupcount);
11484bff34e3Sthurlow 	mb_put_uint8(mbp, 0);
11494bff34e3Sthurlow 	for (i = 0; i < t2p->t2_setupcount; i++) {
11504bff34e3Sthurlow 		mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
11514bff34e3Sthurlow 	}
11524bff34e3Sthurlow 	smb_rq_wend(rqp);
11534bff34e3Sthurlow 	smb_rq_bstart(rqp);
11549c9af259SGordon Ross 	if (t2p->t_name) {
11559c9af259SGordon Ross 		/* Put the string and terminating null. */
115602d09e03SGordon Ross 		error = smb_put_dmem(mbp, vcp, t2p->t_name, nmlen + 1,
11579c9af259SGordon Ross 		    SMB_CS_NONE, NULL);
11589c9af259SGordon Ross 	} else {
11599c9af259SGordon Ross 		/* nmsize accounts for padding, char size. */
116002d09e03SGordon Ross 		error = mb_put_mem(mbp, NULL, nmsize, MB_MZERO);
11619c9af259SGordon Ross 	}
116202d09e03SGordon Ross 	if (error)
116302d09e03SGordon Ross 		goto freerq;
11644bff34e3Sthurlow 	len = mb_fixhdr(mbp);
11654bff34e3Sthurlow 	if (txpcount) {
11664bff34e3Sthurlow 		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
11674bff34e3Sthurlow 		error = md_get_mbuf(&mbparam, txpcount, &m);
11684bff34e3Sthurlow 		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
11694bff34e3Sthurlow 		if (error)
11704bff34e3Sthurlow 			goto freerq;
11714bff34e3Sthurlow 		mb_put_mbuf(mbp, m);
11724bff34e3Sthurlow 	}
11734bff34e3Sthurlow 	len = mb_fixhdr(mbp);
11744bff34e3Sthurlow 	if (txdcount) {
11754bff34e3Sthurlow 		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
11764bff34e3Sthurlow 		error = md_get_mbuf(&mbdata, txdcount, &m);
11774bff34e3Sthurlow 		if (error)
11784bff34e3Sthurlow 			goto freerq;
11794bff34e3Sthurlow 		mb_put_mbuf(mbp, m);
11804bff34e3Sthurlow 	}
11814bff34e3Sthurlow 	smb_rq_bend(rqp);	/* incredible, but thats it... */
11824bff34e3Sthurlow 	error = smb_rq_enqueue(rqp);
11834bff34e3Sthurlow 	if (error)
11844bff34e3Sthurlow 		goto freerq;
11854bff34e3Sthurlow 	if (leftpcount || leftdcount) {
11864bff34e3Sthurlow 		error = smb_rq_reply(rqp);
11874bff34e3Sthurlow 		if (error)
11884bff34e3Sthurlow 			goto bad;
11894bff34e3Sthurlow 		/*
11904bff34e3Sthurlow 		 * this is an interim response, ignore it.
11914bff34e3Sthurlow 		 */
11924bff34e3Sthurlow 		SMBRQ_LOCK(rqp);
11934bff34e3Sthurlow 		md_next_record(&rqp->sr_rp);
11944bff34e3Sthurlow 		SMBRQ_UNLOCK(rqp);
11954bff34e3Sthurlow 	}
11964bff34e3Sthurlow 	while (leftpcount || leftdcount) {
11974bff34e3Sthurlow 		error = smb_rq_new(rqp, t2p->t_name ?
11984bff34e3Sthurlow 		    SMB_COM_TRANSACTION_SECONDARY :
11994bff34e3Sthurlow 		    SMB_COM_TRANSACTION2_SECONDARY);
12004bff34e3Sthurlow 		if (error)
12014bff34e3Sthurlow 			goto bad;
12024bff34e3Sthurlow 		mbp = &rqp->sr_rq;
12034bff34e3Sthurlow 		smb_rq_wstart(rqp);
12044bff34e3Sthurlow 		mb_put_uint16le(mbp, totpcount);
12054bff34e3Sthurlow 		mb_put_uint16le(mbp, totdcount);
12064bff34e3Sthurlow 		len = mb_fixhdr(mbp);
12074bff34e3Sthurlow 		/*
12084bff34e3Sthurlow 		 * now we have known packet size as
12094bff34e3Sthurlow 		 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
12104bff34e3Sthurlow 		 * and need to decide which parts should go into request
12114bff34e3Sthurlow 		 */
12124bff34e3Sthurlow 		len = ALIGN4(len + 6 * 2 + 2);
12134bff34e3Sthurlow 		if (t2p->t_name == NULL)
12144bff34e3Sthurlow 			len += 2;
12154bff34e3Sthurlow 		if (len + leftpcount > txmax) {
12164bff34e3Sthurlow 			txpcount = min(leftpcount, txmax - len);
12174bff34e3Sthurlow 			poff = len;
12184bff34e3Sthurlow 			txdcount = 0;
12194bff34e3Sthurlow 			doff = 0;
12204bff34e3Sthurlow 		} else {
12214bff34e3Sthurlow 			txpcount = leftpcount;
12224bff34e3Sthurlow 			poff = txpcount ? len : 0;
12234bff34e3Sthurlow 			len = ALIGN4(len + txpcount);
12244bff34e3Sthurlow 			txdcount = min(leftdcount, txmax - len);
12254bff34e3Sthurlow 			doff = txdcount ? len : 0;
12264bff34e3Sthurlow 		}
12274bff34e3Sthurlow 		mb_put_uint16le(mbp, txpcount);
12284bff34e3Sthurlow 		mb_put_uint16le(mbp, poff);
12294bff34e3Sthurlow 		mb_put_uint16le(mbp, totpcount - leftpcount);
12304bff34e3Sthurlow 		mb_put_uint16le(mbp, txdcount);
12314bff34e3Sthurlow 		mb_put_uint16le(mbp, doff);
12324bff34e3Sthurlow 		mb_put_uint16le(mbp, totdcount - leftdcount);
12334bff34e3Sthurlow 		leftpcount -= txpcount;
12344bff34e3Sthurlow 		leftdcount -= txdcount;
12354bff34e3Sthurlow 		if (t2p->t_name == NULL)
12364bff34e3Sthurlow 			mb_put_uint16le(mbp, t2p->t2_fid);
12374bff34e3Sthurlow 		smb_rq_wend(rqp);
12384bff34e3Sthurlow 		smb_rq_bstart(rqp);
12394bff34e3Sthurlow 		mb_put_uint8(mbp, 0);	/* name */
12404bff34e3Sthurlow 		len = mb_fixhdr(mbp);
12414bff34e3Sthurlow 		if (txpcount) {
12424bff34e3Sthurlow 			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
12434bff34e3Sthurlow 			error = md_get_mbuf(&mbparam, txpcount, &m);
12444bff34e3Sthurlow 			if (error)
12454bff34e3Sthurlow 				goto bad;
12464bff34e3Sthurlow 			mb_put_mbuf(mbp, m);
12474bff34e3Sthurlow 		}
12484bff34e3Sthurlow 		len = mb_fixhdr(mbp);
12494bff34e3Sthurlow 		if (txdcount) {
12504bff34e3Sthurlow 			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
12514bff34e3Sthurlow 			error = md_get_mbuf(&mbdata, txdcount, &m);
12524bff34e3Sthurlow 			if (error)
12534bff34e3Sthurlow 				goto bad;
12544bff34e3Sthurlow 			mb_put_mbuf(mbp, m);
12554bff34e3Sthurlow 		}
12564bff34e3Sthurlow 		smb_rq_bend(rqp);
1257*adee6784SGordon Ross 		error = smb1_iod_multirq(rqp);
12584bff34e3Sthurlow 		if (error)
12594bff34e3Sthurlow 			goto bad;
12604bff34e3Sthurlow 	}	/* while left params or data */
12614bff34e3Sthurlow 	error = smb_t2_reply(t2p);
12624bff34e3Sthurlow 	if (error && !(t2p->t2_flags & SMBT2_MOREDATA))
12634bff34e3Sthurlow 		goto bad;
12644bff34e3Sthurlow 	mdp = &t2p->t2_rdata;
12654bff34e3Sthurlow 	if (mdp->md_top) {
12664bff34e3Sthurlow 		md_initm(mdp, mdp->md_top);
12674bff34e3Sthurlow 	}
12684bff34e3Sthurlow 	mdp = &t2p->t2_rparam;
12694bff34e3Sthurlow 	if (mdp->md_top) {
12704bff34e3Sthurlow 		md_initm(mdp, mdp->md_top);
12714bff34e3Sthurlow 	}
12724bff34e3Sthurlow bad:
12734bff34e3Sthurlow 	smb_iod_removerq(rqp);
12744bff34e3Sthurlow freerq:
12754bff34e3Sthurlow 	if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) {
12764bff34e3Sthurlow 		if (rqp->sr_flags & SMBR_RESTART)
12774bff34e3Sthurlow 			t2p->t2_flags |= SMBT2_RESTART;
12784bff34e3Sthurlow 		md_done(&t2p->t2_rparam);
12794bff34e3Sthurlow 		md_done(&t2p->t2_rdata);
12804bff34e3Sthurlow 	}
12814bff34e3Sthurlow 	smb_rq_done(rqp);
12824bff34e3Sthurlow 	return (error);
12834bff34e3Sthurlow }
12844bff34e3Sthurlow 
12854bff34e3Sthurlow 
12864bff34e3Sthurlow /*
12874bff34e3Sthurlow  * Perform a full round of NT_TRANSACTION request
12884bff34e3Sthurlow  */
12894bff34e3Sthurlow static int
smb_nt_request_int(struct smb_ntrq * ntp)12904bff34e3Sthurlow smb_nt_request_int(struct smb_ntrq *ntp)
12914bff34e3Sthurlow {
12924bff34e3Sthurlow 	struct smb_vc *vcp = ntp->nt_vc;
12934bff34e3Sthurlow 	struct smb_cred *scred = ntp->nt_cred;
12944bff34e3Sthurlow 	struct mbchain *mbp;
12954bff34e3Sthurlow 	struct mdchain *mdp, mbsetup, mbparam, mbdata;
12964bff34e3Sthurlow 	mblk_t *m;
12974bff34e3Sthurlow 	struct smb_rq *rqp;
12984bff34e3Sthurlow 	int totpcount, leftpcount, totdcount, leftdcount, len, txmax;
12994bff34e3Sthurlow 	int error, doff, poff, txdcount, txpcount;
13004bff34e3Sthurlow 	int totscount;
13014bff34e3Sthurlow 
13024bff34e3Sthurlow 	m = ntp->nt_tsetup.mb_top;
13034bff34e3Sthurlow 	if (m) {
13044bff34e3Sthurlow 		md_initm(&mbsetup, m);	/* do not free it! */
13054bff34e3Sthurlow 		totscount = m_fixhdr(m);
13064bff34e3Sthurlow 		if (totscount > 2 * 0xff)
13074bff34e3Sthurlow 			return (EINVAL);
13084bff34e3Sthurlow 	} else
13094bff34e3Sthurlow 		totscount = 0;
13104bff34e3Sthurlow 	m = ntp->nt_tparam.mb_top;
13114bff34e3Sthurlow 	if (m) {
13124bff34e3Sthurlow 		md_initm(&mbparam, m);	/* do not free it! */
13134bff34e3Sthurlow 		totpcount = m_fixhdr(m);
13144bff34e3Sthurlow 		if (totpcount > 0x7fffffff)
13154bff34e3Sthurlow 			return (EINVAL);
13164bff34e3Sthurlow 	} else
13174bff34e3Sthurlow 		totpcount = 0;
13184bff34e3Sthurlow 	m = ntp->nt_tdata.mb_top;
13194bff34e3Sthurlow 	if (m) {
13204bff34e3Sthurlow 		md_initm(&mbdata, m);	/* do not free it! */
13214bff34e3Sthurlow 		totdcount =  m_fixhdr(m);
13224bff34e3Sthurlow 		if (totdcount > 0x7fffffff)
13234bff34e3Sthurlow 			return (EINVAL);
13244bff34e3Sthurlow 	} else
13254bff34e3Sthurlow 		totdcount = 0;
13264bff34e3Sthurlow 	leftdcount = totdcount;
13274bff34e3Sthurlow 	leftpcount = totpcount;
13284bff34e3Sthurlow 	txmax = vcp->vc_txmax;
13294bff34e3Sthurlow 	error = smb_rq_alloc(ntp->nt_source, SMB_COM_NT_TRANSACT, scred, &rqp);
13304bff34e3Sthurlow 	if (error)
13314bff34e3Sthurlow 		return (error);
13324bff34e3Sthurlow 	rqp->sr_timo = smb_timo_default;
13334bff34e3Sthurlow 	rqp->sr_flags |= SMBR_MULTIPACKET;
13344bff34e3Sthurlow 	ntp->nt_rq = rqp;
13354bff34e3Sthurlow 	mbp = &rqp->sr_rq;
13364bff34e3Sthurlow 	smb_rq_wstart(rqp);
13374bff34e3Sthurlow 	mb_put_uint8(mbp, ntp->nt_maxscount);
13384bff34e3Sthurlow 	mb_put_uint16le(mbp, 0);	/* reserved (flags?) */
13394bff34e3Sthurlow 	mb_put_uint32le(mbp, totpcount);
13404bff34e3Sthurlow 	mb_put_uint32le(mbp, totdcount);
13414bff34e3Sthurlow 	mb_put_uint32le(mbp, ntp->nt_maxpcount);
13424bff34e3Sthurlow 	mb_put_uint32le(mbp, ntp->nt_maxdcount);
13434bff34e3Sthurlow 	len = mb_fixhdr(mbp);
13444bff34e3Sthurlow 	/*
13454bff34e3Sthurlow 	 * now we have known packet size as
13464bff34e3Sthurlow 	 * ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2),
13474bff34e3Sthurlow 	 * and need to decide which parts should go into the first request
13484bff34e3Sthurlow 	 */
13494bff34e3Sthurlow 	len = ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2);
13504bff34e3Sthurlow 	if (len + leftpcount > txmax) {
13514bff34e3Sthurlow 		txpcount = min(leftpcount, txmax - len);
13524bff34e3Sthurlow 		poff = len;
13534bff34e3Sthurlow 		txdcount = 0;
13544bff34e3Sthurlow 		doff = 0;
13554bff34e3Sthurlow 	} else {
13564bff34e3Sthurlow 		txpcount = leftpcount;
13574bff34e3Sthurlow 		poff = txpcount ? len : 0;
13584bff34e3Sthurlow 		len = ALIGN4(len + txpcount);
13594bff34e3Sthurlow 		txdcount = min(leftdcount, txmax - len);
13604bff34e3Sthurlow 		doff = txdcount ? len : 0;
13614bff34e3Sthurlow 	}
13624bff34e3Sthurlow 	leftpcount -= txpcount;
13634bff34e3Sthurlow 	leftdcount -= txdcount;
13644bff34e3Sthurlow 	mb_put_uint32le(mbp, txpcount);
13654bff34e3Sthurlow 	mb_put_uint32le(mbp, poff);
13664bff34e3Sthurlow 	mb_put_uint32le(mbp, txdcount);
13674bff34e3Sthurlow 	mb_put_uint32le(mbp, doff);
13684bff34e3Sthurlow 	mb_put_uint8(mbp, (totscount+1)/2);
13694bff34e3Sthurlow 	mb_put_uint16le(mbp, ntp->nt_function);
13704bff34e3Sthurlow 	if (totscount) {
13714bff34e3Sthurlow 		error = md_get_mbuf(&mbsetup, totscount, &m);
13724bff34e3Sthurlow 		SMBSDEBUG("%d:%d:%d\n", error, totscount, txmax);
13734bff34e3Sthurlow 		if (error)
13744bff34e3Sthurlow 			goto freerq;
13754bff34e3Sthurlow 		mb_put_mbuf(mbp, m);
13764bff34e3Sthurlow 		if (totscount & 1)
13774bff34e3Sthurlow 			mb_put_uint8(mbp, 0); /* setup is in words */
13784bff34e3Sthurlow 	}
13794bff34e3Sthurlow 	smb_rq_wend(rqp);
13804bff34e3Sthurlow 	smb_rq_bstart(rqp);
13814bff34e3Sthurlow 	len = mb_fixhdr(mbp);
13824bff34e3Sthurlow 	if (txpcount) {
13834bff34e3Sthurlow 		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
13844bff34e3Sthurlow 		error = md_get_mbuf(&mbparam, txpcount, &m);
13854bff34e3Sthurlow 		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
13864bff34e3Sthurlow 		if (error)
13874bff34e3Sthurlow 			goto freerq;
13884bff34e3Sthurlow 		mb_put_mbuf(mbp, m);
13894bff34e3Sthurlow 	}
13904bff34e3Sthurlow 	len = mb_fixhdr(mbp);
13914bff34e3Sthurlow 	if (txdcount) {
13924bff34e3Sthurlow 		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
13934bff34e3Sthurlow 		error = md_get_mbuf(&mbdata, txdcount, &m);
13944bff34e3Sthurlow 		if (error)
13954bff34e3Sthurlow 			goto freerq;
13964bff34e3Sthurlow 		mb_put_mbuf(mbp, m);
13974bff34e3Sthurlow 	}
13984bff34e3Sthurlow 	smb_rq_bend(rqp);	/* incredible, but thats it... */
13994bff34e3Sthurlow 	error = smb_rq_enqueue(rqp);
14004bff34e3Sthurlow 	if (error)
14014bff34e3Sthurlow 		goto freerq;
14024bff34e3Sthurlow 	if (leftpcount || leftdcount) {
14034bff34e3Sthurlow 		error = smb_rq_reply(rqp);
14044bff34e3Sthurlow 		if (error)
14054bff34e3Sthurlow 			goto bad;
14064bff34e3Sthurlow 		/*
14074bff34e3Sthurlow 		 * this is an interim response, ignore it.
14084bff34e3Sthurlow 		 */
14094bff34e3Sthurlow 		SMBRQ_LOCK(rqp);
14104bff34e3Sthurlow 		md_next_record(&rqp->sr_rp);
14114bff34e3Sthurlow 		SMBRQ_UNLOCK(rqp);
14124bff34e3Sthurlow 	}
14134bff34e3Sthurlow 	while (leftpcount || leftdcount) {
14144bff34e3Sthurlow 		error = smb_rq_new(rqp, SMB_COM_NT_TRANSACT_SECONDARY);
14154bff34e3Sthurlow 		if (error)
14164bff34e3Sthurlow 			goto bad;
14174bff34e3Sthurlow 		mbp = &rqp->sr_rq;
14184bff34e3Sthurlow 		smb_rq_wstart(rqp);
14194bff34e3Sthurlow 		mb_put_mem(mbp, NULL, 3, MB_MZERO);
14204bff34e3Sthurlow 		mb_put_uint32le(mbp, totpcount);
14214bff34e3Sthurlow 		mb_put_uint32le(mbp, totdcount);
14224bff34e3Sthurlow 		len = mb_fixhdr(mbp);
14234bff34e3Sthurlow 		/*
14244bff34e3Sthurlow 		 * now we have known packet size as
14254bff34e3Sthurlow 		 * ALIGN4(len + 6 * 4  + 2)
14264bff34e3Sthurlow 		 * and need to decide which parts should go into request
14274bff34e3Sthurlow 		 */
14284bff34e3Sthurlow 		len = ALIGN4(len + 6 * 4 + 2);
14294bff34e3Sthurlow 		if (len + leftpcount > txmax) {
14304bff34e3Sthurlow 			txpcount = min(leftpcount, txmax - len);
14314bff34e3Sthurlow 			poff = len;
14324bff34e3Sthurlow 			txdcount = 0;
14334bff34e3Sthurlow 			doff = 0;
14344bff34e3Sthurlow 		} else {
14354bff34e3Sthurlow 			txpcount = leftpcount;
14364bff34e3Sthurlow 			poff = txpcount ? len : 0;
14374bff34e3Sthurlow 			len = ALIGN4(len + txpcount);
14384bff34e3Sthurlow 			txdcount = min(leftdcount, txmax - len);
14394bff34e3Sthurlow 			doff = txdcount ? len : 0;
14404bff34e3Sthurlow 		}
14414bff34e3Sthurlow 		mb_put_uint32le(mbp, txpcount);
14424bff34e3Sthurlow 		mb_put_uint32le(mbp, poff);
14434bff34e3Sthurlow 		mb_put_uint32le(mbp, totpcount - leftpcount);
14444bff34e3Sthurlow 		mb_put_uint32le(mbp, txdcount);
14454bff34e3Sthurlow 		mb_put_uint32le(mbp, doff);
14464bff34e3Sthurlow 		mb_put_uint32le(mbp, totdcount - leftdcount);
14474bff34e3Sthurlow 		leftpcount -= txpcount;
14484bff34e3Sthurlow 		leftdcount -= txdcount;
14494bff34e3Sthurlow 		smb_rq_wend(rqp);
14504bff34e3Sthurlow 		smb_rq_bstart(rqp);
14514bff34e3Sthurlow 		len = mb_fixhdr(mbp);
14524bff34e3Sthurlow 		if (txpcount) {
14534bff34e3Sthurlow 			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
14544bff34e3Sthurlow 			error = md_get_mbuf(&mbparam, txpcount, &m);
14554bff34e3Sthurlow 			if (error)
14564bff34e3Sthurlow 				goto bad;
14574bff34e3Sthurlow 			mb_put_mbuf(mbp, m);
14584bff34e3Sthurlow 		}
14594bff34e3Sthurlow 		len = mb_fixhdr(mbp);
14604bff34e3Sthurlow 		if (txdcount) {
14614bff34e3Sthurlow 			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
14624bff34e3Sthurlow 			error = md_get_mbuf(&mbdata, txdcount, &m);
14634bff34e3Sthurlow 			if (error)
14644bff34e3Sthurlow 				goto bad;
14654bff34e3Sthurlow 			mb_put_mbuf(mbp, m);
14664bff34e3Sthurlow 		}
14674bff34e3Sthurlow 		smb_rq_bend(rqp);
1468*adee6784SGordon Ross 		error = smb1_iod_multirq(rqp);
14694bff34e3Sthurlow 		if (error)
14704bff34e3Sthurlow 			goto bad;
14714bff34e3Sthurlow 	}	/* while left params or data */
14724bff34e3Sthurlow 	error = smb_nt_reply(ntp);
14734bff34e3Sthurlow 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
14744bff34e3Sthurlow 		goto bad;
14754bff34e3Sthurlow 	mdp = &ntp->nt_rdata;
14764bff34e3Sthurlow 	if (mdp->md_top) {
14774bff34e3Sthurlow 		md_initm(mdp, mdp->md_top);
14784bff34e3Sthurlow 	}
14794bff34e3Sthurlow 	mdp = &ntp->nt_rparam;
14804bff34e3Sthurlow 	if (mdp->md_top) {
14814bff34e3Sthurlow 		md_initm(mdp, mdp->md_top);
14824bff34e3Sthurlow 	}
14834bff34e3Sthurlow bad:
14844bff34e3Sthurlow 	smb_iod_removerq(rqp);
14854bff34e3Sthurlow freerq:
14864bff34e3Sthurlow 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) {
14874bff34e3Sthurlow 		if (rqp->sr_flags & SMBR_RESTART)
14884bff34e3Sthurlow 			ntp->nt_flags |= SMBT2_RESTART;
14894bff34e3Sthurlow 		md_done(&ntp->nt_rparam);
14904bff34e3Sthurlow 		md_done(&ntp->nt_rdata);
14914bff34e3Sthurlow 	}
14924bff34e3Sthurlow 	smb_rq_done(rqp);
14934bff34e3Sthurlow 	return (error);
14944bff34e3Sthurlow }
14954bff34e3Sthurlow 
14964bff34e3Sthurlow int
smb_t2_request(struct smb_t2rq * t2p)14974bff34e3Sthurlow smb_t2_request(struct smb_t2rq *t2p)
14984bff34e3Sthurlow {
14994bff34e3Sthurlow 	int error = EINVAL, i;
15004bff34e3Sthurlow 
15014bff34e3Sthurlow 	for (i = 0; ; ) {
15024bff34e3Sthurlow 		/*
15034bff34e3Sthurlow 		 * Don't send any new requests if force unmount is underway.
15044bff34e3Sthurlow 		 * This check was moved into smb_rq_enqueue, called by
15054bff34e3Sthurlow 		 * smb_t2_request_int()
15064bff34e3Sthurlow 		 */
15074bff34e3Sthurlow 		t2p->t2_flags &= ~SMBT2_RESTART;
15084bff34e3Sthurlow 		error = smb_t2_request_int(t2p);
15094bff34e3Sthurlow 		if (!error)
15104bff34e3Sthurlow 			break;
15114bff34e3Sthurlow 		if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) !=
15124bff34e3Sthurlow 		    SMBT2_RESTART)
15134bff34e3Sthurlow 			break;
15144bff34e3Sthurlow 		if (++i > SMBMAXRESTARTS)
15154bff34e3Sthurlow 			break;
15164bff34e3Sthurlow 		mutex_enter(&(t2p)->t2_lock);
1517613a2f6bSGordon Ross 		if (t2p->t2_share) {
151802d09e03SGordon Ross 			(void) cv_reltimedwait(&t2p->t2_cond, &(t2p)->t2_lock,
151902d09e03SGordon Ross 			    SEC_TO_TICK(SMB_RCNDELAY), TR_CLOCK_TICK);
15204bff34e3Sthurlow 		} else {
152102d09e03SGordon Ross 			delay(SEC_TO_TICK(SMB_RCNDELAY));
15224bff34e3Sthurlow 		}
15234bff34e3Sthurlow 		mutex_exit(&(t2p)->t2_lock);
15244bff34e3Sthurlow 	}
15254bff34e3Sthurlow 	return (error);
15264bff34e3Sthurlow }
15274bff34e3Sthurlow 
15284bff34e3Sthurlow 
15294bff34e3Sthurlow int
smb_nt_request(struct smb_ntrq * ntp)15304bff34e3Sthurlow smb_nt_request(struct smb_ntrq *ntp)
15314bff34e3Sthurlow {
15324bff34e3Sthurlow 	int error = EINVAL, i;
15334bff34e3Sthurlow 
15344bff34e3Sthurlow 	for (i = 0; ; ) {
15354bff34e3Sthurlow 		/*
15364bff34e3Sthurlow 		 * Don't send any new requests if force unmount is underway.
15374bff34e3Sthurlow 		 * This check was moved into smb_rq_enqueue, called by
15384bff34e3Sthurlow 		 * smb_nt_request_int()
15394bff34e3Sthurlow 		 */
15404bff34e3Sthurlow 		ntp->nt_flags &= ~SMBT2_RESTART;
15414bff34e3Sthurlow 		error = smb_nt_request_int(ntp);
15424bff34e3Sthurlow 		if (!error)
15434bff34e3Sthurlow 			break;
15444bff34e3Sthurlow 		if ((ntp->nt_flags & (SMBT2_RESTART | SMBT2_NORESTART)) !=
15454bff34e3Sthurlow 		    SMBT2_RESTART)
15464bff34e3Sthurlow 			break;
15474bff34e3Sthurlow 		if (++i > SMBMAXRESTARTS)
15484bff34e3Sthurlow 			break;
15494bff34e3Sthurlow 		mutex_enter(&(ntp)->nt_lock);
1550613a2f6bSGordon Ross 		if (ntp->nt_share) {
155102d09e03SGordon Ross 			(void) cv_reltimedwait(&ntp->nt_cond, &(ntp)->nt_lock,
155202d09e03SGordon Ross 			    SEC_TO_TICK(SMB_RCNDELAY), TR_CLOCK_TICK);
15534bff34e3Sthurlow 
15544bff34e3Sthurlow 		} else {
155502d09e03SGordon Ross 			delay(SEC_TO_TICK(SMB_RCNDELAY));
15564bff34e3Sthurlow 		}
15574bff34e3Sthurlow 		mutex_exit(&(ntp)->nt_lock);
15584bff34e3Sthurlow 	}
15594bff34e3Sthurlow 	return (error);
15604bff34e3Sthurlow }
1561*adee6784SGordon Ross 
1562*adee6784SGordon Ross /*
1563*adee6784SGordon Ross  * Run an SMB transact named pipe.
1564*adee6784SGordon Ross  * Note: send_mb is consumed.
1565*adee6784SGordon Ross  */
1566*adee6784SGordon Ross int
smb_t2_xnp(struct smb_share * ssp,uint16_t fid,struct mbchain * send_mb,struct mdchain * recv_md,uint32_t * data_out_sz,uint32_t * more,struct smb_cred * scrp)1567*adee6784SGordon Ross smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
1568*adee6784SGordon Ross     struct mbchain *send_mb, struct mdchain *recv_md,
1569*adee6784SGordon Ross     uint32_t *data_out_sz, /* max / returned */
1570*adee6784SGordon Ross     uint32_t *more, struct smb_cred *scrp)
1571*adee6784SGordon Ross {
1572*adee6784SGordon Ross 	struct smb_t2rq *t2p = NULL;
1573*adee6784SGordon Ross 	mblk_t *m;
1574*adee6784SGordon Ross 	uint16_t setup[2];
1575*adee6784SGordon Ross 	int err;
1576*adee6784SGordon Ross 
1577*adee6784SGordon Ross 	setup[0] = TRANS_TRANSACT_NAMED_PIPE;
1578*adee6784SGordon Ross 	setup[1] = fid;
1579*adee6784SGordon Ross 
1580*adee6784SGordon Ross 	t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
1581*adee6784SGordon Ross 	err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, scrp);
1582*adee6784SGordon Ross 	if (err) {
1583*adee6784SGordon Ross 		*data_out_sz = 0;
1584*adee6784SGordon Ross 		goto out;
1585*adee6784SGordon Ross 	}
1586*adee6784SGordon Ross 
1587*adee6784SGordon Ross 	t2p->t2_setupcount = 2;
1588*adee6784SGordon Ross 	t2p->t2_setupdata  = setup;
1589*adee6784SGordon Ross 
1590*adee6784SGordon Ross 	t2p->t_name = "\\PIPE\\";
1591*adee6784SGordon Ross 	t2p->t_name_len = 6;
1592*adee6784SGordon Ross 
1593*adee6784SGordon Ross 	t2p->t2_maxscount = 0;
1594*adee6784SGordon Ross 	t2p->t2_maxpcount = 0;
1595*adee6784SGordon Ross 	t2p->t2_maxdcount = (uint16_t)*data_out_sz;
1596*adee6784SGordon Ross 
1597*adee6784SGordon Ross 	/* Transmit parameters (none) */
1598*adee6784SGordon Ross 
1599*adee6784SGordon Ross 	/*
1600*adee6784SGordon Ross 	 * Transmit data
1601*adee6784SGordon Ross 	 *
1602*adee6784SGordon Ross 	 * Copy the mb, and clear the source so we
1603*adee6784SGordon Ross 	 * don't end up with a double free.
1604*adee6784SGordon Ross 	 */
1605*adee6784SGordon Ross 	t2p->t2_tdata = *send_mb;
1606*adee6784SGordon Ross 	bzero(send_mb, sizeof (*send_mb));
1607*adee6784SGordon Ross 
1608*adee6784SGordon Ross 	/*
1609*adee6784SGordon Ross 	 * Run the request
1610*adee6784SGordon Ross 	 */
1611*adee6784SGordon Ross 	err = smb_t2_request(t2p);
1612*adee6784SGordon Ross 
1613*adee6784SGordon Ross 	/* No returned parameters. */
1614*adee6784SGordon Ross 
1615*adee6784SGordon Ross 	if (err == 0 && (m = t2p->t2_rdata.md_top) != NULL) {
1616*adee6784SGordon Ross 		/*
1617*adee6784SGordon Ross 		 * Received data
1618*adee6784SGordon Ross 		 *
1619*adee6784SGordon Ross 		 * Copy the mdchain, and clear the source so we
1620*adee6784SGordon Ross 		 * don't end up with a double free.
1621*adee6784SGordon Ross 		 */
1622*adee6784SGordon Ross 		*data_out_sz = msgdsize(m);
1623*adee6784SGordon Ross 		md_initm(recv_md, m);
1624*adee6784SGordon Ross 		t2p->t2_rdata.md_top = NULL;
1625*adee6784SGordon Ross 	} else {
1626*adee6784SGordon Ross 		*data_out_sz = 0;
1627*adee6784SGordon Ross 	}
1628*adee6784SGordon Ross 
1629*adee6784SGordon Ross 	if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
1630*adee6784SGordon Ross 		*more = 1;
1631*adee6784SGordon Ross 
1632*adee6784SGordon Ross out:
1633*adee6784SGordon Ross 	if (t2p != NULL) {
1634*adee6784SGordon Ross 		/* Note: t2p->t_name no longer allocated */
1635*adee6784SGordon Ross 		smb_t2_done(t2p);
1636*adee6784SGordon Ross 		kmem_free(t2p, sizeof (*t2p));
1637*adee6784SGordon Ross 	}
1638*adee6784SGordon Ross 
1639*adee6784SGordon Ross 	return (err);
1640*adee6784SGordon Ross }
1641