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().

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
          +++ new/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
↓ open down ↓ 26 lines elided ↑ open up ↑
  27   27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28   28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29   29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30   30   * SUCH DAMAGE.
  31   31   *
  32   32   * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
  33   33   */
  34   34  /*
  35   35   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  36   36   * Use is subject to license terms.
  37      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       37 + *
       38 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  38   39   */
  39   40  
  40   41  #include <sys/param.h>
  41   42  #include <sys/systm.h>
  42   43  #include <sys/autoconf.h>
  43   44  #include <sys/sysmacros.h>
  44   45  #include <sys/sunddi.h>
  45   46  #include <sys/kmem.h>
  46   47  #include <sys/proc.h>
  47   48  #include <sys/protosw.h>
↓ open down ↓ 18 lines elided ↑ open up ↑
  66   67  #include <netsmb/smb_osdep.h>
  67   68  #include <netsmb/mchain.h>
  68   69  #include <netsmb/netbios.h>
  69   70  
  70   71  #include <netsmb/smb.h>
  71   72  #include <netsmb/smb_conn.h>
  72   73  #include <netsmb/smb_subr.h>
  73   74  #include <netsmb/smb_tran.h>
  74   75  #include <netsmb/smb_trantcp.h>
  75   76  
  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   77  static int  nb_disconnect(struct nbpcb *nbp);
  84   78  
  85   79  
  86   80  /*
  87   81   * Get mblks into *mpp until the data length is at least mlen.
  88   82   * Note that *mpp may already contain a fragment.
  89   83   *
  90   84   * If we ever have to wait more than 15 sec. to read a message,
  91   85   * return ETIME.  (Caller will declare the VD dead.)
  92   86   */
↓ open down ↓ 63 lines elided ↑ open up ↑
 156  150                          case T_DATA_IND:
 157  151                                  /* remove 1st mblk, keep the rest. */
 158  152                                  im = tm->b_cont;
 159  153                                  tm->b_cont = NULL;
 160  154                                  freeb(tm);
 161  155                                  tm = im;
 162  156                                  break;
 163  157                          case T_DISCON_IND:
 164  158                                  /* Peer disconnected. */
 165  159                                  NBDEBUG("T_DISCON_IND: reason=%d",
 166      -                                    pptr->discon_ind.DISCON_reason);
      160 +                                    (int)pptr->discon_ind.DISCON_reason);
 167  161                                  goto discon;
 168  162                          case T_ORDREL_IND:
 169  163                                  /* Peer disconnecting. */
 170  164                                  NBDEBUG("T_ORDREL_IND");
 171  165                                  goto discon;
 172  166                          case T_OK_ACK:
 173  167                                  switch (pptr->ok_ack.CORRECT_prim) {
 174  168                                  case T_DISCON_REQ:
 175  169                                          NBDEBUG("T_OK_ACK/T_DISCON_REQ");
 176  170                                          goto discon;
 177  171                                  default:
 178  172                                          NBDEBUG("T_OK_ACK/prim=%d",
 179      -                                            pptr->ok_ack.CORRECT_prim);
      173 +                                            (int)pptr->ok_ack.CORRECT_prim);
 180  174                                          goto discon;
 181  175                                  }
 182  176                          default:
 183      -                                NBDEBUG("M_PROTO/type=%d", pptr->type);
      177 +                                NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
 184  178                                  goto discon;
 185  179                          }
 186  180                          break; /* M_PROTO, M_PCPROTO */
 187  181  
 188  182                  default:
 189  183                          NBDEBUG("unexpected msg type=%d",
 190  184                              tm->b_datap->db_type);
 191  185                          /*FALLTHROUGH*/
 192  186  discon:
 193  187                          /*
↓ open down ↓ 284 lines elided ↑ open up ↑
 478  472          *rpcodep = rpcode;
 479  473          return (0);
 480  474  }
 481  475  
 482  476  /*
 483  477   * SMB transport interface
 484  478   *
 485  479   * This is called only by the thread creating this endpoint,
 486  480   * so we're single-threaded here.
 487  481   */
 488      -/*ARGSUSED*/
 489  482  static int
 490  483  smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
 491  484  {
 492      -        struct nbpcb *nbp;
      485 +        TIUSER *tiptr = NULL;
      486 +        struct nbpcb *nbp = NULL;
      487 +        dev_t dev;
      488 +        int rc;
      489 +        ushort_t fmode;
 493  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 +
 494  510          nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
 495  511  
 496  512          nbp->nbp_timo.tv_sec = SMB_NBTIMO;
 497      -        nbp->nbp_state = NBST_CLOSED; /* really IDLE */
      513 +        nbp->nbp_state = NBST_IDLE;
 498  514          nbp->nbp_vc = vcp;
 499      -        nbp->nbp_sndbuf = smb_tcpsndbuf;
 500      -        nbp->nbp_rcvbuf = smb_tcprcvbuf;
      515 +        nbp->nbp_tiptr = tiptr;
      516 +        nbp->nbp_fmode = fmode;
 501  517          nbp->nbp_cred = cr;
 502  518          crhold(cr);
 503  519          mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
      520 +
 504  521          vcp->vc_tdata = nbp;
 505  522  
 506  523          return (0);
 507  524  }
 508  525  
 509  526  /*
 510  527   * destroy a transport endpoint
 511  528   *
 512  529   * This is called only by the thread with the last reference
 513  530   * to this endpoint, so we're single-threaded here.
↓ open down ↓ 20 lines elided ↑ open up ↑
 534  551                  smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
 535  552          if (nbp->nbp_paddr)
 536  553                  smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
 537  554          if (nbp->nbp_cred)
 538  555                  crfree(nbp->nbp_cred);
 539  556          mutex_destroy(&nbp->nbp_lock);
 540  557          kmem_free(nbp, sizeof (*nbp));
 541  558          return (0);
 542  559  }
 543  560  
 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  561  static int
 550      -nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
      562 +smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
 551  563  {
 552      -        TIUSER *tiptr;
      564 +        struct nbpcb *nbp = vcp->vc_tdata;
      565 +        TIUSER *tiptr = nbp->nbp_tiptr;
 553  566          int err;
 554  567  
 555      -        err = t_kopen(fp, 0, 0, &tiptr, cr);
 556      -        if (err != 0)
 557      -                return (err);
      568 +        /* Only default bind supported. */
      569 +        if (sap != NULL)
      570 +                return (ENOTSUP);
 558  571  
 559      -        mutex_enter(&nbp->nbp_lock);
      572 +        err = t_kbind(tiptr, NULL, NULL);
 560  573  
 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);
      574 +        return (err);
 569  575  }
 570  576  
 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)
      577 +static int
      578 +smb_nbst_unbind(struct smb_vc *vcp)
 590  579  {
      580 +        struct nbpcb *nbp = vcp->vc_tdata;
      581 +        TIUSER *tiptr = nbp->nbp_tiptr;
      582 +        int err;
 591  583  
 592      -        mutex_enter(&nbp->nbp_lock);
      584 +        err = t_kunbind(tiptr);
 593  585  
 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);
      586 +        return (err);
 610  587  }
 611  588  
 612  589  static int
 613      -smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
      590 +smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
 614  591  {
 615      -        struct nbpcb *nbp = vcp->vc_tdata;
 616      -        int error = 0;
      592 +        struct t_call   call;
      593 +        struct nbpcb    *nbp = vcp->vc_tdata;
      594 +        TIUSER          *tiptr = nbp->nbp_tiptr;
      595 +        int alen, err;
 617  596  
 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);
      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);
 629  607          }
 630  608  
 631      -        return (error);
 632      -}
      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;
 633  614  
 634      -/*ARGSUSED*/
 635      -static int
 636      -smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
 637      -{
 638      -        return (ENOTSUP);
 639      -}
      615 +        err = t_kconnect(tiptr, &call, NULL);
      616 +        if (err != 0)
      617 +                return (err);
 640  618  
 641      -/*ARGSUSED*/
 642      -static int
 643      -smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
 644      -{
 645      -        return (ENOTSUP);
      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);
 646  627  }
 647  628  
 648      -/*ARGSUSED*/
 649  629  static int
 650  630  smb_nbst_disconnect(struct smb_vc *vcp)
 651  631  {
 652  632          struct nbpcb *nbp = vcp->vc_tdata;
 653  633  
 654  634          if (nbp == NULL)
 655  635                  return (ENOTCONN);
 656  636  
 657  637          return (nb_disconnect(nbp));
 658  638  }
