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,11 +32,12 @@
* $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.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/autoconf.h>
@@ -71,17 +72,10 @@
#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.
@@ -161,11 +155,11 @@
tm = im;
break;
case T_DISCON_IND:
/* Peer disconnected. */
NBDEBUG("T_DISCON_IND: reason=%d",
- pptr->discon_ind.DISCON_reason);
+ (int)pptr->discon_ind.DISCON_reason);
goto discon;
case T_ORDREL_IND:
/* Peer disconnecting. */
NBDEBUG("T_ORDREL_IND");
goto discon;
@@ -174,15 +168,15 @@
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);
+ (int)pptr->ok_ack.CORRECT_prim);
goto discon;
}
default:
- NBDEBUG("M_PROTO/type=%d", pptr->type);
+ NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
goto discon;
}
break; /* M_PROTO, M_PCPROTO */
default:
@@ -483,26 +477,49 @@
* 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;
+ 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_CLOSED; /* really IDLE */
+ nbp->nbp_state = NBST_IDLE;
nbp->nbp_vc = vcp;
- nbp->nbp_sndbuf = smb_tcpsndbuf;
- nbp->nbp_rcvbuf = smb_tcprcvbuf;
+ 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,115 +556,78 @@
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)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
- TIUSER *tiptr;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
int err;
- err = t_kopen(fp, 0, 0, &tiptr, cr);
- if (err != 0)
- return (err);
+ /* Only default bind supported. */
+ if (sap != NULL)
+ return (ENOTSUP);
- mutex_enter(&nbp->nbp_lock);
+ err = t_kbind(tiptr, NULL, NULL);
- 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);
+ return (err);
}
-/*
- * 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)
+static int
+smb_nbst_unbind(struct smb_vc *vcp)
{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
- mutex_enter(&nbp->nbp_lock);
+ err = t_kunbind(tiptr);
- 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);
+ return (err);
}
static int
-smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
{
+ struct t_call call;
struct nbpcb *nbp = vcp->vc_tdata;
- int error = 0;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int alen, err;
- /*
- * 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);
+ /* 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);
}
- return (error);
-}
+ /* sockaddr goes in the "addr" netbuf */
+ bzero(&call, sizeof (call));
+ call.addr.buf = (char *)sap;
+ call.addr.len = alen;
+ call.addr.maxlen = alen;
-/*ARGSUSED*/
-static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
-}
+ err = t_kconnect(tiptr, &call, NULL);
+ if (err != 0)
+ return (err);
-/*ARGSUSED*/
-static int
-smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
+ mutex_enter(&nbp->nbp_lock);
+
+ nbp->nbp_flags |= NBF_CONNECTED;
+ nbp->nbp_state = NBST_SESSION;
+
+ mutex_exit(&nbp->nbp_lock);
+
+ return (0);
}
-/*ARGSUSED*/
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
struct nbpcb *nbp = vcp->vc_tdata;
@@ -830,48 +810,84 @@
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_SNDSZ:
- *(int *)data = nbp->nbp_sndbuf;
+ case SMBTP_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ name = TCP_NODELAY;
break;
- case SMBTP_RCVSZ:
- *(int *)data = nbp->nbp_rcvbuf;
+
+ case SMBTP_TCP_CON_TMO: /* int mSec */
+ level = IPPROTO_TCP;
+ name = TCP_CONN_ABORT_THRESHOLD;
break;
- case SMBTP_TIMEOUT:
- *(struct timespec *)data = nbp->nbp_timo;
+
+ 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;
-#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);
}
+
+ /* 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);
}
-/*ARGSUSED*/
-static int
-smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
-{
- return (EINVAL);
-}
-
/*
* Check for fatal errors
*/
/*ARGSUSED*/
static int
@@ -891,16 +907,16 @@
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_loan_fp,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
{NULL, NULL}
};