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().
*** 32,42 ****
* $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
! * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/autoconf.h>
--- 32,43 ----
* $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
! *
! * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/autoconf.h>
*** 71,87 ****
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
- /*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
- static int smb_tcpsndbuf = 0x20000;
- static int smb_tcprcvbuf = 0x20000;
-
static int nb_disconnect(struct nbpcb *nbp);
/*
* Get mblks into *mpp until the data length is at least mlen.
--- 72,81 ----
*** 161,171 ****
tm = im;
break;
case T_DISCON_IND:
/* Peer disconnected. */
NBDEBUG("T_DISCON_IND: reason=%d",
! pptr->discon_ind.DISCON_reason);
goto discon;
case T_ORDREL_IND:
/* Peer disconnecting. */
NBDEBUG("T_ORDREL_IND");
goto discon;
--- 155,165 ----
tm = im;
break;
case T_DISCON_IND:
/* Peer disconnected. */
NBDEBUG("T_DISCON_IND: reason=%d",
! (int)pptr->discon_ind.DISCON_reason);
goto discon;
case T_ORDREL_IND:
/* Peer disconnecting. */
NBDEBUG("T_ORDREL_IND");
goto discon;
*** 174,188 ****
case T_DISCON_REQ:
NBDEBUG("T_OK_ACK/T_DISCON_REQ");
goto discon;
default:
NBDEBUG("T_OK_ACK/prim=%d",
! pptr->ok_ack.CORRECT_prim);
goto discon;
}
default:
! NBDEBUG("M_PROTO/type=%d", pptr->type);
goto discon;
}
break; /* M_PROTO, M_PCPROTO */
default:
--- 168,182 ----
case T_DISCON_REQ:
NBDEBUG("T_OK_ACK/T_DISCON_REQ");
goto discon;
default:
NBDEBUG("T_OK_ACK/prim=%d",
! (int)pptr->ok_ack.CORRECT_prim);
goto discon;
}
default:
! NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
goto discon;
}
break; /* M_PROTO, M_PCPROTO */
default:
*** 483,508 ****
* SMB transport interface
*
* This is called only by the thread creating this endpoint,
* so we're single-threaded here.
*/
- /*ARGSUSED*/
static int
smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
! struct nbpcb *nbp;
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
! nbp->nbp_state = NBST_CLOSED; /* really IDLE */
nbp->nbp_vc = vcp;
! nbp->nbp_sndbuf = smb_tcpsndbuf;
! nbp->nbp_rcvbuf = smb_tcprcvbuf;
nbp->nbp_cred = cr;
crhold(cr);
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
vcp->vc_tdata = nbp;
return (0);
}
--- 477,525 ----
* SMB transport interface
*
* This is called only by the thread creating this endpoint,
* so we're single-threaded here.
*/
static int
smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
! TIUSER *tiptr = NULL;
! struct nbpcb *nbp = NULL;
! dev_t dev;
! int rc;
! ushort_t fmode;
+ switch (vcp->vc_srvaddr.sa.sa_family) {
+ case AF_INET:
+ dev = nsmb_dev_tcp;
+ break;
+ case AF_INET6:
+ dev = nsmb_dev_tcp6;
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ fmode = FREAD|FWRITE;
+ rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
+ return (rc);
+ }
+ ASSERT(tiptr != NULL);
+
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
! nbp->nbp_state = NBST_IDLE;
nbp->nbp_vc = vcp;
! nbp->nbp_tiptr = tiptr;
! nbp->nbp_fmode = fmode;
nbp->nbp_cred = cr;
crhold(cr);
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
+
vcp->vc_tdata = nbp;
return (0);
}
*** 539,653 ****
mutex_destroy(&nbp->nbp_lock);
kmem_free(nbp, sizeof (*nbp));
return (0);
}
- /*
- * Loan a transport file pointer (from user space) to this
- * IOD endpoint. There should be no other thread using this
- * endpoint when we do this, but lock for consistency.
- */
static int
! nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
{
! TIUSER *tiptr;
int err;
! err = t_kopen(fp, 0, 0, &tiptr, cr);
! if (err != 0)
! return (err);
! mutex_enter(&nbp->nbp_lock);
! nbp->nbp_tiptr = tiptr;
! nbp->nbp_fmode = tiptr->fp->f_flag;
! nbp->nbp_flags |= NBF_CONNECTED;
! nbp->nbp_state = NBST_SESSION;
!
! mutex_exit(&nbp->nbp_lock);
!
! return (0);
}
! /*
! * Take back the transport file pointer we previously loaned.
! * It's possible there may be another thread in here, so let
! * others get out of the way before we pull the rug out.
! *
! * Some notes about the locking here: The higher-level IOD code
! * serializes activity such that at most one reader and writer
! * thread can be active in this code (and possibly both).
! * Keeping nbp_lock held during the activities of these two
! * threads would lead to the possibility of nbp_lock being
! * held by a blocked thread, so this instead sets one of the
! * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a
! * receiver is active (respectively). Lastly, tear-down is
! * the only tricky bit (here) where we must wait for any of
! * these activities to get out of current calls so they will
! * notice that we've turned off the NBF_CONNECTED flag.
! */
! static void
! nb_unloan_fp(struct nbpcb *nbp)
{
! mutex_enter(&nbp->nbp_lock);
! nbp->nbp_flags &= ~NBF_CONNECTED;
! while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) {
! nbp->nbp_flags |= NBF_LOCKWAIT;
! cv_wait(&nbp->nbp_cv, &nbp->nbp_lock);
! }
! if (nbp->nbp_frag != NULL) {
! freemsg(nbp->nbp_frag);
! nbp->nbp_frag = NULL;
! }
! if (nbp->nbp_tiptr != NULL) {
! (void) t_kclose(nbp->nbp_tiptr, 0);
! nbp->nbp_tiptr = NULL;
! }
! nbp->nbp_state = NBST_CLOSED;
!
! mutex_exit(&nbp->nbp_lock);
}
static int
! smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
{
struct nbpcb *nbp = vcp->vc_tdata;
! int error = 0;
! /*
! * Un-loan the existing one, if any.
! */
! (void) nb_disconnect(nbp);
! nb_unloan_fp(nbp);
!
! /*
! * Loan the new one passed in.
! */
! if (fp != NULL) {
! error = nb_loan_fp(nbp, fp, cr);
}
! return (error);
! }
! /*ARGSUSED*/
! static int
! smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
! {
! return (ENOTSUP);
! }
! /*ARGSUSED*/
! static int
! smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
! {
! return (ENOTSUP);
}
- /*ARGSUSED*/
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
struct nbpcb *nbp = vcp->vc_tdata;
--- 556,633 ----
mutex_destroy(&nbp->nbp_lock);
kmem_free(nbp, sizeof (*nbp));
return (0);
}
static int
! smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
! struct nbpcb *nbp = vcp->vc_tdata;
! TIUSER *tiptr = nbp->nbp_tiptr;
int err;
! /* Only default bind supported. */
! if (sap != NULL)
! return (ENOTSUP);
! err = t_kbind(tiptr, NULL, NULL);
! return (err);
}
! static int
! smb_nbst_unbind(struct smb_vc *vcp)
{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
! err = t_kunbind(tiptr);
! return (err);
}
static int
! smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
{
+ struct t_call call;
struct nbpcb *nbp = vcp->vc_tdata;
! TIUSER *tiptr = nbp->nbp_tiptr;
! int alen, err;
! /* Need the address length */
! switch (sap->sa_family) {
! case AF_INET:
! alen = sizeof (struct sockaddr_in);
! break;
! case AF_INET6:
! alen = sizeof (struct sockaddr_in6);
! break;
! default:
! return (EAFNOSUPPORT);
}
! /* sockaddr goes in the "addr" netbuf */
! bzero(&call, sizeof (call));
! call.addr.buf = (char *)sap;
! call.addr.len = alen;
! call.addr.maxlen = alen;
! err = t_kconnect(tiptr, &call, NULL);
! if (err != 0)
! return (err);
! mutex_enter(&nbp->nbp_lock);
!
! nbp->nbp_flags |= NBF_CONNECTED;
! nbp->nbp_state = NBST_SESSION;
!
! mutex_exit(&nbp->nbp_lock);
!
! return (0);
}
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
struct nbpcb *nbp = vcp->vc_tdata;
*** 830,877 ****
smb_nbst_poll(struct smb_vc *vcp, int ticks)
{
return (ENOTSUP);
}
static int
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
{
struct nbpcb *nbp = vcp->vc_tdata;
switch (param) {
! case SMBTP_SNDSZ:
! *(int *)data = nbp->nbp_sndbuf;
break;
! case SMBTP_RCVSZ:
! *(int *)data = nbp->nbp_rcvbuf;
break;
! case SMBTP_TIMEOUT:
! *(struct timespec *)data = nbp->nbp_timo;
break;
! #ifdef SMBTP_SELECTID
! case SMBTP_SELECTID:
! *(void **)data = nbp->nbp_selectid;
! break;
! #endif
! #ifdef SMBTP_UPCALL
! case SMBTP_UPCALL:
! *(void **)data = nbp->nbp_upcall;
! break;
! #endif
default:
return (EINVAL);
}
return (0);
}
- /*ARGSUSED*/
- static int
- smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
- {
- return (EINVAL);
- }
-
/*
* Check for fatal errors
*/
/*ARGSUSED*/
static int
--- 810,893 ----
smb_nbst_poll(struct smb_vc *vcp, int ticks)
{
return (ENOTSUP);
}
+ /*ARGSUSED*/
static int
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
{
+ return (EINVAL);
+ }
+
+ static int
+ smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+ {
+ struct t_optmgmt oreq, ores;
+ struct {
+ struct T_opthdr oh;
+ int ival;
+ } opts;
struct nbpcb *nbp = vcp->vc_tdata;
+ int level, name, err;
switch (param) {
! case SMBTP_TCP_NODELAY:
! level = IPPROTO_TCP;
! name = TCP_NODELAY;
break;
!
! case SMBTP_TCP_CON_TMO: /* int mSec */
! level = IPPROTO_TCP;
! name = TCP_CONN_ABORT_THRESHOLD;
break;
!
! case SMBTP_KEEPALIVE: // SO_KEEPALIVE
! case SMBTP_SNDBUF: // SO_SNDBUF
! case SMBTP_RCVBUF: // SO_RCVBUF
! case SMBTP_RCVTIMEO: // SO_RCVTIMEO
! level = SOL_SOCKET;
! name = param;
break;
!
default:
return (EINVAL);
}
+
+ /* opt header */
+ opts.oh.len = sizeof (opts);
+ opts.oh.level = level;
+ opts.oh.name = name;
+ opts.oh.status = 0;
+ opts.ival = *(int *)data;
+
+ oreq.flags = T_NEGOTIATE;
+ oreq.opt.buf = (void *)&opts;
+ oreq.opt.len = sizeof (opts);
+ oreq.opt.maxlen = oreq.opt.len;
+
+ ores.flags = 0;
+ ores.opt.buf = NULL;
+ ores.opt.len = 0;
+ ores.opt.maxlen = 0;
+
+ err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
+ return (EPROTO);
+ }
+
+ if ((ores.flags & T_SUCCESS) == 0) {
+ cmn_err(CE_NOTE, "smb_nbst_setparam: "
+ "flags 0x%x, status 0x%x",
+ (int)ores.flags, (int)opts.oh.status);
+ return (EPROTO);
+ }
+
return (0);
}
/*
* Check for fatal errors
*/
/*ARGSUSED*/
static int
*** 891,906 ****
struct smb_tran_desc smb_tran_nbtcp_desc = {
SMBT_NBTCP,
smb_nbst_create,
smb_nbst_done,
smb_nbst_bind,
smb_nbst_connect,
smb_nbst_disconnect,
smb_nbst_send,
smb_nbst_recv,
smb_nbst_poll,
- smb_nbst_loan_fp,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
{NULL, NULL}
};
--- 907,922 ----
struct smb_tran_desc smb_tran_nbtcp_desc = {
SMBT_NBTCP,
smb_nbst_create,
smb_nbst_done,
smb_nbst_bind,
+ smb_nbst_unbind,
smb_nbst_connect,
smb_nbst_disconnect,
smb_nbst_send,
smb_nbst_recv,
smb_nbst_poll,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
{NULL, NULL}
};