1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/types.h>
  26 #include <sys/stat.h>
  27 #include <sys/stream.h>
  28 #include <sys/ddi.h>
  29 #include <sys/sunddi.h>
  30 #include <sys/priv_names.h>
  31 
  32 /*
  33  * This file contains generic goo needed to hook the STREAMS modules and
  34  * drivers that live under uts/common/inet into the DDI.  In order to use it,
  35  * each module/driver should #define the symbols below (as appropriate) and
  36  * then #include this source file; see the other uts/common/inet/<star>ddi.c
  37  * files for examples of this in action.
  38  *
  39  * The symbols that all modules and drivers must define are:
  40  *
  41  *      INET_NAME        The name of the module/driver.
  42  *
  43  * The symbols that all modules must define are:
  44  *
  45  *      INET_MODSTRTAB   The name of the `streamtab' structure for this module.
  46  *      INET_MODDESC     The one-line description for this module.
  47  *      INET_MODMTFLAGS  The mt-streams(9F) flags for the module.
  48  *
  49  * The symbols that all drivers must define are:
  50  *
  51  *      INET_DEVSTRTAB   The name of the `streamtab' structure for this driver.
  52  *      INET_DEVDESC     The one-line description for this driver.
  53  *      INET_DEVMTFLAGS  The mt-streams(9F) flags for the driver.
  54  *      INET_DEVMINOR    The minor number of the driver (usually 0).
  55  *
  56  * Drivers that need to masquerade as IP should set INET_DEVMTFLAGS to
  57  * IP_DEVMTFLAGS and set INET_DEVSTRTAB to ipinfo.
  58  *
  59  * The symbols that all socket modules must define are:
  60  *
  61  *      INET_SOCKDESC   The one-line description for this socket module
  62  *      INET_SOCK_PROTO_CREATE_FUNC The function used to create PCBs
  63  *
  64  * In addition, socket modules that can be converted to TPI must define:
  65  *
  66  *      INET_SOCK_PROTO_FB_FUNC The function used to fallback to TPI
  67  */
  68 
  69 #if     !defined(INET_NAME)
  70 #error inetddi.c: INET_NAME is not defined!
  71 #elif   !defined(INET_DEVDESC) && !defined(INET_MODDESC) && \
  72         !defined(INET_SOCKDESC)
  73 #error inetddi.c: at least one of INET_DEVDESC or INET_MODDESC or \
  74 INET_SOCKDESC must be defined!
  75 #elif   defined(INET_DEVDESC) && !defined(INET_DEVSTRTAB)
  76 #error inetddi.c: INET_DEVDESC is defined but INET_DEVSTRTAB is not!
  77 #elif   defined(INET_DEVDESC) && !defined(INET_DEVMTFLAGS)
  78 #error inetddi.c: INET_DEVDESC is defined but INET_DEVMTFLAGS is not!
  79 #elif   defined(INET_DEVDESC) && !defined(INET_DEVMINOR)
  80 #error inetddi.c: INET_DEVDESC is defined but INET_DEVMINOR is not!
  81 #elif   defined(INET_MODDESC) && !defined(INET_MODSTRTAB)
  82 #error inetddi.c: INET_MODDESC is defined but INET_MODSTRTAB is not!
  83 #elif   defined(INET_MODDESC) && !defined(INET_MODMTFLAGS)
  84 #error inetddi.c: INET_MODDESC is defined but INET_MODMTFLAGS is not!
  85 #elif   defined(INET_SOCKDESC) && !defined(SOCKMOD_VERSION)
  86 #error  inetddi.c: INET_SOCKDESC is defined but SOCKMOD_VERSION is not!
  87 #elif   defined(INET_SOCKDESC) && !defined(INET_SOCK_PROTO_CREATE_FUNC)
  88 #error  inetddi.c: INET_SOCKDESC is defined but INET_SOCK_PROTO_CREATE_FUNC \
  89 is not!
  90 #elif   defined(INET_SOCK_PROTO_FB_FUNC) && !defined(INET_SOCK_FALLBACK_DEV_V4)
  91 #error  inetddi.c: INET_SOCK_PROTO_FB_FUNC is defined but \
  92 INET_SOCK_FALLBACK_DEV_V4 is not!
  93 #elif   defined(INET_SOCK_PROTO_FB_FUNC) && !defined(INET_SOCK_FALLBACK_DEV_V6)
  94 #error  inetddi.c: INET_SOCK_PROTO_FB_FUNC is defined but \
  95 INET_SOCK_FALLBACK_DEV_V6 is not!
  96 #endif
  97 
  98 #ifdef  INET_DEVDESC
  99 
 100 extern struct streamtab INET_DEVSTRTAB;
 101 
 102 /*
 103  * Drivers that actually want to be IP would set INET_DEVSTRTAB to ipinfo.
 104  */
 105 
 106 static dev_info_t *inet_dev_info;
 107 
 108 #define INET_DEFAULT_PRIV_MODE  0666
 109 
 110 static struct dev_priv {
 111         char *driver;
 112         int privonly;
 113         const char *read_priv;
 114         const char *write_priv;
 115 } netdev_privs[] = {
 116         {"icmp", PRIVONLY_DEV,  PRIV_NET_ICMPACCESS,    PRIV_NET_ICMPACCESS},
 117         {"icmp6", PRIVONLY_DEV, PRIV_NET_ICMPACCESS,    PRIV_NET_ICMPACCESS},
 118         {"ip", PRIVONLY_DEV,    PRIV_NET_RAWACCESS,     PRIV_NET_RAWACCESS},
 119         {"ip6", PRIVONLY_DEV,   PRIV_NET_RAWACCESS,     PRIV_NET_RAWACCESS},
 120         {"keysock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,   PRIV_SYS_IP_CONFIG},
 121         {"ipsecah", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,   PRIV_SYS_IP_CONFIG},
 122         {"ipsecesp", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,  PRIV_SYS_IP_CONFIG},
 123         {"spdsock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,   PRIV_SYS_IP_CONFIG},
 124         {NULL,  0,              NULL,                   NULL}
 125 };
 126 
 127 static int
 128 inet_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 129 {
 130         int i, ndevs;
 131 
 132         if (cmd != DDI_ATTACH)
 133                 return (DDI_FAILURE);
 134 
 135         inet_dev_info = devi;
 136 
 137         ndevs = sizeof (netdev_privs) / sizeof (struct dev_priv);
 138         for (i = 0; i < ndevs; i++) {
 139                 char *drv = netdev_privs[i].driver;
 140                 if (drv == NULL || strcmp(drv, ddi_driver_name(devi)) == 0)
 141                         break;
 142         }
 143 
 144         return (ddi_create_priv_minor_node(devi, INET_NAME, S_IFCHR,
 145             INET_DEVMINOR, DDI_PSEUDO, netdev_privs[i].privonly,
 146             netdev_privs[i].read_priv, netdev_privs[i].write_priv,
 147             INET_DEFAULT_PRIV_MODE));
 148 }
 149 
 150 static int
 151 inet_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 152 {
 153         if (cmd != DDI_DETACH)
 154                 return (DDI_FAILURE);
 155 
 156         ASSERT(devi == inet_dev_info);
 157 
 158         ddi_remove_minor_node(devi, NULL);
 159         return (DDI_SUCCESS);
 160 }
 161 
 162 
 163 /* ARGSUSED */
 164 static int
 165 inet_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 166 {
 167         int error = DDI_FAILURE;
 168 
 169         switch (cmd) {
 170         case DDI_INFO_DEVT2DEVINFO:
 171                 if (inet_dev_info != NULL) {
 172                         *result = (void *)inet_dev_info;
 173                         error = DDI_SUCCESS;
 174                 }
 175                 break;
 176 
 177         case DDI_INFO_DEVT2INSTANCE:
 178                 *result = NULL;
 179                 error = DDI_SUCCESS;
 180                 break;
 181 
 182         default:
 183                 break;
 184         }
 185 
 186         return (error);
 187 }
 188 
 189 DDI_DEFINE_STREAM_OPS(inet_devops, nulldev, nulldev, inet_attach, inet_detach,
 190     nulldev, inet_info, INET_DEVMTFLAGS, &INET_DEVSTRTAB,
 191     ddi_quiesce_not_supported);
 192 
 193 static struct modldrv modldrv = {
 194         &mod_driverops,
 195         INET_DEVDESC,
 196         &inet_devops
 197 };
 198 
 199 #endif /* INET_DEVDESC */
 200 
 201 #ifdef  INET_MODDESC
 202 extern struct streamtab INET_MODSTRTAB;
 203 
 204 static struct fmodsw fsw = {
 205         INET_NAME,
 206         &INET_MODSTRTAB,
 207         INET_MODMTFLAGS
 208 };
 209 
 210 static struct modlstrmod modlstrmod = {
 211         &mod_strmodops,
 212         INET_MODDESC,
 213         &fsw
 214 };
 215 
 216 #endif /* INET_MODDESC */
 217 
 218 #ifdef  INET_SOCKDESC
 219 
 220 #ifdef  INET_SOCK_PROTO_FB_FUNC
 221 static __smod_priv_t smodpriv = {
 222         NULL,
 223         NULL,
 224         INET_SOCK_PROTO_FB_FUNC,
 225         INET_SOCK_FALLBACK_DEV_V4,
 226         INET_SOCK_FALLBACK_DEV_V6
 227 };
 228 #endif  /* INET_SOCK_PROTO_FB_FUNC */
 229 
 230 static struct smod_reg_s smodreg = {
 231         SOCKMOD_VERSION,
 232         INET_NAME,
 233         SOCK_UC_VERSION,
 234         SOCK_DC_VERSION,
 235         INET_SOCK_PROTO_CREATE_FUNC,
 236 #ifdef  INET_SOCK_PROTO_FB_FUNC
 237         &smodpriv
 238 #else
 239         NULL
 240 #endif  /* INET_SOCK_PROTO_FB_FUNC */
 241 };
 242 
 243 static struct modlsockmod modlsockmod = {
 244         &mod_sockmodops,
 245         INET_SOCKDESC,
 246         &smodreg
 247 };
 248 #endif  /* INET_SOCKDESC */
 249 
 250 static struct modlinkage modlinkage = {
 251         MODREV_1,
 252         {
 253 #ifdef  INET_DEVDESC
 254             &modldrv,
 255 #endif
 256 #ifdef  INET_MODDESC
 257             &modlstrmod,
 258 #endif
 259 #ifdef  INET_SOCKDESC
 260             &modlsockmod,
 261 #endif
 262             NULL
 263         }
 264 };