18348SEric.Yu@Sun.COM /* 28348SEric.Yu@Sun.COM * CDDL HEADER START 38348SEric.Yu@Sun.COM * 48348SEric.Yu@Sun.COM * The contents of this file are subject to the terms of the 58348SEric.Yu@Sun.COM * Common Development and Distribution License (the "License"). 68348SEric.Yu@Sun.COM * You may not use this file except in compliance with the License. 78348SEric.Yu@Sun.COM * 88348SEric.Yu@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98348SEric.Yu@Sun.COM * or http://www.opensolaris.org/os/licensing. 108348SEric.Yu@Sun.COM * See the License for the specific language governing permissions 118348SEric.Yu@Sun.COM * and limitations under the License. 128348SEric.Yu@Sun.COM * 138348SEric.Yu@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148348SEric.Yu@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158348SEric.Yu@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168348SEric.Yu@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178348SEric.Yu@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188348SEric.Yu@Sun.COM * 198348SEric.Yu@Sun.COM * CDDL HEADER END 208348SEric.Yu@Sun.COM */ 218348SEric.Yu@Sun.COM 228348SEric.Yu@Sun.COM /* 2312257SAnders.Persson@Sun.COM * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 248348SEric.Yu@Sun.COM */ 258348SEric.Yu@Sun.COM 268348SEric.Yu@Sun.COM #include <sys/types.h> 278348SEric.Yu@Sun.COM #include <sys/t_lock.h> 288348SEric.Yu@Sun.COM #include <sys/param.h> 298348SEric.Yu@Sun.COM #include <sys/systm.h> 308348SEric.Yu@Sun.COM #include <sys/sysmacros.h> 318348SEric.Yu@Sun.COM #include <sys/cmn_err.h> 328348SEric.Yu@Sun.COM #include <sys/list.h> 338348SEric.Yu@Sun.COM 348348SEric.Yu@Sun.COM #include <sys/stropts.h> 358348SEric.Yu@Sun.COM #include <sys/socket.h> 368348SEric.Yu@Sun.COM #include <sys/socketvar.h> 378348SEric.Yu@Sun.COM 388348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h> 39*12643SAnders.Persson@Sun.COM #include <fs/sockfs/sockfilter_impl.h> 408348SEric.Yu@Sun.COM #include <fs/sockfs/socktpi.h> 418348SEric.Yu@Sun.COM 428348SEric.Yu@Sun.COM /* 438348SEric.Yu@Sun.COM * Socket Parameters 448348SEric.Yu@Sun.COM * 458348SEric.Yu@Sun.COM * Socket parameter (struct sockparams) entries represent the socket types 468348SEric.Yu@Sun.COM * available on the system. 478348SEric.Yu@Sun.COM * 488348SEric.Yu@Sun.COM * Flags (sp_flags): 498348SEric.Yu@Sun.COM * 508348SEric.Yu@Sun.COM * SOCKPARAMS_EPHEMERAL: A temporary sockparams entry that will be deleted 518348SEric.Yu@Sun.COM * as soon as its' ref count drops to zero. In addition, ephemeral entries will 528348SEric.Yu@Sun.COM * never be hooked onto the global sockparams list. Ephemeral entries are 538348SEric.Yu@Sun.COM * created when application requests to create a socket using an application 548348SEric.Yu@Sun.COM * supplied device path, or when a socket is falling back to TPI. 558348SEric.Yu@Sun.COM * 568348SEric.Yu@Sun.COM * Lock order: 57*12643SAnders.Persson@Sun.COM * The lock order is sockconf_lock -> sp_lock. 588348SEric.Yu@Sun.COM */ 598348SEric.Yu@Sun.COM extern int kobj_path_exists(char *, int); 608348SEric.Yu@Sun.COM 618348SEric.Yu@Sun.COM static int sockparams_sdev_init(struct sockparams *, char *, int); 628348SEric.Yu@Sun.COM static void sockparams_sdev_fini(struct sockparams *); 638348SEric.Yu@Sun.COM 648348SEric.Yu@Sun.COM /* 658348SEric.Yu@Sun.COM * Global sockparams list (populated via soconfig(1M)). 668348SEric.Yu@Sun.COM */ 678348SEric.Yu@Sun.COM static list_t sphead; 688348SEric.Yu@Sun.COM 698348SEric.Yu@Sun.COM /* 708348SEric.Yu@Sun.COM * List of ephemeral sockparams. 718348SEric.Yu@Sun.COM */ 728348SEric.Yu@Sun.COM static list_t sp_ephem_list; 738348SEric.Yu@Sun.COM 748964SAnders.Persson@Sun.COM /* Global kstats for sockparams */ 758964SAnders.Persson@Sun.COM typedef struct sockparams_g_stats { 768964SAnders.Persson@Sun.COM kstat_named_t spgs_ephem_nalloc; 778964SAnders.Persson@Sun.COM kstat_named_t spgs_ephem_nreuse; 788964SAnders.Persson@Sun.COM } sockparams_g_stats_t; 798964SAnders.Persson@Sun.COM 808964SAnders.Persson@Sun.COM static sockparams_g_stats_t sp_g_stats; 818964SAnders.Persson@Sun.COM static kstat_t *sp_g_kstat; 828964SAnders.Persson@Sun.COM 838964SAnders.Persson@Sun.COM 848348SEric.Yu@Sun.COM void 858348SEric.Yu@Sun.COM sockparams_init(void) 868348SEric.Yu@Sun.COM { 878348SEric.Yu@Sun.COM list_create(&sphead, sizeof (struct sockparams), 888348SEric.Yu@Sun.COM offsetof(struct sockparams, sp_node)); 898348SEric.Yu@Sun.COM list_create(&sp_ephem_list, sizeof (struct sockparams), 908348SEric.Yu@Sun.COM offsetof(struct sockparams, sp_node)); 918348SEric.Yu@Sun.COM 928964SAnders.Persson@Sun.COM kstat_named_init(&sp_g_stats.spgs_ephem_nalloc, "ephemeral_nalloc", 938964SAnders.Persson@Sun.COM KSTAT_DATA_UINT64); 948964SAnders.Persson@Sun.COM kstat_named_init(&sp_g_stats.spgs_ephem_nreuse, "ephemeral_nreuse", 958964SAnders.Persson@Sun.COM KSTAT_DATA_UINT64); 968964SAnders.Persson@Sun.COM 978964SAnders.Persson@Sun.COM sp_g_kstat = kstat_create("sockfs", 0, "sockparams", "misc", 988964SAnders.Persson@Sun.COM KSTAT_TYPE_NAMED, sizeof (sp_g_stats) / sizeof (kstat_named_t), 998964SAnders.Persson@Sun.COM KSTAT_FLAG_VIRTUAL); 1008964SAnders.Persson@Sun.COM if (sp_g_kstat == NULL) 1018964SAnders.Persson@Sun.COM return; 1028964SAnders.Persson@Sun.COM 1038964SAnders.Persson@Sun.COM sp_g_kstat->ks_data = &sp_g_stats; 1048964SAnders.Persson@Sun.COM 1058964SAnders.Persson@Sun.COM kstat_install(sp_g_kstat); 1068964SAnders.Persson@Sun.COM } 1078964SAnders.Persson@Sun.COM 1088964SAnders.Persson@Sun.COM static int 1098964SAnders.Persson@Sun.COM sockparams_kstat_update(kstat_t *ksp, int rw) 1108964SAnders.Persson@Sun.COM { 1118964SAnders.Persson@Sun.COM struct sockparams *sp = ksp->ks_private; 1128964SAnders.Persson@Sun.COM sockparams_stats_t *sps = ksp->ks_data; 1138964SAnders.Persson@Sun.COM 1148964SAnders.Persson@Sun.COM if (rw == KSTAT_WRITE) 1158964SAnders.Persson@Sun.COM return (EACCES); 1168964SAnders.Persson@Sun.COM 1178964SAnders.Persson@Sun.COM sps->sps_nactive.value.ui64 = sp->sp_refcnt; 1188964SAnders.Persson@Sun.COM 1198964SAnders.Persson@Sun.COM return (0); 1208964SAnders.Persson@Sun.COM } 1218964SAnders.Persson@Sun.COM 1228964SAnders.Persson@Sun.COM /* 1238964SAnders.Persson@Sun.COM * Setup kstats for the given sockparams entry. 1248964SAnders.Persson@Sun.COM */ 1258964SAnders.Persson@Sun.COM static void 1268964SAnders.Persson@Sun.COM sockparams_kstat_init(struct sockparams *sp) 1278964SAnders.Persson@Sun.COM { 1288964SAnders.Persson@Sun.COM char name[KSTAT_STRLEN]; 1298964SAnders.Persson@Sun.COM 1308964SAnders.Persson@Sun.COM (void) snprintf(name, KSTAT_STRLEN, "socket_%d_%d_%d", sp->sp_family, 1318964SAnders.Persson@Sun.COM sp->sp_type, sp->sp_protocol); 1328964SAnders.Persson@Sun.COM 1338964SAnders.Persson@Sun.COM sp->sp_kstat = kstat_create("sockfs", 0, name, "misc", KSTAT_TYPE_NAMED, 1348964SAnders.Persson@Sun.COM sizeof (sockparams_stats_t) / sizeof (kstat_named_t), 1358964SAnders.Persson@Sun.COM KSTAT_FLAG_VIRTUAL); 1368964SAnders.Persson@Sun.COM 1378964SAnders.Persson@Sun.COM if (sp->sp_kstat == NULL) 1388964SAnders.Persson@Sun.COM return; 1398964SAnders.Persson@Sun.COM 1408964SAnders.Persson@Sun.COM sp->sp_kstat->ks_data = &sp->sp_stats; 1418964SAnders.Persson@Sun.COM sp->sp_kstat->ks_update = sockparams_kstat_update; 1428964SAnders.Persson@Sun.COM sp->sp_kstat->ks_private = sp; 1438964SAnders.Persson@Sun.COM kstat_install(sp->sp_kstat); 1448964SAnders.Persson@Sun.COM } 1458964SAnders.Persson@Sun.COM 1468964SAnders.Persson@Sun.COM static void 1478964SAnders.Persson@Sun.COM sockparams_kstat_fini(struct sockparams *sp) 1488964SAnders.Persson@Sun.COM { 1498964SAnders.Persson@Sun.COM if (sp->sp_kstat != NULL) { 1508964SAnders.Persson@Sun.COM kstat_delete(sp->sp_kstat); 1518964SAnders.Persson@Sun.COM sp->sp_kstat = NULL; 1528964SAnders.Persson@Sun.COM } 1538348SEric.Yu@Sun.COM } 1548348SEric.Yu@Sun.COM 1558348SEric.Yu@Sun.COM /* 1568348SEric.Yu@Sun.COM * sockparams_create(int family, int type, int protocol, char *modname, 1578348SEric.Yu@Sun.COM * char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 1588348SEric.Yu@Sun.COM * 1598348SEric.Yu@Sun.COM * Create a new sockparams entry. 1608348SEric.Yu@Sun.COM * 1618348SEric.Yu@Sun.COM * Arguments: 1628348SEric.Yu@Sun.COM * family, type, protocol: specifies the socket type 1638348SEric.Yu@Sun.COM * modname: Name of the module associated with the socket type. The 1648348SEric.Yu@Sun.COM * module can be NULL if a device path is given, in which 1658348SEric.Yu@Sun.COM * case the TPI module is used. 166*12643SAnders.Persson@Sun.COM * devpath: Path to the STREAMS device. Must be NULL for non-STREAMS 167*12643SAnders.Persson@Sun.COM * based transports. 1688348SEric.Yu@Sun.COM * devpathlen: Length of the devpath string. The argument can be 0, 1698348SEric.Yu@Sun.COM * indicating that devpath was allocated statically, and should 1708348SEric.Yu@Sun.COM * not be freed when the sockparams entry is destroyed. 1718348SEric.Yu@Sun.COM * 1728348SEric.Yu@Sun.COM * flags : SOCKPARAMS_EPHEMERAL is the only flag that is allowed. 1738348SEric.Yu@Sun.COM * kmflags: KM_{NO,}SLEEP 1748348SEric.Yu@Sun.COM * errorp : Value-return argument, set when an error occurs. 1758348SEric.Yu@Sun.COM * 1768348SEric.Yu@Sun.COM * Returns: 1778348SEric.Yu@Sun.COM * On success a new sockparams entry is returned, and *errorp is set 1788348SEric.Yu@Sun.COM * to 0. On failure NULL is returned and *errorp is set to indicate the 1798348SEric.Yu@Sun.COM * type of error that occured. 1808348SEric.Yu@Sun.COM * 1818348SEric.Yu@Sun.COM * Notes: 1828348SEric.Yu@Sun.COM * devpath and modname are freed upon failure. 1838348SEric.Yu@Sun.COM */ 1848348SEric.Yu@Sun.COM struct sockparams * 1858348SEric.Yu@Sun.COM sockparams_create(int family, int type, int protocol, char *modname, 1868348SEric.Yu@Sun.COM char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 1878348SEric.Yu@Sun.COM { 1888348SEric.Yu@Sun.COM struct sockparams *sp = NULL; 1898348SEric.Yu@Sun.COM size_t size; 1908348SEric.Yu@Sun.COM 1918348SEric.Yu@Sun.COM ASSERT((flags & ~SOCKPARAMS_EPHEMERAL) == 0); 1928348SEric.Yu@Sun.COM if (flags & ~SOCKPARAMS_EPHEMERAL) { 1938348SEric.Yu@Sun.COM *errorp = EINVAL; 1948348SEric.Yu@Sun.COM goto error; 1958348SEric.Yu@Sun.COM } 1968348SEric.Yu@Sun.COM 197*12643SAnders.Persson@Sun.COM /* either a module or device must be given, but not both */ 1988348SEric.Yu@Sun.COM if (modname == NULL && devpath == NULL) { 1998348SEric.Yu@Sun.COM *errorp = EINVAL; 2008348SEric.Yu@Sun.COM goto error; 2018348SEric.Yu@Sun.COM } 2028348SEric.Yu@Sun.COM 2038348SEric.Yu@Sun.COM sp = kmem_zalloc(sizeof (*sp), kmflags); 2048348SEric.Yu@Sun.COM if (sp == NULL) { 2058348SEric.Yu@Sun.COM *errorp = ENOMEM; 2068348SEric.Yu@Sun.COM goto error; 2078348SEric.Yu@Sun.COM } 2088348SEric.Yu@Sun.COM sp->sp_family = family; 2098348SEric.Yu@Sun.COM sp->sp_type = type; 2108348SEric.Yu@Sun.COM sp->sp_protocol = protocol; 2118348SEric.Yu@Sun.COM sp->sp_refcnt = 0; 2128348SEric.Yu@Sun.COM sp->sp_flags = flags; 2138348SEric.Yu@Sun.COM 214*12643SAnders.Persson@Sun.COM list_create(&sp->sp_auto_filters, sizeof (sp_filter_t), 215*12643SAnders.Persson@Sun.COM offsetof(sp_filter_t, spf_node)); 216*12643SAnders.Persson@Sun.COM list_create(&sp->sp_prog_filters, sizeof (sp_filter_t), 217*12643SAnders.Persson@Sun.COM offsetof(sp_filter_t, spf_node)); 218*12643SAnders.Persson@Sun.COM 2198981SAnders.Persson@Sun.COM kstat_named_init(&sp->sp_stats.sps_nfallback, "nfallback", 2208981SAnders.Persson@Sun.COM KSTAT_DATA_UINT64); 2218981SAnders.Persson@Sun.COM kstat_named_init(&sp->sp_stats.sps_nactive, "nactive", 2228981SAnders.Persson@Sun.COM KSTAT_DATA_UINT64); 2238981SAnders.Persson@Sun.COM kstat_named_init(&sp->sp_stats.sps_ncreate, "ncreate", 2248981SAnders.Persson@Sun.COM KSTAT_DATA_UINT64); 2258981SAnders.Persson@Sun.COM 2268964SAnders.Persson@Sun.COM /* 2278981SAnders.Persson@Sun.COM * Track how many ephemeral entries we have created. 2288964SAnders.Persson@Sun.COM */ 2298964SAnders.Persson@Sun.COM if (sp->sp_flags & SOCKPARAMS_EPHEMERAL) 2308964SAnders.Persson@Sun.COM sp_g_stats.spgs_ephem_nalloc.value.ui64++; 2318964SAnders.Persson@Sun.COM 2328348SEric.Yu@Sun.COM if (modname != NULL) { 2338348SEric.Yu@Sun.COM sp->sp_smod_name = modname; 2348348SEric.Yu@Sun.COM } else { 2358348SEric.Yu@Sun.COM size = strlen(SOTPI_SMOD_NAME) + 1; 2368348SEric.Yu@Sun.COM modname = kmem_zalloc(size, kmflags); 2378348SEric.Yu@Sun.COM if (modname == NULL) { 2388348SEric.Yu@Sun.COM *errorp = ENOMEM; 2398348SEric.Yu@Sun.COM goto error; 2408348SEric.Yu@Sun.COM } 2418348SEric.Yu@Sun.COM sp->sp_smod_name = modname; 2428348SEric.Yu@Sun.COM (void) sprintf(sp->sp_smod_name, "%s", SOTPI_SMOD_NAME); 2438348SEric.Yu@Sun.COM } 2448348SEric.Yu@Sun.COM 2458348SEric.Yu@Sun.COM if (devpath != NULL) { 2468348SEric.Yu@Sun.COM /* Set up the device entry. */ 2478348SEric.Yu@Sun.COM *errorp = sockparams_sdev_init(sp, devpath, devpathlen); 2488348SEric.Yu@Sun.COM if (*errorp != 0) 2498348SEric.Yu@Sun.COM goto error; 2508348SEric.Yu@Sun.COM } 2518348SEric.Yu@Sun.COM 2528348SEric.Yu@Sun.COM mutex_init(&sp->sp_lock, NULL, MUTEX_DEFAULT, NULL); 2538348SEric.Yu@Sun.COM *errorp = 0; 2548348SEric.Yu@Sun.COM return (sp); 2558348SEric.Yu@Sun.COM error: 2568348SEric.Yu@Sun.COM ASSERT(*errorp != 0); 2578348SEric.Yu@Sun.COM if (modname != NULL) 2588348SEric.Yu@Sun.COM kmem_free(modname, strlen(modname) + 1); 2598348SEric.Yu@Sun.COM if (devpathlen != 0) 2608348SEric.Yu@Sun.COM kmem_free(devpath, devpathlen); 2618981SAnders.Persson@Sun.COM if (sp != NULL) 2628348SEric.Yu@Sun.COM kmem_free(sp, sizeof (*sp)); 2638348SEric.Yu@Sun.COM return (NULL); 2648348SEric.Yu@Sun.COM } 2658348SEric.Yu@Sun.COM 2668348SEric.Yu@Sun.COM /* 2678348SEric.Yu@Sun.COM * Initialize the STREAMS device aspect of the sockparams entry. 2688348SEric.Yu@Sun.COM */ 2698348SEric.Yu@Sun.COM static int 2708348SEric.Yu@Sun.COM sockparams_sdev_init(struct sockparams *sp, char *devpath, int devpathlen) 2718348SEric.Yu@Sun.COM { 2728348SEric.Yu@Sun.COM vnode_t *vp = NULL; 2738348SEric.Yu@Sun.COM int error; 2748348SEric.Yu@Sun.COM 2758348SEric.Yu@Sun.COM ASSERT(devpath != NULL); 2768348SEric.Yu@Sun.COM 2778348SEric.Yu@Sun.COM if ((error = sogetvp(devpath, &vp, UIO_SYSSPACE)) != 0) { 2788348SEric.Yu@Sun.COM dprint(0, ("sockparams_sdev_init: vp %s failed with %d\n", 2798348SEric.Yu@Sun.COM devpath, error)); 2808348SEric.Yu@Sun.COM return (error); 2818348SEric.Yu@Sun.COM } 2828348SEric.Yu@Sun.COM 2838348SEric.Yu@Sun.COM ASSERT(vp != NULL); 2848348SEric.Yu@Sun.COM sp->sp_sdev_info.sd_vnode = vp; 2858348SEric.Yu@Sun.COM sp->sp_sdev_info.sd_devpath = devpath; 2868348SEric.Yu@Sun.COM sp->sp_sdev_info.sd_devpathlen = devpathlen; 2878348SEric.Yu@Sun.COM 2888348SEric.Yu@Sun.COM return (0); 2898348SEric.Yu@Sun.COM } 2908348SEric.Yu@Sun.COM 2918348SEric.Yu@Sun.COM /* 2928348SEric.Yu@Sun.COM * sockparams_destroy(struct sockparams *sp) 2938348SEric.Yu@Sun.COM * 2948348SEric.Yu@Sun.COM * Releases all the resources associated with the sockparams entry, 2958348SEric.Yu@Sun.COM * and frees the sockparams entry. 2968348SEric.Yu@Sun.COM * 2978348SEric.Yu@Sun.COM * Arguments: 2988348SEric.Yu@Sun.COM * sp: the sockparams entry to destroy. 2998348SEric.Yu@Sun.COM * 3008348SEric.Yu@Sun.COM * Returns: 3018348SEric.Yu@Sun.COM * Nothing. 3028348SEric.Yu@Sun.COM * 3038348SEric.Yu@Sun.COM * Locking: 3048348SEric.Yu@Sun.COM * The sp_lock of the entry can not be held. 3058348SEric.Yu@Sun.COM */ 3068348SEric.Yu@Sun.COM void 3078348SEric.Yu@Sun.COM sockparams_destroy(struct sockparams *sp) 3088348SEric.Yu@Sun.COM { 3098348SEric.Yu@Sun.COM ASSERT(sp->sp_refcnt == 0); 3108348SEric.Yu@Sun.COM ASSERT(!list_link_active(&sp->sp_node)); 3118348SEric.Yu@Sun.COM 3128348SEric.Yu@Sun.COM sockparams_sdev_fini(sp); 3138348SEric.Yu@Sun.COM 3148348SEric.Yu@Sun.COM if (sp->sp_smod_info != NULL) 31512257SAnders.Persson@Sun.COM SMOD_DEC_REF(sp->sp_smod_info, sp->sp_smod_name); 3168348SEric.Yu@Sun.COM kmem_free(sp->sp_smod_name, strlen(sp->sp_smod_name) + 1); 3178348SEric.Yu@Sun.COM sp->sp_smod_name = NULL; 3188348SEric.Yu@Sun.COM sp->sp_smod_info = NULL; 3198348SEric.Yu@Sun.COM mutex_destroy(&sp->sp_lock); 3208964SAnders.Persson@Sun.COM sockparams_kstat_fini(sp); 3218348SEric.Yu@Sun.COM 322*12643SAnders.Persson@Sun.COM sof_sockparams_fini(sp); 323*12643SAnders.Persson@Sun.COM list_destroy(&sp->sp_auto_filters); 324*12643SAnders.Persson@Sun.COM list_destroy(&sp->sp_prog_filters); 325*12643SAnders.Persson@Sun.COM 3268348SEric.Yu@Sun.COM kmem_free(sp, sizeof (*sp)); 3278348SEric.Yu@Sun.COM } 3288348SEric.Yu@Sun.COM 3298348SEric.Yu@Sun.COM /* 3308348SEric.Yu@Sun.COM * Clean up the STREAMS device part of the sockparams entry. 3318348SEric.Yu@Sun.COM */ 3328348SEric.Yu@Sun.COM static void 3338348SEric.Yu@Sun.COM sockparams_sdev_fini(struct sockparams *sp) 3348348SEric.Yu@Sun.COM { 3358348SEric.Yu@Sun.COM sdev_info_t sd; 3368348SEric.Yu@Sun.COM 3378348SEric.Yu@Sun.COM /* 3388348SEric.Yu@Sun.COM * if the entry does not have a STREAMS device, then there 3398348SEric.Yu@Sun.COM * is nothing to do. 3408348SEric.Yu@Sun.COM */ 3418348SEric.Yu@Sun.COM if (!SOCKPARAMS_HAS_DEVICE(sp)) 3428348SEric.Yu@Sun.COM return; 3438348SEric.Yu@Sun.COM 3448348SEric.Yu@Sun.COM sd = sp->sp_sdev_info; 3458348SEric.Yu@Sun.COM if (sd.sd_vnode != NULL) 3468348SEric.Yu@Sun.COM VN_RELE(sd.sd_vnode); 3478348SEric.Yu@Sun.COM if (sd.sd_devpathlen != 0) 3488348SEric.Yu@Sun.COM kmem_free(sd.sd_devpath, sd.sd_devpathlen); 3498348SEric.Yu@Sun.COM 3508348SEric.Yu@Sun.COM sp->sp_sdev_info.sd_vnode = NULL; 3518348SEric.Yu@Sun.COM sp->sp_sdev_info.sd_devpath = NULL; 3528348SEric.Yu@Sun.COM } 3538348SEric.Yu@Sun.COM 3548348SEric.Yu@Sun.COM /* 3558348SEric.Yu@Sun.COM * Look for a matching sockparams entry on the given list. 3568348SEric.Yu@Sun.COM * The caller must hold the associated list lock. 3578348SEric.Yu@Sun.COM */ 3588348SEric.Yu@Sun.COM static struct sockparams * 3598348SEric.Yu@Sun.COM sockparams_find(list_t *list, int family, int type, int protocol, 3608489Sshenjian boolean_t by_devpath, const char *name) 3618348SEric.Yu@Sun.COM { 3628348SEric.Yu@Sun.COM struct sockparams *sp; 3638348SEric.Yu@Sun.COM 3648348SEric.Yu@Sun.COM for (sp = list_head(list); sp != NULL; sp = list_next(list, sp)) { 3658489Sshenjian if (sp->sp_family == family && sp->sp_type == type) { 3668348SEric.Yu@Sun.COM if (sp->sp_protocol == protocol) { 3678489Sshenjian if (name == NULL) 3688348SEric.Yu@Sun.COM break; 3698489Sshenjian else if (by_devpath && 3708348SEric.Yu@Sun.COM sp->sp_sdev_info.sd_devpath != NULL && 3718348SEric.Yu@Sun.COM strcmp(sp->sp_sdev_info.sd_devpath, 3728348SEric.Yu@Sun.COM name) == 0) 3738348SEric.Yu@Sun.COM break; 3748489Sshenjian else if (strcmp(sp->sp_smod_name, name) == 0) 3758348SEric.Yu@Sun.COM break; 3768348SEric.Yu@Sun.COM } 3778348SEric.Yu@Sun.COM } 3788348SEric.Yu@Sun.COM } 3798489Sshenjian return (sp); 3808348SEric.Yu@Sun.COM } 3818348SEric.Yu@Sun.COM 3828348SEric.Yu@Sun.COM /* 3838348SEric.Yu@Sun.COM * sockparams_hold_ephemeral() 3848348SEric.Yu@Sun.COM * 3858348SEric.Yu@Sun.COM * Returns an ephemeral sockparams entry of the requested family, type and 3868348SEric.Yu@Sun.COM * protocol. The entry is returned held, and the caller is responsible for 3878348SEric.Yu@Sun.COM * dropping the reference using SOCKPARAMS_DEC_REF() once done. 3888348SEric.Yu@Sun.COM * 3898348SEric.Yu@Sun.COM * All ephemeral entries are on list (sp_ephem_list). If there is an 3908348SEric.Yu@Sun.COM * entry on the list that match the search criteria, then a reference is 3918348SEric.Yu@Sun.COM * placed on that entry. Otherwise, a new entry is created and inserted 3928348SEric.Yu@Sun.COM * in the list. The entry is removed from the list when the last reference 3938348SEric.Yu@Sun.COM * is dropped. 3948348SEric.Yu@Sun.COM * 3958348SEric.Yu@Sun.COM * The tpi flag is used to determine whether name refers to a device or 3968348SEric.Yu@Sun.COM * module name. 3978348SEric.Yu@Sun.COM */ 3988348SEric.Yu@Sun.COM static struct sockparams * 3998348SEric.Yu@Sun.COM sockparams_hold_ephemeral(int family, int type, int protocol, 4008489Sshenjian const char *name, boolean_t by_devpath, int kmflag, int *errorp) 4018348SEric.Yu@Sun.COM { 4028348SEric.Yu@Sun.COM struct sockparams *sp = NULL; 4038348SEric.Yu@Sun.COM *errorp = 0; 4048348SEric.Yu@Sun.COM 4058348SEric.Yu@Sun.COM /* 4068348SEric.Yu@Sun.COM * First look for an existing entry 4078348SEric.Yu@Sun.COM */ 408*12643SAnders.Persson@Sun.COM rw_enter(&sockconf_lock, RW_READER); 4098348SEric.Yu@Sun.COM sp = sockparams_find(&sp_ephem_list, family, type, protocol, 4108489Sshenjian by_devpath, name); 4118348SEric.Yu@Sun.COM if (sp != NULL) { 4128348SEric.Yu@Sun.COM SOCKPARAMS_INC_REF(sp); 413*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 4148964SAnders.Persson@Sun.COM sp_g_stats.spgs_ephem_nreuse.value.ui64++; 4158348SEric.Yu@Sun.COM 4168348SEric.Yu@Sun.COM return (sp); 4178348SEric.Yu@Sun.COM } else { 4188348SEric.Yu@Sun.COM struct sockparams *newsp = NULL; 4198348SEric.Yu@Sun.COM char *namebuf = NULL; 4208348SEric.Yu@Sun.COM int namelen = 0; 4218348SEric.Yu@Sun.COM 422*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 4238348SEric.Yu@Sun.COM 4248348SEric.Yu@Sun.COM namelen = strlen(name) + 1; 4258348SEric.Yu@Sun.COM namebuf = kmem_alloc(namelen, kmflag); 4268348SEric.Yu@Sun.COM if (namebuf == NULL) { 4278348SEric.Yu@Sun.COM *errorp = ENOMEM; 4288348SEric.Yu@Sun.COM return (NULL); 4298348SEric.Yu@Sun.COM } 4308348SEric.Yu@Sun.COM 4318348SEric.Yu@Sun.COM (void *)strncpy(namebuf, name, namelen); 4328489Sshenjian if (by_devpath) { 4338348SEric.Yu@Sun.COM newsp = sockparams_create(family, type, 4348348SEric.Yu@Sun.COM protocol, NULL, namebuf, namelen, 4358348SEric.Yu@Sun.COM SOCKPARAMS_EPHEMERAL, kmflag, errorp); 4368348SEric.Yu@Sun.COM } else { 4378348SEric.Yu@Sun.COM newsp = sockparams_create(family, type, 4388348SEric.Yu@Sun.COM protocol, namebuf, NULL, 0, 4398348SEric.Yu@Sun.COM SOCKPARAMS_EPHEMERAL, kmflag, errorp); 4408348SEric.Yu@Sun.COM } 4418348SEric.Yu@Sun.COM 4428348SEric.Yu@Sun.COM if (newsp == NULL) { 4438348SEric.Yu@Sun.COM ASSERT(*errorp != 0); 4448348SEric.Yu@Sun.COM return (NULL); 4458348SEric.Yu@Sun.COM } 4468348SEric.Yu@Sun.COM 4478348SEric.Yu@Sun.COM /* 4488348SEric.Yu@Sun.COM * Time to load the socket module. 4498348SEric.Yu@Sun.COM */ 4508348SEric.Yu@Sun.COM ASSERT(newsp->sp_smod_info == NULL); 4518348SEric.Yu@Sun.COM newsp->sp_smod_info = 4528348SEric.Yu@Sun.COM smod_lookup_byname(newsp->sp_smod_name); 4538348SEric.Yu@Sun.COM if (newsp->sp_smod_info == NULL) { 4548348SEric.Yu@Sun.COM /* Failed to load */ 4558348SEric.Yu@Sun.COM sockparams_destroy(newsp); 4568348SEric.Yu@Sun.COM *errorp = ENXIO; 4578348SEric.Yu@Sun.COM return (NULL); 4588348SEric.Yu@Sun.COM } 4598348SEric.Yu@Sun.COM 4608348SEric.Yu@Sun.COM /* 4618348SEric.Yu@Sun.COM * The sockparams entry was created, now try to add it 4628348SEric.Yu@Sun.COM * to the list. We need to hold the lock as a WRITER. 4638348SEric.Yu@Sun.COM */ 464*12643SAnders.Persson@Sun.COM rw_enter(&sockconf_lock, RW_WRITER); 4658348SEric.Yu@Sun.COM sp = sockparams_find(&sp_ephem_list, family, type, protocol, 4668489Sshenjian by_devpath, name); 4678348SEric.Yu@Sun.COM if (sp != NULL) { 4688348SEric.Yu@Sun.COM /* 4698348SEric.Yu@Sun.COM * Someone has requested a matching entry, so just 4708348SEric.Yu@Sun.COM * place a hold on it and release the entry we alloc'ed. 4718348SEric.Yu@Sun.COM */ 4728348SEric.Yu@Sun.COM SOCKPARAMS_INC_REF(sp); 473*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 4748348SEric.Yu@Sun.COM 4758348SEric.Yu@Sun.COM sockparams_destroy(newsp); 4768348SEric.Yu@Sun.COM } else { 477*12643SAnders.Persson@Sun.COM *errorp = sof_sockparams_init(newsp); 478*12643SAnders.Persson@Sun.COM if (*errorp != 0) { 479*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 480*12643SAnders.Persson@Sun.COM sockparams_destroy(newsp); 481*12643SAnders.Persson@Sun.COM return (NULL); 482*12643SAnders.Persson@Sun.COM } 4838348SEric.Yu@Sun.COM SOCKPARAMS_INC_REF(newsp); 4848348SEric.Yu@Sun.COM list_insert_tail(&sp_ephem_list, newsp); 485*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 4868348SEric.Yu@Sun.COM 4878348SEric.Yu@Sun.COM sp = newsp; 4888348SEric.Yu@Sun.COM } 4898348SEric.Yu@Sun.COM ASSERT(*errorp == 0); 4908348SEric.Yu@Sun.COM 4918348SEric.Yu@Sun.COM return (sp); 4928348SEric.Yu@Sun.COM } 4938348SEric.Yu@Sun.COM } 4948348SEric.Yu@Sun.COM 4958348SEric.Yu@Sun.COM struct sockparams * 4968348SEric.Yu@Sun.COM sockparams_hold_ephemeral_bydev(int family, int type, int protocol, 4978348SEric.Yu@Sun.COM const char *dev, int kmflag, int *errorp) 4988348SEric.Yu@Sun.COM { 4998348SEric.Yu@Sun.COM return (sockparams_hold_ephemeral(family, type, protocol, dev, B_TRUE, 5008348SEric.Yu@Sun.COM kmflag, errorp)); 5018348SEric.Yu@Sun.COM } 5028348SEric.Yu@Sun.COM 5038348SEric.Yu@Sun.COM struct sockparams * 5048348SEric.Yu@Sun.COM sockparams_hold_ephemeral_bymod(int family, int type, int protocol, 5058348SEric.Yu@Sun.COM const char *mod, int kmflag, int *errorp) 5068348SEric.Yu@Sun.COM { 5078348SEric.Yu@Sun.COM return (sockparams_hold_ephemeral(family, type, protocol, mod, B_FALSE, 5088348SEric.Yu@Sun.COM kmflag, errorp)); 5098348SEric.Yu@Sun.COM } 5108348SEric.Yu@Sun.COM 5118348SEric.Yu@Sun.COM /* 5128348SEric.Yu@Sun.COM * Called when the last socket using the ephemeral entry is dropping 5138348SEric.Yu@Sun.COM * its' reference. To maintain lock order we must drop the sockparams 5148348SEric.Yu@Sun.COM * lock before calling this function. As a result, a new reference 5158348SEric.Yu@Sun.COM * might be placed on the entry, in which case there is nothing to 5168348SEric.Yu@Sun.COM * do. However, if ref count goes to zero, we delete the entry. 5178348SEric.Yu@Sun.COM */ 5188348SEric.Yu@Sun.COM void 5198348SEric.Yu@Sun.COM sockparams_ephemeral_drop_last_ref(struct sockparams *sp) 5208348SEric.Yu@Sun.COM { 5218348SEric.Yu@Sun.COM ASSERT(sp->sp_flags & SOCKPARAMS_EPHEMERAL); 5228348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&sp->sp_lock)); 5238348SEric.Yu@Sun.COM 524*12643SAnders.Persson@Sun.COM rw_enter(&sockconf_lock, RW_WRITER); 5258348SEric.Yu@Sun.COM mutex_enter(&sp->sp_lock); 5268348SEric.Yu@Sun.COM 5278348SEric.Yu@Sun.COM if (--sp->sp_refcnt == 0) { 5288348SEric.Yu@Sun.COM list_remove(&sp_ephem_list, sp); 5298348SEric.Yu@Sun.COM mutex_exit(&sp->sp_lock); 530*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 5318348SEric.Yu@Sun.COM 5328348SEric.Yu@Sun.COM sockparams_destroy(sp); 5338348SEric.Yu@Sun.COM } else { 5348348SEric.Yu@Sun.COM mutex_exit(&sp->sp_lock); 535*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 5368348SEric.Yu@Sun.COM } 5378348SEric.Yu@Sun.COM } 5388348SEric.Yu@Sun.COM 5398348SEric.Yu@Sun.COM /* 5408348SEric.Yu@Sun.COM * sockparams_add(struct sockparams *sp) 5418348SEric.Yu@Sun.COM * 5428348SEric.Yu@Sun.COM * Tries to add the given sockparams entry to the global list. 5438348SEric.Yu@Sun.COM * 5448348SEric.Yu@Sun.COM * Arguments: 5458348SEric.Yu@Sun.COM * sp: the sockparms entry to add 5468348SEric.Yu@Sun.COM * 5478348SEric.Yu@Sun.COM * Returns: 5488348SEric.Yu@Sun.COM * On success 0, but if an entry already exists, then EEXIST 5498348SEric.Yu@Sun.COM * is returned. 5508348SEric.Yu@Sun.COM * 5518348SEric.Yu@Sun.COM * Locking: 552*12643SAnders.Persson@Sun.COM * The caller can not be holding sockconf_lock. 5538348SEric.Yu@Sun.COM */ 554*12643SAnders.Persson@Sun.COM int 5558348SEric.Yu@Sun.COM sockparams_add(struct sockparams *sp) 5568348SEric.Yu@Sun.COM { 557*12643SAnders.Persson@Sun.COM int error; 558*12643SAnders.Persson@Sun.COM 5598348SEric.Yu@Sun.COM ASSERT(!(sp->sp_flags & SOCKPARAMS_EPHEMERAL)); 5608348SEric.Yu@Sun.COM 561*12643SAnders.Persson@Sun.COM rw_enter(&sockconf_lock, RW_WRITER); 5628348SEric.Yu@Sun.COM if (sockparams_find(&sphead, sp->sp_family, sp->sp_type, 5638489Sshenjian sp->sp_protocol, B_TRUE, NULL) != 0) { 564*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 5658348SEric.Yu@Sun.COM return (EEXIST); 5668348SEric.Yu@Sun.COM } else { 567*12643SAnders.Persson@Sun.COM /* 568*12643SAnders.Persson@Sun.COM * Unique sockparams entry, so init the kstats. 569*12643SAnders.Persson@Sun.COM */ 570*12643SAnders.Persson@Sun.COM sockparams_kstat_init(sp); 571*12643SAnders.Persson@Sun.COM 572*12643SAnders.Persson@Sun.COM /* 573*12643SAnders.Persson@Sun.COM * Before making the socket type available we must make 574*12643SAnders.Persson@Sun.COM * sure that interested socket filters are aware of it. 575*12643SAnders.Persson@Sun.COM */ 576*12643SAnders.Persson@Sun.COM error = sof_sockparams_init(sp); 577*12643SAnders.Persson@Sun.COM if (error != 0) { 578*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 579*12643SAnders.Persson@Sun.COM return (error); 580*12643SAnders.Persson@Sun.COM } 5818348SEric.Yu@Sun.COM list_insert_tail(&sphead, sp); 582*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 5838348SEric.Yu@Sun.COM return (0); 5848348SEric.Yu@Sun.COM } 5858348SEric.Yu@Sun.COM } 5868348SEric.Yu@Sun.COM 5878348SEric.Yu@Sun.COM /* 5888348SEric.Yu@Sun.COM * sockparams_delete(int family, int type, int protocol) 5898348SEric.Yu@Sun.COM * 5908348SEric.Yu@Sun.COM * Marks the sockparams entry for a specific family, type and protocol 5918348SEric.Yu@Sun.COM * for deletion. The entry is removed from the list and destroyed 5928348SEric.Yu@Sun.COM * if no one is holding a reference to it. 5938348SEric.Yu@Sun.COM * 5948348SEric.Yu@Sun.COM * Arguments: 5958348SEric.Yu@Sun.COM * family, type, protocol: the socket type that should be removed. 5968348SEric.Yu@Sun.COM * 5978348SEric.Yu@Sun.COM * Returns: 5988348SEric.Yu@Sun.COM * On success 0, otherwise ENXIO. 5998348SEric.Yu@Sun.COM * 6008348SEric.Yu@Sun.COM * Locking: 601*12643SAnders.Persson@Sun.COM * Caller can not be holding sockconf_lock or the sp_lock of 6028348SEric.Yu@Sun.COM * any sockparams entry. 6038348SEric.Yu@Sun.COM */ 604*12643SAnders.Persson@Sun.COM int 6058348SEric.Yu@Sun.COM sockparams_delete(int family, int type, int protocol) 6068348SEric.Yu@Sun.COM { 6078348SEric.Yu@Sun.COM struct sockparams *sp; 6088348SEric.Yu@Sun.COM 609*12643SAnders.Persson@Sun.COM rw_enter(&sockconf_lock, RW_WRITER); 6108489Sshenjian sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL); 6118348SEric.Yu@Sun.COM 6128348SEric.Yu@Sun.COM if (sp != NULL) { 6138348SEric.Yu@Sun.COM /* 6148348SEric.Yu@Sun.COM * If no one is holding a reference to the entry, then 6158348SEric.Yu@Sun.COM * we go ahead and remove it from the list and then 6168348SEric.Yu@Sun.COM * destroy it. 6178348SEric.Yu@Sun.COM */ 6188348SEric.Yu@Sun.COM mutex_enter(&sp->sp_lock); 6198348SEric.Yu@Sun.COM if (sp->sp_refcnt != 0) { 6208348SEric.Yu@Sun.COM mutex_exit(&sp->sp_lock); 621*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 6228348SEric.Yu@Sun.COM return (EBUSY); 6238348SEric.Yu@Sun.COM } 6248348SEric.Yu@Sun.COM mutex_exit(&sp->sp_lock); 6258348SEric.Yu@Sun.COM /* Delete the sockparams entry. */ 6268348SEric.Yu@Sun.COM list_remove(&sphead, sp); 627*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 6288348SEric.Yu@Sun.COM 6298348SEric.Yu@Sun.COM sockparams_destroy(sp); 6308348SEric.Yu@Sun.COM return (0); 6318348SEric.Yu@Sun.COM } else { 632*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 6338348SEric.Yu@Sun.COM return (ENXIO); 6348348SEric.Yu@Sun.COM } 6358348SEric.Yu@Sun.COM } 6368348SEric.Yu@Sun.COM 6378348SEric.Yu@Sun.COM 6388348SEric.Yu@Sun.COM /* 6398348SEric.Yu@Sun.COM * solookup(int family, int type, int protocol, struct sockparams **spp) 6408348SEric.Yu@Sun.COM * 6418348SEric.Yu@Sun.COM * Lookup an entry in the sockparams list based on the triple. The returned 6428348SEric.Yu@Sun.COM * entry either exactly match the given tuple, or it is the 'default' entry 6438348SEric.Yu@Sun.COM * for the given <family, type>. A default entry is on with a protocol 6448348SEric.Yu@Sun.COM * value of zero. 6458348SEric.Yu@Sun.COM * 6468348SEric.Yu@Sun.COM * Arguments: 6478348SEric.Yu@Sun.COM * family, type, protocol: tuple to search for 6488348SEric.Yu@Sun.COM * spp: Value-return argument 6498348SEric.Yu@Sun.COM * 6508348SEric.Yu@Sun.COM * Returns: 6518348SEric.Yu@Sun.COM * If an entry is found, 0 is returned and *spp is set to point to the 6528348SEric.Yu@Sun.COM * entry. In case an entry is not found, *spp is set to NULL, and an 6538348SEric.Yu@Sun.COM * error code is returned. The errors are (in decreasing precedence): 6548348SEric.Yu@Sun.COM * EAFNOSUPPORT - address family not in list 6558348SEric.Yu@Sun.COM * EPROTONOSUPPORT - address family supported but not protocol. 6568348SEric.Yu@Sun.COM * EPROTOTYPE - address family and protocol supported but not socket type. 6578348SEric.Yu@Sun.COM * 6588348SEric.Yu@Sun.COM * TODO: should use ddi_modopen()/ddi_modclose() 6598348SEric.Yu@Sun.COM */ 6608348SEric.Yu@Sun.COM int 6618348SEric.Yu@Sun.COM solookup(int family, int type, int protocol, struct sockparams **spp) 6628348SEric.Yu@Sun.COM { 6638348SEric.Yu@Sun.COM struct sockparams *sp = NULL; 6648348SEric.Yu@Sun.COM int error = 0; 6658348SEric.Yu@Sun.COM 6668348SEric.Yu@Sun.COM *spp = NULL; 667*12643SAnders.Persson@Sun.COM rw_enter(&sockconf_lock, RW_READER); 6688348SEric.Yu@Sun.COM 6698348SEric.Yu@Sun.COM /* 6708348SEric.Yu@Sun.COM * Search the sockparams list for an appropiate entry. 6718348SEric.Yu@Sun.COM * Hopefully we find an entry that match the exact family, 6728348SEric.Yu@Sun.COM * type and protocol specified by the user, in which case 6738348SEric.Yu@Sun.COM * we return that entry. However, we also keep track of 6748348SEric.Yu@Sun.COM * the default entry for a specific family and type, the 6758348SEric.Yu@Sun.COM * entry of which would have a protocol value of 0. 6768348SEric.Yu@Sun.COM */ 6778489Sshenjian sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL); 6788348SEric.Yu@Sun.COM 6798348SEric.Yu@Sun.COM if (sp == NULL) { 6808348SEric.Yu@Sun.COM int found = 0; 6818348SEric.Yu@Sun.COM 6828348SEric.Yu@Sun.COM /* Determine correct error code */ 6838348SEric.Yu@Sun.COM for (sp = list_head(&sphead); sp != NULL; 6848348SEric.Yu@Sun.COM sp = list_next(&sphead, sp)) { 6858348SEric.Yu@Sun.COM if (sp->sp_family == family && found < 1) 6868348SEric.Yu@Sun.COM found = 1; 6878348SEric.Yu@Sun.COM if (sp->sp_family == family && 6888348SEric.Yu@Sun.COM sp->sp_protocol == protocol && found < 2) 6898348SEric.Yu@Sun.COM found = 2; 6908348SEric.Yu@Sun.COM } 691*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 6928348SEric.Yu@Sun.COM switch (found) { 6938348SEric.Yu@Sun.COM case 0: 6948348SEric.Yu@Sun.COM error = EAFNOSUPPORT; 6958348SEric.Yu@Sun.COM break; 6968348SEric.Yu@Sun.COM case 1: 6978348SEric.Yu@Sun.COM error = EPROTONOSUPPORT; 6988348SEric.Yu@Sun.COM break; 6998348SEric.Yu@Sun.COM case 2: 7008348SEric.Yu@Sun.COM error = EPROTOTYPE; 7018348SEric.Yu@Sun.COM break; 7028348SEric.Yu@Sun.COM } 7038348SEric.Yu@Sun.COM return (error); 7048348SEric.Yu@Sun.COM } 7058348SEric.Yu@Sun.COM 7068348SEric.Yu@Sun.COM /* 7078348SEric.Yu@Sun.COM * An entry was found. 7088348SEric.Yu@Sun.COM * 7098348SEric.Yu@Sun.COM * We put a hold on the entry early on, so if the 7108348SEric.Yu@Sun.COM * sockmod is not loaded, and we have to exit 711*12643SAnders.Persson@Sun.COM * sockconf_lock to call modload(), we know that the 7128348SEric.Yu@Sun.COM * sockparams entry wont go away. That way we don't 7138348SEric.Yu@Sun.COM * have to look up the entry once we come back from 7148348SEric.Yu@Sun.COM * modload(). 7158348SEric.Yu@Sun.COM */ 7168348SEric.Yu@Sun.COM SOCKPARAMS_INC_REF(sp); 717*12643SAnders.Persson@Sun.COM rw_exit(&sockconf_lock); 7188348SEric.Yu@Sun.COM 7198348SEric.Yu@Sun.COM if (sp->sp_smod_info == NULL) { 72012257SAnders.Persson@Sun.COM smod_info_t *smod = smod_lookup_byname(sp->sp_smod_name); 72112257SAnders.Persson@Sun.COM 72212257SAnders.Persson@Sun.COM if (smod == NULL) { 7238348SEric.Yu@Sun.COM /* 7248348SEric.Yu@Sun.COM * We put a hold on the sockparams entry 7258348SEric.Yu@Sun.COM * earlier, hoping everything would work out. 7268348SEric.Yu@Sun.COM * That obviously did not happen, so release 7278348SEric.Yu@Sun.COM * the hold here. 7288348SEric.Yu@Sun.COM */ 7298348SEric.Yu@Sun.COM SOCKPARAMS_DEC_REF(sp); 7308348SEric.Yu@Sun.COM /* 7318348SEric.Yu@Sun.COM * We should probably mark the sockparams as 7328348SEric.Yu@Sun.COM * "bad", and redo the lookup skipping the 7338348SEric.Yu@Sun.COM * "bad" entries. I.e., sp->sp_mod_state |= BAD, 7348348SEric.Yu@Sun.COM * return (solookup(...)) 7358348SEric.Yu@Sun.COM */ 7368348SEric.Yu@Sun.COM return (ENXIO); 7378348SEric.Yu@Sun.COM } 73812257SAnders.Persson@Sun.COM /* 73912257SAnders.Persson@Sun.COM * Another thread might have already looked up the socket 74012257SAnders.Persson@Sun.COM * module for this entry. In that case we need to drop our 74112257SAnders.Persson@Sun.COM * reference to `smod' to ensure that the sockparams entry 74212257SAnders.Persson@Sun.COM * only holds one reference. 74312257SAnders.Persson@Sun.COM */ 74412257SAnders.Persson@Sun.COM mutex_enter(&sp->sp_lock); 74512257SAnders.Persson@Sun.COM if (sp->sp_smod_info == NULL) 74612257SAnders.Persson@Sun.COM sp->sp_smod_info = smod; 74712257SAnders.Persson@Sun.COM else 74812257SAnders.Persson@Sun.COM SMOD_DEC_REF(smod, sp->sp_smod_name); 74912257SAnders.Persson@Sun.COM mutex_exit(&sp->sp_lock); 7508348SEric.Yu@Sun.COM } 7518348SEric.Yu@Sun.COM 7528348SEric.Yu@Sun.COM /* 7538348SEric.Yu@Sun.COM * Alright, we have a valid sockparams entry. 7548348SEric.Yu@Sun.COM */ 7558348SEric.Yu@Sun.COM *spp = sp; 7568348SEric.Yu@Sun.COM return (0); 7578348SEric.Yu@Sun.COM } 758*12643SAnders.Persson@Sun.COM 759*12643SAnders.Persson@Sun.COM /* 760*12643SAnders.Persson@Sun.COM * Called when filter entry `ent' is going away. All sockparams remove 761*12643SAnders.Persson@Sun.COM * their references to `ent'. 762*12643SAnders.Persson@Sun.COM */ 763*12643SAnders.Persson@Sun.COM static void 764*12643SAnders.Persson@Sun.COM sockparams_filter_cleanup_impl(sof_entry_t *ent, list_t *list) 765*12643SAnders.Persson@Sun.COM { 766*12643SAnders.Persson@Sun.COM struct sockparams *sp; 767*12643SAnders.Persson@Sun.COM sp_filter_t *fil; 768*12643SAnders.Persson@Sun.COM list_t *flist; 769*12643SAnders.Persson@Sun.COM 770*12643SAnders.Persson@Sun.COM ASSERT(RW_WRITE_HELD(&sockconf_lock)); 771*12643SAnders.Persson@Sun.COM 772*12643SAnders.Persson@Sun.COM for (sp = list_head(list); sp != NULL; 773*12643SAnders.Persson@Sun.COM sp = list_next(list, sp)) { 774*12643SAnders.Persson@Sun.COM flist = (ent->sofe_flags & SOFEF_AUTO) ? 775*12643SAnders.Persson@Sun.COM &sp->sp_auto_filters : &sp->sp_prog_filters; 776*12643SAnders.Persson@Sun.COM fil = list_head(flist); 777*12643SAnders.Persson@Sun.COM for (fil = list_head(flist); fil != NULL; 778*12643SAnders.Persson@Sun.COM fil = list_next(flist, fil)) { 779*12643SAnders.Persson@Sun.COM if (fil->spf_filter == ent) { 780*12643SAnders.Persson@Sun.COM list_remove(flist, fil); 781*12643SAnders.Persson@Sun.COM kmem_free(fil, sizeof (sp_filter_t)); 782*12643SAnders.Persson@Sun.COM break; 783*12643SAnders.Persson@Sun.COM } 784*12643SAnders.Persson@Sun.COM } 785*12643SAnders.Persson@Sun.COM } 786*12643SAnders.Persson@Sun.COM } 787*12643SAnders.Persson@Sun.COM void 788*12643SAnders.Persson@Sun.COM sockparams_filter_cleanup(sof_entry_t *ent) 789*12643SAnders.Persson@Sun.COM { 790*12643SAnders.Persson@Sun.COM sockparams_filter_cleanup_impl(ent, &sphead); 791*12643SAnders.Persson@Sun.COM sockparams_filter_cleanup_impl(ent, &sp_ephem_list); 792*12643SAnders.Persson@Sun.COM } 793*12643SAnders.Persson@Sun.COM 794*12643SAnders.Persson@Sun.COM /* 795*12643SAnders.Persson@Sun.COM * New filter is being added; walk the list of sockparams to see if 796*12643SAnders.Persson@Sun.COM * the filter is interested in any of the sockparams. 797*12643SAnders.Persson@Sun.COM */ 798*12643SAnders.Persson@Sun.COM static int 799*12643SAnders.Persson@Sun.COM sockparams_new_filter_impl(sof_entry_t *ent, list_t *list) 800*12643SAnders.Persson@Sun.COM { 801*12643SAnders.Persson@Sun.COM struct sockparams *sp; 802*12643SAnders.Persson@Sun.COM int err; 803*12643SAnders.Persson@Sun.COM 804*12643SAnders.Persson@Sun.COM ASSERT(RW_WRITE_HELD(&sockconf_lock)); 805*12643SAnders.Persson@Sun.COM 806*12643SAnders.Persson@Sun.COM for (sp = list_head(list); sp != NULL; 807*12643SAnders.Persson@Sun.COM sp = list_next(list, sp)) { 808*12643SAnders.Persson@Sun.COM if ((err = sof_entry_proc_sockparams(ent, sp)) != 0) { 809*12643SAnders.Persson@Sun.COM sockparams_filter_cleanup(ent); 810*12643SAnders.Persson@Sun.COM return (err); 811*12643SAnders.Persson@Sun.COM } 812*12643SAnders.Persson@Sun.COM } 813*12643SAnders.Persson@Sun.COM return (0); 814*12643SAnders.Persson@Sun.COM } 815*12643SAnders.Persson@Sun.COM 816*12643SAnders.Persson@Sun.COM int 817*12643SAnders.Persson@Sun.COM sockparams_new_filter(sof_entry_t *ent) 818*12643SAnders.Persson@Sun.COM { 819*12643SAnders.Persson@Sun.COM int error; 820*12643SAnders.Persson@Sun.COM 821*12643SAnders.Persson@Sun.COM if ((error = sockparams_new_filter_impl(ent, &sphead)) != 0) 822*12643SAnders.Persson@Sun.COM return (error); 823*12643SAnders.Persson@Sun.COM 824*12643SAnders.Persson@Sun.COM if ((error = sockparams_new_filter_impl(ent, &sp_ephem_list)) != 0) 825*12643SAnders.Persson@Sun.COM sockparams_filter_cleanup_impl(ent, &sphead); 826*12643SAnders.Persson@Sun.COM return (error); 827*12643SAnders.Persson@Sun.COM } 828