Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
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)

@@ -31,13 +31,15 @@
  *
  * $Id: smb_conn.h,v 1.32.42.1 2005/05/27 02:35:29 lindak Exp $
  */
 
 /*
- * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef _SMB_CONN_H
 #define _SMB_CONN_H
 

@@ -44,10 +46,11 @@
 #include <sys/dditypes.h>
 #include <sys/t_lock.h>
 #include <sys/queue.h> /* for SLIST below */
 #include <sys/uio.h>
 #include <netsmb/smb_dev.h>
+#include "smb_signing.h"
 
 /*
  * Credentials of user/process for processing in the connection procedures
  */
 typedef struct smb_cred {

@@ -59,18 +62,18 @@
  */
 #define SMBO_GONE               0x1000000
 
 /*
  * Bits in vc_flags (a.k.a. vc_co.co_flags)
- * Many of these were duplicates of SMBVOPT_ flags
- * and we now keep those too instead of merging
- * them into vc_flags.
+ * Note: SMBO_GONE is also in vc_flags
  */
-
-#define SMBV_WIN95              0x0010  /* used to apply bugfixes for this OS */
-#define SMBV_NT4                0x0020  /* used when NT4 issues invalid resp */
 #define SMBV_UNICODE            0x0040  /* conn configured to use Unicode */
+#define SMBV_EXT_SEC            0x0080  /* conn to use extended security */
+#define SMBV_SIGNING            0x0100  /* negotiated signing */
+#define SMBV_SMB2               0x0200  /* VC using SMB 2 or 3 */
+#define SMBV_HAS_FILEIDS        0x0400  /* Use File IDs for hash and inode numbers */
+#define SMBV_NO_WRITE_THRU      0x0800  /* Can't use ... */
 
 /*
  * Note: the common "obj" level uses this GONE flag by
  * the name SMBO_GONE.  Keep this alias as a reminder.
  */

@@ -87,10 +90,20 @@
  * Note: the common "obj" level uses this GONE flag by
  * the name SMBO_GONE.  Keep this alias as a reminder.
  */
 #define SMBS_GONE               SMBO_GONE
 
+/*
+ * bits in smb_fh fh_flags (a.k.a. ss_co.co_flags)
+ */
+#define SMBFH_VALID             0x0002  /* FID is valid */
+/*
+ * Note: the common "obj" level uses this GONE flag by
+ * the name SMBO_GONE.  Keep this alias as a reminder.
+ */
+#define SMBFH_GONE              SMBO_GONE
+
 struct smb_rq;
 /* This declares struct smb_rqhead */
 TAILQ_HEAD(smb_rqhead, smb_rq);
 
 #define SMB_NBTIMO      15

@@ -139,15 +152,63 @@
 typedef struct smb_connobj smb_connobj_t;
 
 /*
  * "Level" in the connection object hierarchy
  */
-#define SMBL_SM         0
-#define SMBL_VC         1
-#define SMBL_SHARE      2
+enum smbco_level {
+        SMBL_SM = 0,
+        SMBL_VC = 1,
+        SMBL_SHARE = 2,
+        SMBL_FH = 3
+};
 
 /*
+ * SMB1 Negotiated protocol parameters
+ */
+struct smb_sopt {
+        int16_t         sv_proto;       /* protocol dialect */
+        uchar_t         sv_sm;          /* security mode */
+        int16_t         sv_tz;          /* offset in min relative to UTC */
+        uint16_t        sv_maxmux;      /* max number of outstanding rq's */
+        uint16_t        sv_maxvcs;      /* max number of VCs */
+        uint16_t        sv_rawmode;
+        uint32_t        sv_maxtx;       /* maximum transmit buf size */
+        uint32_t        sv_maxraw;      /* maximum raw-buffer size */
+        uint32_t        sv_skey;        /* session key */
+        uint32_t        sv_caps;        /* capabilites SMB_CAP_ */
+
+        /* SMB2+ fields */
+        uint32_t        sv2_sessflags;  /* final session setup reply flags */
+        uint16_t        sv2_dialect;    /* dialect (non zero for SMB 2/3 */
+        uint32_t        sv2_capabilities;       /* capabilities */
+        uint32_t        sv2_maxtransact;        /* max transact size */
+        uint32_t        sv2_maxread;    /* max read size */
+        uint32_t        sv2_maxwrite;   /* max write size */
+        uint8_t         sv2_guid[16];   /* GUID */
+        uint16_t        sv2_security_mode;      /* security mode */
+};
+typedef struct smb_sopt smb_sopt_t;
+
+/*
+ * SMB1 I/O Deamon state
+ */
+struct smb_iods {
+        uint8_t         is_hflags;      /* SMB header flags */
+        uint16_t        is_hflags2;     /* SMB header flags2 */
+        uint16_t        is_smbuid;      /* SMB header UID */
+        uint16_t        is_next_mid;    /* SMB header MID */
+        uint32_t        is_txmax;       /* max tx/rx packet size */
+        uint32_t        is_rwmax;       /* max read/write data size */
+        uint32_t        is_rxmax;       /* max readx data size */
+        uint32_t        is_wxmax;       /* max writex data size */
+        /* Signing state */
+        uint32_t        is_next_seq;    /* my next sequence number */
+
+};
+typedef struct smb_iods smb_iods_t;
+
+/*
  * Virtual Circuit to a server (really connection + session).
  * Yes, calling this a "Virtual Circuit" is confusining,
  * because it has nothing to do with the SMB notion of a
  * "Virtual Circuit".
  */

@@ -158,25 +219,40 @@
 
         zoneid_t                vc_zoneid;
         uid_t                   vc_owner;       /* Unix owner */
         int                     vc_genid;       /* "generation" ID */
 
-        int                     vc_mackeylen;   /* length of MAC key */
-        uint8_t                 *vc_mackey;     /* MAC key */
+        int                     vc_mackeylen;   /* MAC key length */
+        int                     vc_ssnkeylen;   /* session key length */
+        uint8_t                 *vc_mackey;     /* MAC key buffer */
+        uint8_t                 *vc_ssnkey;     /* session key buffer */
+        smb_sign_mech_t         vc_signmech;
 
-        ksema_t                 vc_sendlock;
         struct smb_tran_desc    *vc_tdesc;      /* transport ops. vector */
         void                    *vc_tdata;      /* transport control block */
 
+        /* SMB2+ fields */
+        uint64_t        vc2_oldest_message_id;
+        uint64_t        vc2_next_message_id;
+        uint64_t        vc2_limit_message_id;
+        uint64_t        vc2_session_id;         /* session id */
+        uint64_t        vc2_prev_session_id;    /* for reconnect */
+        uint32_t        vc2_lease_key;          /* lease key gen */
+
         kcondvar_t              iod_idle;       /* IOD thread idle CV */
         krwlock_t               iod_rqlock;     /* iod_rqlist */
-        struct smb_rqhead       iod_rqlist;     /* list of outstanding reqs */
+        struct smb_rqhead       iod_rqlist;     /* list of active reqs */
         struct _kthread         *iod_thr;       /* the IOD (reader) thread */
         int                     iod_flags;      /* see SMBIOD_* below */
-        int                     iod_newrq;      /* send needed (iod_rqlock) */
-        int                     iod_muxfull;    /* maxmux limit reached */
+        uint_t                  iod_muxcnt;     /* num. active requests */
+        uint_t                  iod_muxwant;    /* waiting to be active */
+        kcondvar_t              iod_muxwait;
+        boolean_t               iod_noresp;     /* Logged "not responding" */
 
+        smb_iods_t              vc_iods;
+        smb_sopt_t              vc_sopt;
+
         /* This is copied in/out when IOD enters/returns */
         smbioc_ssn_work_t       vc_work;
 
         /* session identity, etc. */
         smbioc_ossn_t           vc_ssn;

@@ -185,38 +261,45 @@
 #define vc_lock         vc_co.co_lock
 #define vc_flags        vc_co.co_flags
 
 /* defines for members in vc_ssn */
 #define vc_owner        vc_ssn.ssn_owner
+#define vc_vopt         vc_ssn.ssn_vopt
+#define vc_minver       vc_ssn.ssn_minver
+#define vc_maxver       vc_ssn.ssn_maxver
 #define vc_srvname      vc_ssn.ssn_srvname
 #define vc_srvaddr      vc_ssn.ssn_id.id_srvaddr
 #define vc_domain       vc_ssn.ssn_id.id_domain
 #define vc_username     vc_ssn.ssn_id.id_user
-#define vc_vopt         vc_ssn.ssn_vopt
 
 /* defines for members in vc_work */
-#define vc_sopt         vc_work.wk_sopt
-#define vc_maxmux       vc_work.wk_sopt.sv_maxmux
-#define vc_tran_fd      vc_work.wk_iods.is_tran_fd
-#define vc_hflags       vc_work.wk_iods.is_hflags
-#define vc_hflags2      vc_work.wk_iods.is_hflags2
-#define vc_smbuid       vc_work.wk_iods.is_smbuid
-#define vc_next_mid     vc_work.wk_iods.is_next_mid
-#define vc_txmax        vc_work.wk_iods.is_txmax
-#define vc_rwmax        vc_work.wk_iods.is_rwmax
-#define vc_rxmax        vc_work.wk_iods.is_rxmax
-#define vc_wxmax        vc_work.wk_iods.is_wxmax
-#define vc_ssn_key      vc_work.wk_iods.is_ssn_key
-#define vc_next_seq     vc_work.wk_iods.is_next_seq
-#define vc_u_mackey     vc_work.wk_iods.is_u_mackey
-#define vc_u_maclen     vc_work.wk_iods.is_u_maclen
+#define vc_cl_guid      vc_work.wk_cl_guid
 
+/* defines for members in vc_sopt ? */
+#define vc_maxmux       vc_sopt.sv_maxmux
+
+/* defines for members in vc_iods */
+#define vc_hflags       vc_iods.is_hflags
+#define vc_hflags2      vc_iods.is_hflags2
+#define vc_smbuid       vc_iods.is_smbuid
+#define vc_next_mid     vc_iods.is_next_mid
+#define vc_txmax        vc_iods.is_txmax
+#define vc_rwmax        vc_iods.is_rwmax
+#define vc_rxmax        vc_iods.is_rxmax
+#define vc_wxmax        vc_iods.is_wxmax
+#define vc_next_seq     vc_iods.is_next_seq
+
 #define SMB_VC_LOCK(vcp)        mutex_enter(&(vcp)->vc_lock)
 #define SMB_VC_UNLOCK(vcp)      mutex_exit(&(vcp)->vc_lock)
 
-#define SMB_UNICODE_STRINGS(vcp)        ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE)
+#define CPTOVC(cp)      ((struct smb_vc *)((void *)(cp)))
+#define VCTOCP(vcp)     (&(vcp)->vc_co)
 
+#define SMB_UNICODE_STRINGS(vcp) \
+        (((vcp)->vc_flags & SMBV_SMB2) != 0 ||  \
+        ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0)
+
 /* Bits in iod_flags */
 #define SMBIOD_RUNNING          0x0001
 #define SMBIOD_SHUTDOWN         0x0002
 
 /*

@@ -229,10 +312,13 @@
         kcondvar_t      ss_conn_done;   /* wait for reconnect */
         int             ss_conn_waiters;
         int             ss_vcgenid;     /* check VC generation ID */
         uint16_t        ss_tid;         /* TID */
         uint16_t        ss_options;     /* option support bits */
+        uint32_t        ss2_tree_id;
+        uint32_t        ss2_share_flags;
+        uint32_t        ss2_share_caps;
         smbioc_oshare_t ss_ioc;
 } smb_share_t;
 
 #define ss_lock         ss_co.co_lock
 #define ss_flags        ss_co.co_flags

@@ -243,31 +329,51 @@
 #define ss_pass         ss_ioc.sh_pass
 
 #define SMB_SS_LOCK(ssp)        mutex_enter(&(ssp)->ss_lock)
 #define SMB_SS_UNLOCK(ssp)      mutex_exit(&(ssp)->ss_lock)
 
-#define CPTOVC(cp)      ((struct smb_vc *)((void *)(cp)))
-#define VCTOCP(vcp)     (&(vcp)->vc_co)
-
 #define CPTOSS(cp)      ((struct smb_share *)((void *)(cp)))
-#define SSTOVC(ssp)     CPTOVC(((ssp)->ss_co.co_parent))
 #define SSTOCP(ssp)     (&(ssp)->ss_co)
+#define SSTOVC(ssp)     CPTOVC(((ssp)->ss_co.co_parent))
 
+typedef struct smb2fid {
+        uint64_t fid_persistent;
+        uint64_t fid_volatile;
+} smb2fid_t;
+
 /*
+ * smb_fh struct describes an open file handle under some share.
+ */
+typedef struct smb_fh {
+        struct smb_connobj fh_co;       /* keep first! See CPTOSS */
+        int     fh_vcgenid;             /* check VC generation ID */
+        uint32_t fh_rights;             /* granted access */
+        smb2fid_t fh_fid2;
+        uint16_t fh_fid1;
+} smb_fh_t;
+
+#define fh_lock         fh_co.co_lock
+#define fh_flags        fh_co.co_flags
+
+#define SMB_FH_LOCK(fhp)        mutex_enter(&(fhp)->fh_lock)
+#define SMB_FH_UNLOCK(fhp)      mutex_exit(&(fhp)->fh_lock)
+
+#define CPTOFH(cp)      ((struct smb_fh *)((void *)(cp)))
+#define FHTOCP(fhp)     (&(fhp)->fh_co)
+#define FHTOSS(fhp)     CPTOSS(((fhp)->fh_co.co_parent))
+
+/*
  * Call-back operations vector, so the netsmb module
  * can notify smbfs about events affecting mounts.
  * Installed in netsmb after smbfs loads.
+ * Note: smbfs only uses the fscb_discon hook.
  */
 typedef struct smb_fscb {
         /* Called when the VC has disconnected. */
         void (*fscb_disconn)(smb_share_t *);
         /* Called when the VC has reconnected. */
         void (*fscb_connect)(smb_share_t *);
-        /* Called when the server becomes unresponsive. */
-        void (*fscb_down)(smb_share_t *);
-        /* Called when the server is responding again. */
-        void (*fscb_up)(smb_share_t *);
 } smb_fscb_t;
 /* Install the above vector, or pass NULL to clear it. */
 void smb_fscb_set(smb_fscb_t *);
 
 /*

@@ -276,18 +382,18 @@
  */
 typedef struct smb_dev {
         kmutex_t        sd_lock;
         struct smb_vc   *sd_vc;         /* Reference to VC */
         struct smb_share *sd_share;     /* Reference to share if any */
+        struct smb_fh   *sd_fh;         /* Reference to FH, if any */
         int             sd_level;       /* SMBL_VC, ... */
         int             sd_vcgenid;     /* Generation of share or VC */
         int             sd_poll;        /* Future use */
         int             sd_flags;       /* State of connection */
-#define NSMBFL_OPEN             0x0001
-#define NSMBFL_IOD              0x0002
-#define NSMBFL_IOCTL            0x0004
-        int             sd_smbfid;      /* library read/write */
+#define NSMBFL_OPEN             0x0001  /* Device minor is open */
+#define NSMBFL_IOD              0x0004  /* Open by IOD */
+#define NSMBFL_IOCTL            0x0010  /* Serialize ioctl calls */
         zoneid_t        zoneid;         /* Zone id */
 } smb_dev_t;
 
 extern const uint32_t nsmb_version;
 

@@ -298,10 +404,12 @@
 
 
 /*
  * smb_usr.c
  */
+int smb_usr_ioctl(smb_dev_t *, int, intptr_t, int, cred_t *);
+
 int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
 int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
 int smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags);
 
 int smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);

@@ -317,30 +425,38 @@
 
 int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
 int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
 
 int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
-int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags,
+    cred_t *cr);
 
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
 
+
 /*
  * IOD functions
  */
 int  smb_iod_create(smb_vc_t *vcp);
 int  smb_iod_destroy(smb_vc_t *vcp);
-int  smb_iod_connect(smb_vc_t *vcp);
 void smb_iod_disconnect(smb_vc_t *vcp);
-int  smb_iod_addrq(struct smb_rq *rqp);
-int  smb_iod_multirq(struct smb_rq *rqp);
+int  smb2_iod_addrq(struct smb_rq *rqp);
+int  smb1_iod_addrq(struct smb_rq *rqp);
+int  smb1_iod_multirq(struct smb_rq *rqp);
 int  smb_iod_waitrq(struct smb_rq *rqp);
+int  smb_iod_waitrq_int(struct smb_rq *rqp);
 void smb_iod_removerq(struct smb_rq *rqp);
+int  smb_iod_sendrecv(struct smb_rq *, int);
 void smb_iod_shutdown_share(smb_share_t *ssp);
 
 void smb_iod_sendall(smb_vc_t *);
-int smb_iod_recvall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *, boolean_t);
 
-int smb_iod_vc_work(smb_vc_t *, cred_t *);
+int nsmb_iod_connect(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr);
+int smb_iod_vc_work(smb_vc_t *, int, cred_t *);
 int smb_iod_vc_idle(smb_vc_t *);
 int smb_iod_vc_rcfail(smb_vc_t *);
 int smb_iod_reconnect(smb_vc_t *);
 
 /*

@@ -379,6 +495,15 @@
 void smb_share_kill(smb_share_t *ssp);
 
 void smb_share_invalidate(smb_share_t *ssp);
 int  smb_share_tcon(smb_share_t *, smb_cred_t *);
 
+/*
+ * File handle level functions
+ */
+int smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp);
+void smb_fh_opened(struct smb_fh *fhp);
+void smb_fh_close(struct smb_fh *fhp);
+void smb_fh_hold(struct smb_fh *fhp);
+void smb_fh_rele(struct smb_fh *fhp);
+
 #endif /* _SMB_CONN_H */