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