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. 24*19581f84SAlexander Eremin * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 250f1702c5SYu Xiangning */ 260f1702c5SYu Xiangning 270f1702c5SYu Xiangning #include <sys/types.h> 280f1702c5SYu Xiangning #include <sys/t_lock.h> 290f1702c5SYu Xiangning #include <sys/param.h> 300f1702c5SYu Xiangning #include <sys/systm.h> 310f1702c5SYu Xiangning #include <sys/sysmacros.h> 320f1702c5SYu Xiangning #include <sys/cmn_err.h> 330f1702c5SYu Xiangning #include <sys/list.h> 34*19581f84SAlexander Eremin #include <sys/sunddi.h> 350f1702c5SYu Xiangning 360f1702c5SYu Xiangning #include <sys/stropts.h> 370f1702c5SYu Xiangning #include <sys/socket.h> 380f1702c5SYu Xiangning #include <sys/socketvar.h> 390f1702c5SYu Xiangning 400f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h> 413e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h> 420f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h> 430f1702c5SYu Xiangning 440f1702c5SYu Xiangning /* 450f1702c5SYu Xiangning * Socket Parameters 460f1702c5SYu Xiangning * 470f1702c5SYu Xiangning * Socket parameter (struct sockparams) entries represent the socket types 480f1702c5SYu Xiangning * available on the system. 490f1702c5SYu Xiangning * 500f1702c5SYu Xiangning * Flags (sp_flags): 510f1702c5SYu Xiangning * 520f1702c5SYu Xiangning * SOCKPARAMS_EPHEMERAL: A temporary sockparams entry that will be deleted 530f1702c5SYu Xiangning * as soon as its' ref count drops to zero. In addition, ephemeral entries will 540f1702c5SYu Xiangning * never be hooked onto the global sockparams list. Ephemeral entries are 550f1702c5SYu Xiangning * created when application requests to create a socket using an application 560f1702c5SYu Xiangning * supplied device path, or when a socket is falling back to TPI. 570f1702c5SYu Xiangning * 580f1702c5SYu Xiangning * Lock order: 593e95bd4aSAnders Persson * The lock order is sockconf_lock -> sp_lock. 600f1702c5SYu Xiangning */ 610f1702c5SYu Xiangning extern int kobj_path_exists(char *, int); 620f1702c5SYu Xiangning 630f1702c5SYu Xiangning static int sockparams_sdev_init(struct sockparams *, char *, int); 640f1702c5SYu Xiangning static void sockparams_sdev_fini(struct sockparams *); 650f1702c5SYu Xiangning 660f1702c5SYu Xiangning /* 670f1702c5SYu Xiangning * Global sockparams list (populated via soconfig(1M)). 680f1702c5SYu Xiangning */ 690f1702c5SYu Xiangning static list_t sphead; 700f1702c5SYu Xiangning 710f1702c5SYu Xiangning /* 720f1702c5SYu Xiangning * List of ephemeral sockparams. 730f1702c5SYu Xiangning */ 740f1702c5SYu Xiangning static list_t sp_ephem_list; 750f1702c5SYu Xiangning 767d64f41bSAnders Persson /* Global kstats for sockparams */ 777d64f41bSAnders Persson typedef struct sockparams_g_stats { 787d64f41bSAnders Persson kstat_named_t spgs_ephem_nalloc; 797d64f41bSAnders Persson kstat_named_t spgs_ephem_nreuse; 807d64f41bSAnders Persson } sockparams_g_stats_t; 817d64f41bSAnders Persson 827d64f41bSAnders Persson static sockparams_g_stats_t sp_g_stats; 837d64f41bSAnders Persson static kstat_t *sp_g_kstat; 847d64f41bSAnders Persson 857d64f41bSAnders Persson 860f1702c5SYu Xiangning void 870f1702c5SYu Xiangning sockparams_init(void) 880f1702c5SYu Xiangning { 890f1702c5SYu Xiangning list_create(&sphead, sizeof (struct sockparams), 900f1702c5SYu Xiangning offsetof(struct sockparams, sp_node)); 910f1702c5SYu Xiangning list_create(&sp_ephem_list, sizeof (struct sockparams), 920f1702c5SYu Xiangning offsetof(struct sockparams, sp_node)); 930f1702c5SYu Xiangning 947d64f41bSAnders Persson kstat_named_init(&sp_g_stats.spgs_ephem_nalloc, "ephemeral_nalloc", 957d64f41bSAnders Persson KSTAT_DATA_UINT64); 967d64f41bSAnders Persson kstat_named_init(&sp_g_stats.spgs_ephem_nreuse, "ephemeral_nreuse", 977d64f41bSAnders Persson KSTAT_DATA_UINT64); 987d64f41bSAnders Persson 997d64f41bSAnders Persson sp_g_kstat = kstat_create("sockfs", 0, "sockparams", "misc", 1007d64f41bSAnders Persson KSTAT_TYPE_NAMED, sizeof (sp_g_stats) / sizeof (kstat_named_t), 1017d64f41bSAnders Persson KSTAT_FLAG_VIRTUAL); 1027d64f41bSAnders Persson if (sp_g_kstat == NULL) 1037d64f41bSAnders Persson return; 1047d64f41bSAnders Persson 1057d64f41bSAnders Persson sp_g_kstat->ks_data = &sp_g_stats; 1067d64f41bSAnders Persson 1077d64f41bSAnders Persson kstat_install(sp_g_kstat); 1087d64f41bSAnders Persson } 1097d64f41bSAnders Persson 1107d64f41bSAnders Persson static int 1117d64f41bSAnders Persson sockparams_kstat_update(kstat_t *ksp, int rw) 1127d64f41bSAnders Persson { 1137d64f41bSAnders Persson struct sockparams *sp = ksp->ks_private; 1147d64f41bSAnders Persson sockparams_stats_t *sps = ksp->ks_data; 1157d64f41bSAnders Persson 1167d64f41bSAnders Persson if (rw == KSTAT_WRITE) 1177d64f41bSAnders Persson return (EACCES); 1187d64f41bSAnders Persson 1197d64f41bSAnders Persson sps->sps_nactive.value.ui64 = sp->sp_refcnt; 1207d64f41bSAnders Persson 1217d64f41bSAnders Persson return (0); 1227d64f41bSAnders Persson } 1237d64f41bSAnders Persson 1247d64f41bSAnders Persson /* 1257d64f41bSAnders Persson * Setup kstats for the given sockparams entry. 1267d64f41bSAnders Persson */ 1277d64f41bSAnders Persson static void 1287d64f41bSAnders Persson sockparams_kstat_init(struct sockparams *sp) 1297d64f41bSAnders Persson { 1307d64f41bSAnders Persson char name[KSTAT_STRLEN]; 1317d64f41bSAnders Persson 1327d64f41bSAnders Persson (void) snprintf(name, KSTAT_STRLEN, "socket_%d_%d_%d", sp->sp_family, 1337d64f41bSAnders Persson sp->sp_type, sp->sp_protocol); 1347d64f41bSAnders Persson 1357d64f41bSAnders Persson sp->sp_kstat = kstat_create("sockfs", 0, name, "misc", KSTAT_TYPE_NAMED, 1367d64f41bSAnders Persson sizeof (sockparams_stats_t) / sizeof (kstat_named_t), 1377d64f41bSAnders Persson KSTAT_FLAG_VIRTUAL); 1387d64f41bSAnders Persson 1397d64f41bSAnders Persson if (sp->sp_kstat == NULL) 1407d64f41bSAnders Persson return; 1417d64f41bSAnders Persson 1427d64f41bSAnders Persson sp->sp_kstat->ks_data = &sp->sp_stats; 1437d64f41bSAnders Persson sp->sp_kstat->ks_update = sockparams_kstat_update; 1447d64f41bSAnders Persson sp->sp_kstat->ks_private = sp; 1457d64f41bSAnders Persson kstat_install(sp->sp_kstat); 1467d64f41bSAnders Persson } 1477d64f41bSAnders Persson 1487d64f41bSAnders Persson static void 1497d64f41bSAnders Persson sockparams_kstat_fini(struct sockparams *sp) 1507d64f41bSAnders Persson { 1517d64f41bSAnders Persson if (sp->sp_kstat != NULL) { 1527d64f41bSAnders Persson kstat_delete(sp->sp_kstat); 1537d64f41bSAnders Persson sp->sp_kstat = NULL; 1547d64f41bSAnders Persson } 1550f1702c5SYu Xiangning } 1560f1702c5SYu Xiangning 1570f1702c5SYu Xiangning /* 1580f1702c5SYu Xiangning * sockparams_create(int family, int type, int protocol, char *modname, 1590f1702c5SYu Xiangning * char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 1600f1702c5SYu Xiangning * 1610f1702c5SYu Xiangning * Create a new sockparams entry. 1620f1702c5SYu Xiangning * 1630f1702c5SYu Xiangning * Arguments: 1640f1702c5SYu Xiangning * family, type, protocol: specifies the socket type 1650f1702c5SYu Xiangning * modname: Name of the module associated with the socket type. The 1660f1702c5SYu Xiangning * module can be NULL if a device path is given, in which 1670f1702c5SYu Xiangning * case the TPI module is used. 1683e95bd4aSAnders Persson * devpath: Path to the STREAMS device. Must be NULL for non-STREAMS 1693e95bd4aSAnders Persson * based transports. 1700f1702c5SYu Xiangning * devpathlen: Length of the devpath string. The argument can be 0, 1710f1702c5SYu Xiangning * indicating that devpath was allocated statically, and should 1720f1702c5SYu Xiangning * not be freed when the sockparams entry is destroyed. 1730f1702c5SYu Xiangning * 1740f1702c5SYu Xiangning * flags : SOCKPARAMS_EPHEMERAL is the only flag that is allowed. 1750f1702c5SYu Xiangning * kmflags: KM_{NO,}SLEEP 1760f1702c5SYu Xiangning * errorp : Value-return argument, set when an error occurs. 1770f1702c5SYu Xiangning * 1780f1702c5SYu Xiangning * Returns: 1790f1702c5SYu Xiangning * On success a new sockparams entry is returned, and *errorp is set 1800f1702c5SYu Xiangning * to 0. On failure NULL is returned and *errorp is set to indicate the 1810f1702c5SYu Xiangning * type of error that occured. 1820f1702c5SYu Xiangning * 1830f1702c5SYu Xiangning * Notes: 1840f1702c5SYu Xiangning * devpath and modname are freed upon failure. 1850f1702c5SYu Xiangning */ 1860f1702c5SYu Xiangning struct sockparams * 1870f1702c5SYu Xiangning sockparams_create(int family, int type, int protocol, char *modname, 1880f1702c5SYu Xiangning char *devpath, int devpathlen, int flags, int kmflags, int *errorp) 1890f1702c5SYu Xiangning { 1900f1702c5SYu Xiangning struct sockparams *sp = NULL; 1910f1702c5SYu Xiangning size_t size; 1920f1702c5SYu Xiangning 1930f1702c5SYu Xiangning ASSERT((flags & ~SOCKPARAMS_EPHEMERAL) == 0); 1940f1702c5SYu Xiangning if (flags & ~SOCKPARAMS_EPHEMERAL) { 1950f1702c5SYu Xiangning *errorp = EINVAL; 1960f1702c5SYu Xiangning goto error; 1970f1702c5SYu Xiangning } 1980f1702c5SYu Xiangning 1993e95bd4aSAnders Persson /* either a module or device must be given, but not both */ 2000f1702c5SYu Xiangning if (modname == NULL && devpath == NULL) { 2010f1702c5SYu Xiangning *errorp = EINVAL; 2020f1702c5SYu Xiangning goto error; 2030f1702c5SYu Xiangning } 2040f1702c5SYu Xiangning 2050f1702c5SYu Xiangning sp = kmem_zalloc(sizeof (*sp), kmflags); 2060f1702c5SYu Xiangning if (sp == NULL) { 2070f1702c5SYu Xiangning *errorp = ENOMEM; 2080f1702c5SYu Xiangning goto error; 2090f1702c5SYu Xiangning } 2100f1702c5SYu Xiangning sp->sp_family = family; 2110f1702c5SYu Xiangning sp->sp_type = type; 2120f1702c5SYu Xiangning sp->sp_protocol = protocol; 2130f1702c5SYu Xiangning sp->sp_refcnt = 0; 2140f1702c5SYu Xiangning sp->sp_flags = flags; 2150f1702c5SYu Xiangning 2163e95bd4aSAnders Persson list_create(&sp->sp_auto_filters, sizeof (sp_filter_t), 2173e95bd4aSAnders Persson offsetof(sp_filter_t, spf_node)); 2183e95bd4aSAnders Persson list_create(&sp->sp_prog_filters, sizeof (sp_filter_t), 2193e95bd4aSAnders Persson offsetof(sp_filter_t, spf_node)); 2203e95bd4aSAnders Persson 22151899d8cSAnders Persson kstat_named_init(&sp->sp_stats.sps_nfallback, "nfallback", 22251899d8cSAnders Persson KSTAT_DATA_UINT64); 22351899d8cSAnders Persson kstat_named_init(&sp->sp_stats.sps_nactive, "nactive", 22451899d8cSAnders Persson KSTAT_DATA_UINT64); 22551899d8cSAnders Persson kstat_named_init(&sp->sp_stats.sps_ncreate, "ncreate", 22651899d8cSAnders Persson KSTAT_DATA_UINT64); 22751899d8cSAnders Persson 2287d64f41bSAnders Persson /* 22951899d8cSAnders Persson * Track how many ephemeral entries we have created. 2307d64f41bSAnders Persson */ 2317d64f41bSAnders Persson if (sp->sp_flags & SOCKPARAMS_EPHEMERAL) 2327d64f41bSAnders Persson sp_g_stats.spgs_ephem_nalloc.value.ui64++; 2337d64f41bSAnders Persson 2340f1702c5SYu Xiangning if (modname != NULL) { 2350f1702c5SYu Xiangning sp->sp_smod_name = modname; 2360f1702c5SYu Xiangning } else { 2370f1702c5SYu Xiangning size = strlen(SOTPI_SMOD_NAME) + 1; 2380f1702c5SYu Xiangning modname = kmem_zalloc(size, kmflags); 2390f1702c5SYu Xiangning if (modname == NULL) { 2400f1702c5SYu Xiangning *errorp = ENOMEM; 2410f1702c5SYu Xiangning goto error; 2420f1702c5SYu Xiangning } 2430f1702c5SYu Xiangning sp->sp_smod_name = modname; 2440f1702c5SYu Xiangning (void) sprintf(sp->sp_smod_name, "%s", SOTPI_SMOD_NAME); 2450f1702c5SYu Xiangning } 2460f1702c5SYu Xiangning 2470f1702c5SYu Xiangning if (devpath != NULL) { 2480f1702c5SYu Xiangning /* Set up the device entry. */ 2490f1702c5SYu Xiangning *errorp = sockparams_sdev_init(sp, devpath, devpathlen); 2500f1702c5SYu Xiangning if (*errorp != 0) 2510f1702c5SYu Xiangning goto error; 2520f1702c5SYu Xiangning } 2530f1702c5SYu Xiangning 2540f1702c5SYu Xiangning mutex_init(&sp->sp_lock, NULL, MUTEX_DEFAULT, NULL); 2550f1702c5SYu Xiangning *errorp = 0; 2560f1702c5SYu Xiangning return (sp); 2570f1702c5SYu Xiangning error: 2580f1702c5SYu Xiangning ASSERT(*errorp != 0); 2590f1702c5SYu Xiangning if (modname != NULL) 2600f1702c5SYu Xiangning kmem_free(modname, strlen(modname) + 1); 2610f1702c5SYu Xiangning if (devpathlen != 0) 2620f1702c5SYu Xiangning kmem_free(devpath, devpathlen); 26351899d8cSAnders Persson if (sp != NULL) 2640f1702c5SYu Xiangning kmem_free(sp, sizeof (*sp)); 2650f1702c5SYu Xiangning return (NULL); 2660f1702c5SYu Xiangning } 2670f1702c5SYu Xiangning 2680f1702c5SYu Xiangning /* 2690f1702c5SYu Xiangning * Initialize the STREAMS device aspect of the sockparams entry. 2700f1702c5SYu Xiangning */ 2710f1702c5SYu Xiangning static int 2720f1702c5SYu Xiangning sockparams_sdev_init(struct sockparams *sp, char *devpath, int devpathlen) 2730f1702c5SYu Xiangning { 2740f1702c5SYu Xiangning vnode_t *vp = NULL; 2750f1702c5SYu Xiangning int error; 2760f1702c5SYu Xiangning 2770f1702c5SYu Xiangning ASSERT(devpath != NULL); 2780f1702c5SYu Xiangning 2790f1702c5SYu Xiangning if ((error = sogetvp(devpath, &vp, UIO_SYSSPACE)) != 0) { 2800f1702c5SYu Xiangning dprint(0, ("sockparams_sdev_init: vp %s failed with %d\n", 2810f1702c5SYu Xiangning devpath, error)); 2820f1702c5SYu Xiangning return (error); 2830f1702c5SYu Xiangning } 2840f1702c5SYu Xiangning 2850f1702c5SYu Xiangning ASSERT(vp != NULL); 2860f1702c5SYu Xiangning sp->sp_sdev_info.sd_vnode = vp; 2870f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath = devpath; 2880f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpathlen = devpathlen; 2890f1702c5SYu Xiangning 2900f1702c5SYu Xiangning return (0); 2910f1702c5SYu Xiangning } 2920f1702c5SYu Xiangning 2930f1702c5SYu Xiangning /* 2940f1702c5SYu Xiangning * sockparams_destroy(struct sockparams *sp) 2950f1702c5SYu Xiangning * 2960f1702c5SYu Xiangning * Releases all the resources associated with the sockparams entry, 2970f1702c5SYu Xiangning * and frees the sockparams entry. 2980f1702c5SYu Xiangning * 2990f1702c5SYu Xiangning * Arguments: 3000f1702c5SYu Xiangning * sp: the sockparams entry to destroy. 3010f1702c5SYu Xiangning * 3020f1702c5SYu Xiangning * Returns: 3030f1702c5SYu Xiangning * Nothing. 3040f1702c5SYu Xiangning * 3050f1702c5SYu Xiangning * Locking: 3060f1702c5SYu Xiangning * The sp_lock of the entry can not be held. 3070f1702c5SYu Xiangning */ 3080f1702c5SYu Xiangning void 3090f1702c5SYu Xiangning sockparams_destroy(struct sockparams *sp) 3100f1702c5SYu Xiangning { 3110f1702c5SYu Xiangning ASSERT(sp->sp_refcnt == 0); 3120f1702c5SYu Xiangning ASSERT(!list_link_active(&sp->sp_node)); 3130f1702c5SYu Xiangning 3140f1702c5SYu Xiangning sockparams_sdev_fini(sp); 3150f1702c5SYu Xiangning 3160f1702c5SYu Xiangning if (sp->sp_smod_info != NULL) 3175f1fdc18SAnders Persson SMOD_DEC_REF(sp->sp_smod_info, sp->sp_smod_name); 3180f1702c5SYu Xiangning kmem_free(sp->sp_smod_name, strlen(sp->sp_smod_name) + 1); 3190f1702c5SYu Xiangning sp->sp_smod_name = NULL; 3200f1702c5SYu Xiangning sp->sp_smod_info = NULL; 3210f1702c5SYu Xiangning mutex_destroy(&sp->sp_lock); 3227d64f41bSAnders Persson sockparams_kstat_fini(sp); 3230f1702c5SYu Xiangning 3243e95bd4aSAnders Persson sof_sockparams_fini(sp); 3253e95bd4aSAnders Persson list_destroy(&sp->sp_auto_filters); 3263e95bd4aSAnders Persson list_destroy(&sp->sp_prog_filters); 3273e95bd4aSAnders Persson 3280f1702c5SYu Xiangning kmem_free(sp, sizeof (*sp)); 3290f1702c5SYu Xiangning } 3300f1702c5SYu Xiangning 3310f1702c5SYu Xiangning /* 3320f1702c5SYu Xiangning * Clean up the STREAMS device part of the sockparams entry. 3330f1702c5SYu Xiangning */ 3340f1702c5SYu Xiangning static void 3350f1702c5SYu Xiangning sockparams_sdev_fini(struct sockparams *sp) 3360f1702c5SYu Xiangning { 3370f1702c5SYu Xiangning sdev_info_t sd; 3380f1702c5SYu Xiangning 3390f1702c5SYu Xiangning /* 3400f1702c5SYu Xiangning * if the entry does not have a STREAMS device, then there 3410f1702c5SYu Xiangning * is nothing to do. 3420f1702c5SYu Xiangning */ 3430f1702c5SYu Xiangning if (!SOCKPARAMS_HAS_DEVICE(sp)) 3440f1702c5SYu Xiangning return; 3450f1702c5SYu Xiangning 3460f1702c5SYu Xiangning sd = sp->sp_sdev_info; 3470f1702c5SYu Xiangning if (sd.sd_vnode != NULL) 3480f1702c5SYu Xiangning VN_RELE(sd.sd_vnode); 3490f1702c5SYu Xiangning if (sd.sd_devpathlen != 0) 3500f1702c5SYu Xiangning kmem_free(sd.sd_devpath, sd.sd_devpathlen); 3510f1702c5SYu Xiangning 3520f1702c5SYu Xiangning sp->sp_sdev_info.sd_vnode = NULL; 3530f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath = NULL; 3540f1702c5SYu Xiangning } 3550f1702c5SYu Xiangning 3560f1702c5SYu Xiangning /* 3570f1702c5SYu Xiangning * Look for a matching sockparams entry on the given list. 3580f1702c5SYu Xiangning * The caller must hold the associated list lock. 3590f1702c5SYu Xiangning */ 3600f1702c5SYu Xiangning static struct sockparams * 3610f1702c5SYu Xiangning sockparams_find(list_t *list, int family, int type, int protocol, 36222238f73Sshenjian boolean_t by_devpath, const char *name) 3630f1702c5SYu Xiangning { 3640f1702c5SYu Xiangning struct sockparams *sp; 3650f1702c5SYu Xiangning 3660f1702c5SYu Xiangning for (sp = list_head(list); sp != NULL; sp = list_next(list, sp)) { 36722238f73Sshenjian if (sp->sp_family == family && sp->sp_type == type) { 3680f1702c5SYu Xiangning if (sp->sp_protocol == protocol) { 36922238f73Sshenjian if (name == NULL) 3700f1702c5SYu Xiangning break; 37122238f73Sshenjian else if (by_devpath && 3720f1702c5SYu Xiangning sp->sp_sdev_info.sd_devpath != NULL && 3730f1702c5SYu Xiangning strcmp(sp->sp_sdev_info.sd_devpath, 3740f1702c5SYu Xiangning name) == 0) 3750f1702c5SYu Xiangning break; 37622238f73Sshenjian else if (strcmp(sp->sp_smod_name, name) == 0) 3770f1702c5SYu Xiangning break; 3780f1702c5SYu Xiangning } 3790f1702c5SYu Xiangning } 3800f1702c5SYu Xiangning } 38122238f73Sshenjian return (sp); 3820f1702c5SYu Xiangning } 3830f1702c5SYu Xiangning 3840f1702c5SYu Xiangning /* 3850f1702c5SYu Xiangning * sockparams_hold_ephemeral() 3860f1702c5SYu Xiangning * 3870f1702c5SYu Xiangning * Returns an ephemeral sockparams entry of the requested family, type and 3880f1702c5SYu Xiangning * protocol. The entry is returned held, and the caller is responsible for 3890f1702c5SYu Xiangning * dropping the reference using SOCKPARAMS_DEC_REF() once done. 3900f1702c5SYu Xiangning * 3910f1702c5SYu Xiangning * All ephemeral entries are on list (sp_ephem_list). If there is an 3920f1702c5SYu Xiangning * entry on the list that match the search criteria, then a reference is 3930f1702c5SYu Xiangning * placed on that entry. Otherwise, a new entry is created and inserted 3940f1702c5SYu Xiangning * in the list. The entry is removed from the list when the last reference 3950f1702c5SYu Xiangning * is dropped. 3960f1702c5SYu Xiangning * 3970f1702c5SYu Xiangning * The tpi flag is used to determine whether name refers to a device or 3980f1702c5SYu Xiangning * module name. 3990f1702c5SYu Xiangning */ 4000f1702c5SYu Xiangning static struct sockparams * 4010f1702c5SYu Xiangning sockparams_hold_ephemeral(int family, int type, int protocol, 40222238f73Sshenjian const char *name, boolean_t by_devpath, int kmflag, int *errorp) 4030f1702c5SYu Xiangning { 4040f1702c5SYu Xiangning struct sockparams *sp = NULL; 4050f1702c5SYu Xiangning *errorp = 0; 4060f1702c5SYu Xiangning 4070f1702c5SYu Xiangning /* 4080f1702c5SYu Xiangning * First look for an existing entry 4090f1702c5SYu Xiangning */ 4103e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_READER); 4110f1702c5SYu Xiangning sp = sockparams_find(&sp_ephem_list, family, type, protocol, 41222238f73Sshenjian by_devpath, name); 4130f1702c5SYu Xiangning if (sp != NULL) { 4140f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 4153e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4167d64f41bSAnders Persson sp_g_stats.spgs_ephem_nreuse.value.ui64++; 4170f1702c5SYu Xiangning 4180f1702c5SYu Xiangning return (sp); 4190f1702c5SYu Xiangning } else { 4200f1702c5SYu Xiangning struct sockparams *newsp = NULL; 4210f1702c5SYu Xiangning char *namebuf = NULL; 4220f1702c5SYu Xiangning int namelen = 0; 4230f1702c5SYu Xiangning 4243e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4250f1702c5SYu Xiangning 4260f1702c5SYu Xiangning namelen = strlen(name) + 1; 4270f1702c5SYu Xiangning namebuf = kmem_alloc(namelen, kmflag); 4280f1702c5SYu Xiangning if (namebuf == NULL) { 4290f1702c5SYu Xiangning *errorp = ENOMEM; 4300f1702c5SYu Xiangning return (NULL); 4310f1702c5SYu Xiangning } 4320f1702c5SYu Xiangning 4330f1702c5SYu Xiangning (void *)strncpy(namebuf, name, namelen); 43422238f73Sshenjian if (by_devpath) { 4350f1702c5SYu Xiangning newsp = sockparams_create(family, type, 4360f1702c5SYu Xiangning protocol, NULL, namebuf, namelen, 4370f1702c5SYu Xiangning SOCKPARAMS_EPHEMERAL, kmflag, errorp); 4380f1702c5SYu Xiangning } else { 4390f1702c5SYu Xiangning newsp = sockparams_create(family, type, 4400f1702c5SYu Xiangning protocol, namebuf, NULL, 0, 4410f1702c5SYu Xiangning SOCKPARAMS_EPHEMERAL, kmflag, errorp); 4420f1702c5SYu Xiangning } 4430f1702c5SYu Xiangning 4440f1702c5SYu Xiangning if (newsp == NULL) { 4450f1702c5SYu Xiangning ASSERT(*errorp != 0); 4460f1702c5SYu Xiangning return (NULL); 4470f1702c5SYu Xiangning } 4480f1702c5SYu Xiangning 4490f1702c5SYu Xiangning /* 4500f1702c5SYu Xiangning * Time to load the socket module. 4510f1702c5SYu Xiangning */ 4520f1702c5SYu Xiangning ASSERT(newsp->sp_smod_info == NULL); 4530f1702c5SYu Xiangning newsp->sp_smod_info = 4540f1702c5SYu Xiangning smod_lookup_byname(newsp->sp_smod_name); 4550f1702c5SYu Xiangning if (newsp->sp_smod_info == NULL) { 4560f1702c5SYu Xiangning /* Failed to load */ 4570f1702c5SYu Xiangning sockparams_destroy(newsp); 4580f1702c5SYu Xiangning *errorp = ENXIO; 4590f1702c5SYu Xiangning return (NULL); 4600f1702c5SYu Xiangning } 4610f1702c5SYu Xiangning 4620f1702c5SYu Xiangning /* 4630f1702c5SYu Xiangning * The sockparams entry was created, now try to add it 4640f1702c5SYu Xiangning * to the list. We need to hold the lock as a WRITER. 4650f1702c5SYu Xiangning */ 4663e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 4670f1702c5SYu Xiangning sp = sockparams_find(&sp_ephem_list, family, type, protocol, 46822238f73Sshenjian by_devpath, name); 4690f1702c5SYu Xiangning if (sp != NULL) { 4700f1702c5SYu Xiangning /* 4710f1702c5SYu Xiangning * Someone has requested a matching entry, so just 4720f1702c5SYu Xiangning * place a hold on it and release the entry we alloc'ed. 4730f1702c5SYu Xiangning */ 4740f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 4753e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4760f1702c5SYu Xiangning 4770f1702c5SYu Xiangning sockparams_destroy(newsp); 4780f1702c5SYu Xiangning } else { 4793e95bd4aSAnders Persson *errorp = sof_sockparams_init(newsp); 4803e95bd4aSAnders Persson if (*errorp != 0) { 4813e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4823e95bd4aSAnders Persson sockparams_destroy(newsp); 4833e95bd4aSAnders Persson return (NULL); 4843e95bd4aSAnders Persson } 4850f1702c5SYu Xiangning SOCKPARAMS_INC_REF(newsp); 4860f1702c5SYu Xiangning list_insert_tail(&sp_ephem_list, newsp); 4873e95bd4aSAnders Persson rw_exit(&sockconf_lock); 4880f1702c5SYu Xiangning 4890f1702c5SYu Xiangning sp = newsp; 4900f1702c5SYu Xiangning } 4910f1702c5SYu Xiangning ASSERT(*errorp == 0); 4920f1702c5SYu Xiangning 4930f1702c5SYu Xiangning return (sp); 4940f1702c5SYu Xiangning } 4950f1702c5SYu Xiangning } 4960f1702c5SYu Xiangning 4970f1702c5SYu Xiangning struct sockparams * 4980f1702c5SYu Xiangning sockparams_hold_ephemeral_bydev(int family, int type, int protocol, 4990f1702c5SYu Xiangning const char *dev, int kmflag, int *errorp) 5000f1702c5SYu Xiangning { 5010f1702c5SYu Xiangning return (sockparams_hold_ephemeral(family, type, protocol, dev, B_TRUE, 5020f1702c5SYu Xiangning kmflag, errorp)); 5030f1702c5SYu Xiangning } 5040f1702c5SYu Xiangning 5050f1702c5SYu Xiangning struct sockparams * 5060f1702c5SYu Xiangning sockparams_hold_ephemeral_bymod(int family, int type, int protocol, 5070f1702c5SYu Xiangning const char *mod, int kmflag, int *errorp) 5080f1702c5SYu Xiangning { 5090f1702c5SYu Xiangning return (sockparams_hold_ephemeral(family, type, protocol, mod, B_FALSE, 5100f1702c5SYu Xiangning kmflag, errorp)); 5110f1702c5SYu Xiangning } 5120f1702c5SYu Xiangning 5130f1702c5SYu Xiangning /* 5140f1702c5SYu Xiangning * Called when the last socket using the ephemeral entry is dropping 5150f1702c5SYu Xiangning * its' reference. To maintain lock order we must drop the sockparams 5160f1702c5SYu Xiangning * lock before calling this function. As a result, a new reference 5170f1702c5SYu Xiangning * might be placed on the entry, in which case there is nothing to 5180f1702c5SYu Xiangning * do. However, if ref count goes to zero, we delete the entry. 5190f1702c5SYu Xiangning */ 5200f1702c5SYu Xiangning void 5210f1702c5SYu Xiangning sockparams_ephemeral_drop_last_ref(struct sockparams *sp) 5220f1702c5SYu Xiangning { 5230f1702c5SYu Xiangning ASSERT(sp->sp_flags & SOCKPARAMS_EPHEMERAL); 5240f1702c5SYu Xiangning ASSERT(MUTEX_NOT_HELD(&sp->sp_lock)); 5250f1702c5SYu Xiangning 5263e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 5270f1702c5SYu Xiangning mutex_enter(&sp->sp_lock); 5280f1702c5SYu Xiangning 5290f1702c5SYu Xiangning if (--sp->sp_refcnt == 0) { 5300f1702c5SYu Xiangning list_remove(&sp_ephem_list, sp); 5310f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 5323e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5330f1702c5SYu Xiangning 5340f1702c5SYu Xiangning sockparams_destroy(sp); 5350f1702c5SYu Xiangning } else { 5360f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 5373e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5380f1702c5SYu Xiangning } 5390f1702c5SYu Xiangning } 5400f1702c5SYu Xiangning 5410f1702c5SYu Xiangning /* 5420f1702c5SYu Xiangning * sockparams_add(struct sockparams *sp) 5430f1702c5SYu Xiangning * 5440f1702c5SYu Xiangning * Tries to add the given sockparams entry to the global list. 5450f1702c5SYu Xiangning * 5460f1702c5SYu Xiangning * Arguments: 5470f1702c5SYu Xiangning * sp: the sockparms entry to add 5480f1702c5SYu Xiangning * 5490f1702c5SYu Xiangning * Returns: 5500f1702c5SYu Xiangning * On success 0, but if an entry already exists, then EEXIST 5510f1702c5SYu Xiangning * is returned. 5520f1702c5SYu Xiangning * 5530f1702c5SYu Xiangning * Locking: 5543e95bd4aSAnders Persson * The caller can not be holding sockconf_lock. 5550f1702c5SYu Xiangning */ 5563e95bd4aSAnders Persson int 5570f1702c5SYu Xiangning sockparams_add(struct sockparams *sp) 5580f1702c5SYu Xiangning { 5593e95bd4aSAnders Persson int error; 5603e95bd4aSAnders Persson 5610f1702c5SYu Xiangning ASSERT(!(sp->sp_flags & SOCKPARAMS_EPHEMERAL)); 5620f1702c5SYu Xiangning 5633e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 5640f1702c5SYu Xiangning if (sockparams_find(&sphead, sp->sp_family, sp->sp_type, 56522238f73Sshenjian sp->sp_protocol, B_TRUE, NULL) != 0) { 5663e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5670f1702c5SYu Xiangning return (EEXIST); 5680f1702c5SYu Xiangning } else { 5693e95bd4aSAnders Persson /* 5703e95bd4aSAnders Persson * Unique sockparams entry, so init the kstats. 5713e95bd4aSAnders Persson */ 5723e95bd4aSAnders Persson sockparams_kstat_init(sp); 5733e95bd4aSAnders Persson 5743e95bd4aSAnders Persson /* 5753e95bd4aSAnders Persson * Before making the socket type available we must make 5763e95bd4aSAnders Persson * sure that interested socket filters are aware of it. 5773e95bd4aSAnders Persson */ 5783e95bd4aSAnders Persson error = sof_sockparams_init(sp); 5793e95bd4aSAnders Persson if (error != 0) { 5803e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5813e95bd4aSAnders Persson return (error); 5823e95bd4aSAnders Persson } 5830f1702c5SYu Xiangning list_insert_tail(&sphead, sp); 5843e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5850f1702c5SYu Xiangning return (0); 5860f1702c5SYu Xiangning } 5870f1702c5SYu Xiangning } 5880f1702c5SYu Xiangning 5890f1702c5SYu Xiangning /* 5900f1702c5SYu Xiangning * sockparams_delete(int family, int type, int protocol) 5910f1702c5SYu Xiangning * 5920f1702c5SYu Xiangning * Marks the sockparams entry for a specific family, type and protocol 5930f1702c5SYu Xiangning * for deletion. The entry is removed from the list and destroyed 5940f1702c5SYu Xiangning * if no one is holding a reference to it. 5950f1702c5SYu Xiangning * 5960f1702c5SYu Xiangning * Arguments: 5970f1702c5SYu Xiangning * family, type, protocol: the socket type that should be removed. 5980f1702c5SYu Xiangning * 5990f1702c5SYu Xiangning * Returns: 6000f1702c5SYu Xiangning * On success 0, otherwise ENXIO. 6010f1702c5SYu Xiangning * 6020f1702c5SYu Xiangning * Locking: 6033e95bd4aSAnders Persson * Caller can not be holding sockconf_lock or the sp_lock of 6040f1702c5SYu Xiangning * any sockparams entry. 6050f1702c5SYu Xiangning */ 6063e95bd4aSAnders Persson int 6070f1702c5SYu Xiangning sockparams_delete(int family, int type, int protocol) 6080f1702c5SYu Xiangning { 6090f1702c5SYu Xiangning struct sockparams *sp; 6100f1702c5SYu Xiangning 6113e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 61222238f73Sshenjian sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL); 6130f1702c5SYu Xiangning 6140f1702c5SYu Xiangning if (sp != NULL) { 6150f1702c5SYu Xiangning /* 6160f1702c5SYu Xiangning * If no one is holding a reference to the entry, then 6170f1702c5SYu Xiangning * we go ahead and remove it from the list and then 6180f1702c5SYu Xiangning * destroy it. 6190f1702c5SYu Xiangning */ 6200f1702c5SYu Xiangning mutex_enter(&sp->sp_lock); 6210f1702c5SYu Xiangning if (sp->sp_refcnt != 0) { 6220f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 6233e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6240f1702c5SYu Xiangning return (EBUSY); 6250f1702c5SYu Xiangning } 6260f1702c5SYu Xiangning mutex_exit(&sp->sp_lock); 6270f1702c5SYu Xiangning /* Delete the sockparams entry. */ 6280f1702c5SYu Xiangning list_remove(&sphead, sp); 6293e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6300f1702c5SYu Xiangning 6310f1702c5SYu Xiangning sockparams_destroy(sp); 6320f1702c5SYu Xiangning return (0); 6330f1702c5SYu Xiangning } else { 6343e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6350f1702c5SYu Xiangning return (ENXIO); 6360f1702c5SYu Xiangning } 6370f1702c5SYu Xiangning } 6380f1702c5SYu Xiangning 6390f1702c5SYu Xiangning 6400f1702c5SYu Xiangning /* 6410f1702c5SYu Xiangning * solookup(int family, int type, int protocol, struct sockparams **spp) 6420f1702c5SYu Xiangning * 6430f1702c5SYu Xiangning * Lookup an entry in the sockparams list based on the triple. The returned 6440f1702c5SYu Xiangning * entry either exactly match the given tuple, or it is the 'default' entry 6450f1702c5SYu Xiangning * for the given <family, type>. A default entry is on with a protocol 6460f1702c5SYu Xiangning * value of zero. 6470f1702c5SYu Xiangning * 6480f1702c5SYu Xiangning * Arguments: 6490f1702c5SYu Xiangning * family, type, protocol: tuple to search for 6500f1702c5SYu Xiangning * spp: Value-return argument 6510f1702c5SYu Xiangning * 6520f1702c5SYu Xiangning * Returns: 6530f1702c5SYu Xiangning * If an entry is found, 0 is returned and *spp is set to point to the 6540f1702c5SYu Xiangning * entry. In case an entry is not found, *spp is set to NULL, and an 6550f1702c5SYu Xiangning * error code is returned. The errors are (in decreasing precedence): 6560f1702c5SYu Xiangning * EAFNOSUPPORT - address family not in list 6570f1702c5SYu Xiangning * EPROTONOSUPPORT - address family supported but not protocol. 6580f1702c5SYu Xiangning * EPROTOTYPE - address family and protocol supported but not socket type. 6590f1702c5SYu Xiangning * 6600f1702c5SYu Xiangning * TODO: should use ddi_modopen()/ddi_modclose() 6610f1702c5SYu Xiangning */ 6620f1702c5SYu Xiangning int 6630f1702c5SYu Xiangning solookup(int family, int type, int protocol, struct sockparams **spp) 6640f1702c5SYu Xiangning { 6650f1702c5SYu Xiangning struct sockparams *sp = NULL; 6660f1702c5SYu Xiangning int error = 0; 6670f1702c5SYu Xiangning 6680f1702c5SYu Xiangning *spp = NULL; 6693e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_READER); 6700f1702c5SYu Xiangning 6710f1702c5SYu Xiangning /* 6720f1702c5SYu Xiangning * Search the sockparams list for an appropiate entry. 6730f1702c5SYu Xiangning * Hopefully we find an entry that match the exact family, 6740f1702c5SYu Xiangning * type and protocol specified by the user, in which case 6750f1702c5SYu Xiangning * we return that entry. However, we also keep track of 6760f1702c5SYu Xiangning * the default entry for a specific family and type, the 6770f1702c5SYu Xiangning * entry of which would have a protocol value of 0. 6780f1702c5SYu Xiangning */ 67922238f73Sshenjian sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL); 6800f1702c5SYu Xiangning 6810f1702c5SYu Xiangning if (sp == NULL) { 6820f1702c5SYu Xiangning int found = 0; 6830f1702c5SYu Xiangning 6840f1702c5SYu Xiangning /* Determine correct error code */ 6850f1702c5SYu Xiangning for (sp = list_head(&sphead); sp != NULL; 6860f1702c5SYu Xiangning sp = list_next(&sphead, sp)) { 6870f1702c5SYu Xiangning if (sp->sp_family == family && found < 1) 6880f1702c5SYu Xiangning found = 1; 6890f1702c5SYu Xiangning if (sp->sp_family == family && 6900f1702c5SYu Xiangning sp->sp_protocol == protocol && found < 2) 6910f1702c5SYu Xiangning found = 2; 6920f1702c5SYu Xiangning } 6933e95bd4aSAnders Persson rw_exit(&sockconf_lock); 6940f1702c5SYu Xiangning switch (found) { 6950f1702c5SYu Xiangning case 0: 6960f1702c5SYu Xiangning error = EAFNOSUPPORT; 6970f1702c5SYu Xiangning break; 6980f1702c5SYu Xiangning case 1: 6990f1702c5SYu Xiangning error = EPROTONOSUPPORT; 7000f1702c5SYu Xiangning break; 7010f1702c5SYu Xiangning case 2: 7020f1702c5SYu Xiangning error = EPROTOTYPE; 7030f1702c5SYu Xiangning break; 7040f1702c5SYu Xiangning } 7050f1702c5SYu Xiangning return (error); 7060f1702c5SYu Xiangning } 7070f1702c5SYu Xiangning 7080f1702c5SYu Xiangning /* 7090f1702c5SYu Xiangning * An entry was found. 7100f1702c5SYu Xiangning * 7110f1702c5SYu Xiangning * We put a hold on the entry early on, so if the 7120f1702c5SYu Xiangning * sockmod is not loaded, and we have to exit 7133e95bd4aSAnders Persson * sockconf_lock to call modload(), we know that the 7140f1702c5SYu Xiangning * sockparams entry wont go away. That way we don't 7150f1702c5SYu Xiangning * have to look up the entry once we come back from 7160f1702c5SYu Xiangning * modload(). 7170f1702c5SYu Xiangning */ 7180f1702c5SYu Xiangning SOCKPARAMS_INC_REF(sp); 7193e95bd4aSAnders Persson rw_exit(&sockconf_lock); 7200f1702c5SYu Xiangning 7210f1702c5SYu Xiangning if (sp->sp_smod_info == NULL) { 7225f1fdc18SAnders Persson smod_info_t *smod = smod_lookup_byname(sp->sp_smod_name); 7235f1fdc18SAnders Persson 7245f1fdc18SAnders Persson if (smod == NULL) { 7250f1702c5SYu Xiangning /* 7260f1702c5SYu Xiangning * We put a hold on the sockparams entry 7270f1702c5SYu Xiangning * earlier, hoping everything would work out. 7280f1702c5SYu Xiangning * That obviously did not happen, so release 7290f1702c5SYu Xiangning * the hold here. 7300f1702c5SYu Xiangning */ 7310f1702c5SYu Xiangning SOCKPARAMS_DEC_REF(sp); 7320f1702c5SYu Xiangning /* 7330f1702c5SYu Xiangning * We should probably mark the sockparams as 7340f1702c5SYu Xiangning * "bad", and redo the lookup skipping the 7350f1702c5SYu Xiangning * "bad" entries. I.e., sp->sp_mod_state |= BAD, 7360f1702c5SYu Xiangning * return (solookup(...)) 7370f1702c5SYu Xiangning */ 7380f1702c5SYu Xiangning return (ENXIO); 7390f1702c5SYu Xiangning } 7405f1fdc18SAnders Persson /* 7415f1fdc18SAnders Persson * Another thread might have already looked up the socket 7425f1fdc18SAnders Persson * module for this entry. In that case we need to drop our 7435f1fdc18SAnders Persson * reference to `smod' to ensure that the sockparams entry 7445f1fdc18SAnders Persson * only holds one reference. 7455f1fdc18SAnders Persson */ 7465f1fdc18SAnders Persson mutex_enter(&sp->sp_lock); 7475f1fdc18SAnders Persson if (sp->sp_smod_info == NULL) 7485f1fdc18SAnders Persson sp->sp_smod_info = smod; 7495f1fdc18SAnders Persson else 7505f1fdc18SAnders Persson SMOD_DEC_REF(smod, sp->sp_smod_name); 7515f1fdc18SAnders Persson mutex_exit(&sp->sp_lock); 7520f1702c5SYu Xiangning } 7530f1702c5SYu Xiangning 7540f1702c5SYu Xiangning /* 7550f1702c5SYu Xiangning * Alright, we have a valid sockparams entry. 7560f1702c5SYu Xiangning */ 7570f1702c5SYu Xiangning *spp = sp; 7580f1702c5SYu Xiangning return (0); 7590f1702c5SYu Xiangning } 7603e95bd4aSAnders Persson 7613e95bd4aSAnders Persson /* 7623e95bd4aSAnders Persson * Called when filter entry `ent' is going away. All sockparams remove 7633e95bd4aSAnders Persson * their references to `ent'. 7643e95bd4aSAnders Persson */ 7653e95bd4aSAnders Persson static void 7663e95bd4aSAnders Persson sockparams_filter_cleanup_impl(sof_entry_t *ent, list_t *list) 7673e95bd4aSAnders Persson { 7683e95bd4aSAnders Persson struct sockparams *sp; 7693e95bd4aSAnders Persson sp_filter_t *fil; 7703e95bd4aSAnders Persson list_t *flist; 7713e95bd4aSAnders Persson 7723e95bd4aSAnders Persson ASSERT(RW_WRITE_HELD(&sockconf_lock)); 7733e95bd4aSAnders Persson 7743e95bd4aSAnders Persson for (sp = list_head(list); sp != NULL; 7753e95bd4aSAnders Persson sp = list_next(list, sp)) { 7763e95bd4aSAnders Persson flist = (ent->sofe_flags & SOFEF_AUTO) ? 7773e95bd4aSAnders Persson &sp->sp_auto_filters : &sp->sp_prog_filters; 7783e95bd4aSAnders Persson for (fil = list_head(flist); fil != NULL; 7793e95bd4aSAnders Persson fil = list_next(flist, fil)) { 7803e95bd4aSAnders Persson if (fil->spf_filter == ent) { 7813e95bd4aSAnders Persson list_remove(flist, fil); 7823e95bd4aSAnders Persson kmem_free(fil, sizeof (sp_filter_t)); 7833e95bd4aSAnders Persson break; 7843e95bd4aSAnders Persson } 7853e95bd4aSAnders Persson } 7863e95bd4aSAnders Persson } 7873e95bd4aSAnders Persson } 7883e95bd4aSAnders Persson void 7893e95bd4aSAnders Persson sockparams_filter_cleanup(sof_entry_t *ent) 7903e95bd4aSAnders Persson { 7913e95bd4aSAnders Persson sockparams_filter_cleanup_impl(ent, &sphead); 7923e95bd4aSAnders Persson sockparams_filter_cleanup_impl(ent, &sp_ephem_list); 7933e95bd4aSAnders Persson } 7943e95bd4aSAnders Persson 7953e95bd4aSAnders Persson /* 7963e95bd4aSAnders Persson * New filter is being added; walk the list of sockparams to see if 7973e95bd4aSAnders Persson * the filter is interested in any of the sockparams. 7983e95bd4aSAnders Persson */ 7993e95bd4aSAnders Persson static int 8003e95bd4aSAnders Persson sockparams_new_filter_impl(sof_entry_t *ent, list_t *list) 8013e95bd4aSAnders Persson { 8023e95bd4aSAnders Persson struct sockparams *sp; 8033e95bd4aSAnders Persson int err; 8043e95bd4aSAnders Persson 8053e95bd4aSAnders Persson ASSERT(RW_WRITE_HELD(&sockconf_lock)); 8063e95bd4aSAnders Persson 8073e95bd4aSAnders Persson for (sp = list_head(list); sp != NULL; 8083e95bd4aSAnders Persson sp = list_next(list, sp)) { 8093e95bd4aSAnders Persson if ((err = sof_entry_proc_sockparams(ent, sp)) != 0) { 8103e95bd4aSAnders Persson sockparams_filter_cleanup(ent); 8113e95bd4aSAnders Persson return (err); 8123e95bd4aSAnders Persson } 8133e95bd4aSAnders Persson } 8143e95bd4aSAnders Persson return (0); 8153e95bd4aSAnders Persson } 8163e95bd4aSAnders Persson 8173e95bd4aSAnders Persson int 8183e95bd4aSAnders Persson sockparams_new_filter(sof_entry_t *ent) 8193e95bd4aSAnders Persson { 8203e95bd4aSAnders Persson int error; 8213e95bd4aSAnders Persson 8223e95bd4aSAnders Persson if ((error = sockparams_new_filter_impl(ent, &sphead)) != 0) 8233e95bd4aSAnders Persson return (error); 8243e95bd4aSAnders Persson 8253e95bd4aSAnders Persson if ((error = sockparams_new_filter_impl(ent, &sp_ephem_list)) != 0) 8263e95bd4aSAnders Persson sockparams_filter_cleanup_impl(ent, &sphead); 8273e95bd4aSAnders Persson return (error); 8283e95bd4aSAnders Persson } 829*19581f84SAlexander Eremin 830*19581f84SAlexander Eremin /* 831*19581f84SAlexander Eremin * Setup and return socket configuration table. 832*19581f84SAlexander Eremin */ 833*19581f84SAlexander Eremin int 834*19581f84SAlexander Eremin sockparams_copyout_socktable(uintptr_t socktable) 835*19581f84SAlexander Eremin { 836*19581f84SAlexander Eremin STRUCT_DECL(sockconfig_socktable, st); 837*19581f84SAlexander Eremin struct sockparams *sp; 838*19581f84SAlexander Eremin uint_t count; 839*19581f84SAlexander Eremin uint_t i = 0; 840*19581f84SAlexander Eremin int ret = 0; 841*19581f84SAlexander Eremin sockconfig_socktable_entry_t *se; 842*19581f84SAlexander Eremin 843*19581f84SAlexander Eremin STRUCT_INIT(st, get_udatamodel()); 844*19581f84SAlexander Eremin if (ddi_copyin((void *)socktable, STRUCT_BUF(st), 845*19581f84SAlexander Eremin STRUCT_SIZE(st), 0) != 0) 846*19581f84SAlexander Eremin return (EFAULT); 847*19581f84SAlexander Eremin 848*19581f84SAlexander Eremin rw_enter(&sockconf_lock, RW_READER); 849*19581f84SAlexander Eremin 850*19581f84SAlexander Eremin count = STRUCT_FGET(st, num_of_entries); 851*19581f84SAlexander Eremin /* 852*19581f84SAlexander Eremin * If the output buffer is size zero, just copy out the count. 853*19581f84SAlexander Eremin */ 854*19581f84SAlexander Eremin if (count == 0) { 855*19581f84SAlexander Eremin for (sp = list_head(&sphead); sp != NULL; 856*19581f84SAlexander Eremin sp = list_next(&sphead, sp)) { 857*19581f84SAlexander Eremin count++; 858*19581f84SAlexander Eremin } 859*19581f84SAlexander Eremin STRUCT_FSET(st, num_of_entries, count); 860*19581f84SAlexander Eremin 861*19581f84SAlexander Eremin rw_exit(&sockconf_lock); 862*19581f84SAlexander Eremin if (ddi_copyout(STRUCT_BUF(st), (void *)socktable, 863*19581f84SAlexander Eremin STRUCT_SIZE(st), 0) != 0) 864*19581f84SAlexander Eremin return (EFAULT); 865*19581f84SAlexander Eremin 866*19581f84SAlexander Eremin return (0); 867*19581f84SAlexander Eremin } 868*19581f84SAlexander Eremin 869*19581f84SAlexander Eremin se = kmem_alloc(count * sizeof (sockconfig_socktable_entry_t), 870*19581f84SAlexander Eremin KM_SLEEP); 871*19581f84SAlexander Eremin for (sp = list_head(&sphead); sp != NULL; 872*19581f84SAlexander Eremin sp = list_next(&sphead, sp)) { 873*19581f84SAlexander Eremin if (i >= count) { 874*19581f84SAlexander Eremin /* 875*19581f84SAlexander Eremin * Return if the number of entries has changed. 876*19581f84SAlexander Eremin */ 877*19581f84SAlexander Eremin rw_exit(&sockconf_lock); 878*19581f84SAlexander Eremin kmem_free(se, 879*19581f84SAlexander Eremin count * sizeof (sockconfig_socktable_entry_t)); 880*19581f84SAlexander Eremin return (EAGAIN); 881*19581f84SAlexander Eremin } 882*19581f84SAlexander Eremin se[i].se_family = sp->sp_family; 883*19581f84SAlexander Eremin se[i].se_type = sp->sp_type; 884*19581f84SAlexander Eremin se[i].se_protocol = sp->sp_protocol; 885*19581f84SAlexander Eremin (void) strncpy(se[i].se_modname, sp->sp_smod_name, 886*19581f84SAlexander Eremin MODMAXNAMELEN); 887*19581f84SAlexander Eremin if (sp->sp_sdev_info.sd_devpath != NULL) 888*19581f84SAlexander Eremin (void) strncpy(se[i].se_strdev, 889*19581f84SAlexander Eremin sp->sp_sdev_info.sd_devpath, MAXPATHLEN); 890*19581f84SAlexander Eremin se[i].se_refcnt = sp->sp_refcnt; 891*19581f84SAlexander Eremin se[i].se_flags = sp->sp_flags; 892*19581f84SAlexander Eremin i++; 893*19581f84SAlexander Eremin } 894*19581f84SAlexander Eremin rw_exit(&sockconf_lock); 895*19581f84SAlexander Eremin if (ddi_copyout(se, STRUCT_FGETP(st, st_entries), 896*19581f84SAlexander Eremin i * sizeof (sockconfig_socktable_entry_t), 0) != 0) 897*19581f84SAlexander Eremin ret = EFAULT; 898*19581f84SAlexander Eremin 899*19581f84SAlexander Eremin STRUCT_FSET(st, num_of_entries, i); 900*19581f84SAlexander Eremin kmem_free(se, count * sizeof (sockconfig_socktable_entry_t)); 901*19581f84SAlexander Eremin 902*19581f84SAlexander Eremin if (ddi_copyout(STRUCT_BUF(st), (void *)socktable, 903*19581f84SAlexander Eremin STRUCT_SIZE(st), 0) != 0) 904*19581f84SAlexander Eremin ret = EFAULT; 905*19581f84SAlexander Eremin 906*19581f84SAlexander Eremin return (ret); 907*19581f84SAlexander Eremin } 908