/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* seconds to wait for daemon to reconnect before disabling */
/* length of minor node name - vscan%d */
/*
* vscan_drv_state
*
* Operations on instance 0 represent vscand initiated state
* transition events:
* open(0) - vscand connect
* close(0) - vscan disconnect
* enable(0) - vscand enable (ready to hand requests)
* disable(0) - vscand disable (shutting down)
*
* +------------------------+
* | VS_DRV_UNCONFIG |
* +------------------------+
* | ^
* | attach | detach
* v |
* +------------------------+
* | VS_DRV_IDLE |<------|
* +------------------------+ |
* | ^ |
* | open(0) | close(0) |
* v | |
* +------------------------+ |
* | VS_DRV_CONNECTED |<-| |
* +------------------------+ | |
* | ^ | |
* | enable(0) | disable(0) | |
* v | | |
* +------------------------+ | |
* | VS_DRV_ENABLED | | |
* +------------------------+ | |
* | | |
* | close(0) open(0) |
* v | |
* +------------------------+ | | timeout
* | VS_DRV_DELAYED_DISABLE | -- |
* +------------------------+ ------|
*
*/
typedef enum {
/*
* vscan_drv_inst_state
*
* Instance 0 controls the state of the driver: vscan_drv_state.
* vscan_drv_inst_state[0] should NOT be used.
*
* vscan_drv_inst_state[n] represents the state of driver
* instance n, used by vscand to access file data for the
* scan request with index n in vscan_svc_reqs.
* Minor nodes are created as required then all are destroyed
* during driver detach.
*
* +------------------------+
* | VS_DRV_INST_UNCONFIG |
* +------------------------+
* | ^
* | create_node(n) | detach
* v |
* +------------------------+
* | VS_DRV_INST_INIT |<-|
* +------------------------+ |
* | |
* | open(n) |
* v |
* +------------------------+ |
* | VS_DRV_INST_OPEN |--|
* +------------------------+ |
* | |
* | read(n) |
* v | close(n)
* +------------------------+ |
* | VS_DRV_INST_READING |--|
* +------------------------+
*/
typedef enum {
static int vscan_drv_inst_state_sz;
/*
* DDI entry points.
*/
static boolean_t vscan_drv_in_use(void);
static void vscan_drv_delayed_disable(void);
/*
* module linkage info for the kernel
*/
vscan_drv_open, /* cb_open */
vscan_drv_close, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
vscan_drv_read, /* cb_read */
nodev, /* cb_write */
vscan_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 */
vscan_drv_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
vscan_drv_attach, /* devo_attach */
vscan_drv_detach, /* devo_detach */
nodev, /* devo_reset */
&cbops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
NULL, /* devo_power */
ddi_quiesce_not_needed, /* devo_quiesce */
};
&mod_driverops, /* drv_modops */
"virus scanning", /* drv_linkinfo */
&devops,
};
MODREV_1, /* revision of the module, must be: MODREV_1 */
&modldrv, /* ptr to linkage structures */
NULL,
};
/*
* _init
*/
int
_init(void)
{
int rc;
if (vscan_door_init() != 0)
return (DDI_FAILURE);
if (vscan_svc_init() != 0) {
return (DDI_FAILURE);
}
}
return (rc);
}
/*
* _info
*/
int
{
}
/*
* _fini
*/
int
_fini(void)
{
int rc;
if (vscan_drv_in_use())
return (EBUSY);
}
return (rc);
}
/*
* DDI entry points.
*/
/*
* vscan_drv_getinfo
*/
/* ARGSUSED */
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
*result = vscan_drv_dip;
return (DDI_SUCCESS);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/*
* vscan_drv_attach
*/
static int
{
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
if (ddi_get_instance(dip) != 0)
return (DDI_FAILURE);
vscan_drv_dip = dip;
/* create minor node 0 for daemon-driver synchronization */
if (vscan_drv_create_node(0) == B_FALSE)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* vscan_drv_detach
*/
static int
{
int i;
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
if (ddi_get_instance(dip) != 0)
return (DDI_FAILURE);
if (vscan_drv_in_use())
return (DDI_FAILURE);
/* remove all minor nodes */
for (i = 0; i <= vs_nodes_max; i++)
return (DDI_SUCCESS);
}
/*
* vscan_drv_in_use
*
* If the driver state is not IDLE or UNCONFIG then the
* driver is in use. Otherwise, check the service interface
* (vscan_svc) to see if it is still in use - for example
* there there may be requests still in progress.
*/
static boolean_t
{
if ((vscan_drv_state != VS_DRV_IDLE) &&
(vscan_drv_state != VS_DRV_UNCONFIG)) {
}
if (in_use)
return (B_TRUE);
else
return (vscan_svc_in_use());
}
/*
* vscan_drv_open
*
* If inst == 0, this is vscand initializing.
* If the driver is in DELAYED_DISABLE, ie vscand previously
* disconnected without a clean shutdown and the driver is
* waiting for a period to allow vscand to reconnect, signal
* vscan_drv_cv to cancel the delayed disable.
*
* If inst != 0, open the file associated with inst.
*/
/* ARGSUSED */
static int
{
int rc;
return (EINVAL);
/* check if caller has privilege for virus scanning */
return (EPERM);
}
if (inst == 0) {
switch (vscan_drv_state) {
case VS_DRV_IDLE:
break;
case VS_DRV_DELAYED_DISABLE:
break;
default:
int, vscan_drv_state);
return (EINVAL);
}
} else {
if ((vscan_drv_state != VS_DRV_ENABLED) ||
return (EINVAL);
}
}
return (0);
}
/*
* vscan_drv_close
*
* If inst == 0, this is vscand detaching.
* If the driver is in ENABLED state vscand has terminated without
* a clean shutdown (nod DISABLE received). Enter DELAYED_DISABLE
* state and initiate a delayed disable to allow vscand time to
* reconnect.
*
* If inst != 0, close the file associated with inst
*/
/* ARGSUSED */
static int
{
return (EINVAL);
if (inst != 0) {
return (0);
}
/* instance 0 - daemon disconnect */
if ((vscan_drv_state != VS_DRV_CONNECTED) &&
(vscan_drv_state != VS_DRV_ENABLED)) {
int, vscan_drv_state);
return (EINVAL);
}
for (i = 1; i <= vs_nodes_max; i++) {
if (vscan_drv_inst_state[i] != VS_DRV_INST_UNCONFIG)
}
if (vscan_drv_state == VS_DRV_CONNECTED) {
} else { /* VS_DRV_ENABLED */
} else {
}
}
return (0);
}
/*
* vscan_drv_delayed_disable
*
* Invoked from vscan_drv_close if the daemon disconnects
* without first sending disable (e.g. daemon crashed).
* Delays for vs_reconnect_timeout before disabling, to allow
* the daemon to reconnect. During this time, scan requests
* will be processed locally (see vscan_svc.c)
*/
static void
{
if (vscan_drv_state == VS_DRV_DELAYED_DISABLE) {
} else {
}
}
/*
* vscan_drv_read
*/
/* ARGSUSED */
static int
{
int rc;
return (EINVAL);
if ((vscan_drv_state != VS_DRV_ENABLED) ||
return (EINVAL);
}
return (EINVAL);
return (rc);
}
/*
* vscan_drv_ioctl
*
* Process ioctls from vscand:
* VS_IOCTL_ENABLE - vscand is ready to handle scan requests,
* enable VFS interface.
* VS_IOCTL_DISABLE - vscand is shutting down, disable VFS interface
* VS_IOCTL_RESULT - scan response data
* VS_IOCTL_CONFIG - configuration data from vscand
* VS_IOCTL_MAX_REQ - provide the max request idx to vscand,
* to allow vscand to set appropriate resource allocation limits
*/
/* ARGSUSED */
static int
{
if (inst != 0)
return (EINVAL);
switch (cmd) {
case VS_IOCTL_ENABLE:
if (vscan_drv_state != VS_DRV_CONNECTED) {
int, vscan_drv_state);
return (EINVAL);
}
if ((vscan_door_open((int)arg) != 0) ||
(vscan_svc_enable() != 0)) {
return (EINVAL);
}
break;
case VS_IOCTL_DISABLE:
if (vscan_drv_state != VS_DRV_ENABLED) {
int, vscan_drv_state);
return (EINVAL);
}
break;
case VS_IOCTL_RESULT:
sizeof (vs_scan_rsp_t), 0) == -1)
return (EFAULT);
else
break;
case VS_IOCTL_CONFIG:
sizeof (vs_config_t), 0) == -1)
return (EFAULT);
return (EINVAL);
break;
case VS_IOCTL_MAX_REQ:
sizeof (uint32_t), 0) == -1)
return (EFAULT);
break;
default:
return (ENOTTY);
}
return (0);
}
/*
* vscan_drv_create_node
*
* Create minor node with which vscan daemon will communicate
* to access a file. Invoked from vscan_svc before scan request
* sent up to daemon.
* Minor node 0 is reserved for daemon-driver synchronization
* and is created during attach.
* All minor nodes are removed during detach.
*/
{
} else {
}
}
return (rc);
}