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