smb_rq.c revision 88741
175374Sbp/*
275374Sbp * Copyright (c) 2000-2001, Boris Popov
375374Sbp * All rights reserved.
475374Sbp *
575374Sbp * Redistribution and use in source and binary forms, with or without
675374Sbp * modification, are permitted provided that the following conditions
775374Sbp * are met:
875374Sbp * 1. Redistributions of source code must retain the above copyright
975374Sbp *    notice, this list of conditions and the following disclaimer.
1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright
1175374Sbp *    notice, this list of conditions and the following disclaimer in the
1275374Sbp *    documentation and/or other materials provided with the distribution.
1375374Sbp * 3. All advertising materials mentioning features or use of this software
1475374Sbp *    must display the following acknowledgement:
1575374Sbp *    This product includes software developed by Boris Popov.
1675374Sbp * 4. Neither the name of the author nor the names of any co-contributors
1775374Sbp *    may be used to endorse or promote products derived from this software
1875374Sbp *    without specific prior written permission.
1975374Sbp *
2075374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2175374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2275374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2375374Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2475374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2575374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2675374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2775374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2875374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2975374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3075374Sbp * SUCH DAMAGE.
3175374Sbp *
3275374Sbp * $FreeBSD: head/sys/netsmb/smb_rq.c 88741 2001-12-31 19:29:43Z bp $
3375374Sbp */
3475374Sbp#include <sys/param.h>
3575374Sbp#include <sys/systm.h>
3675374Sbp#include <sys/kernel.h>
3775374Sbp#include <sys/malloc.h>
3875374Sbp#include <sys/proc.h>
3975374Sbp#include <sys/lock.h>
4075374Sbp#include <sys/sysctl.h>
4175374Sbp#include <sys/socket.h>
4275374Sbp#include <sys/socketvar.h>
4375374Sbp#include <sys/mbuf.h>
4475374Sbp
4575374Sbp#include <netsmb/smb.h>
4675374Sbp#include <netsmb/smb_conn.h>
4775374Sbp#include <netsmb/smb_rq.h>
4875374Sbp#include <netsmb/smb_subr.h>
4975374Sbp#include <netsmb/smb_tran.h>
5075374Sbp
5175374SbpMALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
5275374Sbp
5375374SbpMODULE_DEPEND(netsmb, libmchain, 1, 1, 1);
5475374Sbp
5575374Sbpstatic int  smb_rq_reply(struct smb_rq *rqp);
5675374Sbpstatic int  smb_rq_enqueue(struct smb_rq *rqp);
5775374Sbpstatic int  smb_rq_getenv(struct smb_connobj *layer,
5875374Sbp		struct smb_vc **vcpp, struct smb_share **sspp);
5975374Sbpstatic int  smb_rq_new(struct smb_rq *rqp, u_char cmd);
6075374Sbpstatic int  smb_t2_reply(struct smb_t2rq *t2p);
6175374Sbp
6275374Sbpint
6375374Sbpsmb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred,
6475374Sbp	struct smb_rq **rqpp)
6575374Sbp{
6675374Sbp	struct smb_rq *rqp;
6775374Sbp	int error;
6875374Sbp
6975374Sbp	MALLOC(rqp, struct smb_rq *, sizeof(*rqp), M_SMBRQ, M_WAITOK);
7075374Sbp	if (rqp == NULL)
7175374Sbp		return ENOMEM;
7275374Sbp	error = smb_rq_init(rqp, layer, cmd, scred);
7375374Sbp	rqp->sr_flags |= SMBR_ALLOCED;
7475374Sbp	if (error) {
7575374Sbp		smb_rq_done(rqp);
7675374Sbp		return error;
7775374Sbp	}
7875374Sbp	*rqpp = rqp;
7975374Sbp	return 0;
8075374Sbp}
8175374Sbp
8275374Sbpstatic char tzero[12];
8375374Sbp
8475374Sbpint
8575374Sbpsmb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
8675374Sbp	struct smb_cred *scred)
8775374Sbp{
8875374Sbp	int error;
8975374Sbp
9075374Sbp	bzero(rqp, sizeof(*rqp));
9175374Sbp	smb_sl_init(&rqp->sr_slock, "srslock");
9275374Sbp	error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
9375374Sbp	if (error)
9475374Sbp		return error;
9575374Sbp	error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
9675374Sbp	if (error)
9775374Sbp		return error;
9875374Sbp	if (rqp->sr_share) {
9975374Sbp		error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
10075374Sbp		if (error)
10175374Sbp			return error;
10275374Sbp	}
10375374Sbp	rqp->sr_cred = scred;
10475374Sbp	rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
10575374Sbp	return smb_rq_new(rqp, cmd);
10675374Sbp}
10775374Sbp
10875374Sbpstatic int
10975374Sbpsmb_rq_new(struct smb_rq *rqp, u_char cmd)
11075374Sbp{
11175374Sbp	struct smb_vc *vcp = rqp->sr_vc;
11275374Sbp	struct mbchain *mbp = &rqp->sr_rq;
11375374Sbp	int error;
11475374Sbp
11575374Sbp	rqp->sr_sendcnt = 0;
11675374Sbp	mb_done(mbp);
11775374Sbp	md_done(&rqp->sr_rp);
11875374Sbp	error = mb_init(mbp);
11975374Sbp	if (error)
12075374Sbp		return error;
12175374Sbp	mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
12275374Sbp	mb_put_uint8(mbp, cmd);
12375374Sbp	mb_put_uint32le(mbp, 0);		/* DosError */
12475374Sbp	mb_put_uint8(mbp, vcp->vc_hflags);
12575374Sbp	mb_put_uint16le(mbp, vcp->vc_hflags2);
12675374Sbp	mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
12775374Sbp	rqp->sr_rqtid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t));
12875374Sbp	mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/);
12975374Sbp	rqp->sr_rquid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t));
13075374Sbp	mb_put_uint16le(mbp, rqp->sr_mid);
13175374Sbp	return 0;
13275374Sbp}
13375374Sbp
13475374Sbpvoid
13575374Sbpsmb_rq_done(struct smb_rq *rqp)
13675374Sbp{
13775374Sbp	mb_done(&rqp->sr_rq);
13875374Sbp	md_done(&rqp->sr_rp);
13975374Sbp	smb_sl_destroy(&rqp->sr_slock);
14075374Sbp	if (rqp->sr_flags & SMBR_ALLOCED)
14175374Sbp		free(rqp, M_SMBRQ);
14275374Sbp}
14375374Sbp
14475374Sbp/*
14575374Sbp * Simple request-reply exchange
14675374Sbp */
14775374Sbpint
14875374Sbpsmb_rq_simple(struct smb_rq *rqp)
14975374Sbp{
15075374Sbp	struct smb_vc *vcp = rqp->sr_vc;
15175374Sbp	int error = EINVAL, i;
15275374Sbp
15375374Sbp	for (i = 0; i < SMB_MAXRCN; i++) {
15475374Sbp		rqp->sr_flags &= ~SMBR_RESTART;
15575374Sbp		rqp->sr_timo = vcp->vc_timo;
15675374Sbp		rqp->sr_state = SMBRQ_NOTSENT;
15775374Sbp		error = smb_rq_enqueue(rqp);
15875374Sbp		if (error)
15975374Sbp			return error;
16075374Sbp		error = smb_rq_reply(rqp);
16175374Sbp		if (error == 0)
16275374Sbp			break;
16375374Sbp		if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
16475374Sbp			break;
16575374Sbp	}
16675374Sbp	return error;
16775374Sbp}
16875374Sbp
16975374Sbpstatic int
17075374Sbpsmb_rq_enqueue(struct smb_rq *rqp)
17175374Sbp{
17275374Sbp	struct smb_share *ssp = rqp->sr_share;
17375374Sbp	int error;
17475374Sbp
17575374Sbp	if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) {
17675374Sbp		return smb_iod_addrq(rqp);
17775374Sbp	}
17875374Sbp	for (;;) {
17975374Sbp		SMBS_ST_LOCK(ssp);
18075374Sbp		if (ssp->ss_flags & SMBS_RECONNECTING) {
18175374Sbp			msleep(&ssp->ss_vcgenid, SMBS_ST_LOCKPTR(ssp),
18275374Sbp			    PWAIT | PDROP, "90trcn", hz);
18387192Sbp			if (smb_proc_intr(rqp->sr_cred->scr_td->td_proc))
18475374Sbp				return EINTR;
18575374Sbp			continue;
18675374Sbp		}
18775374Sbp		if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) {
18875374Sbp			SMBS_ST_UNLOCK(ssp);
18975374Sbp		} else {
19075374Sbp			SMBS_ST_UNLOCK(ssp);
19175374Sbp			error = smb_iod_request(rqp->sr_vc->vc_iod,
19275374Sbp			    SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp);
19375374Sbp			if (error)
19475374Sbp				return error;
19575374Sbp		}
19675374Sbp		error = smb_iod_addrq(rqp);
19775374Sbp		if (error != EXDEV)
19875374Sbp			break;
19975374Sbp	}
20075374Sbp	return error;
20175374Sbp}
20275374Sbp
20375374Sbpvoid
20475374Sbpsmb_rq_wstart(struct smb_rq *rqp)
20575374Sbp{
20675374Sbp	rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t));
20775374Sbp	rqp->sr_rq.mb_count = 0;
20875374Sbp}
20975374Sbp
21075374Sbpvoid
21175374Sbpsmb_rq_wend(struct smb_rq *rqp)
21275374Sbp{
21375374Sbp	if (rqp->sr_wcount == NULL) {
21475374Sbp		SMBERROR("no wcount\n");	/* actually panic */
21575374Sbp		return;
21675374Sbp	}
21775374Sbp	if (rqp->sr_rq.mb_count & 1)
21875374Sbp		SMBERROR("odd word count\n");
21975374Sbp	*rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
22075374Sbp}
22175374Sbp
22275374Sbpvoid
22375374Sbpsmb_rq_bstart(struct smb_rq *rqp)
22475374Sbp{
22575374Sbp	rqp->sr_bcount = (u_short*)mb_reserve(&rqp->sr_rq, sizeof(u_short));
22675374Sbp	rqp->sr_rq.mb_count = 0;
22775374Sbp}
22875374Sbp
22975374Sbpvoid
23075374Sbpsmb_rq_bend(struct smb_rq *rqp)
23175374Sbp{
23275374Sbp	int bcnt;
23375374Sbp
23475374Sbp	if (rqp->sr_bcount == NULL) {
23575374Sbp		SMBERROR("no bcount\n");	/* actually panic */
23675374Sbp		return;
23775374Sbp	}
23875374Sbp	bcnt = rqp->sr_rq.mb_count;
23975374Sbp	if (bcnt > 0xffff)
24075374Sbp		SMBERROR("byte count too large (%d)\n", bcnt);
24182037Sbp	*rqp->sr_bcount = htoles(bcnt);
24275374Sbp}
24375374Sbp
24475374Sbpint
24575374Sbpsmb_rq_intr(struct smb_rq *rqp)
24675374Sbp{
24787192Sbp	struct proc *p = rqp->sr_cred->scr_td->td_proc;
24875374Sbp
24975374Sbp	if (rqp->sr_flags & SMBR_INTR)
25075374Sbp		return EINTR;
25175374Sbp	return smb_proc_intr(p);
25275374Sbp}
25375374Sbp
25475374Sbpint
25575374Sbpsmb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
25675374Sbp{
25775374Sbp	*mbpp = &rqp->sr_rq;
25875374Sbp	return 0;
25975374Sbp}
26075374Sbp
26175374Sbpint
26275374Sbpsmb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
26375374Sbp{
26475374Sbp	*mbpp = &rqp->sr_rp;
26575374Sbp	return 0;
26675374Sbp}
26775374Sbp
26875374Sbpstatic int
26975374Sbpsmb_rq_getenv(struct smb_connobj *layer,
27075374Sbp	struct smb_vc **vcpp, struct smb_share **sspp)
27175374Sbp{
27275374Sbp	struct smb_vc *vcp = NULL;
27375374Sbp	struct smb_share *ssp = NULL;
27475374Sbp	struct smb_connobj *cp;
27575374Sbp	int error = 0;
27675374Sbp
27775374Sbp	switch (layer->co_level) {
27875374Sbp	    case SMBL_VC:
27975374Sbp		vcp = CPTOVC(layer);
28075374Sbp		if (layer->co_parent == NULL) {
28175374Sbp			SMBERROR("zombie VC %s\n", vcp->vc_srvname);
28275374Sbp			error = EINVAL;
28375374Sbp			break;
28475374Sbp		}
28575374Sbp		break;
28675374Sbp	    case SMBL_SHARE:
28775374Sbp		ssp = CPTOSS(layer);
28875374Sbp		cp = layer->co_parent;
28975374Sbp		if (cp == NULL) {
29075374Sbp			SMBERROR("zombie share %s\n", ssp->ss_name);
29175374Sbp			error = EINVAL;
29275374Sbp			break;
29375374Sbp		}
29475374Sbp		error = smb_rq_getenv(cp, &vcp, NULL);
29575374Sbp		if (error)
29675374Sbp			break;
29775374Sbp		break;
29875374Sbp	    default:
29975374Sbp		SMBERROR("invalid layer %d passed\n", layer->co_level);
30075374Sbp		error = EINVAL;
30175374Sbp	}
30275374Sbp	if (vcpp)
30375374Sbp		*vcpp = vcp;
30475374Sbp	if (sspp)
30575374Sbp		*sspp = ssp;
30675374Sbp	return error;
30775374Sbp}
30875374Sbp
30975374Sbp/*
31075374Sbp * Wait for reply on the request
31175374Sbp */
31275374Sbpstatic int
31375374Sbpsmb_rq_reply(struct smb_rq *rqp)
31475374Sbp{
31575374Sbp	struct mdchain *mdp = &rqp->sr_rp;
31675374Sbp	u_int32_t tdw;
31775374Sbp	u_int8_t tb;
31875374Sbp	int error, rperror = 0;
31975374Sbp
32075374Sbp	error = smb_iod_waitrq(rqp);
32175374Sbp	if (error)
32275374Sbp		return error;
32375374Sbp	error = md_get_uint32(mdp, &tdw);
32475374Sbp	if (error)
32575374Sbp		return error;
32675374Sbp	error = md_get_uint8(mdp, &tb);
32775374Sbp	if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) {
32875374Sbp		error = md_get_uint32le(mdp, &rqp->sr_error);
32975374Sbp	} else {
33075374Sbp		error = md_get_uint8(mdp, &rqp->sr_errclass);
33175374Sbp		error = md_get_uint8(mdp, &tb);
33275374Sbp		error = md_get_uint16le(mdp, &rqp->sr_serror);
33375374Sbp		if (!error)
33475374Sbp			rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
33575374Sbp	}
33675374Sbp	error = md_get_uint8(mdp, &rqp->sr_rpflags);
33775374Sbp	error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
33875374Sbp
33975374Sbp	error = md_get_uint32(mdp, &tdw);
34075374Sbp	error = md_get_uint32(mdp, &tdw);
34175374Sbp	error = md_get_uint32(mdp, &tdw);
34275374Sbp
34375374Sbp	error = md_get_uint16le(mdp, &rqp->sr_rptid);
34475374Sbp	error = md_get_uint16le(mdp, &rqp->sr_rppid);
34575374Sbp	error = md_get_uint16le(mdp, &rqp->sr_rpuid);
34675374Sbp	error = md_get_uint16le(mdp, &rqp->sr_rpmid);
34775374Sbp
34875374Sbp	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
34975374Sbp	    rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
35075374Sbp	    rqp->sr_errclass, rqp->sr_serror);
35175374Sbp	return error ? error : rperror;
35275374Sbp}
35375374Sbp
35475374Sbp
35575374Sbp#define ALIGN4(a)	(((a) + 3) & ~3)
35675374Sbp
35775374Sbp/*
35875374Sbp * TRANS2 request implementation
35975374Sbp */
36075374Sbpint
36175374Sbpsmb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
36275374Sbp	struct smb_t2rq **t2pp)
36375374Sbp{
36475374Sbp	struct smb_t2rq *t2p;
36575374Sbp	int error;
36675374Sbp
36775374Sbp	MALLOC(t2p, struct smb_t2rq *, sizeof(*t2p), M_SMBRQ, M_WAITOK);
36875374Sbp	if (t2p == NULL)
36975374Sbp		return ENOMEM;
37075374Sbp	error = smb_t2_init(t2p, layer, setup, scred);
37175374Sbp	t2p->t2_flags |= SMBT2_ALLOCED;
37275374Sbp	if (error) {
37375374Sbp		smb_t2_done(t2p);
37475374Sbp		return error;
37575374Sbp	}
37675374Sbp	*t2pp = t2p;
37775374Sbp	return 0;
37875374Sbp}
37975374Sbp
38075374Sbpint
38175374Sbpsmb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup,
38275374Sbp	struct smb_cred *scred)
38375374Sbp{
38475374Sbp	int error;
38575374Sbp
38675374Sbp	bzero(t2p, sizeof(*t2p));
38775374Sbp	t2p->t2_source = source;
38875374Sbp	t2p->t2_setupcount = 1;
38975374Sbp	t2p->t2_setupdata = t2p->t2_setup;
39075374Sbp	t2p->t2_setup[0] = setup;
39175374Sbp	t2p->t2_fid = 0xffff;
39275374Sbp	t2p->t2_cred = scred;
39375374Sbp	error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
39475374Sbp	if (error)
39575374Sbp		return error;
39675374Sbp	return 0;
39775374Sbp}
39875374Sbp
39975374Sbpvoid
40075374Sbpsmb_t2_done(struct smb_t2rq *t2p)
40175374Sbp{
40275374Sbp	mb_done(&t2p->t2_tparam);
40375374Sbp	mb_done(&t2p->t2_tdata);
40475374Sbp	md_done(&t2p->t2_rparam);
40575374Sbp	md_done(&t2p->t2_rdata);
40675374Sbp	if (t2p->t2_flags & SMBT2_ALLOCED)
40775374Sbp		free(t2p, M_SMBRQ);
40875374Sbp}
40975374Sbp
41075374Sbpstatic int
41175374Sbpsmb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count,
41275374Sbp	struct mdchain *mdp)
41375374Sbp{
41475374Sbp	struct mbuf *m, *m0;
41575374Sbp	int len;
41675374Sbp
41787565Sarr	m0 = m_split(mtop, offset, M_TRYWAIT);
41875374Sbp	if (m0 == NULL)
41975374Sbp		return EBADRPC;
42075374Sbp	for(len = 0, m = m0; m->m_next; m = m->m_next)
42175374Sbp		len += m->m_len;
42275374Sbp	len += m->m_len;
42375374Sbp	m->m_len -= len - count;
42475374Sbp	if (mdp->md_top == NULL) {
42575374Sbp		md_initm(mdp, m0);
42675374Sbp	} else
42775374Sbp		m_cat(mdp->md_top, m0);
42875374Sbp	return 0;
42975374Sbp}
43075374Sbp
43175374Sbpstatic int
43275374Sbpsmb_t2_reply(struct smb_t2rq *t2p)
43375374Sbp{
43475374Sbp	struct mdchain *mdp;
43575374Sbp	struct smb_rq *rqp = t2p->t2_rq;
43675374Sbp	int error, totpgot, totdgot;
43775374Sbp	u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
43875374Sbp	u_int16_t tmp, bc, dcount;
43975374Sbp	u_int8_t wc;
44075374Sbp
44175374Sbp	error = smb_rq_reply(rqp);
44275374Sbp	if (error)
44375374Sbp		return error;
44475374Sbp	if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
44575374Sbp		/*
44675374Sbp		 * this is an interim response, ignore it.
44775374Sbp		 */
44875374Sbp		SMBRQ_SLOCK(rqp);
44975374Sbp		md_next_record(&rqp->sr_rp);
45075374Sbp		SMBRQ_SUNLOCK(rqp);
45175374Sbp		return 0;
45275374Sbp	}
45375374Sbp	/*
45488741Sbp	 * Now we have to get all subsequent responses. The CIFS specification
45588741Sbp	 * says that they can be disordered which is weird.
45675374Sbp	 * TODO: timo
45775374Sbp	 */
45875374Sbp	totpgot = totdgot = 0;
45975374Sbp	totpcount = totdcount = 0xffff;
46075374Sbp	mdp = &rqp->sr_rp;
46175374Sbp	for (;;) {
46275374Sbp		m_dumpm(mdp->md_top);
46375374Sbp		if ((error = md_get_uint8(mdp, &wc)) != 0)
46475374Sbp			break;
46575374Sbp		if (wc < 10) {
46675374Sbp			error = ENOENT;
46775374Sbp			break;
46875374Sbp		}
46975374Sbp		if ((error = md_get_uint16le(mdp, &tmp)) != 0)
47075374Sbp			break;
47175374Sbp		if (totpcount > tmp)
47275374Sbp			totpcount = tmp;
47375374Sbp		md_get_uint16le(mdp, &tmp);
47475374Sbp		if (totdcount > tmp)
47575374Sbp			totdcount = tmp;
47675374Sbp		if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
47775374Sbp		    (error = md_get_uint16le(mdp, &pcount)) != 0 ||
47875374Sbp		    (error = md_get_uint16le(mdp, &poff)) != 0 ||
47975374Sbp		    (error = md_get_uint16le(mdp, &pdisp)) != 0)
48075374Sbp			break;
48175374Sbp		if (pcount != 0 && pdisp != totpgot) {
48288741Sbp			SMBERROR("Can't handle disordered parameters %d:%d\n",
48375374Sbp			    pdisp, totpgot);
48475374Sbp			error = EINVAL;
48575374Sbp			break;
48675374Sbp		}
48775374Sbp		if ((error = md_get_uint16le(mdp, &dcount)) != 0 ||
48875374Sbp		    (error = md_get_uint16le(mdp, &doff)) != 0 ||
48975374Sbp		    (error = md_get_uint16le(mdp, &ddisp)) != 0)
49075374Sbp			break;
49175374Sbp		if (dcount != 0 && ddisp != totdgot) {
49288741Sbp			SMBERROR("Can't handle disordered data\n");
49375374Sbp			error = EINVAL;
49475374Sbp			break;
49575374Sbp		}
49675374Sbp		md_get_uint8(mdp, &wc);
49775374Sbp		md_get_uint8(mdp, NULL);
49875374Sbp		tmp = wc;
49975374Sbp		while (tmp--)
50075374Sbp			md_get_uint16(mdp, NULL);
50175374Sbp		if ((error = md_get_uint16le(mdp, &bc)) != 0)
50275374Sbp			break;
50375374Sbp/*		tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
50475374Sbp		if (dcount) {
50575374Sbp			error = smb_t2_placedata(mdp->md_top, doff, dcount,
50675374Sbp			    &t2p->t2_rdata);
50775374Sbp			if (error)
50875374Sbp				break;
50975374Sbp		}
51075374Sbp		if (pcount) {
51175374Sbp			error = smb_t2_placedata(mdp->md_top, poff, pcount,
51275374Sbp			    &t2p->t2_rparam);
51375374Sbp			if (error)
51475374Sbp				break;
51575374Sbp		}
51675374Sbp		totpgot += pcount;
51775374Sbp		totdgot += dcount;
51875374Sbp		if (totpgot >= totpcount && totdgot >= totdcount) {
51975374Sbp			error = 0;
52075374Sbp			t2p->t2_flags |= SMBT2_ALLRECV;
52175374Sbp			break;
52275374Sbp		}
52375374Sbp		/*
52475374Sbp		 * We're done with this reply, look for the next one.
52575374Sbp		 */
52675374Sbp		SMBRQ_SLOCK(rqp);
52775374Sbp		md_next_record(&rqp->sr_rp);
52875374Sbp		SMBRQ_SUNLOCK(rqp);
52975374Sbp		error = smb_rq_reply(rqp);
53075374Sbp		if (error)
53175374Sbp			break;
53275374Sbp	}
53375374Sbp	return error;
53475374Sbp}
53575374Sbp
53675374Sbp/*
53775374Sbp * Perform a full round of TRANS2 request
53875374Sbp */
53975374Sbpstatic int
54075374Sbpsmb_t2_request_int(struct smb_t2rq *t2p)
54175374Sbp{
54275374Sbp	struct smb_vc *vcp = t2p->t2_vc;
54375374Sbp	struct smb_cred *scred = t2p->t2_cred;
54475374Sbp	struct mbchain *mbp;
54575374Sbp	struct mdchain *mdp, mbparam, mbdata;
54675374Sbp	struct mbuf *m;
54775374Sbp	struct smb_rq *rqp;
54875374Sbp	int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
54975374Sbp	int error, doff, poff, txdcount, txpcount, nmlen;
55075374Sbp
55175374Sbp	m = t2p->t2_tparam.mb_top;
55275374Sbp	if (m) {
55375374Sbp		md_initm(&mbparam, m);	/* do not free it! */
55475374Sbp		totpcount = m_fixhdr(m);
55575374Sbp		if (totpcount > 0xffff)		/* maxvalue for u_short */
55675374Sbp			return EINVAL;
55775374Sbp	} else
55875374Sbp		totpcount = 0;
55975374Sbp	m = t2p->t2_tdata.mb_top;
56075374Sbp	if (m) {
56175374Sbp		md_initm(&mbdata, m);	/* do not free it! */
56275374Sbp		totdcount =  m_fixhdr(m);
56375374Sbp		if (totdcount > 0xffff)
56475374Sbp			return EINVAL;
56575374Sbp	} else
56675374Sbp		totdcount = 0;
56775374Sbp	leftdcount = totdcount;
56875374Sbp	leftpcount = totpcount;
56975374Sbp	txmax = vcp->vc_txmax;
57075374Sbp	error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
57175374Sbp	    SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
57275374Sbp	if (error)
57375374Sbp		return error;
57475374Sbp	rqp->sr_flags |= SMBR_MULTIPACKET;
57575374Sbp	t2p->t2_rq = rqp;
57675374Sbp	mbp = &rqp->sr_rq;
57775374Sbp	smb_rq_wstart(rqp);
57875374Sbp	mb_put_uint16le(mbp, totpcount);
57975374Sbp	mb_put_uint16le(mbp, totdcount);
58075374Sbp	mb_put_uint16le(mbp, t2p->t2_maxpcount);
58175374Sbp	mb_put_uint16le(mbp, t2p->t2_maxdcount);
58275374Sbp	mb_put_uint8(mbp, t2p->t2_maxscount);
58375374Sbp	mb_put_uint8(mbp, 0);			/* reserved */
58475374Sbp	mb_put_uint16le(mbp, 0);			/* flags */
58575374Sbp	mb_put_uint32le(mbp, 0);			/* Timeout */
58675374Sbp	mb_put_uint16le(mbp, 0);			/* reserved 2 */
58775374Sbp	len = mb_fixhdr(mbp);
58875374Sbp	/*
58975374Sbp	 * now we have known packet size as
59075374Sbp	 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
59175374Sbp	 * and need to decide which parts should go into the first request
59275374Sbp	 */
59375374Sbp	nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
59475374Sbp	len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
59575374Sbp	if (len + leftpcount > txmax) {
59675374Sbp		txpcount = min(leftpcount, txmax - len);
59775374Sbp		poff = len;
59875374Sbp		txdcount = 0;
59975374Sbp		doff = 0;
60075374Sbp	} else {
60175374Sbp		txpcount = leftpcount;
60275374Sbp		poff = txpcount ? len : 0;
60375374Sbp		len = ALIGN4(len + txpcount);
60475374Sbp		txdcount = min(leftdcount, txmax - len);
60575374Sbp		doff = txdcount ? len : 0;
60675374Sbp	}
60775374Sbp	leftpcount -= txpcount;
60875374Sbp	leftdcount -= txdcount;
60975374Sbp	mb_put_uint16le(mbp, txpcount);
61075374Sbp	mb_put_uint16le(mbp, poff);
61175374Sbp	mb_put_uint16le(mbp, txdcount);
61275374Sbp	mb_put_uint16le(mbp, doff);
61375374Sbp	mb_put_uint8(mbp, t2p->t2_setupcount);
61475374Sbp	mb_put_uint8(mbp, 0);
61575374Sbp	for (i = 0; i < t2p->t2_setupcount; i++)
61675374Sbp		mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
61775374Sbp	smb_rq_wend(rqp);
61875374Sbp	smb_rq_bstart(rqp);
61975374Sbp	/* TDUNICODE */
62075374Sbp	if (t2p->t_name)
62175374Sbp		mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
62275374Sbp	mb_put_uint8(mbp, 0);	/* terminating zero */
62375374Sbp	len = mb_fixhdr(mbp);
62475374Sbp	if (txpcount) {
62575374Sbp		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
62675374Sbp		error = md_get_mbuf(&mbparam, txpcount, &m);
62775374Sbp		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
62875374Sbp		if (error)
62975374Sbp			goto freerq;
63075374Sbp		mb_put_mbuf(mbp, m);
63175374Sbp	}
63275374Sbp	len = mb_fixhdr(mbp);
63375374Sbp	if (txdcount) {
63475374Sbp		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
63575374Sbp		error = md_get_mbuf(&mbdata, txdcount, &m);
63675374Sbp		if (error)
63775374Sbp			goto freerq;
63875374Sbp		mb_put_mbuf(mbp, m);
63975374Sbp	}
64075374Sbp	smb_rq_bend(rqp);	/* incredible, but thats it... */
64175374Sbp	error = smb_rq_enqueue(rqp);
64275374Sbp	if (error)
64375374Sbp		goto freerq;
64475374Sbp	if (leftpcount == 0 && leftdcount == 0)
64575374Sbp		t2p->t2_flags |= SMBT2_ALLSENT;
64675374Sbp	error = smb_t2_reply(t2p);
64775374Sbp	if (error)
64875374Sbp		goto bad;
64975374Sbp	while (leftpcount || leftdcount) {
65075374Sbp		error = smb_rq_new(rqp, t2p->t_name ?
65175374Sbp		    SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
65275374Sbp		if (error)
65375374Sbp			goto bad;
65475374Sbp		mbp = &rqp->sr_rq;
65575374Sbp		smb_rq_wstart(rqp);
65675374Sbp		mb_put_uint16le(mbp, totpcount);
65775374Sbp		mb_put_uint16le(mbp, totdcount);
65875374Sbp		len = mb_fixhdr(mbp);
65975374Sbp		/*
66075374Sbp		 * now we have known packet size as
66175374Sbp		 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
66275374Sbp		 * and need to decide which parts should go into request
66375374Sbp		 */
66475374Sbp		len = ALIGN4(len + 6 * 2 + 2);
66575374Sbp		if (t2p->t_name == NULL)
66675374Sbp			len += 2;
66775374Sbp		if (len + leftpcount > txmax) {
66875374Sbp			txpcount = min(leftpcount, txmax - len);
66975374Sbp			poff = len;
67075374Sbp			txdcount = 0;
67175374Sbp			doff = 0;
67275374Sbp		} else {
67375374Sbp			txpcount = leftpcount;
67475374Sbp			poff = txpcount ? len : 0;
67575374Sbp			len = ALIGN4(len + txpcount);
67675374Sbp			txdcount = min(leftdcount, txmax - len);
67775374Sbp			doff = txdcount ? len : 0;
67875374Sbp		}
67975374Sbp		mb_put_uint16le(mbp, txpcount);
68075374Sbp		mb_put_uint16le(mbp, poff);
68175374Sbp		mb_put_uint16le(mbp, totpcount - leftpcount);
68275374Sbp		mb_put_uint16le(mbp, txdcount);
68375374Sbp		mb_put_uint16le(mbp, doff);
68475374Sbp		mb_put_uint16le(mbp, totdcount - leftdcount);
68575374Sbp		leftpcount -= txpcount;
68675374Sbp		leftdcount -= txdcount;
68775374Sbp		if (t2p->t_name == NULL)
68875374Sbp			mb_put_uint16le(mbp, t2p->t2_fid);
68975374Sbp		smb_rq_wend(rqp);
69075374Sbp		smb_rq_bstart(rqp);
69175374Sbp		mb_put_uint8(mbp, 0);	/* name */
69275374Sbp		len = mb_fixhdr(mbp);
69375374Sbp		if (txpcount) {
69475374Sbp			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
69575374Sbp			error = md_get_mbuf(&mbparam, txpcount, &m);
69675374Sbp			if (error)
69775374Sbp				goto bad;
69875374Sbp			mb_put_mbuf(mbp, m);
69975374Sbp		}
70075374Sbp		len = mb_fixhdr(mbp);
70175374Sbp		if (txdcount) {
70275374Sbp			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
70375374Sbp			error = md_get_mbuf(&mbdata, txdcount, &m);
70475374Sbp			if (error)
70575374Sbp				goto bad;
70675374Sbp			mb_put_mbuf(mbp, m);
70775374Sbp		}
70875374Sbp		smb_rq_bend(rqp);
70975374Sbp		rqp->sr_state = SMBRQ_NOTSENT;
71075374Sbp		error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL);
71175374Sbp		if (error)
71275374Sbp			goto bad;
71375374Sbp	}	/* while left params or data */
71475374Sbp	t2p->t2_flags |= SMBT2_ALLSENT;
71575374Sbp	mdp = &t2p->t2_rdata;
71675374Sbp	if (mdp->md_top) {
71775374Sbp		m_fixhdr(mdp->md_top);
71875374Sbp		md_initm(mdp, mdp->md_top);
71975374Sbp	}
72075374Sbp	mdp = &t2p->t2_rparam;
72175374Sbp	if (mdp->md_top) {
72275374Sbp		m_fixhdr(mdp->md_top);
72375374Sbp		md_initm(mdp, mdp->md_top);
72475374Sbp	}
72575374Sbpbad:
72675374Sbp	smb_iod_removerq(rqp);
72775374Sbpfreerq:
72875374Sbp	smb_rq_done(rqp);
72975374Sbp	if (error) {
73075374Sbp		if (rqp->sr_flags & SMBR_RESTART)
73175374Sbp			t2p->t2_flags |= SMBT2_RESTART;
73275374Sbp		md_done(&t2p->t2_rparam);
73375374Sbp		md_done(&t2p->t2_rdata);
73475374Sbp	}
73575374Sbp	return error;
73675374Sbp}
73775374Sbp
73875374Sbpint
73975374Sbpsmb_t2_request(struct smb_t2rq *t2p)
74075374Sbp{
74175374Sbp	int error = EINVAL, i;
74275374Sbp
74375374Sbp	for (i = 0; i < SMB_MAXRCN; i++) {
74475374Sbp		t2p->t2_flags &= ~SMBR_RESTART;
74575374Sbp		error = smb_t2_request_int(t2p);
74675374Sbp		if (error == 0)
74775374Sbp			break;
74875374Sbp		if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
74975374Sbp			break;
75075374Sbp	}
75175374Sbp	return error;
75275374Sbp}
753