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