1*0f1702c5SYu Xiangning /* 2*0f1702c5SYu Xiangning * CDDL HEADER START 3*0f1702c5SYu Xiangning * 4*0f1702c5SYu Xiangning * The contents of this file are subject to the terms of the 5*0f1702c5SYu Xiangning * Common Development and Distribution License (the "License"). 6*0f1702c5SYu Xiangning * You may not use this file except in compliance with the License. 7*0f1702c5SYu Xiangning * 8*0f1702c5SYu Xiangning * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*0f1702c5SYu Xiangning * or http://www.opensolaris.org/os/licensing. 10*0f1702c5SYu Xiangning * See the License for the specific language governing permissions 11*0f1702c5SYu Xiangning * and limitations under the License. 12*0f1702c5SYu Xiangning * 13*0f1702c5SYu Xiangning * When distributing Covered Code, include this CDDL HEADER in each 14*0f1702c5SYu Xiangning * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*0f1702c5SYu Xiangning * If applicable, add the following below this CDDL HEADER, with the 16*0f1702c5SYu Xiangning * fields enclosed by brackets "[]" replaced with your own identifying 17*0f1702c5SYu Xiangning * information: Portions Copyright [yyyy] [name of copyright owner] 18*0f1702c5SYu Xiangning * 19*0f1702c5SYu Xiangning * CDDL HEADER END 20*0f1702c5SYu Xiangning */ 21*0f1702c5SYu Xiangning 22*0f1702c5SYu Xiangning /* 23*0f1702c5SYu Xiangning * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*0f1702c5SYu Xiangning * Use is subject to license terms. 25*0f1702c5SYu Xiangning */ 26*0f1702c5SYu Xiangning 27*0f1702c5SYu Xiangning #include <sys/types.h> 28*0f1702c5SYu Xiangning #include <sys/t_lock.h> 29*0f1702c5SYu Xiangning #include <sys/param.h> 30*0f1702c5SYu Xiangning #include <sys/systm.h> 31*0f1702c5SYu Xiangning #include <sys/sysmacros.h> 32*0f1702c5SYu Xiangning #include <sys/cmn_err.h> 33*0f1702c5SYu Xiangning #include <sys/list.h> 34*0f1702c5SYu Xiangning 35*0f1702c5SYu Xiangning #include <sys/stropts.h> 36*0f1702c5SYu Xiangning #include <sys/socket.h> 37*0f1702c5SYu Xiangning #include <sys/socketvar.h> 38*0f1702c5SYu Xiangning 39*0f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h> 40*0f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h> 41*0f1702c5SYu Xiangning 42*0f1702c5SYu Xiangning /* 43*0f1702c5SYu Xiangning * Socket Parameters 44*0f1702c5SYu Xiangning * 45*0f1702c5SYu Xiangning * Socket parameter (struct sockparams) entries represent the socket types 46*0f1702c5SYu Xiangning * available on the system. 47*0f1702c5SYu Xiangning * 48*0f1702c5SYu Xiangning * Flags (sp_flags): 49*0f1702c5SYu Xiangning * 50*0f1702c5SYu Xiangning * SOCKPARAMS_EPHEMERAL: A temporary sockparams entry that will be deleted 51*0f1702c5SYu Xiangning * as soon as its' ref count drops to zero. In addition, ephemeral entries will 52*0f1702c5SYu Xiangning * never be hooked onto the global sockparams list. Ephemeral entries are 53*0f1702c5SYu Xiangning * created when application requests to create a socket using an application 54*0f1702c5SYu Xiangning * supplied device path, or when a socket is falling back to TPI. 55*0f1702c5SYu Xiangning * 56*0f1702c5SYu Xiangning * Lock order: 57*0f1702c5SYu Xiangning * The lock order is splist_lock -> sp_lock. 58*0f1702c5SYu Xiangning * The lock order is sp_ephem_lock -> sp_lock. 59*0f1702c5SYu Xiangning */ 60*0f1702c5SYu Xiangning extern int kobj_path_exists(char *, int); 61*0f1702c5SYu Xiangning extern void nl7c_init(void); 62*0f1702c5SYu Xiangning extern int sockfs_defer_nl7c_init; 63*0f1702c5SYu Xiangning 64*0f1702c5SYu Xiangning static int sockparams_sdev_init(struct sockparams *, char *, int); 65*0f1702c5SYu Xiangning static void sockparams_sdev_fini(struct sockparams *); 66*0f1702c5SYu Xiangning 67*0f1702c5SYu Xiangning /* 68*0f1702c5SYu Xiangning * Global sockparams list (populated via soconfig(1M)). 69*0f1702c5SYu Xiangning */ 70*0f1702c5SYu Xiangning static list_t sphead; 71*0f1702c5SYu Xiangning static krwlock_t splist_lock; 72*0f1702c5SYu Xiangning 73*0f1702c5SYu Xiangning /* 74*0f1702c5SYu Xiangning * List of ephemeral sockparams. 75*0f1702c5SYu Xiangning */ 76*0f1702c5SYu Xiangning static list_t sp_ephem_list; 77*0f1702c5SYu Xiangning static krwlock_t sp_ephem_lock; 78*0f1702c5SYu Xiangning 79*0f1702c5SYu Xiangning /* 80*0f1702c5SYu Xiangning * Mearch criteria used by sockparams_find() 81*0f1702c5SYu Xiangning */ 82*0f1702c5SYu Xiangning typedef enum sp_match_criteria { 83*0f1702c5SYu Xiangning SP_MATCH_EXACT, /* family, type & proto must match */ 84*0f1702c5SYu Xiangning SP_MATCH_WILDCARD, /* family & type must match, proto can be 0 */ 85*0f1702c5SYu Xiangning SP_MATCH_INC_DEV, /* same as exact, but dev must also match */ 86*0f1702c5SYu Xiangning SP_MATCH_INC_MOD /* same as exact, but mod must also match */ 87*0f1702c5SYu Xiangning } sp_match_criteria_t; 88*0f1702c5SYu Xiangning 89*0f1702c5SYu Xiangning 90*0f1702c5SYu Xiangning void 91*0f1702c5SYu Xiangning sockparams_init(void) 92*0f1702c5SYu Xiangning { 93*0f1702c5SYu Xiangning list_create(&sphead, sizeof (struct sockparams), 94*0f1702c5SYu Xiangning offsetof(struct sockparams, sp_node)); 95*0f1702c5SYu Xiangning list_create(&sp_ephem_list, sizeof (struct sockparams), 96*0f1702c5SYu Xiangning offsetof(struct sockparams, sp_node)); 97*0f1702c5SYu Xiangning 98*0f1702c5SYu Xiangning rw_init(&splist_lock, NULL, RW_DEFAULT, NULL); 99*0f1702c5SYu Xiangning rw_init(&sp_ephem_lock, NULL, RW_DEFAULT, NULL); 100*0f1702c5SYu Xiangning } 101*0f1702c5SYu Xiangning 102*0f1702c5SYu Xiangning /* 103*0f1702c5SYu Xiangning * sockparams_create(int family, int type, int protocol, char *modname, 104*0f1702c5SYu Xiangning * char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 105*0f1702c5SYu Xiangning * 106*0f1702c5SYu Xiangning * Create a new sockparams entry. 107*0f1702c5SYu Xiangning * 108*0f1702c5SYu Xiangning * Arguments: 109*0f1702c5SYu Xiangning * family, type, protocol: specifies the socket type 110*0f1702c5SYu Xiangning * modname: Name of the module associated with the socket type. The 111*0f1702c5SYu Xiangning * module can be NULL if a device path is given, in which 112*0f1702c5SYu Xiangning * case the TPI module is used. 113*0f1702c5SYu Xiangning * devpath: Path to the STREAMS device. May be NULL for non-STREAMS 114*0f1702c5SYu Xiangning * based transports, or those transports that do not provide 115*0f1702c5SYu Xiangning * the capability to fallback to STREAMS. 116*0f1702c5SYu Xiangning * devpathlen: Length of the devpath string. The argument can be 0, 117*0f1702c5SYu Xiangning * indicating that devpath was allocated statically, and should 118*0f1702c5SYu Xiangning * not be freed when the sockparams entry is destroyed. 119*0f1702c5SYu Xiangning * 120*0f1702c5SYu Xiangning * flags : SOCKPARAMS_EPHEMERAL is the only flag that is allowed. 121*0f1702c5SYu Xiangning * kmflags: KM_{NO,}SLEEP 122*0f1702c5SYu Xiangning * errorp : Value-return argument, set when an error occurs. 123*0f1702c5SYu Xiangning * 124*0f1702c5SYu Xiangning * Returns: 125*0f1702c5SYu Xiangning * On success a new sockparams entry is returned, and *errorp is set 126*0f1702c5SYu Xiangning * to 0. On failure NULL is returned and *errorp is set to indicate the 127*0f1702c5SYu Xiangning * type of error that occured. 128*0f1702c5SYu Xiangning * 129*0f1702c5SYu Xiangning * Notes: 130*0f1702c5SYu Xiangning * devpath and modname are freed upon failure. 131*0f1702c5SYu Xiangning */ 132*0f1702c5SYu Xiangning struct sockparams * 133*0f1702c5SYu Xiangning sockparams_create(int family, int type, int protocol, char *modname, 134*0f1702c5SYu Xiangning char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 135*0f1702c5SYu Xiangning { 136*0f1702c5SYu Xiangning struct sockparams *sp = NULL; 137*0f1702c5SYu Xiangning size_t size; 138*0f1702c5SYu Xiangning 139*0f1702c5SYu Xiangning ASSERT((flags & ~SOCKPARAMS_EPHEMERAL) == 0); 140*0f1702c5SYu Xiangning if (flags & ~SOCKPARAMS_EPHEMERAL) { 141*0f1702c5SYu Xiangning *errorp = EINVAL; 142*0f1702c5SYu Xiangning goto error; 143*0f1702c5SYu Xiangning } 144*0f1702c5SYu Xiangning 145*0f1702c5SYu Xiangning /* either a module or device must be given */ 146*0f1702c5SYu Xiangning if (modname == NULL && devpath == NULL) { 147*0f1702c5SYu Xiangning *errorp = EINVAL; 148*0f1702c5SYu Xiangning goto error; 149*0f1702c5SYu Xiangning } 150*0f1702c5SYu Xiangning 151*0f1702c5SYu Xiangning sp = kmem_zalloc(sizeof (*sp), kmflags); 152*0f1702c5SYu Xiangning if (sp == NULL) { 153*0f1702c5SYu Xiangning *errorp = ENOMEM; 154*0f1702c5SYu Xiangning goto error; 155*0f1702c5SYu Xiangning } 156*0f1702c5SYu Xiangning sp->sp_family = family; 157*0f1702c5SYu Xiangning sp->sp_type = type; 158*0f1702c5SYu Xiangning sp->sp_protocol = protocol; 159*0f1702c5SYu Xiangning sp->sp_refcnt = 0; 160*0f1702c5SYu Xiangning sp->sp_flags = flags; 161*0f1702c5SYu Xiangning 162*0f1702c5SYu Xiangning if (modname != NULL) { 163*0f1702c5SYu Xiangning sp->sp_smod_name = modname; 164*0f1702c5SYu Xiangning } else { 165*0f1702c5SYu Xiangning size = strlen(SOTPI_SMOD_NAME) + 1; 166*0f1702c5SYu Xiangning modname = kmem_zalloc(size, kmflags); 167*0f1702c5SYu Xiangning if (modname == NULL) { 168*0f1702c5SYu Xiangning *errorp = ENOMEM; 169*0f1702c5SYu Xiangning goto error; 170*0f1702c5SYu Xiangning } 171*0f1702c5SYu Xiangning sp->sp_smod_name = modname; 172*0f1702c5SYu Xiangning (void) sprintf(sp->sp_smod_name, "%s", SOTPI_SMOD_NAME); 173*0f1702c5SYu Xiangning } 174*0f1702c5SYu Xiangning 175*0f1702c5SYu Xiangning if (devpath != NULL) { 176*0f1702c5SYu Xiangning /* Set up the device entry. */ 177*0f1702c5SYu Xiangning *errorp = sockparams_sdev_init(sp, devpath, devpathlen); 178*0f1702c5SYu Xiangning if (*errorp != 0) 179*0f1702c5SYu Xiangning goto error; 180*0f1702c5SYu Xiangning } 181*0f1702c5SYu Xiangning 182*0f1702c5SYu Xiangning mutex_init(&sp->sp_lock, NULL, MUTEX_DEFAULT, NULL); 183*0f1702c5SYu Xiangning *errorp = 0; 184*0f1702c5SYu Xiangning return (sp); 185*0f1702c5SYu Xiangning error: 186*0f1702c5SYu Xiangning ASSERT(*errorp != 0); 187*0f1702c5SYu Xiangning if (modname != NULL) 188*0f1702c5SYu Xiangning kmem_free(modname, strlen(modname) + 1); 189*0f1702c5SYu Xiangning if (devpathlen != 0) 190*0f1702c5SYu Xiangning kmem_free(devpath, devpathlen); 191*0f1702c5SYu Xiangning if (sp != NULL) 192*0f1702c5SYu Xiangning kmem_free(sp, sizeof (*sp)); 193*0f1702c5SYu Xiangning return (NULL); 194*0f1702c5SYu Xiangning } 195*0f1702c5SYu Xiangning 196*0f1702c5SYu Xiangning /* 197*0f1702c5SYu Xiangning * Initialize the STREAMS device aspect of the sockparams entry. 198*0f1702c5SYu Xiangning */ 199*0f1702c5SYu Xiangning static int 200*0f1702c5SYu Xiangning sockparams_sdev_init(struct sockparams *sp, char *devpath, int devpathlen) 201*0f1702c5SYu Xiangning { 202*0f1702c5SYu Xiangning vnode_t *vp = NULL; 203*0f1702c5SYu Xiangning int error; 204*0f1702c5SYu Xiangning 205*0f1702c5SYu Xiangning ASSERT(devpath != NULL); 206*0f1702c5SYu Xiangning 207*0f1702c5SYu Xiangning if ((error = sogetvp(devpath, &vp, UIO_SYSSPACE)) != 0) { 208*0f1702c5SYu Xiangning dprint(0, ("sockparams_sdev_init: vp %s failed with %d\n", 209*0f1702c5SYu Xiangning devpath, error)); 210*0f1702c5SYu Xiangning return (error); 211*0f1702c5SYu Xiangning } 212*0f1702c5SYu Xiangning 213*0f1702c5SYu Xiangning ASSERT(vp != NULL); 214*0f1702c5SYu Xiangning sp->sp_sdev_info.sd_vnode = vp; 215*0f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath = devpath; 216*0f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpathlen = devpathlen; 217*0f1702c5SYu Xiangning 218*0f1702c5SYu Xiangning return (0); 219*0f1702c5SYu Xiangning } 220*0f1702c5SYu Xiangning 221*0f1702c5SYu Xiangning /* 222*0f1702c5SYu Xiangning * sockparams_destroy(struct sockparams *sp) 223*0f1702c5SYu Xiangning * 224*0f1702c5SYu Xiangning * Releases all the resources associated with the sockparams entry, 225*0f1702c5SYu Xiangning * and frees the sockparams entry. 226*0f1702c5SYu Xiangning * 227*0f1702c5SYu Xiangning * Arguments: 228*0f1702c5SYu Xiangning * sp: the sockparams entry to destroy. 229*0f1702c5SYu Xiangning * 230*0f1702c5SYu Xiangning * Returns: 231*0f1702c5SYu Xiangning * Nothing. 232*0f1702c5SYu Xiangning * 233*0f1702c5SYu Xiangning * Locking: 234*0f1702c5SYu Xiangning * The sp_lock of the entry can not be held. 235*0f1702c5SYu Xiangning */ 236*0f1702c5SYu Xiangning void 237*0f1702c5SYu Xiangning sockparams_destroy(struct sockparams *sp) 238*0f1702c5SYu Xiangning { 239*0f1702c5SYu Xiangning ASSERT(sp->sp_refcnt == 0); 240*0f1702c5SYu Xiangning ASSERT(!list_link_active(&sp->sp_node)); 241*0f1702c5SYu Xiangning 242*0f1702c5SYu Xiangning sockparams_sdev_fini(sp); 243*0f1702c5SYu Xiangning 244*0f1702c5SYu Xiangning if (sp->sp_smod_info != NULL) 245*0f1702c5SYu Xiangning SMOD_DEC_REF(sp, sp->sp_smod_info); 246*0f1702c5SYu Xiangning kmem_free(sp->sp_smod_name, strlen(sp->sp_smod_name) + 1); 247*0f1702c5SYu Xiangning sp->sp_smod_name = NULL; 248*0f1702c5SYu Xiangning sp->sp_smod_info = NULL; 249*0f1702c5SYu Xiangning mutex_destroy(&sp->sp_lock); 250*0f1702c5SYu Xiangning 251*0f1702c5SYu Xiangning kmem_free(sp, sizeof (*sp)); 252*0f1702c5SYu Xiangning } 253*0f1702c5SYu Xiangning 254*0f1702c5SYu Xiangning /* 255*0f1702c5SYu Xiangning * Clean up the STREAMS device part of the sockparams entry. 256*0f1702c5SYu Xiangning */ 257*0f1702c5SYu Xiangning static void 258*0f1702c5SYu Xiangning sockparams_sdev_fini(struct sockparams *sp) 259*0f1702c5SYu Xiangning { 260*0f1702c5SYu Xiangning sdev_info_t sd; 261*0f1702c5SYu Xiangning 262*0f1702c5SYu Xiangning /* 263*0f1702c5SYu Xiangning * if the entry does not have a STREAMS device, then there 264*0f1702c5SYu Xiangning * is nothing to do. 265*0f1702c5SYu Xiangning */ 266*0f1702c5SYu Xiangning if (!SOCKPARAMS_HAS_DEVICE(sp)) 267*0f1702c5SYu Xiangning return; 268*0f1702c5SYu Xiangning 269*0f1702c5SYu Xiangning sd = sp->sp_sdev_info; 270*0f1702c5SYu Xiangning if (sd.sd_vnode != NULL) 271*0f1702c5SYu Xiangning VN_RELE(sd.sd_vnode); 272*0f1702c5SYu Xiangning if (sd.sd_devpathlen != 0) 273*0f1702c5SYu Xiangning kmem_free(sd.sd_devpath, sd.sd_devpathlen); 274*0f1702c5SYu Xiangning 275*0f1702c5SYu Xiangning sp->sp_sdev_info.sd_vnode = NULL; 276*0f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath = NULL; 277*0f1702c5SYu Xiangning } 278*0f1702c5SYu Xiangning 279*0f1702c5SYu Xiangning /* 280*0f1702c5SYu Xiangning * Look for a matching sockparams entry on the given list. 281*0f1702c5SYu Xiangning * 282*0f1702c5SYu Xiangning * The caller must hold the associated list lock. 283*0f1702c5SYu Xiangning */ 284*0f1702c5SYu Xiangning static struct sockparams * 285*0f1702c5SYu Xiangning sockparams_find(list_t *list, int family, int type, int protocol, 286*0f1702c5SYu Xiangning enum sp_match_criteria crit, const char *name) 287*0f1702c5SYu Xiangning { 288*0f1702c5SYu Xiangning struct sockparams *sp; 289*0f1702c5SYu Xiangning struct sockparams *wild = NULL; 290*0f1702c5SYu Xiangning 291*0f1702c5SYu Xiangning for (sp = list_head(list); sp != NULL; sp = list_next(list, sp)) { 292*0f1702c5SYu Xiangning if (sp->sp_family == family && 293*0f1702c5SYu Xiangning sp->sp_type == type) { 294*0f1702c5SYu Xiangning 295*0f1702c5SYu Xiangning if (sp->sp_protocol == protocol) { 296*0f1702c5SYu Xiangning if (crit == SP_MATCH_EXACT || 297*0f1702c5SYu Xiangning crit == SP_MATCH_WILDCARD) 298*0f1702c5SYu Xiangning break; 299*0f1702c5SYu Xiangning else if (crit == SP_MATCH_INC_DEV && 300*0f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath != NULL && 301*0f1702c5SYu Xiangning strcmp(sp->sp_sdev_info.sd_devpath, 302*0f1702c5SYu Xiangning name) == 0) 303*0f1702c5SYu Xiangning break; 304*0f1702c5SYu Xiangning else if (crit == SP_MATCH_INC_MOD && 305*0f1702c5SYu Xiangning strcmp(sp->sp_smod_name, name) == 0) 306*0f1702c5SYu Xiangning break; 307*0f1702c5SYu Xiangning } else if (crit == SP_MATCH_WILDCARD && 308*0f1702c5SYu Xiangning sp->sp_protocol == 0) { 309*0f1702c5SYu Xiangning /* best match so far */ 310*0f1702c5SYu Xiangning wild = sp; 311*0f1702c5SYu Xiangning } 312*0f1702c5SYu Xiangning } 313*0f1702c5SYu Xiangning } 314*0f1702c5SYu Xiangning 315*0f1702c5SYu Xiangning return ((sp == NULL) ? wild : sp); 316*0f1702c5SYu Xiangning } 317*0f1702c5SYu Xiangning 318*0f1702c5SYu Xiangning /* 319*0f1702c5SYu Xiangning * sockparams_hold_ephemeral() 320*0f1702c5SYu Xiangning * 321*0f1702c5SYu Xiangning * Returns an ephemeral sockparams entry of the requested family, type and 322*0f1702c5SYu Xiangning * protocol. The entry is returned held, and the caller is responsible for 323*0f1702c5SYu Xiangning * dropping the reference using SOCKPARAMS_DEC_REF() once done. 324*0f1702c5SYu Xiangning * 325*0f1702c5SYu Xiangning * All ephemeral entries are on list (sp_ephem_list). If there is an 326*0f1702c5SYu Xiangning * entry on the list that match the search criteria, then a reference is 327*0f1702c5SYu Xiangning * placed on that entry. Otherwise, a new entry is created and inserted 328*0f1702c5SYu Xiangning * in the list. The entry is removed from the list when the last reference 329*0f1702c5SYu Xiangning * is dropped. 330*0f1702c5SYu Xiangning * 331*0f1702c5SYu Xiangning * The tpi flag is used to determine whether name refers to a device or 332*0f1702c5SYu Xiangning * module name. 333*0f1702c5SYu Xiangning */ 334*0f1702c5SYu Xiangning static struct sockparams * 335*0f1702c5SYu Xiangning sockparams_hold_ephemeral(int family, int type, int protocol, 336*0f1702c5SYu Xiangning const char *name, boolean_t tpi, int kmflag, int *errorp) 337*0f1702c5SYu Xiangning { 338*0f1702c5SYu Xiangning struct sockparams *sp = NULL; 339*0f1702c5SYu Xiangning sp_match_criteria_t crit = (tpi) ? SP_MATCH_INC_DEV : SP_MATCH_INC_MOD; 340*0f1702c5SYu Xiangning 341*0f1702c5SYu Xiangning *errorp = 0; 342*0f1702c5SYu Xiangning 343*0f1702c5SYu Xiangning /* 344*0f1702c5SYu Xiangning * First look for an existing entry 345*0f1702c5SYu Xiangning */ 346*0f1702c5SYu Xiangning rw_enter(&sp_ephem_lock, RW_READER); 347*0f1702c5SYu Xiangning sp = sockparams_find(&sp_ephem_list, family, type, protocol, 348*0f1702c5SYu Xiangning crit, name); 349*0f1702c5SYu Xiangning if (sp != NULL) { 350*0f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 351*0f1702c5SYu Xiangning rw_exit(&sp_ephem_lock); 352*0f1702c5SYu Xiangning 353*0f1702c5SYu Xiangning return (sp); 354*0f1702c5SYu Xiangning } else { 355*0f1702c5SYu Xiangning struct sockparams *newsp = NULL; 356*0f1702c5SYu Xiangning char *namebuf = NULL; 357*0f1702c5SYu Xiangning int namelen = 0; 358*0f1702c5SYu Xiangning 359*0f1702c5SYu Xiangning rw_exit(&sp_ephem_lock); 360*0f1702c5SYu Xiangning 361*0f1702c5SYu Xiangning namelen = strlen(name) + 1; 362*0f1702c5SYu Xiangning namebuf = kmem_alloc(namelen, kmflag); 363*0f1702c5SYu Xiangning if (namebuf == NULL) { 364*0f1702c5SYu Xiangning *errorp = ENOMEM; 365*0f1702c5SYu Xiangning return (NULL); 366*0f1702c5SYu Xiangning } 367*0f1702c5SYu Xiangning 368*0f1702c5SYu Xiangning (void *)strncpy(namebuf, name, namelen); 369*0f1702c5SYu Xiangning if (tpi) { 370*0f1702c5SYu Xiangning newsp = sockparams_create(family, type, 371*0f1702c5SYu Xiangning protocol, NULL, namebuf, namelen, 372*0f1702c5SYu Xiangning SOCKPARAMS_EPHEMERAL, kmflag, errorp); 373*0f1702c5SYu Xiangning } else { 374*0f1702c5SYu Xiangning newsp = sockparams_create(family, type, 375*0f1702c5SYu Xiangning protocol, namebuf, NULL, 0, 376*0f1702c5SYu Xiangning SOCKPARAMS_EPHEMERAL, kmflag, errorp); 377*0f1702c5SYu Xiangning } 378*0f1702c5SYu Xiangning 379*0f1702c5SYu Xiangning if (newsp == NULL) { 380*0f1702c5SYu Xiangning ASSERT(*errorp != 0); 381*0f1702c5SYu Xiangning return (NULL); 382*0f1702c5SYu Xiangning } 383*0f1702c5SYu Xiangning 384*0f1702c5SYu Xiangning /* 385*0f1702c5SYu Xiangning * Time to load the socket module. 386*0f1702c5SYu Xiangning */ 387*0f1702c5SYu Xiangning ASSERT(newsp->sp_smod_info == NULL); 388*0f1702c5SYu Xiangning newsp->sp_smod_info = 389*0f1702c5SYu Xiangning smod_lookup_byname(newsp->sp_smod_name); 390*0f1702c5SYu Xiangning if (newsp->sp_smod_info == NULL) { 391*0f1702c5SYu Xiangning /* Failed to load */ 392*0f1702c5SYu Xiangning sockparams_destroy(newsp); 393*0f1702c5SYu Xiangning *errorp = ENXIO; 394*0f1702c5SYu Xiangning return (NULL); 395*0f1702c5SYu Xiangning } 396*0f1702c5SYu Xiangning 397*0f1702c5SYu Xiangning /* 398*0f1702c5SYu Xiangning * The sockparams entry was created, now try to add it 399*0f1702c5SYu Xiangning * to the list. We need to hold the lock as a WRITER. 400*0f1702c5SYu Xiangning */ 401*0f1702c5SYu Xiangning rw_enter(&sp_ephem_lock, RW_WRITER); 402*0f1702c5SYu Xiangning sp = sockparams_find(&sp_ephem_list, family, type, protocol, 403*0f1702c5SYu Xiangning crit, name); 404*0f1702c5SYu Xiangning if (sp != NULL) { 405*0f1702c5SYu Xiangning /* 406*0f1702c5SYu Xiangning * Someone has requested a matching entry, so just 407*0f1702c5SYu Xiangning * place a hold on it and release the entry we alloc'ed. 408*0f1702c5SYu Xiangning */ 409*0f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 410*0f1702c5SYu Xiangning rw_exit(&sp_ephem_lock); 411*0f1702c5SYu Xiangning 412*0f1702c5SYu Xiangning sockparams_destroy(newsp); 413*0f1702c5SYu Xiangning } else { 414*0f1702c5SYu Xiangning SOCKPARAMS_INC_REF(newsp); 415*0f1702c5SYu Xiangning list_insert_tail(&sp_ephem_list, newsp); 416*0f1702c5SYu Xiangning rw_exit(&sp_ephem_lock); 417*0f1702c5SYu Xiangning 418*0f1702c5SYu Xiangning sp = newsp; 419*0f1702c5SYu Xiangning } 420*0f1702c5SYu Xiangning ASSERT(*errorp == 0); 421*0f1702c5SYu Xiangning 422*0f1702c5SYu Xiangning return (sp); 423*0f1702c5SYu Xiangning } 424*0f1702c5SYu Xiangning } 425*0f1702c5SYu Xiangning 426*0f1702c5SYu Xiangning struct sockparams * 427*0f1702c5SYu Xiangning sockparams_hold_ephemeral_bydev(int family, int type, int protocol, 428*0f1702c5SYu Xiangning const char *dev, int kmflag, int *errorp) 429*0f1702c5SYu Xiangning { 430*0f1702c5SYu Xiangning return (sockparams_hold_ephemeral(family, type, protocol, dev, B_TRUE, 431*0f1702c5SYu Xiangning kmflag, errorp)); 432*0f1702c5SYu Xiangning } 433*0f1702c5SYu Xiangning 434*0f1702c5SYu Xiangning struct sockparams * 435*0f1702c5SYu Xiangning sockparams_hold_ephemeral_bymod(int family, int type, int protocol, 436*0f1702c5SYu Xiangning const char *mod, int kmflag, int *errorp) 437*0f1702c5SYu Xiangning { 438*0f1702c5SYu Xiangning return (sockparams_hold_ephemeral(family, type, protocol, mod, B_FALSE, 439*0f1702c5SYu Xiangning kmflag, errorp)); 440*0f1702c5SYu Xiangning } 441*0f1702c5SYu Xiangning 442*0f1702c5SYu Xiangning /* 443*0f1702c5SYu Xiangning * Called when the last socket using the ephemeral entry is dropping 444*0f1702c5SYu Xiangning * its' reference. To maintain lock order we must drop the sockparams 445*0f1702c5SYu Xiangning * lock before calling this function. As a result, a new reference 446*0f1702c5SYu Xiangning * might be placed on the entry, in which case there is nothing to 447*0f1702c5SYu Xiangning * do. However, if ref count goes to zero, we delete the entry. 448*0f1702c5SYu Xiangning */ 449*0f1702c5SYu Xiangning void 450*0f1702c5SYu Xiangning sockparams_ephemeral_drop_last_ref(struct sockparams *sp) 451*0f1702c5SYu Xiangning { 452*0f1702c5SYu Xiangning ASSERT(sp->sp_flags & SOCKPARAMS_EPHEMERAL); 453*0f1702c5SYu Xiangning ASSERT(MUTEX_NOT_HELD(&sp->sp_lock)); 454*0f1702c5SYu Xiangning 455*0f1702c5SYu Xiangning rw_enter(&sp_ephem_lock, RW_WRITER); 456*0f1702c5SYu Xiangning mutex_enter(&sp->sp_lock); 457*0f1702c5SYu Xiangning 458*0f1702c5SYu Xiangning if (--sp->sp_refcnt == 0) { 459*0f1702c5SYu Xiangning list_remove(&sp_ephem_list, sp); 460*0f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 461*0f1702c5SYu Xiangning rw_exit(&sp_ephem_lock); 462*0f1702c5SYu Xiangning 463*0f1702c5SYu Xiangning sockparams_destroy(sp); 464*0f1702c5SYu Xiangning } else { 465*0f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 466*0f1702c5SYu Xiangning rw_exit(&sp_ephem_lock); 467*0f1702c5SYu Xiangning } 468*0f1702c5SYu Xiangning } 469*0f1702c5SYu Xiangning 470*0f1702c5SYu Xiangning /* 471*0f1702c5SYu Xiangning * sockparams_add(struct sockparams *sp) 472*0f1702c5SYu Xiangning * 473*0f1702c5SYu Xiangning * Tries to add the given sockparams entry to the global list. 474*0f1702c5SYu Xiangning * 475*0f1702c5SYu Xiangning * Arguments: 476*0f1702c5SYu Xiangning * sp: the sockparms entry to add 477*0f1702c5SYu Xiangning * 478*0f1702c5SYu Xiangning * Returns: 479*0f1702c5SYu Xiangning * On success 0, but if an entry already exists, then EEXIST 480*0f1702c5SYu Xiangning * is returned. 481*0f1702c5SYu Xiangning * 482*0f1702c5SYu Xiangning * Locking: 483*0f1702c5SYu Xiangning * The caller can not be holding splist_lock. 484*0f1702c5SYu Xiangning */ 485*0f1702c5SYu Xiangning static int 486*0f1702c5SYu Xiangning sockparams_add(struct sockparams *sp) 487*0f1702c5SYu Xiangning { 488*0f1702c5SYu Xiangning ASSERT(!(sp->sp_flags & SOCKPARAMS_EPHEMERAL)); 489*0f1702c5SYu Xiangning 490*0f1702c5SYu Xiangning rw_enter(&splist_lock, RW_WRITER); 491*0f1702c5SYu Xiangning if (sockparams_find(&sphead, sp->sp_family, sp->sp_type, 492*0f1702c5SYu Xiangning sp->sp_protocol, SP_MATCH_EXACT, NULL) != 0) { 493*0f1702c5SYu Xiangning rw_exit(&splist_lock); 494*0f1702c5SYu Xiangning return (EEXIST); 495*0f1702c5SYu Xiangning } else { 496*0f1702c5SYu Xiangning list_insert_tail(&sphead, sp); 497*0f1702c5SYu Xiangning rw_exit(&splist_lock); 498*0f1702c5SYu Xiangning return (0); 499*0f1702c5SYu Xiangning } 500*0f1702c5SYu Xiangning } 501*0f1702c5SYu Xiangning 502*0f1702c5SYu Xiangning /* 503*0f1702c5SYu Xiangning * sockparams_delete(int family, int type, int protocol) 504*0f1702c5SYu Xiangning * 505*0f1702c5SYu Xiangning * Marks the sockparams entry for a specific family, type and protocol 506*0f1702c5SYu Xiangning * for deletion. The entry is removed from the list and destroyed 507*0f1702c5SYu Xiangning * if no one is holding a reference to it. 508*0f1702c5SYu Xiangning * 509*0f1702c5SYu Xiangning * Arguments: 510*0f1702c5SYu Xiangning * family, type, protocol: the socket type that should be removed. 511*0f1702c5SYu Xiangning * 512*0f1702c5SYu Xiangning * Returns: 513*0f1702c5SYu Xiangning * On success 0, otherwise ENXIO. 514*0f1702c5SYu Xiangning * 515*0f1702c5SYu Xiangning * Locking: 516*0f1702c5SYu Xiangning * Caller can not be holding splist_lock or the sp_lock of 517*0f1702c5SYu Xiangning * any sockparams entry. 518*0f1702c5SYu Xiangning */ 519*0f1702c5SYu Xiangning static int 520*0f1702c5SYu Xiangning sockparams_delete(int family, int type, int protocol) 521*0f1702c5SYu Xiangning { 522*0f1702c5SYu Xiangning struct sockparams *sp; 523*0f1702c5SYu Xiangning 524*0f1702c5SYu Xiangning rw_enter(&splist_lock, RW_WRITER); 525*0f1702c5SYu Xiangning sp = sockparams_find(&sphead, family, type, protocol, SP_MATCH_EXACT, 526*0f1702c5SYu Xiangning NULL); 527*0f1702c5SYu Xiangning 528*0f1702c5SYu Xiangning if (sp != NULL) { 529*0f1702c5SYu Xiangning /* 530*0f1702c5SYu Xiangning * If no one is holding a reference to the entry, then 531*0f1702c5SYu Xiangning * we go ahead and remove it from the list and then 532*0f1702c5SYu Xiangning * destroy it. 533*0f1702c5SYu Xiangning */ 534*0f1702c5SYu Xiangning mutex_enter(&sp->sp_lock); 535*0f1702c5SYu Xiangning if (sp->sp_refcnt != 0) { 536*0f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 537*0f1702c5SYu Xiangning rw_exit(&splist_lock); 538*0f1702c5SYu Xiangning return (EBUSY); 539*0f1702c5SYu Xiangning } 540*0f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 541*0f1702c5SYu Xiangning /* Delete the sockparams entry. */ 542*0f1702c5SYu Xiangning list_remove(&sphead, sp); 543*0f1702c5SYu Xiangning rw_exit(&splist_lock); 544*0f1702c5SYu Xiangning 545*0f1702c5SYu Xiangning sockparams_destroy(sp); 546*0f1702c5SYu Xiangning return (0); 547*0f1702c5SYu Xiangning } else { 548*0f1702c5SYu Xiangning rw_exit(&splist_lock); 549*0f1702c5SYu Xiangning return (ENXIO); 550*0f1702c5SYu Xiangning } 551*0f1702c5SYu Xiangning } 552*0f1702c5SYu Xiangning 553*0f1702c5SYu Xiangning /* 554*0f1702c5SYu Xiangning * soconfig(int family, int type, int protocol, 555*0f1702c5SYu Xiangning * char *devpath, int devpathlen, char *module) 556*0f1702c5SYu Xiangning * 557*0f1702c5SYu Xiangning * Add or delete an entry to the sockparams table. 558*0f1702c5SYu Xiangning * When devpath and module both are NULL, it will delete an entry. 559*0f1702c5SYu Xiangning * 560*0f1702c5SYu Xiangning * Arguments: 561*0f1702c5SYu Xiangning * family, type, protocol: the tuple in question 562*0f1702c5SYu Xiangning * devpath: STREAMS device path. Can be NULL for module based sockets. 563*0f1702c5SYu Xiangning * module : Name of the socket module. Can be NULL for STREAMS 564*0f1702c5SYu Xiangning * based sockets. 565*0f1702c5SYu Xiangning * devpathlen: length of the devpath string, or 0 if devpath 566*0f1702c5SYu Xiangning * was statically allocated. 567*0f1702c5SYu Xiangning * 568*0f1702c5SYu Xiangning * Note: 569*0f1702c5SYu Xiangning * This routine assumes that the caller has kmem_alloced 570*0f1702c5SYu Xiangning * devpath (if devpathlen > 0) and module for this routine to 571*0f1702c5SYu Xiangning * consume. 572*0f1702c5SYu Xiangning */ 573*0f1702c5SYu Xiangning int 574*0f1702c5SYu Xiangning soconfig(int family, int type, int protocol, 575*0f1702c5SYu Xiangning char *devpath, int devpathlen, char *module) 576*0f1702c5SYu Xiangning { 577*0f1702c5SYu Xiangning struct sockparams *sp; 578*0f1702c5SYu Xiangning int error = 0; 579*0f1702c5SYu Xiangning 580*0f1702c5SYu Xiangning dprint(0, ("soconfig(%d,%d,%d,%s,%d,%s)\n", 581*0f1702c5SYu Xiangning family, type, protocol, devpath, devpathlen, 582*0f1702c5SYu Xiangning module == NULL ? "NULL" : module)); 583*0f1702c5SYu Xiangning 584*0f1702c5SYu Xiangning if (sockfs_defer_nl7c_init) { 585*0f1702c5SYu Xiangning nl7c_init(); 586*0f1702c5SYu Xiangning sockfs_defer_nl7c_init = 0; 587*0f1702c5SYu Xiangning } 588*0f1702c5SYu Xiangning 589*0f1702c5SYu Xiangning if (devpath == NULL && module == NULL) { 590*0f1702c5SYu Xiangning /* 591*0f1702c5SYu Xiangning * Delete existing entry, 592*0f1702c5SYu Xiangning * both socket module and STEAMS device. 593*0f1702c5SYu Xiangning */ 594*0f1702c5SYu Xiangning ASSERT(module == NULL); 595*0f1702c5SYu Xiangning error = sockparams_delete(family, type, protocol); 596*0f1702c5SYu Xiangning } else { 597*0f1702c5SYu Xiangning /* 598*0f1702c5SYu Xiangning * Adding an entry 599*0f1702c5SYu Xiangning * sockparams_create frees mod name and devpath upon failure. 600*0f1702c5SYu Xiangning */ 601*0f1702c5SYu Xiangning sp = sockparams_create(family, type, protocol, module, 602*0f1702c5SYu Xiangning devpath, devpathlen, 0, KM_SLEEP, &error); 603*0f1702c5SYu Xiangning 604*0f1702c5SYu Xiangning if (sp != NULL) { 605*0f1702c5SYu Xiangning error = sockparams_add(sp); 606*0f1702c5SYu Xiangning if (error != 0) 607*0f1702c5SYu Xiangning sockparams_destroy(sp); 608*0f1702c5SYu Xiangning } 609*0f1702c5SYu Xiangning } 610*0f1702c5SYu Xiangning 611*0f1702c5SYu Xiangning return (error); 612*0f1702c5SYu Xiangning } 613*0f1702c5SYu Xiangning 614*0f1702c5SYu Xiangning /* 615*0f1702c5SYu Xiangning * solookup(int family, int type, int protocol, struct sockparams **spp) 616*0f1702c5SYu Xiangning * 617*0f1702c5SYu Xiangning * Lookup an entry in the sockparams list based on the triple. The returned 618*0f1702c5SYu Xiangning * entry either exactly match the given tuple, or it is the 'default' entry 619*0f1702c5SYu Xiangning * for the given <family, type>. A default entry is on with a protocol 620*0f1702c5SYu Xiangning * value of zero. 621*0f1702c5SYu Xiangning * 622*0f1702c5SYu Xiangning * Arguments: 623*0f1702c5SYu Xiangning * family, type, protocol: tuple to search for 624*0f1702c5SYu Xiangning * spp: Value-return argument 625*0f1702c5SYu Xiangning * 626*0f1702c5SYu Xiangning * Returns: 627*0f1702c5SYu Xiangning * If an entry is found, 0 is returned and *spp is set to point to the 628*0f1702c5SYu Xiangning * entry. In case an entry is not found, *spp is set to NULL, and an 629*0f1702c5SYu Xiangning * error code is returned. The errors are (in decreasing precedence): 630*0f1702c5SYu Xiangning * EAFNOSUPPORT - address family not in list 631*0f1702c5SYu Xiangning * EPROTONOSUPPORT - address family supported but not protocol. 632*0f1702c5SYu Xiangning * EPROTOTYPE - address family and protocol supported but not socket type. 633*0f1702c5SYu Xiangning * 634*0f1702c5SYu Xiangning * TODO: should use ddi_modopen()/ddi_modclose() 635*0f1702c5SYu Xiangning */ 636*0f1702c5SYu Xiangning 637*0f1702c5SYu Xiangning int 638*0f1702c5SYu Xiangning solookup(int family, int type, int protocol, struct sockparams **spp) 639*0f1702c5SYu Xiangning { 640*0f1702c5SYu Xiangning struct sockparams *sp = NULL; 641*0f1702c5SYu Xiangning int error = 0; 642*0f1702c5SYu Xiangning 643*0f1702c5SYu Xiangning *spp = NULL; 644*0f1702c5SYu Xiangning rw_enter(&splist_lock, RW_READER); 645*0f1702c5SYu Xiangning 646*0f1702c5SYu Xiangning /* 647*0f1702c5SYu Xiangning * Search the sockparams list for an appropiate entry. 648*0f1702c5SYu Xiangning * Hopefully we find an entry that match the exact family, 649*0f1702c5SYu Xiangning * type and protocol specified by the user, in which case 650*0f1702c5SYu Xiangning * we return that entry. However, we also keep track of 651*0f1702c5SYu Xiangning * the default entry for a specific family and type, the 652*0f1702c5SYu Xiangning * entry of which would have a protocol value of 0. 653*0f1702c5SYu Xiangning */ 654*0f1702c5SYu Xiangning sp = sockparams_find(&sphead, family, type, protocol, SP_MATCH_WILDCARD, 655*0f1702c5SYu Xiangning NULL); 656*0f1702c5SYu Xiangning 657*0f1702c5SYu Xiangning if (sp == NULL) { 658*0f1702c5SYu Xiangning int found = 0; 659*0f1702c5SYu Xiangning 660*0f1702c5SYu Xiangning /* Determine correct error code */ 661*0f1702c5SYu Xiangning for (sp = list_head(&sphead); sp != NULL; 662*0f1702c5SYu Xiangning sp = list_next(&sphead, sp)) { 663*0f1702c5SYu Xiangning if (sp->sp_family == family && found < 1) 664*0f1702c5SYu Xiangning found = 1; 665*0f1702c5SYu Xiangning if (sp->sp_family == family && 666*0f1702c5SYu Xiangning sp->sp_protocol == protocol && found < 2) 667*0f1702c5SYu Xiangning found = 2; 668*0f1702c5SYu Xiangning } 669*0f1702c5SYu Xiangning rw_exit(&splist_lock); 670*0f1702c5SYu Xiangning 671*0f1702c5SYu Xiangning switch (found) { 672*0f1702c5SYu Xiangning case 0: 673*0f1702c5SYu Xiangning error = EAFNOSUPPORT; 674*0f1702c5SYu Xiangning break; 675*0f1702c5SYu Xiangning case 1: 676*0f1702c5SYu Xiangning error = EPROTONOSUPPORT; 677*0f1702c5SYu Xiangning break; 678*0f1702c5SYu Xiangning case 2: 679*0f1702c5SYu Xiangning error = EPROTOTYPE; 680*0f1702c5SYu Xiangning break; 681*0f1702c5SYu Xiangning } 682*0f1702c5SYu Xiangning return (error); 683*0f1702c5SYu Xiangning } 684*0f1702c5SYu Xiangning 685*0f1702c5SYu Xiangning /* 686*0f1702c5SYu Xiangning * An entry was found. 687*0f1702c5SYu Xiangning * 688*0f1702c5SYu Xiangning * We put a hold on the entry early on, so if the 689*0f1702c5SYu Xiangning * sockmod is not loaded, and we have to exit 690*0f1702c5SYu Xiangning * splist_lock to call modload(), we know that the 691*0f1702c5SYu Xiangning * sockparams entry wont go away. That way we don't 692*0f1702c5SYu Xiangning * have to look up the entry once we come back from 693*0f1702c5SYu Xiangning * modload(). 694*0f1702c5SYu Xiangning */ 695*0f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 696*0f1702c5SYu Xiangning rw_exit(&splist_lock); 697*0f1702c5SYu Xiangning 698*0f1702c5SYu Xiangning if (sp->sp_smod_info == NULL) { 699*0f1702c5SYu Xiangning sp->sp_smod_info = smod_lookup_byname(sp->sp_smod_name); 700*0f1702c5SYu Xiangning if (sp->sp_smod_info == NULL) { 701*0f1702c5SYu Xiangning /* 702*0f1702c5SYu Xiangning * We put a hold on the sockparams entry 703*0f1702c5SYu Xiangning * earlier, hoping everything would work out. 704*0f1702c5SYu Xiangning * That obviously did not happen, so release 705*0f1702c5SYu Xiangning * the hold here. 706*0f1702c5SYu Xiangning */ 707*0f1702c5SYu Xiangning SOCKPARAMS_DEC_REF(sp); 708*0f1702c5SYu Xiangning /* 709*0f1702c5SYu Xiangning * We should probably mark the sockparams as 710*0f1702c5SYu Xiangning * "bad", and redo the lookup skipping the 711*0f1702c5SYu Xiangning * "bad" entries. I.e., sp->sp_mod_state |= BAD, 712*0f1702c5SYu Xiangning * return (solookup(...)) 713*0f1702c5SYu Xiangning */ 714*0f1702c5SYu Xiangning return (ENXIO); 715*0f1702c5SYu Xiangning } 716*0f1702c5SYu Xiangning } 717*0f1702c5SYu Xiangning 718*0f1702c5SYu Xiangning /* 719*0f1702c5SYu Xiangning * Alright, we have a valid sockparams entry. 720*0f1702c5SYu Xiangning */ 721*0f1702c5SYu Xiangning *spp = sp; 722*0f1702c5SYu Xiangning return (0); 723*0f1702c5SYu Xiangning } 724