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