/* * 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 #include #include #include #include #include /* * 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/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) { size_t 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; } /* smatch has no idea what VERIFY does. */ if (i == ndevs) { VERIFY(i < ndevs); return (DDI_FAILURE); } 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 };