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