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 * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $ 33 */ 34 /* 35 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 36 * Use is subject to license terms. 37 * 38 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/autoconf.h> 44 #include <sys/sysmacros.h> 45 #include <sys/sunddi.h> 46 #include <sys/kmem.h> 47 #include <sys/proc.h> 48 #include <sys/protosw.h> 49 #include <sys/socket.h> 50 #include <sys/poll.h> 51 #include <sys/stream.h> 52 #include <sys/strsubr.h> 53 #include <sys/strsun.h> 54 #include <sys/stropts.h> 55 #include <sys/cmn_err.h> 56 #include <sys/tihdr.h> 57 #include <sys/tiuser.h> 58 #include <sys/t_kuser.h> 59 #include <sys/priv.h> 60 61 #include <net/if.h> 62 #include <net/route.h> 63 64 #include <netinet/in.h> 65 #include <netinet/tcp.h> 66 67 #include <netsmb/smb_osdep.h> 68 #include <netsmb/mchain.h> 69 #include <netsmb/netbios.h> 70 71 #include <netsmb/smb.h> 72 #include <netsmb/smb_conn.h> 73 #include <netsmb/smb_subr.h> 74 #include <netsmb/smb_tran.h> 75 #include <netsmb/smb_trantcp.h> 76 77 /* 78 * SMB messages are up to 64K. 79 * Let's leave room for two. 80 */ 81 static int smb_tcpsndbuf = 0x20000; 82 static int smb_tcprcvbuf = 0x20000; 83 84 static int nb_disconnect(struct nbpcb *nbp); 85 86 87 /* 88 * Get mblks into *mpp until the data length is at least mlen. 89 * Note that *mpp may already contain a fragment. 90 * 91 * If we ever have to wait more than 15 sec. to read a message, 92 * return ETIME. (Caller will declare the VD dead.) 93 */ 94 static int 95 nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen) 96 { 97 mblk_t *im, *tm; 98 union T_primitives *pptr; 99 size_t dlen; 100 int events, fmode, timo, waitflg; 101 int error = 0; 102 103 /* We should be the only reader. */ 104 ASSERT(nbp->nbp_flags & NBF_RECVLOCK); 105 /* nbp->nbp_tiptr checked by caller */ 106 107 /* 108 * Get the first message (fragment) if 109 * we don't already have a left-over. 110 */ 111 dlen = msgdsize(*mpp); /* *mpp==null is OK */ 112 while (dlen < mlen) { 113 114 /* 115 * I think we still want this to return ETIME 116 * if nothing arrives for SMB_NBTIMO (15) sec. 117 * so we can report "server not responding". 118 * We _could_ just block here now that our 119 * IOD is just a reader. 120 */ 121 #if 1 122 /* Wait with timeout... */ 123 events = 0; 124 waitflg = READWAIT; 125 timo = SEC_TO_TICK(SMB_NBTIMO); 126 error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events); 127 if (!error && !events) 128 error = ETIME; 129 if (error) 130 break; 131 /* file mode for recv is: */ 132 fmode = FNDELAY; /* non-blocking */ 133 #else 134 fmode = 0; /* normal (blocking) */ 135 #endif 136 137 /* Get some more... */ 138 tm = NULL; 139 error = tli_recv(nbp->nbp_tiptr, &tm, fmode); 140 if (error == EAGAIN) 141 continue; 142 if (error) 143 break; 144 145 /* 146 * Normally get M_DATA messages here, 147 * but have to check for other types. 148 */ 149 switch (tm->b_datap->db_type) { 150 case M_DATA: 151 break; 152 case M_PROTO: 153 case M_PCPROTO: 154 /*LINTED*/ 155 pptr = (union T_primitives *)tm->b_rptr; 156 switch (pptr->type) { 157 case T_DATA_IND: 158 /* remove 1st mblk, keep the rest. */ 159 im = tm->b_cont; 160 tm->b_cont = NULL; 161 freeb(tm); 162 tm = im; 163 break; 164 case T_DISCON_IND: 165 /* Peer disconnected. */ 166 NBDEBUG("T_DISCON_IND: reason=%d", 167 (int)pptr->discon_ind.DISCON_reason); 168 goto discon; 169 case T_ORDREL_IND: 170 /* Peer disconnecting. */ 171 NBDEBUG("T_ORDREL_IND"); 172 goto discon; 173 case T_OK_ACK: 174 switch (pptr->ok_ack.CORRECT_prim) { 175 case T_DISCON_REQ: 176 NBDEBUG("T_OK_ACK/T_DISCON_REQ"); 177 goto discon; 178 default: 179 NBDEBUG("T_OK_ACK/prim=%d", 180 (int)pptr->ok_ack.CORRECT_prim); 181 goto discon; 182 } 183 default: 184 NBDEBUG("M_PROTO/type=%d", (int)pptr->type); 185 goto discon; 186 } 187 break; /* M_PROTO, M_PCPROTO */ 188 189 default: 190 NBDEBUG("unexpected msg type=%d", 191 tm->b_datap->db_type); 192 /*FALLTHROUGH*/ 193 discon: 194 /* 195 * The connection is no longer usable. 196 * Drop this message and disconnect. 197 * 198 * Note: nb_disconnect only does t_snddis 199 * on the first call, but does important 200 * cleanup and state change on any call. 201 */ 202 freemsg(tm); 203 (void) nb_disconnect(nbp); 204 return (ENOTCONN); 205 } 206 207 /* 208 * If we have a data message, append it to 209 * the previous chunk(s) and update dlen 210 */ 211 if (!tm) 212 continue; 213 if (*mpp == NULL) { 214 *mpp = tm; 215 } else { 216 /* Append */ 217 for (im = *mpp; im->b_cont; im = im->b_cont) 218 ; 219 im->b_cont = tm; 220 } 221 dlen += msgdsize(tm); 222 } 223 224 return (error); 225 } 226 227 /* 228 * Send a T_DISCON_REQ (disconnect) 229 */ 230 static int 231 nb_snddis(struct nbpcb *nbp) 232 { 233 TIUSER *tiptr = nbp->nbp_tiptr; 234 cred_t *cr = nbp->nbp_cred; 235 mblk_t *mp; 236 struct T_discon_req *dreq; 237 int error, mlen; 238 239 ASSERT(MUTEX_HELD(&nbp->nbp_lock)); 240 241 if (tiptr == NULL) 242 return (EBADF); 243 244 mlen = sizeof (struct T_discon_req); 245 if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID))) 246 return (error); 247 248 mp->b_datap->db_type = M_PROTO; 249 /*LINTED*/ 250 dreq = (struct T_discon_req *)mp->b_wptr; 251 dreq->PRIM_type = T_DISCON_REQ; 252 dreq->SEQ_number = -1; 253 mp->b_wptr += sizeof (struct T_discon_req); 254 255 error = tli_send(tiptr, mp, tiptr->fp->f_flag); 256 /* 257 * There is an OK/ACK response expected, which is 258 * either handled by our receiver thread, or just 259 * discarded if we're closing this endpoint. 260 */ 261 262 return (error); 263 } 264 265 /* 266 * Stuff the NetBIOS header into space already prepended. 267 */ 268 static void 269 nb_sethdr(mblk_t *m, uint8_t type, uint32_t len) 270 { 271 uint32_t *p; 272 273 len &= 0x1FFFF; 274 len |= (type << 24); 275 276 /*LINTED*/ 277 p = (uint32_t *)m->b_rptr; 278 *p = htonl(len); 279 } 280 281 /* 282 * Wait for up to 15 sec. for the next packet. 283 * Often return ETIME and do nothing else. 284 * When a packet header is available, check 285 * the header and get the length, but don't 286 * consume it. No side effects here except 287 * for the pullupmsg call. 288 */ 289 static int 290 nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep) 291 { 292 uint32_t len, *hdr; 293 int error; 294 295 /* 296 * Get the first message (fragment) if 297 * we don't already have a left-over. 298 */ 299 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len)); 300 if (error) 301 return (error); 302 303 if (!pullupmsg(nbp->nbp_frag, sizeof (len))) 304 return (ENOSR); 305 306 /* 307 * Check the NetBIOS header. 308 * (NOT consumed here) 309 */ 310 /*LINTED*/ 311 hdr = (uint32_t *)nbp->nbp_frag->b_rptr; 312 313 len = ntohl(*hdr); 314 if ((len >> 16) & 0xFE) { 315 NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len); 316 return (EPIPE); 317 } 318 *rpcodep = (len >> 24) & 0xFF; 319 switch (*rpcodep) { 320 case NB_SSN_MESSAGE: 321 case NB_SSN_REQUEST: 322 case NB_SSN_POSRESP: 323 case NB_SSN_NEGRESP: 324 case NB_SSN_RTGRESP: 325 case NB_SSN_KEEPALIVE: 326 break; 327 default: 328 NBDEBUG("bad nb header received 0x%x (bogus type)\n", len); 329 return (EPIPE); 330 } 331 len &= 0x1ffff; 332 if (len > NB_MAXPKTLEN) { 333 NBDEBUG("packet too long (%d)\n", len); 334 return (EFBIG); 335 } 336 *lenp = len; 337 return (0); 338 } 339 340 /* 341 * Receive a NetBIOS message. This may block to wait for the entire 342 * message to arrive. The caller knows there is (or should be) a 343 * message to be read. When we receive and drop a keepalive or 344 * zero-length message, return EAGAIN so the caller knows that 345 * something was received. This avoids false triggering of the 346 * "server not responding" state machine. 347 * 348 * Calls to this are serialized at a higher level. 349 */ 350 static int 351 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp, 352 uint8_t *rpcodep) 353 { 354 mblk_t *m0; 355 uint8_t rpcode; 356 int error; 357 size_t rlen, len; 358 359 /* We should be the only reader. */ 360 ASSERT(nbp->nbp_flags & NBF_RECVLOCK); 361 362 if (nbp->nbp_tiptr == NULL) 363 return (EBADF); 364 if (mpp) { 365 if (*mpp) { 366 NBDEBUG("*mpp not 0 - leak?"); 367 } 368 *mpp = NULL; 369 } 370 m0 = NULL; 371 372 /* 373 * Get the NetBIOS header (not consumed yet) 374 */ 375 error = nbssn_peekhdr(nbp, &len, &rpcode); 376 if (error) { 377 if (error != ETIME) 378 NBDEBUG("peekhdr, error=%d\n", error); 379 return (error); 380 } 381 NBDEBUG("Have pkt, type=0x%x len=0x%x\n", 382 (int)rpcode, (int)len); 383 384 /* 385 * Block here waiting for the whole packet to arrive. 386 * If we get a timeout, return without side effects. 387 * The data length we wait for here includes both the 388 * NetBIOS header and the payload. 389 */ 390 error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4); 391 if (error) { 392 NBDEBUG("getmsg(body), error=%d\n", error); 393 return (error); 394 } 395 396 /* 397 * We now have an entire NetBIOS message. 398 * Trim off the NetBIOS header and consume it. 399 * Note: _peekhdr has done pullupmsg for us, 400 * so we know it's safe to advance b_rptr. 401 */ 402 m0 = nbp->nbp_frag; 403 m0->b_rptr += 4; 404 405 /* 406 * There may be more data after the message 407 * we're about to return, in which case we 408 * split it and leave the remainder. 409 */ 410 rlen = msgdsize(m0); 411 ASSERT(rlen >= len); 412 nbp->nbp_frag = NULL; 413 if (rlen > len) 414 nbp->nbp_frag = m_split(m0, len, 1); 415 416 if (nbp->nbp_state != NBST_SESSION) { 417 /* 418 * No session is established. 419 * Return whatever packet we got. 420 */ 421 goto out; 422 } 423 424 /* 425 * A session is established; the only packets 426 * we should see are session message and 427 * keep-alive packets. Drop anything else. 428 */ 429 switch (rpcode) { 430 431 case NB_SSN_KEEPALIVE: 432 /* 433 * It's a keepalive. Discard any data in it 434 * (there's not supposed to be any, but that 435 * doesn't mean some server won't send some) 436 */ 437 if (len) 438 NBDEBUG("Keepalive with data %d\n", (int)len); 439 error = EAGAIN; 440 break; 441 442 case NB_SSN_MESSAGE: 443 /* 444 * Session message. Does it have any data? 445 */ 446 if (len == 0) { 447 /* 448 * No data - treat as keepalive (drop). 449 */ 450 error = EAGAIN; 451 break; 452 } 453 /* 454 * Yes, has data. Return it. 455 */ 456 error = 0; 457 break; 458 459 default: 460 /* 461 * Drop anything else. 462 */ 463 NBDEBUG("non-session packet %x\n", rpcode); 464 error = EAGAIN; 465 break; 466 } 467 468 out: 469 if (error) { 470 if (m0) 471 m_freem(m0); 472 return (error); 473 } 474 if (mpp) 475 *mpp = m0; 476 else 477 m_freem(m0); 478 *lenp = (int)len; 479 *rpcodep = rpcode; 480 return (0); 481 } 482 483 /* 484 * SMB transport interface 485 * 486 * This is called only by the thread creating this endpoint, 487 * so we're single-threaded here. 488 */ 489 /*ARGSUSED*/ 490 static int 491 smb_nbst_create(struct smb_vc *vcp, cred_t *cr) 492 { 493 struct nbpcb *nbp; 494 495 nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP); 496 497 nbp->nbp_timo.tv_sec = SMB_NBTIMO; 498 nbp->nbp_state = NBST_CLOSED; /* really IDLE */ 499 nbp->nbp_vc = vcp; 500 nbp->nbp_sndbuf = smb_tcpsndbuf; 501 nbp->nbp_rcvbuf = smb_tcprcvbuf; 502 nbp->nbp_cred = cr; 503 crhold(cr); 504 mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL); 505 vcp->vc_tdata = nbp; 506 507 return (0); 508 } 509 510 /* 511 * destroy a transport endpoint 512 * 513 * This is called only by the thread with the last reference 514 * to this endpoint, so we're single-threaded here. 515 */ 516 static int 517 smb_nbst_done(struct smb_vc *vcp) 518 { 519 struct nbpcb *nbp = vcp->vc_tdata; 520 521 if (nbp == NULL) 522 return (ENOTCONN); 523 vcp->vc_tdata = NULL; 524 525 /* 526 * Don't really need to disconnect here, 527 * because the close following will do it. 528 * But it's harmless. 529 */ 530 if (nbp->nbp_flags & NBF_CONNECTED) 531 (void) nb_disconnect(nbp); 532 if (nbp->nbp_tiptr) 533 (void) t_kclose(nbp->nbp_tiptr, 0); 534 if (nbp->nbp_laddr) 535 smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr); 536 if (nbp->nbp_paddr) 537 smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr); 538 if (nbp->nbp_cred) 539 crfree(nbp->nbp_cred); 540 mutex_destroy(&nbp->nbp_lock); 541 kmem_free(nbp, sizeof (*nbp)); 542 return (0); 543 } 544 545 /* 546 * Loan a transport file pointer (from user space) to this 547 * IOD endpoint. There should be no other thread using this 548 * endpoint when we do this, but lock for consistency. 549 */ 550 static int 551 nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr) 552 { 553 TIUSER *tiptr; 554 int err; 555 556 err = t_kopen(fp, 0, 0, &tiptr, cr); 557 if (err != 0) 558 return (err); 559 560 mutex_enter(&nbp->nbp_lock); 561 562 nbp->nbp_tiptr = tiptr; 563 nbp->nbp_fmode = tiptr->fp->f_flag; 564 nbp->nbp_flags |= NBF_CONNECTED; 565 nbp->nbp_state = NBST_SESSION; 566 567 mutex_exit(&nbp->nbp_lock); 568 569 return (0); 570 } 571 572 /* 573 * Take back the transport file pointer we previously loaned. 574 * It's possible there may be another thread in here, so let 575 * others get out of the way before we pull the rug out. 576 * 577 * Some notes about the locking here: The higher-level IOD code 578 * serializes activity such that at most one reader and writer 579 * thread can be active in this code (and possibly both). 580 * Keeping nbp_lock held during the activities of these two 581 * threads would lead to the possibility of nbp_lock being 582 * held by a blocked thread, so this instead sets one of the 583 * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a 584 * receiver is active (respectively). Lastly, tear-down is 585 * the only tricky bit (here) where we must wait for any of 586 * these activities to get out of current calls so they will 587 * notice that we've turned off the NBF_CONNECTED flag. 588 */ 589 static void 590 nb_unloan_fp(struct nbpcb *nbp) 591 { 592 593 mutex_enter(&nbp->nbp_lock); 594 595 nbp->nbp_flags &= ~NBF_CONNECTED; 596 while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) { 597 nbp->nbp_flags |= NBF_LOCKWAIT; 598 cv_wait(&nbp->nbp_cv, &nbp->nbp_lock); 599 } 600 if (nbp->nbp_frag != NULL) { 601 freemsg(nbp->nbp_frag); 602 nbp->nbp_frag = NULL; 603 } 604 if (nbp->nbp_tiptr != NULL) { 605 (void) t_kclose(nbp->nbp_tiptr, 0); 606 nbp->nbp_tiptr = NULL; 607 } 608 nbp->nbp_state = NBST_CLOSED; 609 610 mutex_exit(&nbp->nbp_lock); 611 } 612 613 static int 614 smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr) 615 { 616 struct nbpcb *nbp = vcp->vc_tdata; 617 int error = 0; 618 619 /* 620 * Un-loan the existing one, if any. 621 */ 622 (void) nb_disconnect(nbp); 623 nb_unloan_fp(nbp); 624 625 /* 626 * Loan the new one passed in. 627 */ 628 if (fp != NULL) { 629 error = nb_loan_fp(nbp, fp, cr); 630 } 631 632 return (error); 633 } 634 635 /*ARGSUSED*/ 636 static int 637 smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap) 638 { 639 return (ENOTSUP); 640 } 641 642 /*ARGSUSED*/ 643 static int 644 smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap) 645 { 646 return (ENOTSUP); 647 } 648 649 /*ARGSUSED*/ 650 static int 651 smb_nbst_disconnect(struct smb_vc *vcp) 652 { 653 struct nbpcb *nbp = vcp->vc_tdata; 654 655 if (nbp == NULL) 656 return (ENOTCONN); 657 658 return (nb_disconnect(nbp)); 659 } 660 661 static int 662 nb_disconnect(struct nbpcb *nbp) 663 { 664 int err = 0; 665 666 mutex_enter(&nbp->nbp_lock); 667 668 if ((nbp->nbp_flags & NBF_CONNECTED) != 0) { 669 nbp->nbp_flags &= ~NBF_CONNECTED; 670 err = nb_snddis(nbp); 671 } 672 673 mutex_exit(&nbp->nbp_lock); 674 return (err); 675 } 676 677 /* 678 * Add the NetBIOS session header and send. 679 * 680 * Calls to this are serialized at a higher level. 681 */ 682 static int 683 nbssn_send(struct nbpcb *nbp, mblk_t *m) 684 { 685 ptrdiff_t diff; 686 uint32_t mlen; 687 int error; 688 689 /* We should be the only sender. */ 690 ASSERT(nbp->nbp_flags & NBF_SENDLOCK); 691 692 if (nbp->nbp_tiptr == NULL) { 693 error = EBADF; 694 goto errout; 695 } 696 697 /* 698 * Get the message length, which 699 * does NOT include the NetBIOS header 700 */ 701 mlen = msgdsize(m); 702 703 /* 704 * Normally, mb_init() will have left space 705 * for us to prepend the NetBIOS header in 706 * the data block of the first mblk. 707 * However, we have to check in case other 708 * code did not leave this space, or if the 709 * message is from dupmsg (db_ref > 1) 710 * 711 * If don't find room in the first data block, 712 * we have to allocb a new message and link it 713 * on the front of the chain. We try not to 714 * do this becuase it's less efficient. Also, 715 * some network drivers will apparently send 716 * each mblk in the chain as separate frames. 717 * (That's arguably a driver bug.) 718 * 719 * Not bothering with allocb_cred_wait below 720 * because the message we're prepending to 721 * should already have a db_credp. 722 */ 723 724 diff = MBLKHEAD(m); 725 if (diff == 4 && DB_REF(m) == 1) { 726 /* We can use the first dblk. */ 727 m->b_rptr -= 4; 728 } else { 729 /* Link a new mblk on the head. */ 730 mblk_t *m0; 731 732 /* M_PREPEND */ 733 m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error); 734 if (m0 == NULL) 735 goto errout; 736 737 m0->b_wptr += 4; 738 m0->b_cont = m; 739 m = m0; 740 } 741 742 nb_sethdr(m, NB_SSN_MESSAGE, mlen); 743 error = tli_send(nbp->nbp_tiptr, m, 0); 744 return (error); 745 746 errout: 747 if (m != NULL) 748 m_freem(m); 749 return (error); 750 } 751 752 /* 753 * Always consume the message. 754 * (On error too!) 755 */ 756 static int 757 smb_nbst_send(struct smb_vc *vcp, mblk_t *m) 758 { 759 struct nbpcb *nbp = vcp->vc_tdata; 760 int err; 761 762 mutex_enter(&nbp->nbp_lock); 763 if ((nbp->nbp_flags & NBF_CONNECTED) == 0) { 764 err = ENOTCONN; 765 goto out; 766 } 767 if (nbp->nbp_flags & NBF_SENDLOCK) { 768 NBDEBUG("multiple smb_nbst_send!\n"); 769 err = EWOULDBLOCK; 770 goto out; 771 } 772 nbp->nbp_flags |= NBF_SENDLOCK; 773 mutex_exit(&nbp->nbp_lock); 774 775 err = nbssn_send(nbp, m); 776 m = NULL; /* nbssn_send always consumes this */ 777 778 mutex_enter(&nbp->nbp_lock); 779 nbp->nbp_flags &= ~NBF_SENDLOCK; 780 if (nbp->nbp_flags & NBF_LOCKWAIT) { 781 nbp->nbp_flags &= ~NBF_LOCKWAIT; 782 cv_broadcast(&nbp->nbp_cv); 783 } 784 out: 785 mutex_exit(&nbp->nbp_lock); 786 if (m != NULL) 787 m_freem(m); 788 return (err); 789 } 790 791 static int 792 smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp) 793 { 794 struct nbpcb *nbp = vcp->vc_tdata; 795 uint8_t rpcode; 796 int err, rplen; 797 798 mutex_enter(&nbp->nbp_lock); 799 if ((nbp->nbp_flags & NBF_CONNECTED) == 0) { 800 err = ENOTCONN; 801 goto out; 802 } 803 if (nbp->nbp_flags & NBF_RECVLOCK) { 804 NBDEBUG("multiple smb_nbst_recv!\n"); 805 err = EWOULDBLOCK; 806 goto out; 807 } 808 nbp->nbp_flags |= NBF_RECVLOCK; 809 mutex_exit(&nbp->nbp_lock); 810 811 err = nbssn_recv(nbp, mpp, &rplen, &rpcode); 812 813 mutex_enter(&nbp->nbp_lock); 814 nbp->nbp_flags &= ~NBF_RECVLOCK; 815 if (nbp->nbp_flags & NBF_LOCKWAIT) { 816 nbp->nbp_flags &= ~NBF_LOCKWAIT; 817 cv_broadcast(&nbp->nbp_cv); 818 } 819 out: 820 mutex_exit(&nbp->nbp_lock); 821 return (err); 822 } 823 824 /* 825 * Wait for up to "ticks" clock ticks for input on vcp. 826 * Returns zero if input is available, otherwise ETIME 827 * indicating time expired, or other error codes. 828 */ 829 /*ARGSUSED*/ 830 static int 831 smb_nbst_poll(struct smb_vc *vcp, int ticks) 832 { 833 return (ENOTSUP); 834 } 835 836 static int 837 smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) 838 { 839 struct nbpcb *nbp = vcp->vc_tdata; 840 841 switch (param) { 842 case SMBTP_SNDSZ: 843 *(int *)data = nbp->nbp_sndbuf; 844 break; 845 case SMBTP_RCVSZ: 846 *(int *)data = nbp->nbp_rcvbuf; 847 break; 848 case SMBTP_TIMEOUT: 849 *(struct timespec *)data = nbp->nbp_timo; 850 break; 851 #ifdef SMBTP_SELECTID 852 case SMBTP_SELECTID: 853 *(void **)data = nbp->nbp_selectid; 854 break; 855 #endif 856 #ifdef SMBTP_UPCALL 857 case SMBTP_UPCALL: 858 *(void **)data = nbp->nbp_upcall; 859 break; 860 #endif 861 default: 862 return (EINVAL); 863 } 864 return (0); 865 } 866 867 /*ARGSUSED*/ 868 static int 869 smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) 870 { 871 return (EINVAL); 872 } 873 874 /* 875 * Check for fatal errors 876 */ 877 /*ARGSUSED*/ 878 static int 879 smb_nbst_fatal(struct smb_vc *vcp, int error) 880 { 881 switch (error) { 882 case ENOTCONN: 883 case ENETRESET: 884 case ECONNABORTED: 885 case EPIPE: 886 return (1); 887 } 888 return (0); 889 } 890 891 892 struct smb_tran_desc smb_tran_nbtcp_desc = { 893 SMBT_NBTCP, 894 smb_nbst_create, 895 smb_nbst_done, 896 smb_nbst_bind, 897 smb_nbst_connect, 898 smb_nbst_disconnect, 899 smb_nbst_send, 900 smb_nbst_recv, 901 smb_nbst_poll, 902 smb_nbst_loan_fp, 903 smb_nbst_getparam, 904 smb_nbst_setparam, 905 smb_nbst_fatal, 906 {NULL, NULL} 907 }; 908