/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stream.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/priv_names.h>
/*
* This file contains generic goo needed to hook the STREAMS modules and
* drivers that live under uts/common/inet into the DDI. In order to use it,
* each module/driver should #define the symbols below (as appropriate) and
* then #include this source file; see the other uts/common/inet/<star>ddi.c
* files for examples of this in action.
*
* The symbols that all modules and drivers must define are:
*
* INET_NAME The name of the module/driver.
*
* The symbols that all modules must define are:
*
* INET_MODSTRTAB The name of the `streamtab' structure for this module.
* INET_MODDESC The one-line description for this module.
* INET_MODMTFLAGS The mt-streams(9F) flags for the module.
*
* The symbols that all drivers must define are:
*
* INET_DEVSTRTAB The name of the `streamtab' structure for this driver.
* INET_DEVDESC The one-line description for this driver.
* INET_DEVMTFLAGS The mt-streams(9F) flags for the driver.
* INET_DEVMINOR The minor number of the driver (usually 0).
*
* Drivers that need to masquerade as IP should set INET_DEVMTFLAGS to
* IP_DEVMTFLAGS and set INET_DEVSTRTAB to ipinfo.
*
* The symbols that all socket modules must define are:
*
* INET_SOCKDESC The one-line description for this socket module
* INET_SOCK_PROTO_CREATE_FUNC The function used to create PCBs
*
* In addition, socket modules that can be converted to TPI must define:
*
* INET_SOCK_PROTO_FB_FUNC The function used to fallback to TPI
*/
#if !defined(INET_NAME)
#error inetddi.c: INET_NAME is not defined!
#elif !defined(INET_DEVDESC) && !defined(INET_MODDESC) && \
!defined(INET_SOCKDESC)
#error inetddi.c: at least one of INET_DEVDESC or INET_MODDESC or \
INET_SOCKDESC must be defined!
#elif defined(INET_DEVDESC) && !defined(INET_DEVSTRTAB)
#error inetddi.c: INET_DEVDESC is defined but INET_DEVSTRTAB is not!
#elif defined(INET_DEVDESC) && !defined(INET_DEVMTFLAGS)
#error inetddi.c: INET_DEVDESC is defined but INET_DEVMTFLAGS is not!
#elif defined(INET_DEVDESC) && !defined(INET_DEVMINOR)
#error inetddi.c: INET_DEVDESC is defined but INET_DEVMINOR is not!
#elif defined(INET_MODDESC) && !defined(INET_MODSTRTAB)
#error inetddi.c: INET_MODDESC is defined but INET_MODSTRTAB is not!
#elif defined(INET_MODDESC) && !defined(INET_MODMTFLAGS)
#error inetddi.c: INET_MODDESC is defined but INET_MODMTFLAGS is not!
#elif defined(INET_SOCKDESC) && !defined(SOCKMOD_VERSION)
#error inetddi.c: INET_SOCKDESC is defined but SOCKMOD_VERSION is not!
#elif defined(INET_SOCKDESC) && !defined(INET_SOCK_PROTO_CREATE_FUNC)
#error inetddi.c: INET_SOCKDESC is defined but INET_SOCK_PROTO_CREATE_FUNC \
is not!
#elif defined(INET_SOCK_PROTO_FB_FUNC) && !defined(INET_SOCK_FALLBACK_DEV_V4)
#error inetddi.c: INET_SOCK_PROTO_FB_FUNC is defined but \
INET_SOCK_FALLBACK_DEV_V4 is not!
#elif defined(INET_SOCK_PROTO_FB_FUNC) && !defined(INET_SOCK_FALLBACK_DEV_V6)
#error inetddi.c: INET_SOCK_PROTO_FB_FUNC is defined but \
INET_SOCK_FALLBACK_DEV_V6 is not!
#endif
#ifdef INET_DEVDESC
extern struct streamtab INET_DEVSTRTAB;
/*
* Drivers that actually want to be IP would set INET_DEVSTRTAB to ipinfo.
*/
static dev_info_t *inet_dev_info;
#define INET_DEFAULT_PRIV_MODE 0666
static struct dev_priv {
char *driver;
int privonly;
const char *read_priv;
const char *write_priv;
} netdev_privs[] = {
{"icmp", PRIVONLY_DEV, PRIV_NET_ICMPACCESS, PRIV_NET_ICMPACCESS},
{"icmp6", PRIVONLY_DEV, PRIV_NET_ICMPACCESS, PRIV_NET_ICMPACCESS},
{"ip", PRIVONLY_DEV, PRIV_NET_RAWACCESS, PRIV_NET_RAWACCESS},
{"ip6", PRIVONLY_DEV, PRIV_NET_RAWACCESS, PRIV_NET_RAWACCESS},
{"keysock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG, PRIV_SYS_IP_CONFIG},
{"ipsecah", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG, PRIV_SYS_IP_CONFIG},
{"ipsecesp", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG, PRIV_SYS_IP_CONFIG},
{"spdsock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG, PRIV_SYS_IP_CONFIG},
{NULL, 0, NULL, NULL}
};
static int
inet_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
int i, ndevs;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
inet_dev_info = devi;
ndevs = sizeof (netdev_privs) / sizeof (struct dev_priv);
for (i = 0; i < ndevs; i++) {
char *drv = netdev_privs[i].driver;
if (drv == NULL || strcmp(drv, ddi_driver_name(devi)) == 0)
break;
}
return (ddi_create_priv_minor_node(devi, INET_NAME, S_IFCHR,
INET_DEVMINOR, DDI_PSEUDO, netdev_privs[i].privonly,
netdev_privs[i].read_priv, netdev_privs[i].write_priv,
INET_DEFAULT_PRIV_MODE));
}
static int
inet_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
ASSERT(devi == inet_dev_info);
ddi_remove_minor_node(devi, NULL);
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
inet_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
{
int error = DDI_FAILURE;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
if (inet_dev_info != NULL) {
*result = (void *)inet_dev_info;
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
*result = NULL;
error = DDI_SUCCESS;
break;
default:
break;
}
return (error);
}
DDI_DEFINE_STREAM_OPS(inet_devops, nulldev, nulldev, inet_attach, inet_detach,
nulldev, inet_info, INET_DEVMTFLAGS, &INET_DEVSTRTAB,
ddi_quiesce_not_supported);
static struct modldrv modldrv = {
&mod_driverops,
INET_DEVDESC,
&inet_devops
};
#endif /* INET_DEVDESC */
#ifdef INET_MODDESC
extern struct streamtab INET_MODSTRTAB;
static struct fmodsw fsw = {
INET_NAME,
&INET_MODSTRTAB,
INET_MODMTFLAGS
};
static struct modlstrmod modlstrmod = {
&mod_strmodops,
INET_MODDESC,
&fsw
};
#endif /* INET_MODDESC */
#ifdef INET_SOCKDESC
#ifdef INET_SOCK_PROTO_FB_FUNC
static __smod_priv_t smodpriv = {
NULL,
NULL,
INET_SOCK_PROTO_FB_FUNC,
INET_SOCK_FALLBACK_DEV_V4,
INET_SOCK_FALLBACK_DEV_V6
};
#endif /* INET_SOCK_PROTO_FB_FUNC */
static struct smod_reg_s smodreg = {
SOCKMOD_VERSION,
INET_NAME,
SOCK_UC_VERSION,
SOCK_DC_VERSION,
INET_SOCK_PROTO_CREATE_FUNC,
#ifdef INET_SOCK_PROTO_FB_FUNC
&smodpriv
#else
NULL
#endif /* INET_SOCK_PROTO_FB_FUNC */
};
static struct modlsockmod modlsockmod = {
&mod_sockmodops,
INET_SOCKDESC,
&smodreg
};
#endif /* INET_SOCKDESC */
static struct modlinkage modlinkage = {
MODREV_1,
#ifdef INET_DEVDESC
&modldrv,
#endif
#ifdef INET_MODDESC
&modlstrmod,
#endif
#ifdef INET_SOCKDESC
&modlsockmod,
#endif
NULL
};