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