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