10f1702c5SYu Xiangning /* 20f1702c5SYu Xiangning * CDDL HEADER START 30f1702c5SYu Xiangning * 40f1702c5SYu Xiangning * The contents of this file are subject to the terms of the 50f1702c5SYu Xiangning * Common Development and Distribution License (the "License"). 60f1702c5SYu Xiangning * You may not use this file except in compliance with the License. 70f1702c5SYu Xiangning * 80f1702c5SYu Xiangning * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90f1702c5SYu Xiangning * or http://www.opensolaris.org/os/licensing. 100f1702c5SYu Xiangning * See the License for the specific language governing permissions 110f1702c5SYu Xiangning * and limitations under the License. 120f1702c5SYu Xiangning * 130f1702c5SYu Xiangning * When distributing Covered Code, include this CDDL HEADER in each 140f1702c5SYu Xiangning * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150f1702c5SYu Xiangning * If applicable, add the following below this CDDL HEADER, with the 160f1702c5SYu Xiangning * fields enclosed by brackets "[]" replaced with your own identifying 170f1702c5SYu Xiangning * information: Portions Copyright [yyyy] [name of copyright owner] 180f1702c5SYu Xiangning * 190f1702c5SYu Xiangning * CDDL HEADER END 200f1702c5SYu Xiangning */ 210f1702c5SYu Xiangning 220f1702c5SYu Xiangning /* 235f1fdc18SAnders Persson * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 240f1702c5SYu Xiangning */ 250f1702c5SYu Xiangning 260f1702c5SYu Xiangning #include <sys/types.h> 270f1702c5SYu Xiangning #include <sys/t_lock.h> 280f1702c5SYu Xiangning #include <sys/param.h> 290f1702c5SYu Xiangning #include <sys/systm.h> 300f1702c5SYu Xiangning #include <sys/sysmacros.h> 310f1702c5SYu Xiangning #include <sys/cmn_err.h> 320f1702c5SYu Xiangning #include <sys/list.h> 330f1702c5SYu Xiangning 340f1702c5SYu Xiangning #include <sys/stropts.h> 350f1702c5SYu Xiangning #include <sys/socket.h> 360f1702c5SYu Xiangning #include <sys/socketvar.h> 370f1702c5SYu Xiangning 380f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h> 39*3e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h> 400f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h> 410f1702c5SYu Xiangning 420f1702c5SYu Xiangning /* 430f1702c5SYu Xiangning * Socket Parameters 440f1702c5SYu Xiangning * 450f1702c5SYu Xiangning * Socket parameter (struct sockparams) entries represent the socket types 460f1702c5SYu Xiangning * available on the system. 470f1702c5SYu Xiangning * 480f1702c5SYu Xiangning * Flags (sp_flags): 490f1702c5SYu Xiangning * 500f1702c5SYu Xiangning * SOCKPARAMS_EPHEMERAL: A temporary sockparams entry that will be deleted 510f1702c5SYu Xiangning * as soon as its' ref count drops to zero. In addition, ephemeral entries will 520f1702c5SYu Xiangning * never be hooked onto the global sockparams list. Ephemeral entries are 530f1702c5SYu Xiangning * created when application requests to create a socket using an application 540f1702c5SYu Xiangning * supplied device path, or when a socket is falling back to TPI. 550f1702c5SYu Xiangning * 560f1702c5SYu Xiangning * Lock order: 57*3e95bd4aSAnders Persson * The lock order is sockconf_lock -> sp_lock. 580f1702c5SYu Xiangning */ 590f1702c5SYu Xiangning extern int kobj_path_exists(char *, int); 600f1702c5SYu Xiangning 610f1702c5SYu Xiangning static int sockparams_sdev_init(struct sockparams *, char *, int); 620f1702c5SYu Xiangning static void sockparams_sdev_fini(struct sockparams *); 630f1702c5SYu Xiangning 640f1702c5SYu Xiangning /* 650f1702c5SYu Xiangning * Global sockparams list (populated via soconfig(1M)). 660f1702c5SYu Xiangning */ 670f1702c5SYu Xiangning static list_t sphead; 680f1702c5SYu Xiangning 690f1702c5SYu Xiangning /* 700f1702c5SYu Xiangning * List of ephemeral sockparams. 710f1702c5SYu Xiangning */ 720f1702c5SYu Xiangning static list_t sp_ephem_list; 730f1702c5SYu Xiangning 747d64f41bSAnders Persson /* Global kstats for sockparams */ 757d64f41bSAnders Persson typedef struct sockparams_g_stats { 767d64f41bSAnders Persson kstat_named_t spgs_ephem_nalloc; 777d64f41bSAnders Persson kstat_named_t spgs_ephem_nreuse; 787d64f41bSAnders Persson } sockparams_g_stats_t; 797d64f41bSAnders Persson 807d64f41bSAnders Persson static sockparams_g_stats_t sp_g_stats; 817d64f41bSAnders Persson static kstat_t *sp_g_kstat; 827d64f41bSAnders Persson 837d64f41bSAnders Persson 840f1702c5SYu Xiangning void 850f1702c5SYu Xiangning sockparams_init(void) 860f1702c5SYu Xiangning { 870f1702c5SYu Xiangning list_create(&sphead, sizeof (struct sockparams), 880f1702c5SYu Xiangning offsetof(struct sockparams, sp_node)); 890f1702c5SYu Xiangning list_create(&sp_ephem_list, sizeof (struct sockparams), 900f1702c5SYu Xiangning offsetof(struct sockparams, sp_node)); 910f1702c5SYu Xiangning 927d64f41bSAnders Persson kstat_named_init(&sp_g_stats.spgs_ephem_nalloc, "ephemeral_nalloc", 937d64f41bSAnders Persson KSTAT_DATA_UINT64); 947d64f41bSAnders Persson kstat_named_init(&sp_g_stats.spgs_ephem_nreuse, "ephemeral_nreuse", 957d64f41bSAnders Persson KSTAT_DATA_UINT64); 967d64f41bSAnders Persson 977d64f41bSAnders Persson sp_g_kstat = kstat_create("sockfs", 0, "sockparams", "misc", 987d64f41bSAnders Persson KSTAT_TYPE_NAMED, sizeof (sp_g_stats) / sizeof (kstat_named_t), 997d64f41bSAnders Persson KSTAT_FLAG_VIRTUAL); 1007d64f41bSAnders Persson if (sp_g_kstat == NULL) 1017d64f41bSAnders Persson return; 1027d64f41bSAnders Persson 1037d64f41bSAnders Persson sp_g_kstat->ks_data = &sp_g_stats; 1047d64f41bSAnders Persson 1057d64f41bSAnders Persson kstat_install(sp_g_kstat); 1067d64f41bSAnders Persson } 1077d64f41bSAnders Persson 1087d64f41bSAnders Persson static int 1097d64f41bSAnders Persson sockparams_kstat_update(kstat_t *ksp, int rw) 1107d64f41bSAnders Persson { 1117d64f41bSAnders Persson struct sockparams *sp = ksp->ks_private; 1127d64f41bSAnders Persson sockparams_stats_t *sps = ksp->ks_data; 1137d64f41bSAnders Persson 1147d64f41bSAnders Persson if (rw == KSTAT_WRITE) 1157d64f41bSAnders Persson return (EACCES); 1167d64f41bSAnders Persson 1177d64f41bSAnders Persson sps->sps_nactive.value.ui64 = sp->sp_refcnt; 1187d64f41bSAnders Persson 1197d64f41bSAnders Persson return (0); 1207d64f41bSAnders Persson } 1217d64f41bSAnders Persson 1227d64f41bSAnders Persson /* 1237d64f41bSAnders Persson * Setup kstats for the given sockparams entry. 1247d64f41bSAnders Persson */ 1257d64f41bSAnders Persson static void 1267d64f41bSAnders Persson sockparams_kstat_init(struct sockparams *sp) 1277d64f41bSAnders Persson { 1287d64f41bSAnders Persson char name[KSTAT_STRLEN]; 1297d64f41bSAnders Persson 1307d64f41bSAnders Persson (void) snprintf(name, KSTAT_STRLEN, "socket_%d_%d_%d", sp->sp_family, 1317d64f41bSAnders Persson sp->sp_type, sp->sp_protocol); 1327d64f41bSAnders Persson 1337d64f41bSAnders Persson sp->sp_kstat = kstat_create("sockfs", 0, name, "misc", KSTAT_TYPE_NAMED, 1347d64f41bSAnders Persson sizeof (sockparams_stats_t) / sizeof (kstat_named_t), 1357d64f41bSAnders Persson KSTAT_FLAG_VIRTUAL); 1367d64f41bSAnders Persson 1377d64f41bSAnders Persson if (sp->sp_kstat == NULL) 1387d64f41bSAnders Persson return; 1397d64f41bSAnders Persson 1407d64f41bSAnders Persson sp->sp_kstat->ks_data = &sp->sp_stats; 1417d64f41bSAnders Persson sp->sp_kstat->ks_update = sockparams_kstat_update; 1427d64f41bSAnders Persson sp->sp_kstat->ks_private = sp; 1437d64f41bSAnders Persson kstat_install(sp->sp_kstat); 1447d64f41bSAnders Persson } 1457d64f41bSAnders Persson 1467d64f41bSAnders Persson static void 1477d64f41bSAnders Persson sockparams_kstat_fini(struct sockparams *sp) 1487d64f41bSAnders Persson { 1497d64f41bSAnders Persson if (sp->sp_kstat != NULL) { 1507d64f41bSAnders Persson kstat_delete(sp->sp_kstat); 1517d64f41bSAnders Persson sp->sp_kstat = NULL; 1527d64f41bSAnders Persson } 1530f1702c5SYu Xiangning } 1540f1702c5SYu Xiangning 1550f1702c5SYu Xiangning /* 1560f1702c5SYu Xiangning * sockparams_create(int family, int type, int protocol, char *modname, 1570f1702c5SYu Xiangning * char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 1580f1702c5SYu Xiangning * 1590f1702c5SYu Xiangning * Create a new sockparams entry. 1600f1702c5SYu Xiangning * 1610f1702c5SYu Xiangning * Arguments: 1620f1702c5SYu Xiangning * family, type, protocol: specifies the socket type 1630f1702c5SYu Xiangning * modname: Name of the module associated with the socket type. The 1640f1702c5SYu Xiangning * module can be NULL if a device path is given, in which 1650f1702c5SYu Xiangning * case the TPI module is used. 166*3e95bd4aSAnders Persson * devpath: Path to the STREAMS device. Must be NULL for non-STREAMS 167*3e95bd4aSAnders Persson * based transports. 1680f1702c5SYu Xiangning * devpathlen: Length of the devpath string. The argument can be 0, 1690f1702c5SYu Xiangning * indicating that devpath was allocated statically, and should 1700f1702c5SYu Xiangning * not be freed when the sockparams entry is destroyed. 1710f1702c5SYu Xiangning * 1720f1702c5SYu Xiangning * flags : SOCKPARAMS_EPHEMERAL is the only flag that is allowed. 1730f1702c5SYu Xiangning * kmflags: KM_{NO,}SLEEP 1740f1702c5SYu Xiangning * errorp : Value-return argument, set when an error occurs. 1750f1702c5SYu Xiangning * 1760f1702c5SYu Xiangning * Returns: 1770f1702c5SYu Xiangning * On success a new sockparams entry is returned, and *errorp is set 1780f1702c5SYu Xiangning * to 0. On failure NULL is returned and *errorp is set to indicate the 1790f1702c5SYu Xiangning * type of error that occured. 1800f1702c5SYu Xiangning * 1810f1702c5SYu Xiangning * Notes: 1820f1702c5SYu Xiangning * devpath and modname are freed upon failure. 1830f1702c5SYu Xiangning */ 1840f1702c5SYu Xiangning struct sockparams * 1850f1702c5SYu Xiangning sockparams_create(int family, int type, int protocol, char *modname, 1860f1702c5SYu Xiangning char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 1870f1702c5SYu Xiangning { 1880f1702c5SYu Xiangning struct sockparams *sp = NULL; 1890f1702c5SYu Xiangning size_t size; 1900f1702c5SYu Xiangning 1910f1702c5SYu Xiangning ASSERT((flags & ~SOCKPARAMS_EPHEMERAL) == 0); 1920f1702c5SYu Xiangning if (flags & ~SOCKPARAMS_EPHEMERAL) { 1930f1702c5SYu Xiangning *errorp = EINVAL; 1940f1702c5SYu Xiangning goto error; 1950f1702c5SYu Xiangning } 1960f1702c5SYu Xiangning 197*3e95bd4aSAnders Persson /* either a module or device must be given, but not both */ 1980f1702c5SYu Xiangning if (modname == NULL && devpath == NULL) { 1990f1702c5SYu Xiangning *errorp = EINVAL; 2000f1702c5SYu Xiangning goto error; 2010f1702c5SYu Xiangning } 2020f1702c5SYu Xiangning 2030f1702c5SYu Xiangning sp = kmem_zalloc(sizeof (*sp), kmflags); 2040f1702c5SYu Xiangning if (sp == NULL) { 2050f1702c5SYu Xiangning *errorp = ENOMEM; 2060f1702c5SYu Xiangning goto error; 2070f1702c5SYu Xiangning } 2080f1702c5SYu Xiangning sp->sp_family = family; 2090f1702c5SYu Xiangning sp->sp_type = type; 2100f1702c5SYu Xiangning sp->sp_protocol = protocol; 2110f1702c5SYu Xiangning sp->sp_refcnt = 0; 2120f1702c5SYu Xiangning sp->sp_flags = flags; 2130f1702c5SYu Xiangning 214*3e95bd4aSAnders Persson list_create(&sp->sp_auto_filters, sizeof (sp_filter_t), 215*3e95bd4aSAnders Persson offsetof(sp_filter_t, spf_node)); 216*3e95bd4aSAnders Persson list_create(&sp->sp_prog_filters, sizeof (sp_filter_t), 217*3e95bd4aSAnders Persson offsetof(sp_filter_t, spf_node)); 218*3e95bd4aSAnders Persson 21951899d8cSAnders Persson kstat_named_init(&sp->sp_stats.sps_nfallback, "nfallback", 22051899d8cSAnders Persson KSTAT_DATA_UINT64); 22151899d8cSAnders Persson kstat_named_init(&sp->sp_stats.sps_nactive, "nactive", 22251899d8cSAnders Persson KSTAT_DATA_UINT64); 22351899d8cSAnders Persson kstat_named_init(&sp->sp_stats.sps_ncreate, "ncreate", 22451899d8cSAnders Persson KSTAT_DATA_UINT64); 22551899d8cSAnders Persson 2267d64f41bSAnders Persson /* 22751899d8cSAnders Persson * Track how many ephemeral entries we have created. 2287d64f41bSAnders Persson */ 2297d64f41bSAnders Persson if (sp->sp_flags & SOCKPARAMS_EPHEMERAL) 2307d64f41bSAnders Persson sp_g_stats.spgs_ephem_nalloc.value.ui64++; 2317d64f41bSAnders Persson 2320f1702c5SYu Xiangning if (modname != NULL) { 2330f1702c5SYu Xiangning sp->sp_smod_name = modname; 2340f1702c5SYu Xiangning } else { 2350f1702c5SYu Xiangning size = strlen(SOTPI_SMOD_NAME) + 1; 2360f1702c5SYu Xiangning modname = kmem_zalloc(size, kmflags); 2370f1702c5SYu Xiangning if (modname == NULL) { 2380f1702c5SYu Xiangning *errorp = ENOMEM; 2390f1702c5SYu Xiangning goto error; 2400f1702c5SYu Xiangning } 2410f1702c5SYu Xiangning sp->sp_smod_name = modname; 2420f1702c5SYu Xiangning (void) sprintf(sp->sp_smod_name, "%s", SOTPI_SMOD_NAME); 2430f1702c5SYu Xiangning } 2440f1702c5SYu Xiangning 2450f1702c5SYu Xiangning if (devpath != NULL) { 2460f1702c5SYu Xiangning /* Set up the device entry. */ 2470f1702c5SYu Xiangning *errorp = sockparams_sdev_init(sp, devpath, devpathlen); 2480f1702c5SYu Xiangning if (*errorp != 0) 2490f1702c5SYu Xiangning goto error; 2500f1702c5SYu Xiangning } 2510f1702c5SYu Xiangning 2520f1702c5SYu Xiangning mutex_init(&sp->sp_lock, NULL, MUTEX_DEFAULT, NULL); 2530f1702c5SYu Xiangning *errorp = 0; 2540f1702c5SYu Xiangning return (sp); 2550f1702c5SYu Xiangning error: 2560f1702c5SYu Xiangning ASSERT(*errorp != 0); 2570f1702c5SYu Xiangning if (modname != NULL) 2580f1702c5SYu Xiangning kmem_free(modname, strlen(modname) + 1); 2590f1702c5SYu Xiangning if (devpathlen != 0) 2600f1702c5SYu Xiangning kmem_free(devpath, devpathlen); 26151899d8cSAnders Persson if (sp != NULL) 2620f1702c5SYu Xiangning kmem_free(sp, sizeof (*sp)); 2630f1702c5SYu Xiangning return (NULL); 2640f1702c5SYu Xiangning } 2650f1702c5SYu Xiangning 2660f1702c5SYu Xiangning /* 2670f1702c5SYu Xiangning * Initialize the STREAMS device aspect of the sockparams entry. 2680f1702c5SYu Xiangning */ 2690f1702c5SYu Xiangning static int 2700f1702c5SYu Xiangning sockparams_sdev_init(struct sockparams *sp, char *devpath, int devpathlen) 2710f1702c5SYu Xiangning { 2720f1702c5SYu Xiangning vnode_t *vp = NULL; 2730f1702c5SYu Xiangning int error; 2740f1702c5SYu Xiangning 2750f1702c5SYu Xiangning ASSERT(devpath != NULL); 2760f1702c5SYu Xiangning 2770f1702c5SYu Xiangning if ((error = sogetvp(devpath, &vp, UIO_SYSSPACE)) != 0) { 2780f1702c5SYu Xiangning dprint(0, ("sockparams_sdev_init: vp %s failed with %d\n", 2790f1702c5SYu Xiangning devpath, error)); 2800f1702c5SYu Xiangning return (error); 2810f1702c5SYu Xiangning } 2820f1702c5SYu Xiangning 2830f1702c5SYu Xiangning ASSERT(vp != NULL); 2840f1702c5SYu Xiangning sp->sp_sdev_info.sd_vnode = vp; 2850f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath = devpath; 2860f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpathlen = devpathlen; 2870f1702c5SYu Xiangning 2880f1702c5SYu Xiangning return (0); 2890f1702c5SYu Xiangning } 2900f1702c5SYu Xiangning 2910f1702c5SYu Xiangning /* 2920f1702c5SYu Xiangning * sockparams_destroy(struct sockparams *sp) 2930f1702c5SYu Xiangning * 2940f1702c5SYu Xiangning * Releases all the resources associated with the sockparams entry, 2950f1702c5SYu Xiangning * and frees the sockparams entry. 2960f1702c5SYu Xiangning * 2970f1702c5SYu Xiangning * Arguments: 2980f1702c5SYu Xiangning * sp: the sockparams entry to destroy. 2990f1702c5SYu Xiangning * 3000f1702c5SYu Xiangning * Returns: 3010f1702c5SYu Xiangning * Nothing. 3020f1702c5SYu Xiangning * 3030f1702c5SYu Xiangning * Locking: 3040f1702c5SYu Xiangning * The sp_lock of the entry can not be held. 3050f1702c5SYu Xiangning */ 3060f1702c5SYu Xiangning void 3070f1702c5SYu Xiangning sockparams_destroy(struct sockparams *sp) 3080f1702c5SYu Xiangning { 3090f1702c5SYu Xiangning ASSERT(sp->sp_refcnt == 0); 3100f1702c5SYu Xiangning ASSERT(!list_link_active(&sp->sp_node)); 3110f1702c5SYu Xiangning 3120f1702c5SYu Xiangning sockparams_sdev_fini(sp); 3130f1702c5SYu Xiangning 3140f1702c5SYu Xiangning if (sp->sp_smod_info != NULL) 3155f1fdc18SAnders Persson SMOD_DEC_REF(sp->sp_smod_info, sp->sp_smod_name); 3160f1702c5SYu Xiangning kmem_free(sp->sp_smod_name, strlen(sp->sp_smod_name) + 1); 3170f1702c5SYu Xiangning sp->sp_smod_name = NULL; 3180f1702c5SYu Xiangning sp->sp_smod_info = NULL; 3190f1702c5SYu Xiangning mutex_destroy(&sp->sp_lock); 3207d64f41bSAnders Persson sockparams_kstat_fini(sp); 3210f1702c5SYu Xiangning 322*3e95bd4aSAnders Persson sof_sockparams_fini(sp); 323*3e95bd4aSAnders Persson list_destroy(&sp->sp_auto_filters); 324*3e95bd4aSAnders Persson list_destroy(&sp->sp_prog_filters); 325*3e95bd4aSAnders Persson 3260f1702c5SYu Xiangning kmem_free(sp, sizeof (*sp)); 3270f1702c5SYu Xiangning } 3280f1702c5SYu Xiangning 3290f1702c5SYu Xiangning /* 3300f1702c5SYu Xiangning * Clean up the STREAMS device part of the sockparams entry. 3310f1702c5SYu Xiangning */ 3320f1702c5SYu Xiangning static void 3330f1702c5SYu Xiangning sockparams_sdev_fini(struct sockparams *sp) 3340f1702c5SYu Xiangning { 3350f1702c5SYu Xiangning sdev_info_t sd; 3360f1702c5SYu Xiangning 3370f1702c5SYu Xiangning /* 3380f1702c5SYu Xiangning * if the entry does not have a STREAMS device, then there 3390f1702c5SYu Xiangning * is nothing to do. 3400f1702c5SYu Xiangning */ 3410f1702c5SYu Xiangning if (!SOCKPARAMS_HAS_DEVICE(sp)) 3420f1702c5SYu Xiangning return; 3430f1702c5SYu Xiangning 3440f1702c5SYu Xiangning sd = sp->sp_sdev_info; 3450f1702c5SYu Xiangning if (sd.sd_vnode != NULL) 3460f1702c5SYu Xiangning VN_RELE(sd.sd_vnode); 3470f1702c5SYu Xiangning if (sd.sd_devpathlen != 0) 3480f1702c5SYu Xiangning kmem_free(sd.sd_devpath, sd.sd_devpathlen); 3490f1702c5SYu Xiangning 3500f1702c5SYu Xiangning sp->sp_sdev_info.sd_vnode = NULL; 3510f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath = NULL; 3520f1702c5SYu Xiangning } 3530f1702c5SYu Xiangning 3540f1702c5SYu Xiangning /* 3550f1702c5SYu Xiangning * Look for a matching sockparams entry on the given list. 3560f1702c5SYu Xiangning * The caller must hold the associated list lock. 3570f1702c5SYu Xiangning */ 3580f1702c5SYu Xiangning static struct sockparams * 3590f1702c5SYu Xiangning sockparams_find(list_t *list, int family, int type, int protocol, 36022238f73Sshenjian boolean_t by_devpath, const char *name) 3610f1702c5SYu Xiangning { 3620f1702c5SYu Xiangning struct sockparams *sp; 3630f1702c5SYu Xiangning 3640f1702c5SYu Xiangning for (sp = list_head(list); sp != NULL; sp = list_next(list, sp)) { 36522238f73Sshenjian if (sp->sp_family == family && sp->sp_type == type) { 3660f1702c5SYu Xiangning if (sp->sp_protocol == protocol) { 36722238f73Sshenjian if (name == NULL) 3680f1702c5SYu Xiangning break; 36922238f73Sshenjian else if (by_devpath && 3700f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath != NULL && 3710f1702c5SYu Xiangning strcmp(sp->sp_sdev_info.sd_devpath, 3720f1702c5SYu Xiangning name) == 0) 3730f1702c5SYu Xiangning break; 37422238f73Sshenjian else if (strcmp(sp->sp_smod_name, name) == 0) 3750f1702c5SYu Xiangning break; 3760f1702c5SYu Xiangning } 3770f1702c5SYu Xiangning } 3780f1702c5SYu Xiangning } 37922238f73Sshenjian return (sp); 3800f1702c5SYu Xiangning } 3810f1702c5SYu Xiangning 3820f1702c5SYu Xiangning /* 3830f1702c5SYu Xiangning * sockparams_hold_ephemeral() 3840f1702c5SYu Xiangning * 3850f1702c5SYu Xiangning * Returns an ephemeral sockparams entry of the requested family, type and 3860f1702c5SYu Xiangning * protocol. The entry is returned held, and the caller is responsible for 3870f1702c5SYu Xiangning * dropping the reference using SOCKPARAMS_DEC_REF() once done. 3880f1702c5SYu Xiangning * 3890f1702c5SYu Xiangning * All ephemeral entries are on list (sp_ephem_list). If there is an 3900f1702c5SYu Xiangning * entry on the list that match the search criteria, then a reference is 3910f1702c5SYu Xiangning * placed on that entry. Otherwise, a new entry is created and inserted 3920f1702c5SYu Xiangning * in the list. The entry is removed from the list when the last reference 3930f1702c5SYu Xiangning * is dropped. 3940f1702c5SYu Xiangning * 3950f1702c5SYu Xiangning * The tpi flag is used to determine whether name refers to a device or 3960f1702c5SYu Xiangning * module name. 3970f1702c5SYu Xiangning */ 3980f1702c5SYu Xiangning static struct sockparams * 3990f1702c5SYu Xiangning sockparams_hold_ephemeral(int family, int type, int protocol, 40022238f73Sshenjian const char *name, boolean_t by_devpath, int kmflag, int *errorp) 4010f1702c5SYu Xiangning { 4020f1702c5SYu Xiangning struct sockparams *sp = NULL; 4030f1702c5SYu Xiangning *errorp = 0; 4040f1702c5SYu Xiangning 4050f1702c5SYu Xiangning /* 4060f1702c5SYu Xiangning * First look for an existing entry 4070f1702c5SYu Xiangning */ 408*3e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_READER); 4090f1702c5SYu Xiangning sp = sockparams_find(&sp_ephem_list, family, type, protocol, 41022238f73Sshenjian by_devpath, name); 4110f1702c5SYu Xiangning if (sp != NULL) { 4120f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 413*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4147d64f41bSAnders Persson sp_g_stats.spgs_ephem_nreuse.value.ui64++; 4150f1702c5SYu Xiangning 4160f1702c5SYu Xiangning return (sp); 4170f1702c5SYu Xiangning } else { 4180f1702c5SYu Xiangning struct sockparams *newsp = NULL; 4190f1702c5SYu Xiangning char *namebuf = NULL; 4200f1702c5SYu Xiangning int namelen = 0; 4210f1702c5SYu Xiangning 422*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4230f1702c5SYu Xiangning 4240f1702c5SYu Xiangning namelen = strlen(name) + 1; 4250f1702c5SYu Xiangning namebuf = kmem_alloc(namelen, kmflag); 4260f1702c5SYu Xiangning if (namebuf == NULL) { 4270f1702c5SYu Xiangning *errorp = ENOMEM; 4280f1702c5SYu Xiangning return (NULL); 4290f1702c5SYu Xiangning } 4300f1702c5SYu Xiangning 4310f1702c5SYu Xiangning (void *)strncpy(namebuf, name, namelen); 43222238f73Sshenjian if (by_devpath) { 4330f1702c5SYu Xiangning newsp = sockparams_create(family, type, 4340f1702c5SYu Xiangning protocol, NULL, namebuf, namelen, 4350f1702c5SYu Xiangning SOCKPARAMS_EPHEMERAL, kmflag, errorp); 4360f1702c5SYu Xiangning } else { 4370f1702c5SYu Xiangning newsp = sockparams_create(family, type, 4380f1702c5SYu Xiangning protocol, namebuf, NULL, 0, 4390f1702c5SYu Xiangning SOCKPARAMS_EPHEMERAL, kmflag, errorp); 4400f1702c5SYu Xiangning } 4410f1702c5SYu Xiangning 4420f1702c5SYu Xiangning if (newsp == NULL) { 4430f1702c5SYu Xiangning ASSERT(*errorp != 0); 4440f1702c5SYu Xiangning return (NULL); 4450f1702c5SYu Xiangning } 4460f1702c5SYu Xiangning 4470f1702c5SYu Xiangning /* 4480f1702c5SYu Xiangning * Time to load the socket module. 4490f1702c5SYu Xiangning */ 4500f1702c5SYu Xiangning ASSERT(newsp->sp_smod_info == NULL); 4510f1702c5SYu Xiangning newsp->sp_smod_info = 4520f1702c5SYu Xiangning smod_lookup_byname(newsp->sp_smod_name); 4530f1702c5SYu Xiangning if (newsp->sp_smod_info == NULL) { 4540f1702c5SYu Xiangning /* Failed to load */ 4550f1702c5SYu Xiangning sockparams_destroy(newsp); 4560f1702c5SYu Xiangning *errorp = ENXIO; 4570f1702c5SYu Xiangning return (NULL); 4580f1702c5SYu Xiangning } 4590f1702c5SYu Xiangning 4600f1702c5SYu Xiangning /* 4610f1702c5SYu Xiangning * The sockparams entry was created, now try to add it 4620f1702c5SYu Xiangning * to the list. We need to hold the lock as a WRITER. 4630f1702c5SYu Xiangning */ 464*3e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 4650f1702c5SYu Xiangning sp = sockparams_find(&sp_ephem_list, family, type, protocol, 46622238f73Sshenjian by_devpath, name); 4670f1702c5SYu Xiangning if (sp != NULL) { 4680f1702c5SYu Xiangning /* 4690f1702c5SYu Xiangning * Someone has requested a matching entry, so just 4700f1702c5SYu Xiangning * place a hold on it and release the entry we alloc'ed. 4710f1702c5SYu Xiangning */ 4720f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 473*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4740f1702c5SYu Xiangning 4750f1702c5SYu Xiangning sockparams_destroy(newsp); 4760f1702c5SYu Xiangning } else { 477*3e95bd4aSAnders Persson *errorp = sof_sockparams_init(newsp); 478*3e95bd4aSAnders Persson if (*errorp != 0) { 479*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 480*3e95bd4aSAnders Persson sockparams_destroy(newsp); 481*3e95bd4aSAnders Persson return (NULL); 482*3e95bd4aSAnders Persson } 4830f1702c5SYu Xiangning SOCKPARAMS_INC_REF(newsp); 4840f1702c5SYu Xiangning list_insert_tail(&sp_ephem_list, newsp); 485*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4860f1702c5SYu Xiangning 4870f1702c5SYu Xiangning sp = newsp; 4880f1702c5SYu Xiangning } 4890f1702c5SYu Xiangning ASSERT(*errorp == 0); 4900f1702c5SYu Xiangning 4910f1702c5SYu Xiangning return (sp); 4920f1702c5SYu Xiangning } 4930f1702c5SYu Xiangning } 4940f1702c5SYu Xiangning 4950f1702c5SYu Xiangning struct sockparams * 4960f1702c5SYu Xiangning sockparams_hold_ephemeral_bydev(int family, int type, int protocol, 4970f1702c5SYu Xiangning const char *dev, int kmflag, int *errorp) 4980f1702c5SYu Xiangning { 4990f1702c5SYu Xiangning return (sockparams_hold_ephemeral(family, type, protocol, dev, B_TRUE, 5000f1702c5SYu Xiangning kmflag, errorp)); 5010f1702c5SYu Xiangning } 5020f1702c5SYu Xiangning 5030f1702c5SYu Xiangning struct sockparams * 5040f1702c5SYu Xiangning sockparams_hold_ephemeral_bymod(int family, int type, int protocol, 5050f1702c5SYu Xiangning const char *mod, int kmflag, int *errorp) 5060f1702c5SYu Xiangning { 5070f1702c5SYu Xiangning return (sockparams_hold_ephemeral(family, type, protocol, mod, B_FALSE, 5080f1702c5SYu Xiangning kmflag, errorp)); 5090f1702c5SYu Xiangning } 5100f1702c5SYu Xiangning 5110f1702c5SYu Xiangning /* 5120f1702c5SYu Xiangning * Called when the last socket using the ephemeral entry is dropping 5130f1702c5SYu Xiangning * its' reference. To maintain lock order we must drop the sockparams 5140f1702c5SYu Xiangning * lock before calling this function. As a result, a new reference 5150f1702c5SYu Xiangning * might be placed on the entry, in which case there is nothing to 5160f1702c5SYu Xiangning * do. However, if ref count goes to zero, we delete the entry. 5170f1702c5SYu Xiangning */ 5180f1702c5SYu Xiangning void 5190f1702c5SYu Xiangning sockparams_ephemeral_drop_last_ref(struct sockparams *sp) 5200f1702c5SYu Xiangning { 5210f1702c5SYu Xiangning ASSERT(sp->sp_flags & SOCKPARAMS_EPHEMERAL); 5220f1702c5SYu Xiangning ASSERT(MUTEX_NOT_HELD(&sp->sp_lock)); 5230f1702c5SYu Xiangning 524*3e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 5250f1702c5SYu Xiangning mutex_enter(&sp->sp_lock); 5260f1702c5SYu Xiangning 5270f1702c5SYu Xiangning if (--sp->sp_refcnt == 0) { 5280f1702c5SYu Xiangning list_remove(&sp_ephem_list, sp); 5290f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 530*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5310f1702c5SYu Xiangning 5320f1702c5SYu Xiangning sockparams_destroy(sp); 5330f1702c5SYu Xiangning } else { 5340f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 535*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5360f1702c5SYu Xiangning } 5370f1702c5SYu Xiangning } 5380f1702c5SYu Xiangning 5390f1702c5SYu Xiangning /* 5400f1702c5SYu Xiangning * sockparams_add(struct sockparams *sp) 5410f1702c5SYu Xiangning * 5420f1702c5SYu Xiangning * Tries to add the given sockparams entry to the global list. 5430f1702c5SYu Xiangning * 5440f1702c5SYu Xiangning * Arguments: 5450f1702c5SYu Xiangning * sp: the sockparms entry to add 5460f1702c5SYu Xiangning * 5470f1702c5SYu Xiangning * Returns: 5480f1702c5SYu Xiangning * On success 0, but if an entry already exists, then EEXIST 5490f1702c5SYu Xiangning * is returned. 5500f1702c5SYu Xiangning * 5510f1702c5SYu Xiangning * Locking: 552*3e95bd4aSAnders Persson * The caller can not be holding sockconf_lock. 5530f1702c5SYu Xiangning */ 554*3e95bd4aSAnders Persson int 5550f1702c5SYu Xiangning sockparams_add(struct sockparams *sp) 5560f1702c5SYu Xiangning { 557*3e95bd4aSAnders Persson int error; 558*3e95bd4aSAnders Persson 5590f1702c5SYu Xiangning ASSERT(!(sp->sp_flags & SOCKPARAMS_EPHEMERAL)); 5600f1702c5SYu Xiangning 561*3e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 5620f1702c5SYu Xiangning if (sockparams_find(&sphead, sp->sp_family, sp->sp_type, 56322238f73Sshenjian sp->sp_protocol, B_TRUE, NULL) != 0) { 564*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5650f1702c5SYu Xiangning return (EEXIST); 5660f1702c5SYu Xiangning } else { 567*3e95bd4aSAnders Persson /* 568*3e95bd4aSAnders Persson * Unique sockparams entry, so init the kstats. 569*3e95bd4aSAnders Persson */ 570*3e95bd4aSAnders Persson sockparams_kstat_init(sp); 571*3e95bd4aSAnders Persson 572*3e95bd4aSAnders Persson /* 573*3e95bd4aSAnders Persson * Before making the socket type available we must make 574*3e95bd4aSAnders Persson * sure that interested socket filters are aware of it. 575*3e95bd4aSAnders Persson */ 576*3e95bd4aSAnders Persson error = sof_sockparams_init(sp); 577*3e95bd4aSAnders Persson if (error != 0) { 578*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 579*3e95bd4aSAnders Persson return (error); 580*3e95bd4aSAnders Persson } 5810f1702c5SYu Xiangning list_insert_tail(&sphead, sp); 582*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5830f1702c5SYu Xiangning return (0); 5840f1702c5SYu Xiangning } 5850f1702c5SYu Xiangning } 5860f1702c5SYu Xiangning 5870f1702c5SYu Xiangning /* 5880f1702c5SYu Xiangning * sockparams_delete(int family, int type, int protocol) 5890f1702c5SYu Xiangning * 5900f1702c5SYu Xiangning * Marks the sockparams entry for a specific family, type and protocol 5910f1702c5SYu Xiangning * for deletion. The entry is removed from the list and destroyed 5920f1702c5SYu Xiangning * if no one is holding a reference to it. 5930f1702c5SYu Xiangning * 5940f1702c5SYu Xiangning * Arguments: 5950f1702c5SYu Xiangning * family, type, protocol: the socket type that should be removed. 5960f1702c5SYu Xiangning * 5970f1702c5SYu Xiangning * Returns: 5980f1702c5SYu Xiangning * On success 0, otherwise ENXIO. 5990f1702c5SYu Xiangning * 6000f1702c5SYu Xiangning * Locking: 601*3e95bd4aSAnders Persson * Caller can not be holding sockconf_lock or the sp_lock of 6020f1702c5SYu Xiangning * any sockparams entry. 6030f1702c5SYu Xiangning */ 604*3e95bd4aSAnders Persson int 6050f1702c5SYu Xiangning sockparams_delete(int family, int type, int protocol) 6060f1702c5SYu Xiangning { 6070f1702c5SYu Xiangning struct sockparams *sp; 6080f1702c5SYu Xiangning 609*3e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 61022238f73Sshenjian sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL); 6110f1702c5SYu Xiangning 6120f1702c5SYu Xiangning if (sp != NULL) { 6130f1702c5SYu Xiangning /* 6140f1702c5SYu Xiangning * If no one is holding a reference to the entry, then 6150f1702c5SYu Xiangning * we go ahead and remove it from the list and then 6160f1702c5SYu Xiangning * destroy it. 6170f1702c5SYu Xiangning */ 6180f1702c5SYu Xiangning mutex_enter(&sp->sp_lock); 6190f1702c5SYu Xiangning if (sp->sp_refcnt != 0) { 6200f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 621*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6220f1702c5SYu Xiangning return (EBUSY); 6230f1702c5SYu Xiangning } 6240f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 6250f1702c5SYu Xiangning /* Delete the sockparams entry. */ 6260f1702c5SYu Xiangning list_remove(&sphead, sp); 627*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6280f1702c5SYu Xiangning 6290f1702c5SYu Xiangning sockparams_destroy(sp); 6300f1702c5SYu Xiangning return (0); 6310f1702c5SYu Xiangning } else { 632*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6330f1702c5SYu Xiangning return (ENXIO); 6340f1702c5SYu Xiangning } 6350f1702c5SYu Xiangning } 6360f1702c5SYu Xiangning 6370f1702c5SYu Xiangning 6380f1702c5SYu Xiangning /* 6390f1702c5SYu Xiangning * solookup(int family, int type, int protocol, struct sockparams **spp) 6400f1702c5SYu Xiangning * 6410f1702c5SYu Xiangning * Lookup an entry in the sockparams list based on the triple. The returned 6420f1702c5SYu Xiangning * entry either exactly match the given tuple, or it is the 'default' entry 6430f1702c5SYu Xiangning * for the given <family, type>. A default entry is on with a protocol 6440f1702c5SYu Xiangning * value of zero. 6450f1702c5SYu Xiangning * 6460f1702c5SYu Xiangning * Arguments: 6470f1702c5SYu Xiangning * family, type, protocol: tuple to search for 6480f1702c5SYu Xiangning * spp: Value-return argument 6490f1702c5SYu Xiangning * 6500f1702c5SYu Xiangning * Returns: 6510f1702c5SYu Xiangning * If an entry is found, 0 is returned and *spp is set to point to the 6520f1702c5SYu Xiangning * entry. In case an entry is not found, *spp is set to NULL, and an 6530f1702c5SYu Xiangning * error code is returned. The errors are (in decreasing precedence): 6540f1702c5SYu Xiangning * EAFNOSUPPORT - address family not in list 6550f1702c5SYu Xiangning * EPROTONOSUPPORT - address family supported but not protocol. 6560f1702c5SYu Xiangning * EPROTOTYPE - address family and protocol supported but not socket type. 6570f1702c5SYu Xiangning * 6580f1702c5SYu Xiangning * TODO: should use ddi_modopen()/ddi_modclose() 6590f1702c5SYu Xiangning */ 6600f1702c5SYu Xiangning int 6610f1702c5SYu Xiangning solookup(int family, int type, int protocol, struct sockparams **spp) 6620f1702c5SYu Xiangning { 6630f1702c5SYu Xiangning struct sockparams *sp = NULL; 6640f1702c5SYu Xiangning int error = 0; 6650f1702c5SYu Xiangning 6660f1702c5SYu Xiangning *spp = NULL; 667*3e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_READER); 6680f1702c5SYu Xiangning 6690f1702c5SYu Xiangning /* 6700f1702c5SYu Xiangning * Search the sockparams list for an appropiate entry. 6710f1702c5SYu Xiangning * Hopefully we find an entry that match the exact family, 6720f1702c5SYu Xiangning * type and protocol specified by the user, in which case 6730f1702c5SYu Xiangning * we return that entry. However, we also keep track of 6740f1702c5SYu Xiangning * the default entry for a specific family and type, the 6750f1702c5SYu Xiangning * entry of which would have a protocol value of 0. 6760f1702c5SYu Xiangning */ 67722238f73Sshenjian sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL); 6780f1702c5SYu Xiangning 6790f1702c5SYu Xiangning if (sp == NULL) { 6800f1702c5SYu Xiangning int found = 0; 6810f1702c5SYu Xiangning 6820f1702c5SYu Xiangning /* Determine correct error code */ 6830f1702c5SYu Xiangning for (sp = list_head(&sphead); sp != NULL; 6840f1702c5SYu Xiangning sp = list_next(&sphead, sp)) { 6850f1702c5SYu Xiangning if (sp->sp_family == family && found < 1) 6860f1702c5SYu Xiangning found = 1; 6870f1702c5SYu Xiangning if (sp->sp_family == family && 6880f1702c5SYu Xiangning sp->sp_protocol == protocol && found < 2) 6890f1702c5SYu Xiangning found = 2; 6900f1702c5SYu Xiangning } 691*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6920f1702c5SYu Xiangning switch (found) { 6930f1702c5SYu Xiangning case 0: 6940f1702c5SYu Xiangning error = EAFNOSUPPORT; 6950f1702c5SYu Xiangning break; 6960f1702c5SYu Xiangning case 1: 6970f1702c5SYu Xiangning error = EPROTONOSUPPORT; 6980f1702c5SYu Xiangning break; 6990f1702c5SYu Xiangning case 2: 7000f1702c5SYu Xiangning error = EPROTOTYPE; 7010f1702c5SYu Xiangning break; 7020f1702c5SYu Xiangning } 7030f1702c5SYu Xiangning return (error); 7040f1702c5SYu Xiangning } 7050f1702c5SYu Xiangning 7060f1702c5SYu Xiangning /* 7070f1702c5SYu Xiangning * An entry was found. 7080f1702c5SYu Xiangning * 7090f1702c5SYu Xiangning * We put a hold on the entry early on, so if the 7100f1702c5SYu Xiangning * sockmod is not loaded, and we have to exit 711*3e95bd4aSAnders Persson * sockconf_lock to call modload(), we know that the 7120f1702c5SYu Xiangning * sockparams entry wont go away. That way we don't 7130f1702c5SYu Xiangning * have to look up the entry once we come back from 7140f1702c5SYu Xiangning * modload(). 7150f1702c5SYu Xiangning */ 7160f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 717*3e95bd4aSAnders Persson rw_exit(&sockconf_lock); 7180f1702c5SYu Xiangning 7190f1702c5SYu Xiangning if (sp->sp_smod_info == NULL) { 7205f1fdc18SAnders Persson smod_info_t *smod = smod_lookup_byname(sp->sp_smod_name); 7215f1fdc18SAnders Persson 7225f1fdc18SAnders Persson if (smod == NULL) { 7230f1702c5SYu Xiangning /* 7240f1702c5SYu Xiangning * We put a hold on the sockparams entry 7250f1702c5SYu Xiangning * earlier, hoping everything would work out. 7260f1702c5SYu Xiangning * That obviously did not happen, so release 7270f1702c5SYu Xiangning * the hold here. 7280f1702c5SYu Xiangning */ 7290f1702c5SYu Xiangning SOCKPARAMS_DEC_REF(sp); 7300f1702c5SYu Xiangning /* 7310f1702c5SYu Xiangning * We should probably mark the sockparams as 7320f1702c5SYu Xiangning * "bad", and redo the lookup skipping the 7330f1702c5SYu Xiangning * "bad" entries. I.e., sp->sp_mod_state |= BAD, 7340f1702c5SYu Xiangning * return (solookup(...)) 7350f1702c5SYu Xiangning */ 7360f1702c5SYu Xiangning return (ENXIO); 7370f1702c5SYu Xiangning } 7385f1fdc18SAnders Persson /* 7395f1fdc18SAnders Persson * Another thread might have already looked up the socket 7405f1fdc18SAnders Persson * module for this entry. In that case we need to drop our 7415f1fdc18SAnders Persson * reference to `smod' to ensure that the sockparams entry 7425f1fdc18SAnders Persson * only holds one reference. 7435f1fdc18SAnders Persson */ 7445f1fdc18SAnders Persson mutex_enter(&sp->sp_lock); 7455f1fdc18SAnders Persson if (sp->sp_smod_info == NULL) 7465f1fdc18SAnders Persson sp->sp_smod_info = smod; 7475f1fdc18SAnders Persson else 7485f1fdc18SAnders Persson SMOD_DEC_REF(smod, sp->sp_smod_name); 7495f1fdc18SAnders Persson mutex_exit(&sp->sp_lock); 7500f1702c5SYu Xiangning } 7510f1702c5SYu Xiangning 7520f1702c5SYu Xiangning /* 7530f1702c5SYu Xiangning * Alright, we have a valid sockparams entry. 7540f1702c5SYu Xiangning */ 7550f1702c5SYu Xiangning *spp = sp; 7560f1702c5SYu Xiangning return (0); 7570f1702c5SYu Xiangning } 758*3e95bd4aSAnders Persson 759*3e95bd4aSAnders Persson /* 760*3e95bd4aSAnders Persson * Called when filter entry `ent' is going away. All sockparams remove 761*3e95bd4aSAnders Persson * their references to `ent'. 762*3e95bd4aSAnders Persson */ 763*3e95bd4aSAnders Persson static void 764*3e95bd4aSAnders Persson sockparams_filter_cleanup_impl(sof_entry_t *ent, list_t *list) 765*3e95bd4aSAnders Persson { 766*3e95bd4aSAnders Persson struct sockparams *sp; 767*3e95bd4aSAnders Persson sp_filter_t *fil; 768*3e95bd4aSAnders Persson list_t *flist; 769*3e95bd4aSAnders Persson 770*3e95bd4aSAnders Persson ASSERT(RW_WRITE_HELD(&sockconf_lock)); 771*3e95bd4aSAnders Persson 772*3e95bd4aSAnders Persson for (sp = list_head(list); sp != NULL; 773*3e95bd4aSAnders Persson sp = list_next(list, sp)) { 774*3e95bd4aSAnders Persson flist = (ent->sofe_flags & SOFEF_AUTO) ? 775*3e95bd4aSAnders Persson &sp->sp_auto_filters : &sp->sp_prog_filters; 776*3e95bd4aSAnders Persson fil = list_head(flist); 777*3e95bd4aSAnders Persson for (fil = list_head(flist); fil != NULL; 778*3e95bd4aSAnders Persson fil = list_next(flist, fil)) { 779*3e95bd4aSAnders Persson if (fil->spf_filter == ent) { 780*3e95bd4aSAnders Persson list_remove(flist, fil); 781*3e95bd4aSAnders Persson kmem_free(fil, sizeof (sp_filter_t)); 782*3e95bd4aSAnders Persson break; 783*3e95bd4aSAnders Persson } 784*3e95bd4aSAnders Persson } 785*3e95bd4aSAnders Persson } 786*3e95bd4aSAnders Persson } 787*3e95bd4aSAnders Persson void 788*3e95bd4aSAnders Persson sockparams_filter_cleanup(sof_entry_t *ent) 789*3e95bd4aSAnders Persson { 790*3e95bd4aSAnders Persson sockparams_filter_cleanup_impl(ent, &sphead); 791*3e95bd4aSAnders Persson sockparams_filter_cleanup_impl(ent, &sp_ephem_list); 792*3e95bd4aSAnders Persson } 793*3e95bd4aSAnders Persson 794*3e95bd4aSAnders Persson /* 795*3e95bd4aSAnders Persson * New filter is being added; walk the list of sockparams to see if 796*3e95bd4aSAnders Persson * the filter is interested in any of the sockparams. 797*3e95bd4aSAnders Persson */ 798*3e95bd4aSAnders Persson static int 799*3e95bd4aSAnders Persson sockparams_new_filter_impl(sof_entry_t *ent, list_t *list) 800*3e95bd4aSAnders Persson { 801*3e95bd4aSAnders Persson struct sockparams *sp; 802*3e95bd4aSAnders Persson int err; 803*3e95bd4aSAnders Persson 804*3e95bd4aSAnders Persson ASSERT(RW_WRITE_HELD(&sockconf_lock)); 805*3e95bd4aSAnders Persson 806*3e95bd4aSAnders Persson for (sp = list_head(list); sp != NULL; 807*3e95bd4aSAnders Persson sp = list_next(list, sp)) { 808*3e95bd4aSAnders Persson if ((err = sof_entry_proc_sockparams(ent, sp)) != 0) { 809*3e95bd4aSAnders Persson sockparams_filter_cleanup(ent); 810*3e95bd4aSAnders Persson return (err); 811*3e95bd4aSAnders Persson } 812*3e95bd4aSAnders Persson } 813*3e95bd4aSAnders Persson return (0); 814*3e95bd4aSAnders Persson } 815*3e95bd4aSAnders Persson 816*3e95bd4aSAnders Persson int 817*3e95bd4aSAnders Persson sockparams_new_filter(sof_entry_t *ent) 818*3e95bd4aSAnders Persson { 819*3e95bd4aSAnders Persson int error; 820*3e95bd4aSAnders Persson 821*3e95bd4aSAnders Persson if ((error = sockparams_new_filter_impl(ent, &sphead)) != 0) 822*3e95bd4aSAnders Persson return (error); 823*3e95bd4aSAnders Persson 824*3e95bd4aSAnders Persson if ((error = sockparams_new_filter_impl(ent, &sp_ephem_list)) != 0) 825*3e95bd4aSAnders Persson sockparams_filter_cleanup_impl(ent, &sphead); 826*3e95bd4aSAnders Persson return (error); 827*3e95bd4aSAnders Persson } 828