Print this page
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
SUP-538 System panic in NULL pointer dereference in nsmb'nbssn_peekhdr().


  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. */


 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);


 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;


 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 };


  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. */


 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);


 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;


 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 };