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