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