↓ open down ↓ 166 lines elided ↑ open up ↑
 825  805   * Returns zero if input is available, otherwise ETIME
 826  806   * indicating time expired, or other error codes.
 827  807   */
 828  808  /*ARGSUSED*/
 829  809  static int
 830  810  smb_nbst_poll(struct smb_vc *vcp, int ticks)
 831  811  {
 832  812          return (ENOTSUP);
 833  813  }
 834  814  
      815 +/*ARGSUSED*/
 835  816  static int
 836  817  smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
 837  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;
 838  830          struct nbpcb *nbp = vcp->vc_tdata;
      831 +        int level, name, err;
 839  832  
 840  833          switch (param) {
 841      -        case SMBTP_SNDSZ:
 842      -                *(int *)data = nbp->nbp_sndbuf;
      834 +        case SMBTP_TCP_NODELAY:
      835 +                level = IPPROTO_TCP;
      836 +                name = TCP_NODELAY;
 843  837                  break;
 844      -        case SMBTP_RCVSZ:
 845      -                *(int *)data = nbp->nbp_rcvbuf;
      838 +
      839 +        case SMBTP_TCP_CON_TMO: /* int mSec */
      840 +                level = IPPROTO_TCP;
      841 +                name = TCP_CONN_ABORT_THRESHOLD;
 846  842                  break;
 847      -        case SMBTP_TIMEOUT:
 848      -                *(struct timespec *)data = nbp->nbp_timo;
      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;
 849  850                  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
      851 +
 860  852          default:
 861  853                  return (EINVAL);
 862  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 +
 863  886          return (0);
 864  887  }
 865  888  
 866      -/*ARGSUSED*/
 867      -static int
 868      -smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
 869      -{
 870      -        return (EINVAL);
 871      -}
 872      -
 873  889  /*
 874  890   * Check for fatal errors
 875  891   */
 876  892  /*ARGSUSED*/
 877  893  static int
 878  894  smb_nbst_fatal(struct smb_vc *vcp, int error)
 879  895  {
 880  896          switch (error) {
 881  897          case ENOTCONN:
 882  898          case ENETRESET:
↓ open down ↓ 3 lines elided ↑ open up ↑
 886  902          }
 887  903          return (0);
 888  904  }
 889  905  
 890  906  
 891  907  struct smb_tran_desc smb_tran_nbtcp_desc = {
 892  908          SMBT_NBTCP,
 893  909          smb_nbst_create,
 894  910          smb_nbst_done,
 895  911          smb_nbst_bind,
      912 +        smb_nbst_unbind,
 896  913          smb_nbst_connect,
 897  914          smb_nbst_disconnect,
 898  915          smb_nbst_send,
 899  916          smb_nbst_recv,
 900  917          smb_nbst_poll,
 901      -        smb_nbst_loan_fp,
 902  918          smb_nbst_getparam,
 903  919          smb_nbst_setparam,
 904  920          smb_nbst_fatal,
 905  921          {NULL, NULL}
 906  922  };
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX