smb_init.c revision 55bf511df53aad0fdb7eb3fa349f0308cc05234c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/socketvar.h>
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_door_svc.h>
#include <smbsrv/smb_ioctl.h>
#include <smbsrv/smb_kproto.h>
/*
* DDI entry points.
*/
static int smb_drv_busy(void);
/*
* module linkage info for the kernel
*/
smb_drv_open, /* cb_open */
smb_drv_close, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
smb_drv_ioctl, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* cb_streamtab */
D_MP, /* cb_flag */
CB_REV, /* cb_rev */
nodev, /* cb_aread */
nodev, /* cb_awrite */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
smb_drv_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
smb_drv_attach, /* devo_attach */
smb_drv_detach, /* devo_detach */
nodev, /* devo_reset */
&cbops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
NULL, /* devo_power */
};
&mod_driverops, /* drv_modops */
"CIFS Server Protocol %I%", /* drv_linkinfo */
&devops,
};
static struct modlinkage modlinkage = {
MODREV_1, /* revision of the module, must be: MODREV_1 */
&modldrv, /* ptr to linkage structures */
NULL,
};
extern int smb_fsop_start(void);
extern void smb_fsop_stop(void);
extern int nt_mapk_start(void);
extern void nt_mapk_stop(void);
extern void smb_session_worker(void *arg);
extern int smb_maxbufsize;
extern time_t smb_oplock_timeout;
/* Debug logging level: 0=Disabled, 1=Quiet, 2=Verbose */
int smbsrv_debug_level;
static kmutex_t smb_drv_opencount_lock;
static int smb_drv_opencount = 0;
/*
* Kstat smb_info statistics.
*/
static struct smbinfo_stats {
} smbinfo_stats = {
{ "state", KSTAT_DATA_UINT32 },
{ "open_files", KSTAT_DATA_UINT32 },
{ "connections", KSTAT_DATA_UINT32 },
{ "sessions", KSTAT_DATA_UINT32 }
};
static int smb_kstat_init(void);
static void smb_kstat_fini(void);
extern void smb_initialize_dispatch_kstat(void);
extern void smb_remove_dispatch_kstat(void);
/*
* SMB pseudo-driver entry points
*/
int
_init(void)
{
int rc;
return (rc);
}
return (0);
}
int
{
}
int
_fini(void)
{
int rc;
if (smb_drv_busy()) {
return (EBUSY);
}
return (rc);
}
/*
* DDI entry points.
*/
/* ARGSUSED */
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
*result = smb_drv_dip;
return (DDI_SUCCESS);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
default:
break;
}
return (DDI_FAILURE);
}
static int
{
if (cmd != DDI_ATTACH) {
return (DDI_FAILURE);
}
if (ddi_get_instance(dip) != 0) {
/* we only allow instance 0 to attach */
return (DDI_FAILURE);
}
smb_drv_dip = dip;
/* create the minor node */
DDI_PSEUDO, 0) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
if (smb_service_init() != 0) {
"SMB service");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
/*
* Service state value is not protected by a lock in this case but
* it shouldn't be possible for the service state machine to transition
* TO a busy state at a time when smb_drv_busy() would return false.
*/
if (smb_drv_busy() || smb_svcstate_sm_busy()) {
return (DDI_FAILURE);
}
smb_drv_dip = NULL;
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
int *retval)
{
int gmtoff;
int door_id;
switch (cmd) {
case SMB_IOC_GMTOFF:
return (EFAULT);
break;
case SMB_IOC_CONFIG:
#if 0
#endif
break;
case SMB_IOC_WINPIPE:
return (EFAULT);
if (smb_winpipe_open(door_id) != 0)
return (EPIPE);
break;
default:
break;
}
return (0);
}
/* ARGSUSED */
static int
{
int rc = 0;
/*
* Only allow one open at a time
*/
if (smb_drv_busy()) {
return (EBUSY);
}
/*
* Check caller's privileges.
*/
if (secpolicy_smb(credp) != 0) {
return (EPERM);
}
/*
* Start SMB service state machine
*/
if (rc != 0) {
return (rc);
}
return (0);
}
/* ARGSUSED */
static int
{
if (!smb_drv_busy()) {
return (0);
}
return (0);
}
/*
* Convenience function - must be called with smb_drv_opencount_lock held.
*/
static int
smb_drv_busy(void)
{
return (smb_drv_opencount);
}
/*
* SMB Service initialization and startup functions
*/
int
smb_service_init(void)
{
int rc;
if (rc != 0) {
return (rc);
}
if (rc != 0) {
return (rc);
}
rc = smb_kstat_init();
if (rc != 0) {
return (rc);
}
return (0);
}
void
smb_service_fini(void)
{
}
/*
* Progress bits for smb_info.si_open_progress. For use only by
*/
#define SMB_FS_STARTED 0x01
#define LMSHRD_KCLIENT_STARTED 0x02
#define SMB_KDOOR_CLNT_STARTED 0x04
#define SMB_KDOOR_SRV_STARTED 0x08
#define SMB_THREADS_STARTED 0x10
int
{
int rc;
int size; /* XXX TEMPORARY (remove when kconfig is removed) */
/* Track progress so we can cleanup from a partial failure */
si->si_open_progress = 0;
si->si_connect_progress = 0;
/* XXX TEMPORARY */
if (size != 0) {
size = 37;
}
/*
* XXX should not override configuration.
* For now, this disables server side
* signing regardless of configuration.
*/
/*
* XXX The following code was pulled from smb_oplock_init.
* It should be combined with with the config process if
* this info will be stored with the configuration or with
* the smb_fsop_start function if the data will be stored
* in the root of the fs.
*/
/*
* XXX oplock enable flag.
* Should be stored in extended attribute in root of fs
* or a ZFS user-defined property.
*/
}
/*
* XXX oplock timeout. Can a customer configure this?
*/
} else {
return (EIO); /* XXX Errno? */
}
if ((rc = smb_fsop_start()) != 0) {
return (rc);
}
if ((rc = lmshrd_kclient_start()) != 0) {
return (rc);
}
if ((rc = smb_kdoor_clnt_start()) != 0) {
return (rc);
}
if ((rc = smb_kdoor_srv_start()) != 0) {
return (rc);
}
return (rc);
}
return (0);
}
void
{
}
/*
* Start the Netbios and TCP services.
*
* Awaken arguments are not known until thread starts.
*
* XXX We give up the NET_MAC_AWARE privilege because it keeps us from
* re-opening the connection when there are leftover TCP connections in
* TCPS_TIME_WAIT state. There seem to be some security ramifications
* around reestablishing a connection while possessing the NET_MAC_AWARE
* privilege.
*
* This approach may cause problems when we try to support zones. An
* alternative would be to retry the connection setup for a fixed period
* of time until the stale connections clear up but that implies we
* would be offline for a couple minutes every time the service is
* restarted with active connections.
*/
int
{
return (rc1);
}
if (rc2 != 0)
return (rc1);
}
void
{
}
/*
* Start any service-related kernel threads except for the NBT and TCP
* daemon threads. Those service daemon threads are handled separately.
*
* Returns 0 for success, non-zero for failure. If failure is returned the
* caller should call smb_service_stop_threads to cleanup any threads that
* were successfully started.
*/
int
{
int rval;
"smb_workers",
if (rval != 0)
return (rval);
if (rval != 0) {
return (rval);
}
return (0);
}
void
{
}
static int
{
int i;
for (i = 0; i <= SMBND_HASH_MASK; i++) {
}
return (0);
}
static void
{
int i;
for (i = 0; i <= SMBND_HASH_MASK; i++) {
/*
* The following sequence is just intended for sanity check.
* This will have to be modified when the code goes into
* production.
*
* The SMB node hash table should be emtpy at this point. If the
* hash table is not empty all the nodes remaining are displayed
* (it should help figure out what actions led to this state)
* and "oops" will be set to B_TRUE which will trigger the
* ASSERT that follows.
*
* The reason why SMB nodes are still remaining in the hash
* table is problably due to a mismatch between calls to
* smb_node_lookup() and smb_node_release(). You must track that
* down.
*
* Now if you are reading this comment because you actually hit
* the ASSERT, the temptation to ignore it is going to be very
* strong. To help you make the right decision you should know
* that when the ASSERT happened a message containing you SunID
* has been sent to cifsgate. By now it has been logged into a
* special database.
*
* You are being watched...
*/
}
for (i = 0; i <= SMBND_HASH_MASK; i++) {
}
}
static int
{
/* create and initialize smb kstats - smb_info stats */
if (smbinfo_ksp) {
}
/* create and initialize smb kstats - smb_dispatch stats */
return (0);
}
static void
{
if (smbinfo_ksp != NULL) {
smbinfo_ksp = NULL;
}
}
/* ARGSUSED */
static int
{
if (rw == KSTAT_WRITE) {
return (EACCES);
} else {
}
return (0);
}