1c398230bSWarner Losh /*- 2681a5bbeSBoris Popov * Copyright (c) 2000-2001, Boris Popov 3681a5bbeSBoris Popov * All rights reserved. 4681a5bbeSBoris Popov * 5681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 6681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 7681a5bbeSBoris Popov * are met: 8681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 9681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 10681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 12681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 13681a5bbeSBoris Popov * 3. All advertising materials mentioning features or use of this software 14681a5bbeSBoris Popov * must display the following acknowledgement: 15681a5bbeSBoris Popov * This product includes software developed by Boris Popov. 16681a5bbeSBoris Popov * 4. Neither the name of the author nor the names of any co-contributors 17681a5bbeSBoris Popov * may be used to endorse or promote products derived from this software 18681a5bbeSBoris Popov * without specific prior written permission. 19681a5bbeSBoris Popov * 20681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30681a5bbeSBoris Popov * SUCH DAMAGE. 31681a5bbeSBoris Popov */ 32ab0de15bSDavid E. O'Brien 33ab0de15bSDavid E. O'Brien #include <sys/cdefs.h> 34ab0de15bSDavid E. O'Brien __FBSDID("$FreeBSD$"); 35ab0de15bSDavid E. O'Brien 36681a5bbeSBoris Popov #include <sys/param.h> 37681a5bbeSBoris Popov #include <sys/systm.h> 38a30d4b32SMike Barcroft #include <sys/endian.h> 39681a5bbeSBoris Popov #include <sys/kernel.h> 40681a5bbeSBoris Popov #include <sys/malloc.h> 415dba30f1SPoul-Henning Kamp #include <sys/module.h> 42681a5bbeSBoris Popov #include <sys/proc.h> 43681a5bbeSBoris Popov #include <sys/lock.h> 44681a5bbeSBoris Popov #include <sys/sysctl.h> 45681a5bbeSBoris Popov #include <sys/socket.h> 46681a5bbeSBoris Popov #include <sys/socketvar.h> 47681a5bbeSBoris Popov #include <sys/mbuf.h> 48681a5bbeSBoris Popov 49681a5bbeSBoris Popov #include <netsmb/smb.h> 50681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 51681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 52681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 53681a5bbeSBoris Popov #include <netsmb/smb_tran.h> 54681a5bbeSBoris Popov 55681a5bbeSBoris Popov MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request"); 56681a5bbeSBoris Popov 57681a5bbeSBoris Popov MODULE_DEPEND(netsmb, libmchain, 1, 1, 1); 58681a5bbeSBoris Popov 59681a5bbeSBoris Popov static int smb_rq_reply(struct smb_rq *rqp); 60681a5bbeSBoris Popov static int smb_rq_enqueue(struct smb_rq *rqp); 61681a5bbeSBoris Popov static int smb_rq_getenv(struct smb_connobj *layer, 62681a5bbeSBoris Popov struct smb_vc **vcpp, struct smb_share **sspp); 63681a5bbeSBoris Popov static int smb_rq_new(struct smb_rq *rqp, u_char cmd); 64681a5bbeSBoris Popov static int smb_t2_reply(struct smb_t2rq *t2p); 65681a5bbeSBoris Popov 66681a5bbeSBoris Popov int 67681a5bbeSBoris Popov smb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred, 68681a5bbeSBoris Popov struct smb_rq **rqpp) 69681a5bbeSBoris Popov { 70681a5bbeSBoris Popov struct smb_rq *rqp; 71681a5bbeSBoris Popov int error; 72681a5bbeSBoris Popov 73a163d034SWarner Losh MALLOC(rqp, struct smb_rq *, sizeof(*rqp), M_SMBRQ, M_WAITOK); 74681a5bbeSBoris Popov if (rqp == NULL) 75681a5bbeSBoris Popov return ENOMEM; 76681a5bbeSBoris Popov error = smb_rq_init(rqp, layer, cmd, scred); 77681a5bbeSBoris Popov rqp->sr_flags |= SMBR_ALLOCED; 78681a5bbeSBoris Popov if (error) { 79681a5bbeSBoris Popov smb_rq_done(rqp); 80681a5bbeSBoris Popov return error; 81681a5bbeSBoris Popov } 82681a5bbeSBoris Popov *rqpp = rqp; 83681a5bbeSBoris Popov return 0; 84681a5bbeSBoris Popov } 85681a5bbeSBoris Popov 86681a5bbeSBoris Popov static char tzero[12]; 87681a5bbeSBoris Popov 88681a5bbeSBoris Popov int 89681a5bbeSBoris Popov smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd, 90681a5bbeSBoris Popov struct smb_cred *scred) 91681a5bbeSBoris Popov { 92681a5bbeSBoris Popov int error; 93681a5bbeSBoris Popov 94681a5bbeSBoris Popov bzero(rqp, sizeof(*rqp)); 95681a5bbeSBoris Popov smb_sl_init(&rqp->sr_slock, "srslock"); 96681a5bbeSBoris Popov error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share); 97681a5bbeSBoris Popov if (error) 98681a5bbeSBoris Popov return error; 99681a5bbeSBoris Popov error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC); 100681a5bbeSBoris Popov if (error) 101681a5bbeSBoris Popov return error; 102681a5bbeSBoris Popov if (rqp->sr_share) { 103681a5bbeSBoris Popov error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC); 104681a5bbeSBoris Popov if (error) 105681a5bbeSBoris Popov return error; 106681a5bbeSBoris Popov } 107681a5bbeSBoris Popov rqp->sr_cred = scred; 108681a5bbeSBoris Popov rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc); 109681a5bbeSBoris Popov return smb_rq_new(rqp, cmd); 110681a5bbeSBoris Popov } 111681a5bbeSBoris Popov 112681a5bbeSBoris Popov static int 113681a5bbeSBoris Popov smb_rq_new(struct smb_rq *rqp, u_char cmd) 114681a5bbeSBoris Popov { 115681a5bbeSBoris Popov struct smb_vc *vcp = rqp->sr_vc; 116681a5bbeSBoris Popov struct mbchain *mbp = &rqp->sr_rq; 117681a5bbeSBoris Popov int error; 118190b2c4fSTim J. Robbins u_int16_t flags2; 119681a5bbeSBoris Popov 120681a5bbeSBoris Popov rqp->sr_sendcnt = 0; 121681a5bbeSBoris Popov mb_done(mbp); 122681a5bbeSBoris Popov md_done(&rqp->sr_rp); 123681a5bbeSBoris Popov error = mb_init(mbp); 124681a5bbeSBoris Popov if (error) 125681a5bbeSBoris Popov return error; 126681a5bbeSBoris Popov mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM); 127681a5bbeSBoris Popov mb_put_uint8(mbp, cmd); 128681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* DosError */ 129681a5bbeSBoris Popov mb_put_uint8(mbp, vcp->vc_hflags); 130190b2c4fSTim J. Robbins flags2 = vcp->vc_hflags2; 131ab93c874SBoris Popov if (cmd == SMB_COM_TRANSACTION || cmd == SMB_COM_TRANSACTION_SECONDARY) 132190b2c4fSTim J. Robbins flags2 &= ~SMB_FLAGS2_UNICODE; 133190b2c4fSTim J. Robbins if (cmd == SMB_COM_NEGOTIATE) 134190b2c4fSTim J. Robbins flags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE; 135190b2c4fSTim J. Robbins mb_put_uint16le(mbp, flags2); 136190b2c4fSTim J. Robbins if ((flags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { 137681a5bbeSBoris Popov mb_put_mem(mbp, tzero, 12, MB_MSYSTEM); 138190b2c4fSTim J. Robbins rqp->sr_rqsig = NULL; 139190b2c4fSTim J. Robbins } else { 140190b2c4fSTim J. Robbins mb_put_uint16le(mbp, 0 /*scred->sc_p->p_pid >> 16*/); 141190b2c4fSTim J. Robbins rqp->sr_rqsig = (u_int8_t *)mb_reserve(mbp, 8); 142190b2c4fSTim J. Robbins mb_put_uint16le(mbp, 0); 143190b2c4fSTim J. Robbins } 144681a5bbeSBoris Popov rqp->sr_rqtid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t)); 145681a5bbeSBoris Popov mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/); 146681a5bbeSBoris Popov rqp->sr_rquid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t)); 147681a5bbeSBoris Popov mb_put_uint16le(mbp, rqp->sr_mid); 148681a5bbeSBoris Popov return 0; 149681a5bbeSBoris Popov } 150681a5bbeSBoris Popov 151681a5bbeSBoris Popov void 152681a5bbeSBoris Popov smb_rq_done(struct smb_rq *rqp) 153681a5bbeSBoris Popov { 154681a5bbeSBoris Popov mb_done(&rqp->sr_rq); 155681a5bbeSBoris Popov md_done(&rqp->sr_rp); 156681a5bbeSBoris Popov smb_sl_destroy(&rqp->sr_slock); 157681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_ALLOCED) 158681a5bbeSBoris Popov free(rqp, M_SMBRQ); 159681a5bbeSBoris Popov } 160681a5bbeSBoris Popov 161681a5bbeSBoris Popov /* 162681a5bbeSBoris Popov * Simple request-reply exchange 163681a5bbeSBoris Popov */ 164681a5bbeSBoris Popov int 165681a5bbeSBoris Popov smb_rq_simple(struct smb_rq *rqp) 166681a5bbeSBoris Popov { 167681a5bbeSBoris Popov struct smb_vc *vcp = rqp->sr_vc; 168681a5bbeSBoris Popov int error = EINVAL, i; 169681a5bbeSBoris Popov 170681a5bbeSBoris Popov for (i = 0; i < SMB_MAXRCN; i++) { 171681a5bbeSBoris Popov rqp->sr_flags &= ~SMBR_RESTART; 172681a5bbeSBoris Popov rqp->sr_timo = vcp->vc_timo; 173681a5bbeSBoris Popov rqp->sr_state = SMBRQ_NOTSENT; 174681a5bbeSBoris Popov error = smb_rq_enqueue(rqp); 175681a5bbeSBoris Popov if (error) 176681a5bbeSBoris Popov return error; 177681a5bbeSBoris Popov error = smb_rq_reply(rqp); 178681a5bbeSBoris Popov if (error == 0) 179681a5bbeSBoris Popov break; 180681a5bbeSBoris Popov if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART) 181681a5bbeSBoris Popov break; 182681a5bbeSBoris Popov } 183681a5bbeSBoris Popov return error; 184681a5bbeSBoris Popov } 185681a5bbeSBoris Popov 186681a5bbeSBoris Popov static int 187681a5bbeSBoris Popov smb_rq_enqueue(struct smb_rq *rqp) 188681a5bbeSBoris Popov { 189681a5bbeSBoris Popov struct smb_share *ssp = rqp->sr_share; 190681a5bbeSBoris Popov int error; 191681a5bbeSBoris Popov 192681a5bbeSBoris Popov if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) { 193681a5bbeSBoris Popov return smb_iod_addrq(rqp); 194681a5bbeSBoris Popov } 195681a5bbeSBoris Popov for (;;) { 196681a5bbeSBoris Popov SMBS_ST_LOCK(ssp); 197681a5bbeSBoris Popov if (ssp->ss_flags & SMBS_RECONNECTING) { 198681a5bbeSBoris Popov msleep(&ssp->ss_vcgenid, SMBS_ST_LOCKPTR(ssp), 199681a5bbeSBoris Popov PWAIT | PDROP, "90trcn", hz); 2004093529dSJeff Roberson if (smb_td_intr(rqp->sr_cred->scr_td)) 201681a5bbeSBoris Popov return EINTR; 202681a5bbeSBoris Popov continue; 203681a5bbeSBoris Popov } 204681a5bbeSBoris Popov if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) { 205681a5bbeSBoris Popov SMBS_ST_UNLOCK(ssp); 206681a5bbeSBoris Popov } else { 207681a5bbeSBoris Popov SMBS_ST_UNLOCK(ssp); 208681a5bbeSBoris Popov error = smb_iod_request(rqp->sr_vc->vc_iod, 209681a5bbeSBoris Popov SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp); 210681a5bbeSBoris Popov if (error) 211681a5bbeSBoris Popov return error; 212681a5bbeSBoris Popov } 213681a5bbeSBoris Popov error = smb_iod_addrq(rqp); 214681a5bbeSBoris Popov if (error != EXDEV) 215681a5bbeSBoris Popov break; 216681a5bbeSBoris Popov } 217681a5bbeSBoris Popov return error; 218681a5bbeSBoris Popov } 219681a5bbeSBoris Popov 220681a5bbeSBoris Popov void 221681a5bbeSBoris Popov smb_rq_wstart(struct smb_rq *rqp) 222681a5bbeSBoris Popov { 223681a5bbeSBoris Popov rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t)); 224681a5bbeSBoris Popov rqp->sr_rq.mb_count = 0; 225681a5bbeSBoris Popov } 226681a5bbeSBoris Popov 227681a5bbeSBoris Popov void 228681a5bbeSBoris Popov smb_rq_wend(struct smb_rq *rqp) 229681a5bbeSBoris Popov { 230681a5bbeSBoris Popov if (rqp->sr_wcount == NULL) { 231681a5bbeSBoris Popov SMBERROR("no wcount\n"); /* actually panic */ 232681a5bbeSBoris Popov return; 233681a5bbeSBoris Popov } 234681a5bbeSBoris Popov if (rqp->sr_rq.mb_count & 1) 235681a5bbeSBoris Popov SMBERROR("odd word count\n"); 236681a5bbeSBoris Popov *rqp->sr_wcount = rqp->sr_rq.mb_count / 2; 237681a5bbeSBoris Popov } 238681a5bbeSBoris Popov 239681a5bbeSBoris Popov void 240681a5bbeSBoris Popov smb_rq_bstart(struct smb_rq *rqp) 241681a5bbeSBoris Popov { 242681a5bbeSBoris Popov rqp->sr_bcount = (u_short*)mb_reserve(&rqp->sr_rq, sizeof(u_short)); 243681a5bbeSBoris Popov rqp->sr_rq.mb_count = 0; 244681a5bbeSBoris Popov } 245681a5bbeSBoris Popov 246681a5bbeSBoris Popov void 247681a5bbeSBoris Popov smb_rq_bend(struct smb_rq *rqp) 248681a5bbeSBoris Popov { 249681a5bbeSBoris Popov int bcnt; 250681a5bbeSBoris Popov 251681a5bbeSBoris Popov if (rqp->sr_bcount == NULL) { 252681a5bbeSBoris Popov SMBERROR("no bcount\n"); /* actually panic */ 253681a5bbeSBoris Popov return; 254681a5bbeSBoris Popov } 255681a5bbeSBoris Popov bcnt = rqp->sr_rq.mb_count; 256681a5bbeSBoris Popov if (bcnt > 0xffff) 257681a5bbeSBoris Popov SMBERROR("byte count too large (%d)\n", bcnt); 2580adb6d7aSRobert Drehmel *rqp->sr_bcount = htole16(bcnt); 259681a5bbeSBoris Popov } 260681a5bbeSBoris Popov 261681a5bbeSBoris Popov int 262681a5bbeSBoris Popov smb_rq_intr(struct smb_rq *rqp) 263681a5bbeSBoris Popov { 264681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_INTR) 265681a5bbeSBoris Popov return EINTR; 2664093529dSJeff Roberson return smb_td_intr(rqp->sr_cred->scr_td); 267681a5bbeSBoris Popov } 268681a5bbeSBoris Popov 269681a5bbeSBoris Popov int 270681a5bbeSBoris Popov smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp) 271681a5bbeSBoris Popov { 272681a5bbeSBoris Popov *mbpp = &rqp->sr_rq; 273681a5bbeSBoris Popov return 0; 274681a5bbeSBoris Popov } 275681a5bbeSBoris Popov 276681a5bbeSBoris Popov int 277681a5bbeSBoris Popov smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp) 278681a5bbeSBoris Popov { 279681a5bbeSBoris Popov *mbpp = &rqp->sr_rp; 280681a5bbeSBoris Popov return 0; 281681a5bbeSBoris Popov } 282681a5bbeSBoris Popov 283681a5bbeSBoris Popov static int 284681a5bbeSBoris Popov smb_rq_getenv(struct smb_connobj *layer, 285681a5bbeSBoris Popov struct smb_vc **vcpp, struct smb_share **sspp) 286681a5bbeSBoris Popov { 287681a5bbeSBoris Popov struct smb_vc *vcp = NULL; 288681a5bbeSBoris Popov struct smb_share *ssp = NULL; 289681a5bbeSBoris Popov struct smb_connobj *cp; 290681a5bbeSBoris Popov int error = 0; 291681a5bbeSBoris Popov 292681a5bbeSBoris Popov switch (layer->co_level) { 293681a5bbeSBoris Popov case SMBL_VC: 294681a5bbeSBoris Popov vcp = CPTOVC(layer); 295681a5bbeSBoris Popov if (layer->co_parent == NULL) { 296681a5bbeSBoris Popov SMBERROR("zombie VC %s\n", vcp->vc_srvname); 297681a5bbeSBoris Popov error = EINVAL; 298681a5bbeSBoris Popov break; 299681a5bbeSBoris Popov } 300681a5bbeSBoris Popov break; 301681a5bbeSBoris Popov case SMBL_SHARE: 302681a5bbeSBoris Popov ssp = CPTOSS(layer); 303681a5bbeSBoris Popov cp = layer->co_parent; 304681a5bbeSBoris Popov if (cp == NULL) { 305681a5bbeSBoris Popov SMBERROR("zombie share %s\n", ssp->ss_name); 306681a5bbeSBoris Popov error = EINVAL; 307681a5bbeSBoris Popov break; 308681a5bbeSBoris Popov } 309681a5bbeSBoris Popov error = smb_rq_getenv(cp, &vcp, NULL); 310681a5bbeSBoris Popov if (error) 311681a5bbeSBoris Popov break; 312681a5bbeSBoris Popov break; 313681a5bbeSBoris Popov default: 314681a5bbeSBoris Popov SMBERROR("invalid layer %d passed\n", layer->co_level); 315681a5bbeSBoris Popov error = EINVAL; 316681a5bbeSBoris Popov } 317681a5bbeSBoris Popov if (vcpp) 318681a5bbeSBoris Popov *vcpp = vcp; 319681a5bbeSBoris Popov if (sspp) 320681a5bbeSBoris Popov *sspp = ssp; 321681a5bbeSBoris Popov return error; 322681a5bbeSBoris Popov } 323681a5bbeSBoris Popov 324681a5bbeSBoris Popov /* 325681a5bbeSBoris Popov * Wait for reply on the request 326681a5bbeSBoris Popov */ 327681a5bbeSBoris Popov static int 328681a5bbeSBoris Popov smb_rq_reply(struct smb_rq *rqp) 329681a5bbeSBoris Popov { 330681a5bbeSBoris Popov struct mdchain *mdp = &rqp->sr_rp; 331681a5bbeSBoris Popov u_int32_t tdw; 332681a5bbeSBoris Popov u_int8_t tb; 333681a5bbeSBoris Popov int error, rperror = 0; 334681a5bbeSBoris Popov 335681a5bbeSBoris Popov error = smb_iod_waitrq(rqp); 336681a5bbeSBoris Popov if (error) 337681a5bbeSBoris Popov return error; 338681a5bbeSBoris Popov error = md_get_uint32(mdp, &tdw); 339681a5bbeSBoris Popov if (error) 340681a5bbeSBoris Popov return error; 341681a5bbeSBoris Popov error = md_get_uint8(mdp, &tb); 342681a5bbeSBoris Popov if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) { 343681a5bbeSBoris Popov error = md_get_uint32le(mdp, &rqp->sr_error); 344681a5bbeSBoris Popov } else { 345681a5bbeSBoris Popov error = md_get_uint8(mdp, &rqp->sr_errclass); 346681a5bbeSBoris Popov error = md_get_uint8(mdp, &tb); 347681a5bbeSBoris Popov error = md_get_uint16le(mdp, &rqp->sr_serror); 348681a5bbeSBoris Popov if (!error) 349681a5bbeSBoris Popov rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror); 350681a5bbeSBoris Popov } 351681a5bbeSBoris Popov error = md_get_uint8(mdp, &rqp->sr_rpflags); 352681a5bbeSBoris Popov error = md_get_uint16le(mdp, &rqp->sr_rpflags2); 353681a5bbeSBoris Popov 354681a5bbeSBoris Popov error = md_get_uint32(mdp, &tdw); 355681a5bbeSBoris Popov error = md_get_uint32(mdp, &tdw); 356681a5bbeSBoris Popov error = md_get_uint32(mdp, &tdw); 357681a5bbeSBoris Popov 358681a5bbeSBoris Popov error = md_get_uint16le(mdp, &rqp->sr_rptid); 359681a5bbeSBoris Popov error = md_get_uint16le(mdp, &rqp->sr_rppid); 360681a5bbeSBoris Popov error = md_get_uint16le(mdp, &rqp->sr_rpuid); 361681a5bbeSBoris Popov error = md_get_uint16le(mdp, &rqp->sr_rpmid); 362681a5bbeSBoris Popov 363190b2c4fSTim J. Robbins if (error == 0 && 364190b2c4fSTim J. Robbins (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) 365190b2c4fSTim J. Robbins error = smb_rq_verify(rqp); 366190b2c4fSTim J. Robbins 367681a5bbeSBoris Popov SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n", 368681a5bbeSBoris Popov rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid, 369681a5bbeSBoris Popov rqp->sr_errclass, rqp->sr_serror); 370681a5bbeSBoris Popov return error ? error : rperror; 371681a5bbeSBoris Popov } 372681a5bbeSBoris Popov 373681a5bbeSBoris Popov 374681a5bbeSBoris Popov #define ALIGN4(a) (((a) + 3) & ~3) 375681a5bbeSBoris Popov 376681a5bbeSBoris Popov /* 377681a5bbeSBoris Popov * TRANS2 request implementation 378681a5bbeSBoris Popov */ 379681a5bbeSBoris Popov int 380681a5bbeSBoris Popov smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred, 381681a5bbeSBoris Popov struct smb_t2rq **t2pp) 382681a5bbeSBoris Popov { 383681a5bbeSBoris Popov struct smb_t2rq *t2p; 384681a5bbeSBoris Popov int error; 385681a5bbeSBoris Popov 386a163d034SWarner Losh MALLOC(t2p, struct smb_t2rq *, sizeof(*t2p), M_SMBRQ, M_WAITOK); 387681a5bbeSBoris Popov if (t2p == NULL) 388681a5bbeSBoris Popov return ENOMEM; 389681a5bbeSBoris Popov error = smb_t2_init(t2p, layer, setup, scred); 390681a5bbeSBoris Popov t2p->t2_flags |= SMBT2_ALLOCED; 391681a5bbeSBoris Popov if (error) { 392681a5bbeSBoris Popov smb_t2_done(t2p); 393681a5bbeSBoris Popov return error; 394681a5bbeSBoris Popov } 395681a5bbeSBoris Popov *t2pp = t2p; 396681a5bbeSBoris Popov return 0; 397681a5bbeSBoris Popov } 398681a5bbeSBoris Popov 399681a5bbeSBoris Popov int 400681a5bbeSBoris Popov smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup, 401681a5bbeSBoris Popov struct smb_cred *scred) 402681a5bbeSBoris Popov { 403681a5bbeSBoris Popov int error; 404681a5bbeSBoris Popov 405681a5bbeSBoris Popov bzero(t2p, sizeof(*t2p)); 406681a5bbeSBoris Popov t2p->t2_source = source; 407681a5bbeSBoris Popov t2p->t2_setupcount = 1; 408681a5bbeSBoris Popov t2p->t2_setupdata = t2p->t2_setup; 409681a5bbeSBoris Popov t2p->t2_setup[0] = setup; 410681a5bbeSBoris Popov t2p->t2_fid = 0xffff; 411681a5bbeSBoris Popov t2p->t2_cred = scred; 412681a5bbeSBoris Popov error = smb_rq_getenv(source, &t2p->t2_vc, NULL); 413681a5bbeSBoris Popov if (error) 414681a5bbeSBoris Popov return error; 415681a5bbeSBoris Popov return 0; 416681a5bbeSBoris Popov } 417681a5bbeSBoris Popov 418681a5bbeSBoris Popov void 419681a5bbeSBoris Popov smb_t2_done(struct smb_t2rq *t2p) 420681a5bbeSBoris Popov { 421681a5bbeSBoris Popov mb_done(&t2p->t2_tparam); 422681a5bbeSBoris Popov mb_done(&t2p->t2_tdata); 423681a5bbeSBoris Popov md_done(&t2p->t2_rparam); 424681a5bbeSBoris Popov md_done(&t2p->t2_rdata); 425681a5bbeSBoris Popov if (t2p->t2_flags & SMBT2_ALLOCED) 426681a5bbeSBoris Popov free(t2p, M_SMBRQ); 427681a5bbeSBoris Popov } 428681a5bbeSBoris Popov 429681a5bbeSBoris Popov static int 430681a5bbeSBoris Popov smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count, 431681a5bbeSBoris Popov struct mdchain *mdp) 432681a5bbeSBoris Popov { 433681a5bbeSBoris Popov struct mbuf *m, *m0; 434681a5bbeSBoris Popov int len; 435681a5bbeSBoris Popov 436a163d034SWarner Losh m0 = m_split(mtop, offset, M_TRYWAIT); 437681a5bbeSBoris Popov if (m0 == NULL) 438681a5bbeSBoris Popov return EBADRPC; 4397ed60de8SPoul-Henning Kamp len = m_length(m0, &m); 440681a5bbeSBoris Popov m->m_len -= len - count; 441681a5bbeSBoris Popov if (mdp->md_top == NULL) { 442681a5bbeSBoris Popov md_initm(mdp, m0); 443681a5bbeSBoris Popov } else 444681a5bbeSBoris Popov m_cat(mdp->md_top, m0); 445681a5bbeSBoris Popov return 0; 446681a5bbeSBoris Popov } 447681a5bbeSBoris Popov 448681a5bbeSBoris Popov static int 449681a5bbeSBoris Popov smb_t2_reply(struct smb_t2rq *t2p) 450681a5bbeSBoris Popov { 451681a5bbeSBoris Popov struct mdchain *mdp; 452681a5bbeSBoris Popov struct smb_rq *rqp = t2p->t2_rq; 453681a5bbeSBoris Popov int error, totpgot, totdgot; 454681a5bbeSBoris Popov u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; 455681a5bbeSBoris Popov u_int16_t tmp, bc, dcount; 456681a5bbeSBoris Popov u_int8_t wc; 457681a5bbeSBoris Popov 458681a5bbeSBoris Popov error = smb_rq_reply(rqp); 459681a5bbeSBoris Popov if (error) 460681a5bbeSBoris Popov return error; 461681a5bbeSBoris Popov if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) { 462681a5bbeSBoris Popov /* 463681a5bbeSBoris Popov * this is an interim response, ignore it. 464681a5bbeSBoris Popov */ 465681a5bbeSBoris Popov SMBRQ_SLOCK(rqp); 466681a5bbeSBoris Popov md_next_record(&rqp->sr_rp); 467681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 468681a5bbeSBoris Popov return 0; 469681a5bbeSBoris Popov } 470681a5bbeSBoris Popov /* 471fc75194cSBoris Popov * Now we have to get all subsequent responses. The CIFS specification 472fc75194cSBoris Popov * says that they can be disordered which is weird. 473681a5bbeSBoris Popov * TODO: timo 474681a5bbeSBoris Popov */ 475681a5bbeSBoris Popov totpgot = totdgot = 0; 476681a5bbeSBoris Popov totpcount = totdcount = 0xffff; 477681a5bbeSBoris Popov mdp = &rqp->sr_rp; 478681a5bbeSBoris Popov for (;;) { 479681a5bbeSBoris Popov m_dumpm(mdp->md_top); 480681a5bbeSBoris Popov if ((error = md_get_uint8(mdp, &wc)) != 0) 481681a5bbeSBoris Popov break; 482681a5bbeSBoris Popov if (wc < 10) { 483681a5bbeSBoris Popov error = ENOENT; 484681a5bbeSBoris Popov break; 485681a5bbeSBoris Popov } 486681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tmp)) != 0) 487681a5bbeSBoris Popov break; 488681a5bbeSBoris Popov if (totpcount > tmp) 489681a5bbeSBoris Popov totpcount = tmp; 490681a5bbeSBoris Popov md_get_uint16le(mdp, &tmp); 491681a5bbeSBoris Popov if (totdcount > tmp) 492681a5bbeSBoris Popov totdcount = tmp; 493681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */ 494681a5bbeSBoris Popov (error = md_get_uint16le(mdp, &pcount)) != 0 || 495681a5bbeSBoris Popov (error = md_get_uint16le(mdp, &poff)) != 0 || 496681a5bbeSBoris Popov (error = md_get_uint16le(mdp, &pdisp)) != 0) 497681a5bbeSBoris Popov break; 498681a5bbeSBoris Popov if (pcount != 0 && pdisp != totpgot) { 499fc75194cSBoris Popov SMBERROR("Can't handle disordered parameters %d:%d\n", 500681a5bbeSBoris Popov pdisp, totpgot); 501681a5bbeSBoris Popov error = EINVAL; 502681a5bbeSBoris Popov break; 503681a5bbeSBoris Popov } 504681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &dcount)) != 0 || 505681a5bbeSBoris Popov (error = md_get_uint16le(mdp, &doff)) != 0 || 506681a5bbeSBoris Popov (error = md_get_uint16le(mdp, &ddisp)) != 0) 507681a5bbeSBoris Popov break; 508681a5bbeSBoris Popov if (dcount != 0 && ddisp != totdgot) { 509fc75194cSBoris Popov SMBERROR("Can't handle disordered data\n"); 510681a5bbeSBoris Popov error = EINVAL; 511681a5bbeSBoris Popov break; 512681a5bbeSBoris Popov } 513681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 514681a5bbeSBoris Popov md_get_uint8(mdp, NULL); 515681a5bbeSBoris Popov tmp = wc; 516681a5bbeSBoris Popov while (tmp--) 517681a5bbeSBoris Popov md_get_uint16(mdp, NULL); 518681a5bbeSBoris Popov if ((error = md_get_uint16le(mdp, &bc)) != 0) 519681a5bbeSBoris Popov break; 520681a5bbeSBoris Popov /* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/ 521681a5bbeSBoris Popov if (dcount) { 522681a5bbeSBoris Popov error = smb_t2_placedata(mdp->md_top, doff, dcount, 523681a5bbeSBoris Popov &t2p->t2_rdata); 524681a5bbeSBoris Popov if (error) 525681a5bbeSBoris Popov break; 526681a5bbeSBoris Popov } 527681a5bbeSBoris Popov if (pcount) { 528681a5bbeSBoris Popov error = smb_t2_placedata(mdp->md_top, poff, pcount, 529681a5bbeSBoris Popov &t2p->t2_rparam); 530681a5bbeSBoris Popov if (error) 531681a5bbeSBoris Popov break; 532681a5bbeSBoris Popov } 533681a5bbeSBoris Popov totpgot += pcount; 534681a5bbeSBoris Popov totdgot += dcount; 535681a5bbeSBoris Popov if (totpgot >= totpcount && totdgot >= totdcount) { 536681a5bbeSBoris Popov error = 0; 537681a5bbeSBoris Popov t2p->t2_flags |= SMBT2_ALLRECV; 538681a5bbeSBoris Popov break; 539681a5bbeSBoris Popov } 540681a5bbeSBoris Popov /* 541681a5bbeSBoris Popov * We're done with this reply, look for the next one. 542681a5bbeSBoris Popov */ 543681a5bbeSBoris Popov SMBRQ_SLOCK(rqp); 544681a5bbeSBoris Popov md_next_record(&rqp->sr_rp); 545681a5bbeSBoris Popov SMBRQ_SUNLOCK(rqp); 546681a5bbeSBoris Popov error = smb_rq_reply(rqp); 547681a5bbeSBoris Popov if (error) 548681a5bbeSBoris Popov break; 549681a5bbeSBoris Popov } 550681a5bbeSBoris Popov return error; 551681a5bbeSBoris Popov } 552681a5bbeSBoris Popov 553681a5bbeSBoris Popov /* 554681a5bbeSBoris Popov * Perform a full round of TRANS2 request 555681a5bbeSBoris Popov */ 556681a5bbeSBoris Popov static int 557681a5bbeSBoris Popov smb_t2_request_int(struct smb_t2rq *t2p) 558681a5bbeSBoris Popov { 559681a5bbeSBoris Popov struct smb_vc *vcp = t2p->t2_vc; 560681a5bbeSBoris Popov struct smb_cred *scred = t2p->t2_cred; 561681a5bbeSBoris Popov struct mbchain *mbp; 562681a5bbeSBoris Popov struct mdchain *mdp, mbparam, mbdata; 563681a5bbeSBoris Popov struct mbuf *m; 564681a5bbeSBoris Popov struct smb_rq *rqp; 565681a5bbeSBoris Popov int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i; 566681a5bbeSBoris Popov int error, doff, poff, txdcount, txpcount, nmlen; 567681a5bbeSBoris Popov 568681a5bbeSBoris Popov m = t2p->t2_tparam.mb_top; 569681a5bbeSBoris Popov if (m) { 570681a5bbeSBoris Popov md_initm(&mbparam, m); /* do not free it! */ 571681a5bbeSBoris Popov totpcount = m_fixhdr(m); 572681a5bbeSBoris Popov if (totpcount > 0xffff) /* maxvalue for u_short */ 573681a5bbeSBoris Popov return EINVAL; 574681a5bbeSBoris Popov } else 575681a5bbeSBoris Popov totpcount = 0; 576681a5bbeSBoris Popov m = t2p->t2_tdata.mb_top; 577681a5bbeSBoris Popov if (m) { 578681a5bbeSBoris Popov md_initm(&mbdata, m); /* do not free it! */ 579681a5bbeSBoris Popov totdcount = m_fixhdr(m); 580681a5bbeSBoris Popov if (totdcount > 0xffff) 581681a5bbeSBoris Popov return EINVAL; 582681a5bbeSBoris Popov } else 583681a5bbeSBoris Popov totdcount = 0; 584681a5bbeSBoris Popov leftdcount = totdcount; 585681a5bbeSBoris Popov leftpcount = totpcount; 586681a5bbeSBoris Popov txmax = vcp->vc_txmax; 587681a5bbeSBoris Popov error = smb_rq_alloc(t2p->t2_source, t2p->t_name ? 588681a5bbeSBoris Popov SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp); 589681a5bbeSBoris Popov if (error) 590681a5bbeSBoris Popov return error; 591681a5bbeSBoris Popov rqp->sr_flags |= SMBR_MULTIPACKET; 592681a5bbeSBoris Popov t2p->t2_rq = rqp; 593190b2c4fSTim J. Robbins rqp->sr_t2 = t2p; 594681a5bbeSBoris Popov mbp = &rqp->sr_rq; 595681a5bbeSBoris Popov smb_rq_wstart(rqp); 596681a5bbeSBoris Popov mb_put_uint16le(mbp, totpcount); 597681a5bbeSBoris Popov mb_put_uint16le(mbp, totdcount); 598681a5bbeSBoris Popov mb_put_uint16le(mbp, t2p->t2_maxpcount); 599681a5bbeSBoris Popov mb_put_uint16le(mbp, t2p->t2_maxdcount); 600681a5bbeSBoris Popov mb_put_uint8(mbp, t2p->t2_maxscount); 601681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* reserved */ 602681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); /* flags */ 603681a5bbeSBoris Popov mb_put_uint32le(mbp, 0); /* Timeout */ 604681a5bbeSBoris Popov mb_put_uint16le(mbp, 0); /* reserved 2 */ 605681a5bbeSBoris Popov len = mb_fixhdr(mbp); 606681a5bbeSBoris Popov /* 607681a5bbeSBoris Popov * now we have known packet size as 608681a5bbeSBoris Popov * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1), 609681a5bbeSBoris Popov * and need to decide which parts should go into the first request 610681a5bbeSBoris Popov */ 611681a5bbeSBoris Popov nmlen = t2p->t_name ? strlen(t2p->t_name) : 0; 612681a5bbeSBoris Popov len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1); 613681a5bbeSBoris Popov if (len + leftpcount > txmax) { 614681a5bbeSBoris Popov txpcount = min(leftpcount, txmax - len); 615681a5bbeSBoris Popov poff = len; 616681a5bbeSBoris Popov txdcount = 0; 617681a5bbeSBoris Popov doff = 0; 618681a5bbeSBoris Popov } else { 619681a5bbeSBoris Popov txpcount = leftpcount; 620681a5bbeSBoris Popov poff = txpcount ? len : 0; 621681a5bbeSBoris Popov len = ALIGN4(len + txpcount); 622681a5bbeSBoris Popov txdcount = min(leftdcount, txmax - len); 623681a5bbeSBoris Popov doff = txdcount ? len : 0; 624681a5bbeSBoris Popov } 625681a5bbeSBoris Popov leftpcount -= txpcount; 626681a5bbeSBoris Popov leftdcount -= txdcount; 627681a5bbeSBoris Popov mb_put_uint16le(mbp, txpcount); 628681a5bbeSBoris Popov mb_put_uint16le(mbp, poff); 629681a5bbeSBoris Popov mb_put_uint16le(mbp, txdcount); 630681a5bbeSBoris Popov mb_put_uint16le(mbp, doff); 631681a5bbeSBoris Popov mb_put_uint8(mbp, t2p->t2_setupcount); 632681a5bbeSBoris Popov mb_put_uint8(mbp, 0); 633681a5bbeSBoris Popov for (i = 0; i < t2p->t2_setupcount; i++) 634681a5bbeSBoris Popov mb_put_uint16le(mbp, t2p->t2_setupdata[i]); 635681a5bbeSBoris Popov smb_rq_wend(rqp); 636681a5bbeSBoris Popov smb_rq_bstart(rqp); 637681a5bbeSBoris Popov /* TDUNICODE */ 638681a5bbeSBoris Popov if (t2p->t_name) 639681a5bbeSBoris Popov mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM); 640681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* terminating zero */ 641681a5bbeSBoris Popov len = mb_fixhdr(mbp); 642681a5bbeSBoris Popov if (txpcount) { 643681a5bbeSBoris Popov mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); 644681a5bbeSBoris Popov error = md_get_mbuf(&mbparam, txpcount, &m); 645681a5bbeSBoris Popov SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); 646681a5bbeSBoris Popov if (error) 647681a5bbeSBoris Popov goto freerq; 648681a5bbeSBoris Popov mb_put_mbuf(mbp, m); 649681a5bbeSBoris Popov } 650681a5bbeSBoris Popov len = mb_fixhdr(mbp); 651681a5bbeSBoris Popov if (txdcount) { 652681a5bbeSBoris Popov mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); 653681a5bbeSBoris Popov error = md_get_mbuf(&mbdata, txdcount, &m); 654681a5bbeSBoris Popov if (error) 655681a5bbeSBoris Popov goto freerq; 656681a5bbeSBoris Popov mb_put_mbuf(mbp, m); 657681a5bbeSBoris Popov } 658681a5bbeSBoris Popov smb_rq_bend(rqp); /* incredible, but thats it... */ 659681a5bbeSBoris Popov error = smb_rq_enqueue(rqp); 660681a5bbeSBoris Popov if (error) 661681a5bbeSBoris Popov goto freerq; 662681a5bbeSBoris Popov if (leftpcount == 0 && leftdcount == 0) 663681a5bbeSBoris Popov t2p->t2_flags |= SMBT2_ALLSENT; 664681a5bbeSBoris Popov error = smb_t2_reply(t2p); 665681a5bbeSBoris Popov if (error) 666681a5bbeSBoris Popov goto bad; 667681a5bbeSBoris Popov while (leftpcount || leftdcount) { 668190b2c4fSTim J. Robbins t2p->t2_flags |= SMBT2_SECONDARY; 669681a5bbeSBoris Popov error = smb_rq_new(rqp, t2p->t_name ? 670681a5bbeSBoris Popov SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY); 671681a5bbeSBoris Popov if (error) 672681a5bbeSBoris Popov goto bad; 673681a5bbeSBoris Popov mbp = &rqp->sr_rq; 674681a5bbeSBoris Popov smb_rq_wstart(rqp); 675681a5bbeSBoris Popov mb_put_uint16le(mbp, totpcount); 676681a5bbeSBoris Popov mb_put_uint16le(mbp, totdcount); 677681a5bbeSBoris Popov len = mb_fixhdr(mbp); 678681a5bbeSBoris Popov /* 679681a5bbeSBoris Popov * now we have known packet size as 680681a5bbeSBoris Popov * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one, 681681a5bbeSBoris Popov * and need to decide which parts should go into request 682681a5bbeSBoris Popov */ 683681a5bbeSBoris Popov len = ALIGN4(len + 6 * 2 + 2); 684681a5bbeSBoris Popov if (t2p->t_name == NULL) 685681a5bbeSBoris Popov len += 2; 686681a5bbeSBoris Popov if (len + leftpcount > txmax) { 687681a5bbeSBoris Popov txpcount = min(leftpcount, txmax - len); 688681a5bbeSBoris Popov poff = len; 689681a5bbeSBoris Popov txdcount = 0; 690681a5bbeSBoris Popov doff = 0; 691681a5bbeSBoris Popov } else { 692681a5bbeSBoris Popov txpcount = leftpcount; 693681a5bbeSBoris Popov poff = txpcount ? len : 0; 694681a5bbeSBoris Popov len = ALIGN4(len + txpcount); 695681a5bbeSBoris Popov txdcount = min(leftdcount, txmax - len); 696681a5bbeSBoris Popov doff = txdcount ? len : 0; 697681a5bbeSBoris Popov } 698681a5bbeSBoris Popov mb_put_uint16le(mbp, txpcount); 699681a5bbeSBoris Popov mb_put_uint16le(mbp, poff); 700681a5bbeSBoris Popov mb_put_uint16le(mbp, totpcount - leftpcount); 701681a5bbeSBoris Popov mb_put_uint16le(mbp, txdcount); 702681a5bbeSBoris Popov mb_put_uint16le(mbp, doff); 703681a5bbeSBoris Popov mb_put_uint16le(mbp, totdcount - leftdcount); 704681a5bbeSBoris Popov leftpcount -= txpcount; 705681a5bbeSBoris Popov leftdcount -= txdcount; 706681a5bbeSBoris Popov if (t2p->t_name == NULL) 707681a5bbeSBoris Popov mb_put_uint16le(mbp, t2p->t2_fid); 708681a5bbeSBoris Popov smb_rq_wend(rqp); 709681a5bbeSBoris Popov smb_rq_bstart(rqp); 710681a5bbeSBoris Popov mb_put_uint8(mbp, 0); /* name */ 711681a5bbeSBoris Popov len = mb_fixhdr(mbp); 712681a5bbeSBoris Popov if (txpcount) { 713681a5bbeSBoris Popov mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); 714681a5bbeSBoris Popov error = md_get_mbuf(&mbparam, txpcount, &m); 715681a5bbeSBoris Popov if (error) 716681a5bbeSBoris Popov goto bad; 717681a5bbeSBoris Popov mb_put_mbuf(mbp, m); 718681a5bbeSBoris Popov } 719681a5bbeSBoris Popov len = mb_fixhdr(mbp); 720681a5bbeSBoris Popov if (txdcount) { 721681a5bbeSBoris Popov mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); 722681a5bbeSBoris Popov error = md_get_mbuf(&mbdata, txdcount, &m); 723681a5bbeSBoris Popov if (error) 724681a5bbeSBoris Popov goto bad; 725681a5bbeSBoris Popov mb_put_mbuf(mbp, m); 726681a5bbeSBoris Popov } 727681a5bbeSBoris Popov smb_rq_bend(rqp); 728681a5bbeSBoris Popov rqp->sr_state = SMBRQ_NOTSENT; 729681a5bbeSBoris Popov error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL); 730681a5bbeSBoris Popov if (error) 731681a5bbeSBoris Popov goto bad; 732681a5bbeSBoris Popov } /* while left params or data */ 733681a5bbeSBoris Popov t2p->t2_flags |= SMBT2_ALLSENT; 734681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 735681a5bbeSBoris Popov if (mdp->md_top) { 736681a5bbeSBoris Popov m_fixhdr(mdp->md_top); 737681a5bbeSBoris Popov md_initm(mdp, mdp->md_top); 738681a5bbeSBoris Popov } 739681a5bbeSBoris Popov mdp = &t2p->t2_rparam; 740681a5bbeSBoris Popov if (mdp->md_top) { 741681a5bbeSBoris Popov m_fixhdr(mdp->md_top); 742681a5bbeSBoris Popov md_initm(mdp, mdp->md_top); 743681a5bbeSBoris Popov } 744681a5bbeSBoris Popov bad: 745681a5bbeSBoris Popov smb_iod_removerq(rqp); 746681a5bbeSBoris Popov freerq: 747681a5bbeSBoris Popov smb_rq_done(rqp); 748681a5bbeSBoris Popov if (error) { 749681a5bbeSBoris Popov if (rqp->sr_flags & SMBR_RESTART) 750681a5bbeSBoris Popov t2p->t2_flags |= SMBT2_RESTART; 751681a5bbeSBoris Popov md_done(&t2p->t2_rparam); 752681a5bbeSBoris Popov md_done(&t2p->t2_rdata); 753681a5bbeSBoris Popov } 754681a5bbeSBoris Popov return error; 755681a5bbeSBoris Popov } 756681a5bbeSBoris Popov 757681a5bbeSBoris Popov int 758681a5bbeSBoris Popov smb_t2_request(struct smb_t2rq *t2p) 759681a5bbeSBoris Popov { 760681a5bbeSBoris Popov int error = EINVAL, i; 761681a5bbeSBoris Popov 762681a5bbeSBoris Popov for (i = 0; i < SMB_MAXRCN; i++) { 763681a5bbeSBoris Popov t2p->t2_flags &= ~SMBR_RESTART; 764681a5bbeSBoris Popov error = smb_t2_request_int(t2p); 765681a5bbeSBoris Popov if (error == 0) 766681a5bbeSBoris Popov break; 767681a5bbeSBoris Popov if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART) 768681a5bbeSBoris Popov break; 769681a5bbeSBoris Popov } 770681a5bbeSBoris Popov return error; 771681a5bbeSBoris Popov } 772