1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/endian.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38#include <sys/proc.h>
39#include <sys/lock.h>
40#include <sys/sysctl.h>
41#include <sys/socket.h>
42#include <sys/socketvar.h>
43#include <sys/mbuf.h>
44
45#include <netsmb/smb.h>
46#include <netsmb/smb_conn.h>
47#include <netsmb/smb_rq.h>
48#include <netsmb/smb_subr.h>
49#include <netsmb/smb_tran.h>
50
51static MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
52
53MODULE_DEPEND(netsmb, libmchain, 1, 1, 1);
54
55static int  smb_rq_reply(struct smb_rq *rqp);
56static int  smb_rq_enqueue(struct smb_rq *rqp);
57static int  smb_rq_getenv(struct smb_connobj *layer,
58		struct smb_vc **vcpp, struct smb_share **sspp);
59static int  smb_rq_new(struct smb_rq *rqp, u_char cmd);
60static int  smb_t2_reply(struct smb_t2rq *t2p);
61
62int
63smb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred,
64	struct smb_rq **rqpp)
65{
66	struct smb_rq *rqp;
67	int error;
68
69	rqp = malloc(sizeof(*rqp), M_SMBRQ, M_WAITOK);
70	if (rqp == NULL)
71		return ENOMEM;
72	error = smb_rq_init(rqp, layer, cmd, scred);
73	rqp->sr_flags |= SMBR_ALLOCED;
74	if (error) {
75		smb_rq_done(rqp);
76		return error;
77	}
78	*rqpp = rqp;
79	return 0;
80}
81
82static char tzero[12];
83
84int
85smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
86	struct smb_cred *scred)
87{
88	int error;
89
90	bzero(rqp, sizeof(*rqp));
91	smb_sl_init(&rqp->sr_slock, "srslock");
92	error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
93	if (error)
94		return error;
95	error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
96	if (error)
97		return error;
98	if (rqp->sr_share) {
99		error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
100		if (error)
101			return error;
102	}
103	rqp->sr_cred = scred;
104	rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
105	return smb_rq_new(rqp, cmd);
106}
107
108static int
109smb_rq_new(struct smb_rq *rqp, u_char cmd)
110{
111	struct smb_vc *vcp = rqp->sr_vc;
112	struct mbchain *mbp = &rqp->sr_rq;
113	int error;
114	u_int16_t flags2;
115
116	rqp->sr_sendcnt = 0;
117	mb_done(mbp);
118	md_done(&rqp->sr_rp);
119	error = mb_init(mbp);
120	if (error)
121		return error;
122	mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
123	mb_put_uint8(mbp, cmd);
124	mb_put_uint32le(mbp, 0);		/* DosError */
125	mb_put_uint8(mbp, vcp->vc_hflags);
126	flags2 = vcp->vc_hflags2;
127	if (cmd == SMB_COM_TRANSACTION || cmd == SMB_COM_TRANSACTION_SECONDARY)
128		flags2 &= ~SMB_FLAGS2_UNICODE;
129	if (cmd == SMB_COM_NEGOTIATE)
130		flags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE;
131	mb_put_uint16le(mbp, flags2);
132	if ((flags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
133		mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
134		rqp->sr_rqsig = NULL;
135	} else {
136		mb_put_uint16le(mbp, 0 /*scred->sc_p->p_pid >> 16*/);
137		rqp->sr_rqsig = (u_int8_t *)mb_reserve(mbp, 8);
138		mb_put_uint16le(mbp, 0);
139	}
140	rqp->sr_rqtid = mb_reserve(mbp, sizeof(u_int16_t));
141	mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/);
142	rqp->sr_rquid = mb_reserve(mbp, sizeof(u_int16_t));
143	mb_put_uint16le(mbp, rqp->sr_mid);
144	return 0;
145}
146
147void
148smb_rq_done(struct smb_rq *rqp)
149{
150	mb_done(&rqp->sr_rq);
151	md_done(&rqp->sr_rp);
152	smb_sl_destroy(&rqp->sr_slock);
153	if (rqp->sr_flags & SMBR_ALLOCED)
154		free(rqp, M_SMBRQ);
155}
156
157/*
158 * Simple request-reply exchange
159 */
160int
161smb_rq_simple(struct smb_rq *rqp)
162{
163	struct smb_vc *vcp = rqp->sr_vc;
164	int error = EINVAL, i;
165
166	for (i = 0; i < SMB_MAXRCN; i++) {
167		rqp->sr_flags &= ~SMBR_RESTART;
168		rqp->sr_timo = vcp->vc_timo;
169		rqp->sr_state = SMBRQ_NOTSENT;
170		error = smb_rq_enqueue(rqp);
171		if (error)
172			return error;
173		error = smb_rq_reply(rqp);
174		if (error == 0)
175			break;
176		if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
177			break;
178	}
179	return error;
180}
181
182static int
183smb_rq_enqueue(struct smb_rq *rqp)
184{
185	struct smb_share *ssp = rqp->sr_share;
186	int error;
187
188	if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) {
189		return smb_iod_addrq(rqp);
190	}
191	for (;;) {
192		SMBS_ST_LOCK(ssp);
193		if (ssp->ss_flags & SMBS_RECONNECTING) {
194			msleep(&ssp->ss_vcgenid, SMBS_ST_LOCKPTR(ssp),
195			    PWAIT | PDROP, "90trcn", hz);
196			if (smb_td_intr(rqp->sr_cred->scr_td))
197				return EINTR;
198			continue;
199		}
200		if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) {
201			SMBS_ST_UNLOCK(ssp);
202		} else {
203			SMBS_ST_UNLOCK(ssp);
204			error = smb_iod_request(rqp->sr_vc->vc_iod,
205			    SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp);
206			if (error)
207				return error;
208		}
209		error = smb_iod_addrq(rqp);
210		if (error != EXDEV)
211			break;
212	}
213	return error;
214}
215
216void
217smb_rq_wstart(struct smb_rq *rqp)
218{
219	rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t));
220	rqp->sr_rq.mb_count = 0;
221}
222
223void
224smb_rq_wend(struct smb_rq *rqp)
225{
226	if (rqp->sr_wcount == NULL) {
227		SMBERROR("no wcount\n");	/* actually panic */
228		return;
229	}
230	if (rqp->sr_rq.mb_count & 1)
231		SMBERROR("odd word count\n");
232	*rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
233}
234
235void
236smb_rq_bstart(struct smb_rq *rqp)
237{
238	rqp->sr_bcount = mb_reserve(&rqp->sr_rq, sizeof(u_short));
239	rqp->sr_rq.mb_count = 0;
240}
241
242void
243smb_rq_bend(struct smb_rq *rqp)
244{
245	int bcnt;
246
247	if (rqp->sr_bcount == NULL) {
248		SMBERROR("no bcount\n");	/* actually panic */
249		return;
250	}
251	bcnt = rqp->sr_rq.mb_count;
252	if (bcnt > 0xffff)
253		SMBERROR("byte count too large (%d)\n", bcnt);
254	le16enc(rqp->sr_bcount, bcnt);
255}
256
257int
258smb_rq_intr(struct smb_rq *rqp)
259{
260	if (rqp->sr_flags & SMBR_INTR)
261		return EINTR;
262	return smb_td_intr(rqp->sr_cred->scr_td);
263}
264
265int
266smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
267{
268	*mbpp = &rqp->sr_rq;
269	return 0;
270}
271
272int
273smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
274{
275	*mbpp = &rqp->sr_rp;
276	return 0;
277}
278
279static int
280smb_rq_getenv(struct smb_connobj *layer,
281	struct smb_vc **vcpp, struct smb_share **sspp)
282{
283	struct smb_vc *vcp = NULL;
284	struct smb_share *ssp = NULL;
285	struct smb_connobj *cp;
286	int error = 0;
287
288	switch (layer->co_level) {
289	    case SMBL_VC:
290		vcp = CPTOVC(layer);
291		if (layer->co_parent == NULL) {
292			SMBERROR("zombie VC %s\n", vcp->vc_srvname);
293			error = EINVAL;
294			break;
295		}
296		break;
297	    case SMBL_SHARE:
298		ssp = CPTOSS(layer);
299		cp = layer->co_parent;
300		if (cp == NULL) {
301			SMBERROR("zombie share %s\n", ssp->ss_name);
302			error = EINVAL;
303			break;
304		}
305		error = smb_rq_getenv(cp, &vcp, NULL);
306		if (error)
307			break;
308		break;
309	    default:
310		SMBERROR("invalid layer %d passed\n", layer->co_level);
311		error = EINVAL;
312	}
313	if (vcpp)
314		*vcpp = vcp;
315	if (sspp)
316		*sspp = ssp;
317	return error;
318}
319
320/*
321 * Wait for reply on the request
322 */
323static int
324smb_rq_reply(struct smb_rq *rqp)
325{
326	struct mdchain *mdp = &rqp->sr_rp;
327	u_int32_t tdw;
328	u_int8_t tb;
329	int error, rperror = 0;
330
331	error = smb_iod_waitrq(rqp);
332	if (error)
333		return error;
334	error = md_get_uint32(mdp, &tdw);
335	if (error)
336		return error;
337	error = md_get_uint8(mdp, &tb);
338	if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) {
339		error = md_get_uint32le(mdp, &rqp->sr_error);
340	} else {
341		error = md_get_uint8(mdp, &rqp->sr_errclass);
342		error = md_get_uint8(mdp, &tb);
343		error = md_get_uint16le(mdp, &rqp->sr_serror);
344		if (!error)
345			rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
346	}
347	error = md_get_uint8(mdp, &rqp->sr_rpflags);
348	error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
349
350	error = md_get_uint32(mdp, &tdw);
351	error = md_get_uint32(mdp, &tdw);
352	error = md_get_uint32(mdp, &tdw);
353
354	error = md_get_uint16le(mdp, &rqp->sr_rptid);
355	error = md_get_uint16le(mdp, &rqp->sr_rppid);
356	error = md_get_uint16le(mdp, &rqp->sr_rpuid);
357	error = md_get_uint16le(mdp, &rqp->sr_rpmid);
358
359	if (error == 0 &&
360	    (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE))
361		error = smb_rq_verify(rqp);
362
363	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
364	    rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
365	    rqp->sr_errclass, rqp->sr_serror);
366	return error ? error : rperror;
367}
368
369
370#define ALIGN4(a)	(((a) + 3) & ~3)
371
372/*
373 * TRANS2 request implementation
374 */
375int
376smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
377	struct smb_t2rq **t2pp)
378{
379	struct smb_t2rq *t2p;
380	int error;
381
382	t2p = malloc(sizeof(*t2p), M_SMBRQ, M_WAITOK);
383	if (t2p == NULL)
384		return ENOMEM;
385	error = smb_t2_init(t2p, layer, setup, scred);
386	t2p->t2_flags |= SMBT2_ALLOCED;
387	if (error) {
388		smb_t2_done(t2p);
389		return error;
390	}
391	*t2pp = t2p;
392	return 0;
393}
394
395int
396smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup,
397	struct smb_cred *scred)
398{
399	int error;
400
401	bzero(t2p, sizeof(*t2p));
402	t2p->t2_source = source;
403	t2p->t2_setupcount = 1;
404	t2p->t2_setupdata = t2p->t2_setup;
405	t2p->t2_setup[0] = setup;
406	t2p->t2_fid = 0xffff;
407	t2p->t2_cred = scred;
408	error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
409	if (error)
410		return error;
411	return 0;
412}
413
414void
415smb_t2_done(struct smb_t2rq *t2p)
416{
417	mb_done(&t2p->t2_tparam);
418	mb_done(&t2p->t2_tdata);
419	md_done(&t2p->t2_rparam);
420	md_done(&t2p->t2_rdata);
421	if (t2p->t2_flags & SMBT2_ALLOCED)
422		free(t2p, M_SMBRQ);
423}
424
425static int
426smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count,
427	struct mdchain *mdp)
428{
429	struct mbuf *m, *m0;
430	int len;
431
432	m0 = m_split(mtop, offset, M_WAITOK);
433	len = m_length(m0, &m);
434	m->m_len -= len - count;
435	if (mdp->md_top == NULL) {
436		md_initm(mdp, m0);
437	} else
438		m_cat(mdp->md_top, m0);
439	return 0;
440}
441
442static int
443smb_t2_reply(struct smb_t2rq *t2p)
444{
445	struct mdchain *mdp;
446	struct smb_rq *rqp = t2p->t2_rq;
447	int error, totpgot, totdgot;
448	u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
449	u_int16_t tmp, bc, dcount;
450	u_int8_t wc;
451
452	error = smb_rq_reply(rqp);
453	if (error)
454		return error;
455	if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
456		/*
457		 * this is an interim response, ignore it.
458		 */
459		SMBRQ_SLOCK(rqp);
460		md_next_record(&rqp->sr_rp);
461		SMBRQ_SUNLOCK(rqp);
462		return 0;
463	}
464	/*
465	 * Now we have to get all subsequent responses. The CIFS specification
466	 * says that they can be disordered which is weird.
467	 * TODO: timo
468	 */
469	totpgot = totdgot = 0;
470	totpcount = totdcount = 0xffff;
471	mdp = &rqp->sr_rp;
472	for (;;) {
473		m_dumpm(mdp->md_top);
474		if ((error = md_get_uint8(mdp, &wc)) != 0)
475			break;
476		if (wc < 10) {
477			error = ENOENT;
478			break;
479		}
480		if ((error = md_get_uint16le(mdp, &tmp)) != 0)
481			break;
482		if (totpcount > tmp)
483			totpcount = tmp;
484		md_get_uint16le(mdp, &tmp);
485		if (totdcount > tmp)
486			totdcount = tmp;
487		if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
488		    (error = md_get_uint16le(mdp, &pcount)) != 0 ||
489		    (error = md_get_uint16le(mdp, &poff)) != 0 ||
490		    (error = md_get_uint16le(mdp, &pdisp)) != 0)
491			break;
492		if (pcount != 0 && pdisp != totpgot) {
493			SMBERROR("Can't handle disordered parameters %d:%d\n",
494			    pdisp, totpgot);
495			error = EINVAL;
496			break;
497		}
498		if ((error = md_get_uint16le(mdp, &dcount)) != 0 ||
499		    (error = md_get_uint16le(mdp, &doff)) != 0 ||
500		    (error = md_get_uint16le(mdp, &ddisp)) != 0)
501			break;
502		if (dcount != 0 && ddisp != totdgot) {
503			SMBERROR("Can't handle disordered data\n");
504			error = EINVAL;
505			break;
506		}
507		md_get_uint8(mdp, &wc);
508		md_get_uint8(mdp, NULL);
509		tmp = wc;
510		while (tmp--)
511			md_get_uint16(mdp, NULL);
512		if ((error = md_get_uint16le(mdp, &bc)) != 0)
513			break;
514/*		tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
515		if (dcount) {
516			error = smb_t2_placedata(mdp->md_top, doff, dcount,
517			    &t2p->t2_rdata);
518			if (error)
519				break;
520		}
521		if (pcount) {
522			error = smb_t2_placedata(mdp->md_top, poff, pcount,
523			    &t2p->t2_rparam);
524			if (error)
525				break;
526		}
527		totpgot += pcount;
528		totdgot += dcount;
529		if (totpgot >= totpcount && totdgot >= totdcount) {
530			error = 0;
531			t2p->t2_flags |= SMBT2_ALLRECV;
532			break;
533		}
534		/*
535		 * We're done with this reply, look for the next one.
536		 */
537		SMBRQ_SLOCK(rqp);
538		md_next_record(&rqp->sr_rp);
539		SMBRQ_SUNLOCK(rqp);
540		error = smb_rq_reply(rqp);
541		if (error)
542			break;
543	}
544	return error;
545}
546
547/*
548 * Perform a full round of TRANS2 request
549 */
550static int
551smb_t2_request_int(struct smb_t2rq *t2p)
552{
553	struct smb_vc *vcp = t2p->t2_vc;
554	struct smb_cred *scred = t2p->t2_cred;
555	struct mbchain *mbp;
556	struct mdchain *mdp, mbparam, mbdata;
557	struct mbuf *m;
558	struct smb_rq *rqp;
559	int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
560	int error, doff, poff, txdcount, txpcount, nmlen;
561
562	m = t2p->t2_tparam.mb_top;
563	if (m) {
564		md_initm(&mbparam, m);	/* do not free it! */
565		totpcount = m_fixhdr(m);
566		if (totpcount > 0xffff)		/* maxvalue for u_short */
567			return EINVAL;
568	} else
569		totpcount = 0;
570	m = t2p->t2_tdata.mb_top;
571	if (m) {
572		md_initm(&mbdata, m);	/* do not free it! */
573		totdcount =  m_fixhdr(m);
574		if (totdcount > 0xffff)
575			return EINVAL;
576	} else
577		totdcount = 0;
578	leftdcount = totdcount;
579	leftpcount = totpcount;
580	txmax = vcp->vc_txmax;
581	error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
582	    SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
583	if (error)
584		return error;
585	rqp->sr_flags |= SMBR_MULTIPACKET;
586	t2p->t2_rq = rqp;
587	rqp->sr_t2 = t2p;
588	mbp = &rqp->sr_rq;
589	smb_rq_wstart(rqp);
590	mb_put_uint16le(mbp, totpcount);
591	mb_put_uint16le(mbp, totdcount);
592	mb_put_uint16le(mbp, t2p->t2_maxpcount);
593	mb_put_uint16le(mbp, t2p->t2_maxdcount);
594	mb_put_uint8(mbp, t2p->t2_maxscount);
595	mb_put_uint8(mbp, 0);			/* reserved */
596	mb_put_uint16le(mbp, 0);			/* flags */
597	mb_put_uint32le(mbp, 0);			/* Timeout */
598	mb_put_uint16le(mbp, 0);			/* reserved 2 */
599	len = mb_fixhdr(mbp);
600	/*
601	 * now we have known packet size as
602	 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
603	 * and need to decide which parts should go into the first request
604	 */
605	nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
606	len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
607	if (len + leftpcount > txmax) {
608		txpcount = min(leftpcount, txmax - len);
609		poff = len;
610		txdcount = 0;
611		doff = 0;
612	} else {
613		txpcount = leftpcount;
614		poff = txpcount ? len : 0;
615		len = ALIGN4(len + txpcount);
616		txdcount = min(leftdcount, txmax - len);
617		doff = txdcount ? len : 0;
618	}
619	leftpcount -= txpcount;
620	leftdcount -= txdcount;
621	mb_put_uint16le(mbp, txpcount);
622	mb_put_uint16le(mbp, poff);
623	mb_put_uint16le(mbp, txdcount);
624	mb_put_uint16le(mbp, doff);
625	mb_put_uint8(mbp, t2p->t2_setupcount);
626	mb_put_uint8(mbp, 0);
627	for (i = 0; i < t2p->t2_setupcount; i++)
628		mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
629	smb_rq_wend(rqp);
630	smb_rq_bstart(rqp);
631	/* TDUNICODE */
632	if (t2p->t_name)
633		mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
634	mb_put_uint8(mbp, 0);	/* terminating zero */
635	len = mb_fixhdr(mbp);
636	if (txpcount) {
637		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
638		error = md_get_mbuf(&mbparam, txpcount, &m);
639		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
640		if (error)
641			goto freerq;
642		mb_put_mbuf(mbp, m);
643	}
644	len = mb_fixhdr(mbp);
645	if (txdcount) {
646		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
647		error = md_get_mbuf(&mbdata, txdcount, &m);
648		if (error)
649			goto freerq;
650		mb_put_mbuf(mbp, m);
651	}
652	smb_rq_bend(rqp);	/* incredible, but thats it... */
653	error = smb_rq_enqueue(rqp);
654	if (error)
655		goto freerq;
656	if (leftpcount == 0 && leftdcount == 0)
657		t2p->t2_flags |= SMBT2_ALLSENT;
658	error = smb_t2_reply(t2p);
659	if (error)
660		goto bad;
661	while (leftpcount || leftdcount) {
662		t2p->t2_flags |= SMBT2_SECONDARY;
663		error = smb_rq_new(rqp, t2p->t_name ?
664		    SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
665		if (error)
666			goto bad;
667		mbp = &rqp->sr_rq;
668		smb_rq_wstart(rqp);
669		mb_put_uint16le(mbp, totpcount);
670		mb_put_uint16le(mbp, totdcount);
671		len = mb_fixhdr(mbp);
672		/*
673		 * now we have known packet size as
674		 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
675		 * and need to decide which parts should go into request
676		 */
677		len = ALIGN4(len + 6 * 2 + 2);
678		if (t2p->t_name == NULL)
679			len += 2;
680		if (len + leftpcount > txmax) {
681			txpcount = min(leftpcount, txmax - len);
682			poff = len;
683			txdcount = 0;
684			doff = 0;
685		} else {
686			txpcount = leftpcount;
687			poff = txpcount ? len : 0;
688			len = ALIGN4(len + txpcount);
689			txdcount = min(leftdcount, txmax - len);
690			doff = txdcount ? len : 0;
691		}
692		mb_put_uint16le(mbp, txpcount);
693		mb_put_uint16le(mbp, poff);
694		mb_put_uint16le(mbp, totpcount - leftpcount);
695		mb_put_uint16le(mbp, txdcount);
696		mb_put_uint16le(mbp, doff);
697		mb_put_uint16le(mbp, totdcount - leftdcount);
698		leftpcount -= txpcount;
699		leftdcount -= txdcount;
700		if (t2p->t_name == NULL)
701			mb_put_uint16le(mbp, t2p->t2_fid);
702		smb_rq_wend(rqp);
703		smb_rq_bstart(rqp);
704		mb_put_uint8(mbp, 0);	/* name */
705		len = mb_fixhdr(mbp);
706		if (txpcount) {
707			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
708			error = md_get_mbuf(&mbparam, txpcount, &m);
709			if (error)
710				goto bad;
711			mb_put_mbuf(mbp, m);
712		}
713		len = mb_fixhdr(mbp);
714		if (txdcount) {
715			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
716			error = md_get_mbuf(&mbdata, txdcount, &m);
717			if (error)
718				goto bad;
719			mb_put_mbuf(mbp, m);
720		}
721		smb_rq_bend(rqp);
722		rqp->sr_state = SMBRQ_NOTSENT;
723		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL);
724		if (error)
725			goto bad;
726	}	/* while left params or data */
727	t2p->t2_flags |= SMBT2_ALLSENT;
728	mdp = &t2p->t2_rdata;
729	if (mdp->md_top) {
730		m_fixhdr(mdp->md_top);
731		md_initm(mdp, mdp->md_top);
732	}
733	mdp = &t2p->t2_rparam;
734	if (mdp->md_top) {
735		m_fixhdr(mdp->md_top);
736		md_initm(mdp, mdp->md_top);
737	}
738bad:
739	smb_iod_removerq(rqp);
740freerq:
741	smb_rq_done(rqp);
742	if (error) {
743		if (rqp->sr_flags & SMBR_RESTART)
744			t2p->t2_flags |= SMBT2_RESTART;
745		md_done(&t2p->t2_rparam);
746		md_done(&t2p->t2_rdata);
747	}
748	return error;
749}
750
751int
752smb_t2_request(struct smb_t2rq *t2p)
753{
754	int error = EINVAL, i;
755
756	for (i = 0; i < SMB_MAXRCN; i++) {
757		t2p->t2_flags &= ~SMBR_RESTART;
758		error = smb_t2_request_int(t2p);
759		if (error == 0)
760			break;
761		if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
762			break;
763	}
764	return error;
765}
766