13e95bd4aSAnders Persson /* 23e95bd4aSAnders Persson * CDDL HEADER START 33e95bd4aSAnders Persson * 43e95bd4aSAnders Persson * The contents of this file are subject to the terms of the 53e95bd4aSAnders Persson * Common Development and Distribution License (the "License"). 63e95bd4aSAnders Persson * You may not use this file except in compliance with the License. 73e95bd4aSAnders Persson * 83e95bd4aSAnders Persson * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93e95bd4aSAnders Persson * or http://www.opensolaris.org/os/licensing. 103e95bd4aSAnders Persson * See the License for the specific language governing permissions 113e95bd4aSAnders Persson * and limitations under the License. 123e95bd4aSAnders Persson * 133e95bd4aSAnders Persson * When distributing Covered Code, include this CDDL HEADER in each 143e95bd4aSAnders Persson * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153e95bd4aSAnders Persson * If applicable, add the following below this CDDL HEADER, with the 163e95bd4aSAnders Persson * fields enclosed by brackets "[]" replaced with your own identifying 173e95bd4aSAnders Persson * information: Portions Copyright [yyyy] [name of copyright owner] 183e95bd4aSAnders Persson * 193e95bd4aSAnders Persson * CDDL HEADER END 203e95bd4aSAnders Persson */ 213e95bd4aSAnders Persson /* 223e95bd4aSAnders Persson * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 233e95bd4aSAnders Persson */ 243e95bd4aSAnders Persson 253e95bd4aSAnders Persson #include <sys/systm.h> 263e95bd4aSAnders Persson #include <sys/sysmacros.h> 273e95bd4aSAnders Persson #include <sys/cmn_err.h> 283e95bd4aSAnders Persson #include <sys/disp.h> 293e95bd4aSAnders Persson #include <sys/list.h> 303e95bd4aSAnders Persson #include <sys/mutex.h> 313e95bd4aSAnders Persson #include <sys/note.h> 323e95bd4aSAnders Persson #include <sys/rwlock.h> 333e95bd4aSAnders Persson #include <sys/stropts.h> 343e95bd4aSAnders Persson #include <sys/taskq.h> 353e95bd4aSAnders Persson #include <sys/socketvar.h> 363e95bd4aSAnders Persson #include <fs/sockfs/sockcommon.h> 373e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h> 383e95bd4aSAnders Persson 393e95bd4aSAnders Persson /* 403e95bd4aSAnders Persson * Socket Filter Framework 413e95bd4aSAnders Persson * 423e95bd4aSAnders Persson * Socket filter entry (sof_entry_t): 433e95bd4aSAnders Persson * 443e95bd4aSAnders Persson * There exists one entry for each configured filter (done via soconfig(1M)), 453e95bd4aSAnders Persson * and they are all in sof_entry_list. In addition to the global list, each 463e95bd4aSAnders Persson * sockparams entry maintains a list of filters that is interested in that 473e95bd4aSAnders Persson * particular socket type. So the filter entry may be referenced by multiple 483e95bd4aSAnders Persson * sockparams. The set of sockparams referencing a filter may change as 493e95bd4aSAnders Persson * socket types are added and/or removed from the system. Both sof_entry_list 503e95bd4aSAnders Persson * and the sockparams list is protected by sockconf_lock. 513e95bd4aSAnders Persson * 523e95bd4aSAnders Persson * Each filter entry has a ref count which is incremented whenever a filter 533e95bd4aSAnders Persson * is attached to a socket. An entry is marked SOFEF_CONDEMED when it is 543e95bd4aSAnders Persson * unconfigured, which will result in the entry being freed when its ref 553e95bd4aSAnders Persson * count reaches zero. 563e95bd4aSAnders Persson * 573e95bd4aSAnders Persson * Socket filter module (sof_module_t): 583e95bd4aSAnders Persson * 593e95bd4aSAnders Persson * Modules are created by sof_register() and placed in sof_module_list, 603e95bd4aSAnders Persson * which is protected by sof_module_lock. Each module has a reference count 613e95bd4aSAnders Persson * that is incremented when a filter entry is using the module. A module 62*e82bc0baSAnders Persson * can be destroyed by sof_unregister() only when its ref count is zero. 633e95bd4aSAnders Persson * 643e95bd4aSAnders Persson * Socket filter instance (sof_instance_t): 653e95bd4aSAnders Persson * 663e95bd4aSAnders Persson * Whenever a filter is attached to a socket (sonode), a new instance is 673e95bd4aSAnders Persson * created. The socket is guaranteed to be single threaded when filters are 683e95bd4aSAnders Persson * being attached/detached. The instance uses the sonode's so_lock for 693e95bd4aSAnders Persson * protection. 703e95bd4aSAnders Persson * 713e95bd4aSAnders Persson * The lifetime of an instance is the same as the socket it's attached to. 723e95bd4aSAnders Persson * 733e95bd4aSAnders Persson * How things link together: 743e95bd4aSAnders Persson * 753e95bd4aSAnders Persson * sockparams.sp_{auto,prog}_filters -> sp_filter_t -> sp_filter_t 763e95bd4aSAnders Persson * ^ | | 773e95bd4aSAnders Persson * | | | 783e95bd4aSAnders Persson * sonode.so_filter_top -> sof_instance_t | | 793e95bd4aSAnders Persson * | | | 803e95bd4aSAnders Persson * v v v 813e95bd4aSAnders Persson * sof_entry_list -> sof_entry_t -> sof_entry -> ... -> sof_entry_t 823e95bd4aSAnders Persson * | 833e95bd4aSAnders Persson * v 843e95bd4aSAnders Persson * sof_module_list -> sof_module_t -> ... -> sof_module_t 853e95bd4aSAnders Persson */ 863e95bd4aSAnders Persson 873e95bd4aSAnders Persson static list_t sof_entry_list; /* list of configured filters */ 883e95bd4aSAnders Persson 893e95bd4aSAnders Persson static list_t sof_module_list; /* list of loaded filter modules */ 903e95bd4aSAnders Persson static kmutex_t sof_module_lock; /* protect the module list */ 913e95bd4aSAnders Persson 923e95bd4aSAnders Persson static sof_kstat_t sof_stat; 933e95bd4aSAnders Persson static kstat_t *sof_stat_ksp; 943e95bd4aSAnders Persson 953e95bd4aSAnders Persson #ifdef DEBUG 963e95bd4aSAnders Persson static int socket_filter_debug = 0; 973e95bd4aSAnders Persson #endif 983e95bd4aSAnders Persson 993e95bd4aSAnders Persson /* 1003e95bd4aSAnders Persson * A connection that has been deferred for more than `sof_defer_drop_time' 1013e95bd4aSAnders Persson * ticks can be dropped to make room for new connections. A connection that 1023e95bd4aSAnders Persson * is to be dropped is moved over to `sof_close_deferred_list' where it will 1033e95bd4aSAnders Persson * be closed by sof_close_deferred() (which is running on a taskq). Connections 1043e95bd4aSAnders Persson * will not be moved over to the close list if it grows larger than 1053e95bd4aSAnders Persson * `sof_close_deferred_max_backlog'. 1063e95bd4aSAnders Persson */ 1073e95bd4aSAnders Persson clock_t sof_defer_drop_time = 3000; 1083e95bd4aSAnders Persson uint_t sof_close_deferred_max_backlog = 1000; 1093e95bd4aSAnders Persson 1103e95bd4aSAnders Persson taskq_t *sof_close_deferred_taskq; 1113e95bd4aSAnders Persson boolean_t sof_close_deferred_running; 1123e95bd4aSAnders Persson uint_t sof_close_deferred_backlog; 1133e95bd4aSAnders Persson list_t sof_close_deferred_list; 1143e95bd4aSAnders Persson kmutex_t sof_close_deferred_lock; 1153e95bd4aSAnders Persson 1163e95bd4aSAnders Persson static void sof_close_deferred(void *); 1173e95bd4aSAnders Persson 1183e95bd4aSAnders Persson static void sof_module_rele(sof_module_t *); 1193e95bd4aSAnders Persson static sof_module_t *sof_module_hold_by_name(const char *, const char *); 1203e95bd4aSAnders Persson 1213e95bd4aSAnders Persson static int sof_entry_load_module(sof_entry_t *); 1223e95bd4aSAnders Persson static void sof_entry_hold(sof_entry_t *); 1233e95bd4aSAnders Persson static void sof_entry_rele(sof_entry_t *); 1243e95bd4aSAnders Persson static int sof_entry_kstat_create(sof_entry_t *); 1253e95bd4aSAnders Persson static void sof_entry_kstat_destroy(sof_entry_t *); 1263e95bd4aSAnders Persson 1273e95bd4aSAnders Persson static sof_instance_t *sof_instance_create(sof_entry_t *, struct sonode *); 1283e95bd4aSAnders Persson static void sof_instance_destroy(sof_instance_t *); 1293e95bd4aSAnders Persson 1303e95bd4aSAnders Persson static int 1313e95bd4aSAnders Persson sof_kstat_update(kstat_t *ksp, int rw) 1323e95bd4aSAnders Persson { 1333e95bd4aSAnders Persson _NOTE(ARGUNUSED(ksp)); 1343e95bd4aSAnders Persson 1353e95bd4aSAnders Persson if (rw == KSTAT_WRITE) 1363e95bd4aSAnders Persson return (EACCES); 1373e95bd4aSAnders Persson 1383e95bd4aSAnders Persson sof_stat.sofks_defer_close_backlog.value.ui64 = 1393e95bd4aSAnders Persson sof_close_deferred_backlog; 1403e95bd4aSAnders Persson 1413e95bd4aSAnders Persson return (0); 1423e95bd4aSAnders Persson } 1433e95bd4aSAnders Persson 1443e95bd4aSAnders Persson void 1453e95bd4aSAnders Persson sof_init(void) 1463e95bd4aSAnders Persson { 1473e95bd4aSAnders Persson list_create(&sof_entry_list, sizeof (sof_entry_t), 1483e95bd4aSAnders Persson offsetof(sof_entry_t, sofe_node)); 1493e95bd4aSAnders Persson list_create(&sof_module_list, sizeof (sof_module_t), 1503e95bd4aSAnders Persson offsetof(sof_module_t, sofm_node)); 1513e95bd4aSAnders Persson list_create(&sof_close_deferred_list, sizeof (struct sonode), 1523e95bd4aSAnders Persson offsetof(struct sonode, so_acceptq_node)); 1533e95bd4aSAnders Persson 1543e95bd4aSAnders Persson sof_close_deferred_taskq = taskq_create("sof_close_deferred_taskq", 1553e95bd4aSAnders Persson 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE); 1563e95bd4aSAnders Persson sof_close_deferred_running = B_FALSE; 1573e95bd4aSAnders Persson sof_close_deferred_backlog = 0; 1583e95bd4aSAnders Persson 1593e95bd4aSAnders Persson mutex_init(&sof_close_deferred_lock, NULL, MUTEX_DEFAULT, 0); 1603e95bd4aSAnders Persson mutex_init(&sof_module_lock, NULL, MUTEX_DEFAULT, 0); 1613e95bd4aSAnders Persson 1623e95bd4aSAnders Persson sof_stat_ksp = kstat_create("sockfs", 0, "sockfilter", "misc", 1633e95bd4aSAnders Persson KSTAT_TYPE_NAMED, sizeof (sof_kstat_t) / sizeof (kstat_named_t), 1643e95bd4aSAnders Persson KSTAT_FLAG_VIRTUAL); 1653e95bd4aSAnders Persson 1663e95bd4aSAnders Persson if (sof_stat_ksp == NULL) 1673e95bd4aSAnders Persson return; 1683e95bd4aSAnders Persson 1693e95bd4aSAnders Persson kstat_named_init(&sof_stat.sofks_defer_closed, "defer_closed", 1703e95bd4aSAnders Persson KSTAT_DATA_UINT64); 1713e95bd4aSAnders Persson kstat_named_init(&sof_stat.sofks_defer_close_backlog, 1723e95bd4aSAnders Persson "defer_close_backlog", KSTAT_DATA_UINT64); 1733e95bd4aSAnders Persson kstat_named_init(&sof_stat.sofks_defer_close_failed_backlog_too_big, 1743e95bd4aSAnders Persson "defer_close_failed_backlog_too_big", KSTAT_DATA_UINT64); 1753e95bd4aSAnders Persson 1763e95bd4aSAnders Persson sof_stat_ksp->ks_data = &sof_stat; 1773e95bd4aSAnders Persson sof_stat_ksp->ks_update = sof_kstat_update; 1783e95bd4aSAnders Persson kstat_install(sof_stat_ksp); 1793e95bd4aSAnders Persson } 1803e95bd4aSAnders Persson 1813e95bd4aSAnders Persson /* 1823e95bd4aSAnders Persson * Process filter options. 1833e95bd4aSAnders Persson */ 1843e95bd4aSAnders Persson static int 1853e95bd4aSAnders Persson sof_setsockopt_impl(struct sonode *so, int option_name, 1863e95bd4aSAnders Persson const void *optval, socklen_t optlen, struct cred *cr) 1873e95bd4aSAnders Persson { 1883e95bd4aSAnders Persson struct sockparams *sp = so->so_sockparams; 1893e95bd4aSAnders Persson sof_entry_t *ent = NULL; 1903e95bd4aSAnders Persson sp_filter_t *fil; 1913e95bd4aSAnders Persson sof_instance_t *inst; 1923e95bd4aSAnders Persson sof_rval_t rval; 1933e95bd4aSAnders Persson int error; 1943e95bd4aSAnders Persson 1953e95bd4aSAnders Persson _NOTE(ARGUNUSED(optlen)); 1963e95bd4aSAnders Persson 1973e95bd4aSAnders Persson /* 1983e95bd4aSAnders Persson * Is the filter in a state where filters can be attached? 1993e95bd4aSAnders Persson */ 2003e95bd4aSAnders Persson if (!(so->so_state & SS_FILOP_OK)) 2013e95bd4aSAnders Persson return (EINVAL); 2023e95bd4aSAnders Persson 2033e95bd4aSAnders Persson if (option_name == FIL_ATTACH) { 2043e95bd4aSAnders Persson /* 2053e95bd4aSAnders Persson * Make sure there isn't already another instance of the 2063e95bd4aSAnders Persson * same filter attached to the socket. 2073e95bd4aSAnders Persson */ 2083e95bd4aSAnders Persson for (inst = so->so_filter_top; inst != NULL; 2093e95bd4aSAnders Persson inst = inst->sofi_next) { 2103e95bd4aSAnders Persson if (strncmp(inst->sofi_filter->sofe_name, 2113e95bd4aSAnders Persson (const char *)optval, SOF_MAXNAMELEN) == 0) 2123e95bd4aSAnders Persson return (EEXIST); 2133e95bd4aSAnders Persson } 2143e95bd4aSAnders Persson /* Look up the filter. */ 2153e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_READER); 2163e95bd4aSAnders Persson for (fil = list_head(&sp->sp_prog_filters); fil != NULL; 2173e95bd4aSAnders Persson fil = list_next(&sp->sp_prog_filters, fil)) { 2183e95bd4aSAnders Persson ent = fil->spf_filter; 2193e95bd4aSAnders Persson ASSERT(ent->sofe_flags & SOFEF_PROG); 2203e95bd4aSAnders Persson 2213e95bd4aSAnders Persson if (strncmp(ent->sofe_name, (const char *)optval, 2223e95bd4aSAnders Persson SOF_MAXNAMELEN) == 0) 2233e95bd4aSAnders Persson break; 2243e95bd4aSAnders Persson } 2253e95bd4aSAnders Persson /* No such filter */ 2263e95bd4aSAnders Persson if (fil == NULL) { 2273e95bd4aSAnders Persson rw_exit(&sockconf_lock); 2283e95bd4aSAnders Persson return (ENOENT); 2293e95bd4aSAnders Persson } 2303e95bd4aSAnders Persson inst = sof_instance_create(ent, so); 2313e95bd4aSAnders Persson rw_exit(&sockconf_lock); 2323e95bd4aSAnders Persson 2333e95bd4aSAnders Persson /* Failed to create an instance; must be out of memory */ 2343e95bd4aSAnders Persson if (inst == NULL) 2353e95bd4aSAnders Persson return (ENOMEM); 2363e95bd4aSAnders Persson 2373e95bd4aSAnders Persson /* 2383e95bd4aSAnders Persson * This might be the first time the filter is being used, 2393e95bd4aSAnders Persson * so try to load the module if it's not already registered. 2403e95bd4aSAnders Persson */ 2413e95bd4aSAnders Persson if (ent->sofe_mod == NULL && 2423e95bd4aSAnders Persson (error = sof_entry_load_module(ent)) != 0) { 2433e95bd4aSAnders Persson sof_instance_destroy(inst); 2443e95bd4aSAnders Persson return (error); 2453e95bd4aSAnders Persson } 2463e95bd4aSAnders Persson 2473e95bd4aSAnders Persson /* Module loaded OK, so there must be an ops vector */ 2483e95bd4aSAnders Persson ASSERT(ent->sofe_mod != NULL); 2493e95bd4aSAnders Persson inst->sofi_ops = &ent->sofe_mod->sofm_ops; 2503e95bd4aSAnders Persson 2513e95bd4aSAnders Persson SOF_STAT_ADD(inst, tot_active_attach, 1); 2523e95bd4aSAnders Persson if (inst->sofi_ops->sofop_attach_active != NULL) { 2533e95bd4aSAnders Persson rval = inst->sofi_ops->sofop_attach_active( 2543e95bd4aSAnders Persson (sof_handle_t)inst, so->so_family, so->so_type, 2553e95bd4aSAnders Persson so->so_protocol, cr, &inst->sofi_cookie); 2563e95bd4aSAnders Persson if (rval != SOF_RVAL_CONTINUE) { 2573e95bd4aSAnders Persson switch (rval) { 2583e95bd4aSAnders Persson case SOF_RVAL_DETACH: 2593e95bd4aSAnders Persson /* 2603e95bd4aSAnders Persson * Filter does not want to to attach. 2613e95bd4aSAnders Persson * An error is returned so the user 2623e95bd4aSAnders Persson * knows the request did not go 2633e95bd4aSAnders Persson * through. 2643e95bd4aSAnders Persson */ 2653e95bd4aSAnders Persson error = EINVAL; 2663e95bd4aSAnders Persson break; 2673e95bd4aSAnders Persson default: 2683e95bd4aSAnders Persson SOF_STAT_ADD(inst, attach_failures, 1); 2693e95bd4aSAnders Persson /* Not a valid rval for active attach */ 2703e95bd4aSAnders Persson ASSERT(rval != SOF_RVAL_DEFER); 2713e95bd4aSAnders Persson error = sof_rval2errno(rval); 2723e95bd4aSAnders Persson break; 2733e95bd4aSAnders Persson } 274700f2bdfSAnil udupa sof_instance_destroy(inst); 2753e95bd4aSAnders Persson return (error); 2763e95bd4aSAnders Persson } 2773e95bd4aSAnders Persson } 2783e95bd4aSAnders Persson return (0); 2793e95bd4aSAnders Persson } else if (option_name == FIL_DETACH) { 2803e95bd4aSAnders Persson for (inst = so->so_filter_top; inst != NULL; 2813e95bd4aSAnders Persson inst = inst->sofi_next) { 2823e95bd4aSAnders Persson 2833e95bd4aSAnders Persson ent = inst->sofi_filter; 2843e95bd4aSAnders Persson if (strncmp(ent->sofe_name, (const char *)optval, 2853e95bd4aSAnders Persson SOF_MAXNAMELEN) == 0) 2863e95bd4aSAnders Persson break; 2873e95bd4aSAnders Persson } 2883e95bd4aSAnders Persson if (inst == NULL) 2893e95bd4aSAnders Persson return (ENXIO); 2903e95bd4aSAnders Persson 2913e95bd4aSAnders Persson /* automatic filters cannot be detached */ 2923e95bd4aSAnders Persson if (inst->sofi_filter->sofe_flags & SOFEF_AUTO) 2933e95bd4aSAnders Persson return (EINVAL); 2943e95bd4aSAnders Persson 2953e95bd4aSAnders Persson if (inst->sofi_ops->sofop_detach != NULL) 2963e95bd4aSAnders Persson inst->sofi_ops->sofop_detach((sof_handle_t)inst, 2973e95bd4aSAnders Persson inst->sofi_cookie, cr); 2983e95bd4aSAnders Persson sof_instance_destroy(inst); 2993e95bd4aSAnders Persson 3003e95bd4aSAnders Persson return (0); 3013e95bd4aSAnders Persson } else { 3023e95bd4aSAnders Persson return (EINVAL); 3033e95bd4aSAnders Persson } 3043e95bd4aSAnders Persson } 3053e95bd4aSAnders Persson 3063e95bd4aSAnders Persson int 3073e95bd4aSAnders Persson sof_setsockopt(struct sonode *so, int option_name, 3083e95bd4aSAnders Persson const void *optval, socklen_t optlen, struct cred *cr) 3093e95bd4aSAnders Persson { 3103e95bd4aSAnders Persson int error; 3113e95bd4aSAnders Persson 3123e95bd4aSAnders Persson /* 3133e95bd4aSAnders Persson * By grabbing the lock as a writer we ensure that no other socket 3143e95bd4aSAnders Persson * operations can start while the filter stack is being manipulated. 3153e95bd4aSAnders Persson * 3163e95bd4aSAnders Persson * We do a tryenter so that in case there is an active thread we 3173e95bd4aSAnders Persson * ask the caller to try again instead of blocking here until the 3183e95bd4aSAnders Persson * other thread is done (which could be indefinitely in case of recv). 3193e95bd4aSAnders Persson */ 3203e95bd4aSAnders Persson if (!rw_tryenter(&so->so_fallback_rwlock, RW_WRITER)) { 3213e95bd4aSAnders Persson return (EAGAIN); 3223e95bd4aSAnders Persson } 3233e95bd4aSAnders Persson 3243e95bd4aSAnders Persson /* Bail out if a fallback has taken place */ 3253e95bd4aSAnders Persson if (so->so_state & SS_FALLBACK_COMP) 3263e95bd4aSAnders Persson error = EINVAL; 3273e95bd4aSAnders Persson else 3283e95bd4aSAnders Persson error = sof_setsockopt_impl(so, option_name, optval, 3293e95bd4aSAnders Persson optlen, cr); 3303e95bd4aSAnders Persson rw_exit(&so->so_fallback_rwlock); 3313e95bd4aSAnders Persson 3323e95bd4aSAnders Persson return (error); 3333e95bd4aSAnders Persson } 3343e95bd4aSAnders Persson 3353e95bd4aSAnders Persson /* 3363e95bd4aSAnders Persson * Get filter socket options. 3373e95bd4aSAnders Persson */ 3383e95bd4aSAnders Persson static int 3393e95bd4aSAnders Persson sof_getsockopt_impl(struct sonode *so, int option_name, 3403e95bd4aSAnders Persson void *optval, socklen_t *optlenp, struct cred *cr) 3413e95bd4aSAnders Persson { 3423e95bd4aSAnders Persson sof_instance_t *inst; 3433e95bd4aSAnders Persson struct fil_info *fi; 3443e95bd4aSAnders Persson socklen_t maxsz = *optlenp; 3453e95bd4aSAnders Persson int i; 3463e95bd4aSAnders Persson uint_t cnt; 3473e95bd4aSAnders Persson 3483e95bd4aSAnders Persson _NOTE(ARGUNUSED(cr)); 3493e95bd4aSAnders Persson 3503e95bd4aSAnders Persson if (option_name == FIL_LIST) { 3513e95bd4aSAnders Persson fi = (struct fil_info *)optval; 3523e95bd4aSAnders Persson 3533e95bd4aSAnders Persson if (maxsz < sizeof (*fi)) 3543e95bd4aSAnders Persson return (EINVAL); 3553e95bd4aSAnders Persson 3563e95bd4aSAnders Persson for (inst = so->so_filter_top, cnt = 0; inst != NULL; 3573e95bd4aSAnders Persson inst = inst->sofi_next) 3583e95bd4aSAnders Persson cnt++; 3593e95bd4aSAnders Persson for (inst = so->so_filter_top, i = 0; 3603e95bd4aSAnders Persson inst != NULL && (i+1) * sizeof (*fi) <= maxsz; 3613e95bd4aSAnders Persson inst = inst->sofi_next, i++) { 3623e95bd4aSAnders Persson fi[i].fi_flags = 3633e95bd4aSAnders Persson (inst->sofi_filter->sofe_flags & SOFEF_AUTO) ? 3643e95bd4aSAnders Persson FILF_AUTO : FILF_PROG; 3653e95bd4aSAnders Persson if (inst->sofi_flags & SOFIF_BYPASS) 3663e95bd4aSAnders Persson fi[i].fi_flags |= FILF_BYPASS; 3673e95bd4aSAnders Persson (void) strncpy(fi[i].fi_name, 3683e95bd4aSAnders Persson inst->sofi_filter->sofe_name, FILNAME_MAX); 3693e95bd4aSAnders Persson ASSERT(cnt > 0); 3703e95bd4aSAnders Persson fi[i].fi_pos = --cnt; 3713e95bd4aSAnders Persson } 3723e95bd4aSAnders Persson *optlenp = i * sizeof (*fi); 3733e95bd4aSAnders Persson return (0); 3743e95bd4aSAnders Persson } else { 3753e95bd4aSAnders Persson return (EINVAL); 3763e95bd4aSAnders Persson } 3773e95bd4aSAnders Persson } 3783e95bd4aSAnders Persson 3793e95bd4aSAnders Persson int 3803e95bd4aSAnders Persson sof_getsockopt(struct sonode *so, int option_name, 3813e95bd4aSAnders Persson void *optval, socklen_t *optlenp, struct cred *cr) 3823e95bd4aSAnders Persson { 3833e95bd4aSAnders Persson int error; 3843e95bd4aSAnders Persson 3853e95bd4aSAnders Persson /* 3863e95bd4aSAnders Persson * The fallback lock is used here to serialize set and get 3873e95bd4aSAnders Persson * filter operations. 3883e95bd4aSAnders Persson */ 3893e95bd4aSAnders Persson rw_enter(&so->so_fallback_rwlock, RW_READER); 3903e95bd4aSAnders Persson if (so->so_state & SS_FALLBACK_COMP) 3913e95bd4aSAnders Persson error = EINVAL; 3923e95bd4aSAnders Persson else 3933e95bd4aSAnders Persson error = sof_getsockopt_impl(so, option_name, optval, optlenp, 3943e95bd4aSAnders Persson cr); 3953e95bd4aSAnders Persson rw_exit(&so->so_fallback_rwlock); 3963e95bd4aSAnders Persson 3973e95bd4aSAnders Persson return (error); 3983e95bd4aSAnders Persson } 3993e95bd4aSAnders Persson 4003e95bd4aSAnders Persson /* 4013e95bd4aSAnders Persson * The socket `so' wants to inherit the filter stack from `pso'. 4023e95bd4aSAnders Persson * Returns 0 if all went well or an errno otherwise. 4033e95bd4aSAnders Persson */ 4043e95bd4aSAnders Persson int 4053e95bd4aSAnders Persson sof_sonode_inherit_filters(struct sonode *so, struct sonode *pso) 4063e95bd4aSAnders Persson { 4073e95bd4aSAnders Persson sof_instance_t *inst, *pinst; 4083e95bd4aSAnders Persson sof_rval_t rval; 4093e95bd4aSAnders Persson int error; 4103e95bd4aSAnders Persson struct sockaddr_in6 laddrbuf, faddrbuf; 4113e95bd4aSAnders Persson struct sockaddr_in6 *laddr, *faddr; 4123e95bd4aSAnders Persson socklen_t laddrlen, faddrlen; 4133e95bd4aSAnders Persson 4143e95bd4aSAnders Persson /* 4153e95bd4aSAnders Persson * Make sure there is enough room to retrieve the addresses 4163e95bd4aSAnders Persson */ 4173e95bd4aSAnders Persson if (so->so_proto_props.sopp_maxaddrlen > sizeof (laddrbuf)) { 4183e95bd4aSAnders Persson laddr = kmem_zalloc(so->so_proto_props.sopp_maxaddrlen, 4193e95bd4aSAnders Persson KM_NOSLEEP); 4203e95bd4aSAnders Persson if (laddr == NULL) 4213e95bd4aSAnders Persson return (ENOMEM); 4223e95bd4aSAnders Persson faddr = kmem_zalloc(so->so_proto_props.sopp_maxaddrlen, 4233e95bd4aSAnders Persson KM_NOSLEEP); 4243e95bd4aSAnders Persson if (faddr == NULL) { 4253e95bd4aSAnders Persson kmem_free(laddr, so->so_proto_props.sopp_maxaddrlen); 4263e95bd4aSAnders Persson return (ENOMEM); 4273e95bd4aSAnders Persson } 4283e95bd4aSAnders Persson laddrlen = faddrlen = so->so_proto_props.sopp_maxaddrlen; 4293e95bd4aSAnders Persson } else { 4303e95bd4aSAnders Persson laddrlen = faddrlen = sizeof (laddrbuf); 4313e95bd4aSAnders Persson laddr = &laddrbuf; 4323e95bd4aSAnders Persson faddr = &faddrbuf; 4333e95bd4aSAnders Persson } 4343e95bd4aSAnders Persson 4353e95bd4aSAnders Persson error = (*so->so_downcalls->sd_getpeername) 4363e95bd4aSAnders Persson (so->so_proto_handle, (struct sockaddr *)faddr, &faddrlen, kcred); 4373e95bd4aSAnders Persson if (error != 0) 4383e95bd4aSAnders Persson goto out; 4393e95bd4aSAnders Persson error = (*so->so_downcalls->sd_getsockname) 4403e95bd4aSAnders Persson (so->so_proto_handle, (struct sockaddr *)laddr, &laddrlen, kcred); 4413e95bd4aSAnders Persson if (error != 0) 4423e95bd4aSAnders Persson goto out; 4433e95bd4aSAnders Persson 4443e95bd4aSAnders Persson /* 4453e95bd4aSAnders Persson * The stack is built bottom up. Filters are allowed to modify the 4463e95bd4aSAnders Persson * the foreign and local addresses during attach. 4473e95bd4aSAnders Persson */ 4483e95bd4aSAnders Persson for (pinst = pso->so_filter_bottom; 4493e95bd4aSAnders Persson pinst != NULL && !(pinst->sofi_flags & SOFIF_BYPASS); 4503e95bd4aSAnders Persson pinst = pinst->sofi_prev) { 4513e95bd4aSAnders Persson inst = sof_instance_create(pinst->sofi_filter, so); 4523e95bd4aSAnders Persson if (inst == NULL) { 4533e95bd4aSAnders Persson error = ENOMEM; 4543e95bd4aSAnders Persson goto out; 4553e95bd4aSAnders Persson } 4563e95bd4aSAnders Persson /* 4573e95bd4aSAnders Persson * The filter module must be loaded since it's already 4583e95bd4aSAnders Persson * attached to the listener. 4593e95bd4aSAnders Persson */ 4603e95bd4aSAnders Persson ASSERT(pinst->sofi_ops != NULL); 4613e95bd4aSAnders Persson inst->sofi_ops = pinst->sofi_ops; 4623e95bd4aSAnders Persson 4633e95bd4aSAnders Persson SOF_STAT_ADD(inst, tot_passive_attach, 1); 4643e95bd4aSAnders Persson if (inst->sofi_ops->sofop_attach_passive != NULL) { 4653e95bd4aSAnders Persson rval = inst->sofi_ops->sofop_attach_passive( 4663e95bd4aSAnders Persson (sof_handle_t)inst, 4673e95bd4aSAnders Persson (sof_handle_t)pinst, pinst->sofi_cookie, 4683e95bd4aSAnders Persson (struct sockaddr *)laddr, laddrlen, 4693e95bd4aSAnders Persson (struct sockaddr *)faddr, faddrlen, 4703e95bd4aSAnders Persson &inst->sofi_cookie); 4713e95bd4aSAnders Persson if (rval != SOF_RVAL_CONTINUE) { 4723e95bd4aSAnders Persson if (rval == SOF_RVAL_DEFER) { 4733e95bd4aSAnders Persson mutex_enter(&so->so_lock); 4743e95bd4aSAnders Persson inst->sofi_flags |= SOFIF_DEFER; 4753e95bd4aSAnders Persson so->so_state |= SS_FIL_DEFER; 4763e95bd4aSAnders Persson mutex_exit(&so->so_lock); 4773e95bd4aSAnders Persson so->so_filter_defertime = 4783e95bd4aSAnders Persson ddi_get_lbolt(); 4793e95bd4aSAnders Persson SOF_STAT_ADD(inst, ndeferred, 1); 4803e95bd4aSAnders Persson } else if (rval == SOF_RVAL_DETACH) { 4813e95bd4aSAnders Persson sof_instance_destroy(inst); 4823e95bd4aSAnders Persson } else { 4833e95bd4aSAnders Persson SOF_STAT_ADD(inst, attach_failures, 1); 4843e95bd4aSAnders Persson error = sof_rval2errno(rval); 4853e95bd4aSAnders Persson /* 4863e95bd4aSAnders Persson * Filters that called attached will be 4873e95bd4aSAnders Persson * destroyed when the socket goes away, 4883e95bd4aSAnders Persson * after detach is called. 4893e95bd4aSAnders Persson */ 4903e95bd4aSAnders Persson goto out; 4913e95bd4aSAnders Persson } 4923e95bd4aSAnders Persson } 4933e95bd4aSAnders Persson } 4943e95bd4aSAnders Persson } 4953e95bd4aSAnders Persson 4963e95bd4aSAnders Persson out: 4973e95bd4aSAnders Persson if (laddr != &laddrbuf) { 4983e95bd4aSAnders Persson kmem_free(laddr, so->so_proto_props.sopp_maxaddrlen); 4993e95bd4aSAnders Persson kmem_free(faddr, so->so_proto_props.sopp_maxaddrlen); 5003e95bd4aSAnders Persson } 5013e95bd4aSAnders Persson return (error); 5023e95bd4aSAnders Persson } 5033e95bd4aSAnders Persson 5043e95bd4aSAnders Persson /* 5053e95bd4aSAnders Persson * Attach any automatic filters to sonode `so'. Returns 0 if all went well 5063e95bd4aSAnders Persson * and an errno otherwise. 5073e95bd4aSAnders Persson */ 5083e95bd4aSAnders Persson int 5093e95bd4aSAnders Persson sof_sonode_autoattach_filters(struct sonode *so, cred_t *cr) 5103e95bd4aSAnders Persson { 5113e95bd4aSAnders Persson struct sockparams *sp = so->so_sockparams; 5123e95bd4aSAnders Persson sp_filter_t *fil; 5133e95bd4aSAnders Persson sof_instance_t *inst; 5143e95bd4aSAnders Persson sof_rval_t rval; 5153e95bd4aSAnders Persson int error; 5163e95bd4aSAnders Persson 5173e95bd4aSAnders Persson /* 5183e95bd4aSAnders Persson * A created instance is added to the top of the sonode's filter 5193e95bd4aSAnders Persson * stack, so traverse the config list in reverse order. 5203e95bd4aSAnders Persson */ 5213e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_READER); 5223e95bd4aSAnders Persson for (fil = list_tail(&sp->sp_auto_filters); 5233e95bd4aSAnders Persson fil != NULL; fil = list_prev(&sp->sp_auto_filters, fil)) { 5243e95bd4aSAnders Persson ASSERT(fil->spf_filter->sofe_flags & SOFEF_AUTO); 5253e95bd4aSAnders Persson if (!sof_instance_create(fil->spf_filter, so)) { 5263e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5273e95bd4aSAnders Persson error = ENOMEM; /* must have run out of memory */ 5283e95bd4aSAnders Persson goto free_all; 5293e95bd4aSAnders Persson } 5303e95bd4aSAnders Persson } 5313e95bd4aSAnders Persson rw_exit(&sockconf_lock); 5323e95bd4aSAnders Persson 5333e95bd4aSAnders Persson /* 5343e95bd4aSAnders Persson * Notify each filter that it's being attached. 5353e95bd4aSAnders Persson */ 5363e95bd4aSAnders Persson inst = so->so_filter_top; 5373e95bd4aSAnders Persson while (inst != NULL) { 5383e95bd4aSAnders Persson sof_entry_t *ent = inst->sofi_filter; 5393e95bd4aSAnders Persson sof_instance_t *ninst = inst->sofi_next; 5403e95bd4aSAnders Persson 5413e95bd4aSAnders Persson /* 5423e95bd4aSAnders Persson * This might be the first time the filter is being used, 5433e95bd4aSAnders Persson * so try to load the module if it's not already registered. 5443e95bd4aSAnders Persson */ 5453e95bd4aSAnders Persson if (ent->sofe_mod == NULL && 5463e95bd4aSAnders Persson (error = sof_entry_load_module(ent)) != 0) 5473e95bd4aSAnders Persson goto free_detached; 5483e95bd4aSAnders Persson 5493e95bd4aSAnders Persson /* Module loaded OK, so there must be an ops vector */ 5503e95bd4aSAnders Persson ASSERT(ent->sofe_mod != NULL); 5513e95bd4aSAnders Persson inst->sofi_ops = &ent->sofe_mod->sofm_ops; 5523e95bd4aSAnders Persson 5533e95bd4aSAnders Persson SOF_STAT_ADD(inst, tot_active_attach, 1); 5543e95bd4aSAnders Persson if (inst->sofi_ops->sofop_attach_active != NULL) { 5553e95bd4aSAnders Persson rval = inst->sofi_ops->sofop_attach_active( 5563e95bd4aSAnders Persson (sof_handle_t)inst, so->so_family, so->so_type, 5573e95bd4aSAnders Persson so->so_protocol, cr, &inst->sofi_cookie); 5583e95bd4aSAnders Persson if (rval != SOF_RVAL_CONTINUE) { 5593e95bd4aSAnders Persson switch (rval) { 5603e95bd4aSAnders Persson case SOF_RVAL_DETACH: 5613e95bd4aSAnders Persson /* filter does not want to attach */ 5623e95bd4aSAnders Persson sof_instance_destroy(inst); 5633e95bd4aSAnders Persson break; 5643e95bd4aSAnders Persson default: 5653e95bd4aSAnders Persson SOF_STAT_ADD(inst, attach_failures, 1); 5663e95bd4aSAnders Persson /* Not a valid rval for active attach */ 5673e95bd4aSAnders Persson ASSERT(rval != SOF_RVAL_DEFER); 5683e95bd4aSAnders Persson error = sof_rval2errno(rval); 5693e95bd4aSAnders Persson goto free_detached; 5703e95bd4aSAnders Persson } 5713e95bd4aSAnders Persson } 5723e95bd4aSAnders Persson } 5733e95bd4aSAnders Persson inst = ninst; 5743e95bd4aSAnders Persson } 5753e95bd4aSAnders Persson return (0); 5763e95bd4aSAnders Persson 5773e95bd4aSAnders Persson free_all: 5783e95bd4aSAnders Persson inst = so->so_filter_top; 5793e95bd4aSAnders Persson free_detached: 5803e95bd4aSAnders Persson ASSERT(inst != NULL); 5813e95bd4aSAnders Persson /* 5823e95bd4aSAnders Persson * Destroy all filters for which attach was not called. The other 5833e95bd4aSAnders Persson * filters will be destroyed (and detach called) when the socket 5843e95bd4aSAnders Persson * is freed. 5853e95bd4aSAnders Persson */ 5863e95bd4aSAnders Persson do { 5873e95bd4aSAnders Persson sof_instance_t *t = inst->sofi_next; 5883e95bd4aSAnders Persson sof_instance_destroy(inst); 5893e95bd4aSAnders Persson inst = t; 5903e95bd4aSAnders Persson } while (inst != NULL); 5913e95bd4aSAnders Persson 5923e95bd4aSAnders Persson return (error); 5933e95bd4aSAnders Persson } 5943e95bd4aSAnders Persson 5953e95bd4aSAnders Persson /* 5963e95bd4aSAnders Persson * Detaches and frees all filters attached to sonode `so'. 5973e95bd4aSAnders Persson */ 5983e95bd4aSAnders Persson void 5993e95bd4aSAnders Persson sof_sonode_cleanup(struct sonode *so) 6003e95bd4aSAnders Persson { 6013e95bd4aSAnders Persson sof_instance_t *inst; 6023e95bd4aSAnders Persson 6033e95bd4aSAnders Persson while ((inst = so->so_filter_top) != NULL) { 6043e95bd4aSAnders Persson (inst->sofi_ops->sofop_detach)((sof_handle_t)inst, 6053e95bd4aSAnders Persson inst->sofi_cookie, kcred); 6063e95bd4aSAnders Persson sof_instance_destroy(inst); 6073e95bd4aSAnders Persson } 6083e95bd4aSAnders Persson } 6093e95bd4aSAnders Persson 6103e95bd4aSAnders Persson /* 6113e95bd4aSAnders Persson * Notifies all active filters attached to `so' about the `event' and 6123e95bd4aSAnders Persson * where `arg' is an event specific argument. 6133e95bd4aSAnders Persson */ 6143e95bd4aSAnders Persson void 6153e95bd4aSAnders Persson sof_sonode_notify_filters(struct sonode *so, sof_event_t event, uintptr_t arg) 6163e95bd4aSAnders Persson { 6173e95bd4aSAnders Persson sof_instance_t *inst; 6183e95bd4aSAnders Persson 6193e95bd4aSAnders Persson for (inst = so->so_filter_bottom; inst != NULL; 6203e95bd4aSAnders Persson inst = inst->sofi_prev) { 6213e95bd4aSAnders Persson if (SOF_INTERESTED(inst, notify)) 6223e95bd4aSAnders Persson (inst->sofi_ops->sofop_notify)((sof_handle_t)inst, 6233e95bd4aSAnders Persson inst->sofi_cookie, event, arg); 6243e95bd4aSAnders Persson } 6253e95bd4aSAnders Persson } 6263e95bd4aSAnders Persson 6273e95bd4aSAnders Persson /* 6283e95bd4aSAnders Persson * The socket `so' is closing. Notify filters and make sure that there 6293e95bd4aSAnders Persson * are no pending tx operations. 6303e95bd4aSAnders Persson */ 6313e95bd4aSAnders Persson void 6323e95bd4aSAnders Persson sof_sonode_closing(struct sonode *so) 6333e95bd4aSAnders Persson { 6343e95bd4aSAnders Persson /* 6353e95bd4aSAnders Persson * Notify filters that the socket is being closed. It's OK for 6363e95bd4aSAnders Persson * filters to inject data. 6373e95bd4aSAnders Persson */ 6383e95bd4aSAnders Persson sof_sonode_notify_filters(so, SOF_EV_CLOSING, (uintptr_t)B_TRUE); 6393e95bd4aSAnders Persson 640*e82bc0baSAnders Persson /* 641*e82bc0baSAnders Persson * Stop any future attempts to inject data, and wait for any 642*e82bc0baSAnders Persson * pending operations to complete. This has to be done to ensure 643*e82bc0baSAnders Persson * that no data is sent down to the protocol once a close 644*e82bc0baSAnders Persson * downcall has been made. 645*e82bc0baSAnders Persson */ 6463e95bd4aSAnders Persson mutex_enter(&so->so_lock); 647*e82bc0baSAnders Persson so->so_state |= SS_FIL_STOP; 6483e95bd4aSAnders Persson while (so->so_filter_tx > 0) 6493e95bd4aSAnders Persson cv_wait(&so->so_closing_cv, &so->so_lock); 6503e95bd4aSAnders Persson mutex_exit(&so->so_lock); 6513e95bd4aSAnders Persson } 6523e95bd4aSAnders Persson 6533e95bd4aSAnders Persson /* 6543e95bd4aSAnders Persson * Called when socket `so' wants to get rid of a deferred connection. 6553e95bd4aSAnders Persson * Returns TRUE if a connection was dropped. 6563e95bd4aSAnders Persson */ 6573e95bd4aSAnders Persson boolean_t 6583e95bd4aSAnders Persson sof_sonode_drop_deferred(struct sonode *so) 6593e95bd4aSAnders Persson { 6603e95bd4aSAnders Persson struct sonode *def; 6613e95bd4aSAnders Persson clock_t now = ddi_get_lbolt(); 6623e95bd4aSAnders Persson 6633e95bd4aSAnders Persson if (sof_close_deferred_backlog > sof_close_deferred_max_backlog) { 6643e95bd4aSAnders Persson SOF_GLOBAL_STAT_BUMP(defer_close_failed_backlog_too_big); 6653e95bd4aSAnders Persson return (B_FALSE); 6663e95bd4aSAnders Persson } 6673e95bd4aSAnders Persson mutex_enter(&so->so_acceptq_lock); 6683e95bd4aSAnders Persson if ((def = list_head(&so->so_acceptq_defer)) != NULL && 6693e95bd4aSAnders Persson (now - def->so_filter_defertime) > sof_defer_drop_time) { 6703e95bd4aSAnders Persson list_remove(&so->so_acceptq_defer, def); 6713e95bd4aSAnders Persson so->so_acceptq_len--; 6723e95bd4aSAnders Persson mutex_exit(&so->so_acceptq_lock); 6733e95bd4aSAnders Persson def->so_listener = NULL; 6743e95bd4aSAnders Persson } else { 6753e95bd4aSAnders Persson mutex_exit(&so->so_acceptq_lock); 6763e95bd4aSAnders Persson return (B_FALSE); 6773e95bd4aSAnders Persson } 6783e95bd4aSAnders Persson 6793e95bd4aSAnders Persson mutex_enter(&sof_close_deferred_lock); 6803e95bd4aSAnders Persson list_insert_tail(&sof_close_deferred_list, def); 6813e95bd4aSAnders Persson sof_close_deferred_backlog++; 6823e95bd4aSAnders Persson if (!sof_close_deferred_running) { 6833e95bd4aSAnders Persson mutex_exit(&sof_close_deferred_lock); 6843e95bd4aSAnders Persson (void) taskq_dispatch(sof_close_deferred_taskq, 6853e95bd4aSAnders Persson sof_close_deferred, NULL, TQ_NOSLEEP); 6863e95bd4aSAnders Persson } else { 6873e95bd4aSAnders Persson mutex_exit(&sof_close_deferred_lock); 6883e95bd4aSAnders Persson } 6893e95bd4aSAnders Persson return (B_TRUE); 6903e95bd4aSAnders Persson } 6913e95bd4aSAnders Persson 6923e95bd4aSAnders Persson /* 6933e95bd4aSAnders Persson * Called from a taskq to close connections that have been deferred for 6943e95bd4aSAnders Persson * too long. 6953e95bd4aSAnders Persson */ 6963e95bd4aSAnders Persson void 6973e95bd4aSAnders Persson sof_close_deferred(void *unused) 6983e95bd4aSAnders Persson { 6993e95bd4aSAnders Persson struct sonode *drop; 7003e95bd4aSAnders Persson 7013e95bd4aSAnders Persson _NOTE(ARGUNUSED(unused)); 7023e95bd4aSAnders Persson 7033e95bd4aSAnders Persson mutex_enter(&sof_close_deferred_lock); 7043e95bd4aSAnders Persson if (!sof_close_deferred_running) { 7053e95bd4aSAnders Persson sof_close_deferred_running = B_TRUE; 7063e95bd4aSAnders Persson while ((drop = 7073e95bd4aSAnders Persson list_remove_head(&sof_close_deferred_list)) != NULL) { 7083e95bd4aSAnders Persson sof_close_deferred_backlog--; 7093e95bd4aSAnders Persson mutex_exit(&sof_close_deferred_lock); 7103e95bd4aSAnders Persson 7113e95bd4aSAnders Persson SOF_GLOBAL_STAT_BUMP(defer_closed); 7123e95bd4aSAnders Persson (void) socket_close(drop, 0, kcred); 7133e95bd4aSAnders Persson socket_destroy(drop); 7143e95bd4aSAnders Persson 7153e95bd4aSAnders Persson mutex_enter(&sof_close_deferred_lock); 7163e95bd4aSAnders Persson } 7173e95bd4aSAnders Persson sof_close_deferred_running = B_FALSE; 7183e95bd4aSAnders Persson ASSERT(sof_close_deferred_backlog == 0); 7193e95bd4aSAnders Persson } 7203e95bd4aSAnders Persson mutex_exit(&sof_close_deferred_lock); 7213e95bd4aSAnders Persson } 7223e95bd4aSAnders Persson 7233e95bd4aSAnders Persson /* 7243e95bd4aSAnders Persson * Creates a new filter instance from the entry `ent' and attaches 7253e95bd4aSAnders Persson * it to the sonode `so'. On success, return a pointer to the created 7263e95bd4aSAnders Persson * instance. 7273e95bd4aSAnders Persson * 7283e95bd4aSAnders Persson * The new instance will be placed on the top of the filter stack. 7293e95bd4aSAnders Persson * 7303e95bd4aSAnders Persson * The caller is responsible for assigning the instance's ops vector and 7313e95bd4aSAnders Persson * calling the filter's attach callback. 7323e95bd4aSAnders Persson * 7333e95bd4aSAnders Persson * No locks are held while manipulating the sonode fields because we are 7343e95bd4aSAnders Persson * guaranteed that this operation is serialized. 7353e95bd4aSAnders Persson * 7363e95bd4aSAnders Persson * We can be sure that the entry `ent' will not disappear, because the 7373e95bd4aSAnders Persson * caller is either holding sockconf_lock (in case of an active open), or is 7383e95bd4aSAnders Persson * already holding a reference (in case of a passive open, the listener has 7393e95bd4aSAnders Persson * one). 7403e95bd4aSAnders Persson */ 7413e95bd4aSAnders Persson static sof_instance_t * 7423e95bd4aSAnders Persson sof_instance_create(sof_entry_t *ent, struct sonode *so) 7433e95bd4aSAnders Persson { 7443e95bd4aSAnders Persson sof_instance_t *inst; 7453e95bd4aSAnders Persson 7463e95bd4aSAnders Persson inst = kmem_zalloc(sizeof (sof_instance_t), KM_NOSLEEP); 7473e95bd4aSAnders Persson if (inst == NULL) 7483e95bd4aSAnders Persson return (NULL); 7493e95bd4aSAnders Persson sof_entry_hold(ent); 7503e95bd4aSAnders Persson inst->sofi_filter = ent; 7513e95bd4aSAnders Persson inst->sofi_sonode = so; 7523e95bd4aSAnders Persson 7533e95bd4aSAnders Persson inst->sofi_next = so->so_filter_top; 7543e95bd4aSAnders Persson if (so->so_filter_top != NULL) 7553e95bd4aSAnders Persson so->so_filter_top->sofi_prev = inst; 7563e95bd4aSAnders Persson else 7573e95bd4aSAnders Persson so->so_filter_bottom = inst; 7583e95bd4aSAnders Persson so->so_filter_top = inst; 7593e95bd4aSAnders Persson so->so_filter_active++; 7603e95bd4aSAnders Persson 7613e95bd4aSAnders Persson return (inst); 7623e95bd4aSAnders Persson } 7633e95bd4aSAnders Persson /* 7643e95bd4aSAnders Persson * Destroys the filter instance `inst' and unlinks it from the sonode. 7653e95bd4aSAnders Persson * 7663e95bd4aSAnders Persson * Any filter private state must be destroyed (via the detach callback) 7673e95bd4aSAnders Persson * before the instance is destroyed. 7683e95bd4aSAnders Persson */ 7693e95bd4aSAnders Persson static void 7703e95bd4aSAnders Persson sof_instance_destroy(sof_instance_t *inst) 7713e95bd4aSAnders Persson { 7723e95bd4aSAnders Persson struct sonode *so = inst->sofi_sonode; 7733e95bd4aSAnders Persson 7743e95bd4aSAnders Persson ASSERT(inst->sofi_sonode != NULL); 7753e95bd4aSAnders Persson ASSERT(inst->sofi_filter != NULL); 7763e95bd4aSAnders Persson ASSERT(inst->sofi_prev != NULL || so->so_filter_top == inst); 7773e95bd4aSAnders Persson ASSERT(inst->sofi_next != NULL || so->so_filter_bottom == inst); 7783e95bd4aSAnders Persson 7793e95bd4aSAnders Persson if (inst->sofi_prev != NULL) 7803e95bd4aSAnders Persson inst->sofi_prev->sofi_next = inst->sofi_next; 7813e95bd4aSAnders Persson else 7823e95bd4aSAnders Persson so->so_filter_top = inst->sofi_next; 7833e95bd4aSAnders Persson 7843e95bd4aSAnders Persson if (inst->sofi_next != NULL) 7853e95bd4aSAnders Persson inst->sofi_next->sofi_prev = inst->sofi_prev; 7863e95bd4aSAnders Persson else 7873e95bd4aSAnders Persson so->so_filter_bottom = inst->sofi_prev; 7883e95bd4aSAnders Persson 7893e95bd4aSAnders Persson if (!(inst->sofi_flags & SOFIF_BYPASS)) { 7903e95bd4aSAnders Persson ASSERT(so->so_filter_active > 0); 7913e95bd4aSAnders Persson so->so_filter_active--; 7923e95bd4aSAnders Persson } 7933e95bd4aSAnders Persson if (inst->sofi_flags & SOFIF_DEFER) 7943e95bd4aSAnders Persson SOF_STAT_ADD(inst, ndeferred, -1); 7953e95bd4aSAnders Persson sof_entry_rele(inst->sofi_filter); 7963e95bd4aSAnders Persson kmem_free(inst, sizeof (sof_instance_t)); 7973e95bd4aSAnders Persson } 7983e95bd4aSAnders Persson 7993e95bd4aSAnders Persson static sof_entry_t * 8003e95bd4aSAnders Persson sof_entry_find(const char *name) 8013e95bd4aSAnders Persson { 8023e95bd4aSAnders Persson sof_entry_t *ent; 8033e95bd4aSAnders Persson 8043e95bd4aSAnders Persson for (ent = list_head(&sof_entry_list); ent != NULL; 8053e95bd4aSAnders Persson ent = list_next(&sof_entry_list, ent)) { 8063e95bd4aSAnders Persson if (strncmp(ent->sofe_name, name, SOF_MAXNAMELEN) == 0) 8073e95bd4aSAnders Persson return (ent); 8083e95bd4aSAnders Persson } 8093e95bd4aSAnders Persson return (NULL); 8103e95bd4aSAnders Persson } 8113e95bd4aSAnders Persson 8123e95bd4aSAnders Persson void 8133e95bd4aSAnders Persson sof_entry_free(sof_entry_t *ent) 8143e95bd4aSAnders Persson { 8153e95bd4aSAnders Persson ASSERT(ent->sofe_refcnt == 0); 8163e95bd4aSAnders Persson ASSERT(!list_link_active(&ent->sofe_node)); 8173e95bd4aSAnders Persson 8183e95bd4aSAnders Persson if (ent->sofe_hintarg != NULL) { 8193e95bd4aSAnders Persson ASSERT(ent->sofe_hint == SOF_HINT_BEFORE || 8203e95bd4aSAnders Persson ent->sofe_hint == SOF_HINT_AFTER); 8213e95bd4aSAnders Persson kmem_free(ent->sofe_hintarg, strlen(ent->sofe_hintarg) + 1); 8223e95bd4aSAnders Persson ent->sofe_hintarg = NULL; 8233e95bd4aSAnders Persson } 8243e95bd4aSAnders Persson if (ent->sofe_socktuple_cnt > 0) { 8253e95bd4aSAnders Persson ASSERT(ent->sofe_socktuple != NULL); 8263e95bd4aSAnders Persson kmem_free(ent->sofe_socktuple, 8273e95bd4aSAnders Persson sizeof (sof_socktuple_t) * ent->sofe_socktuple_cnt); 8283e95bd4aSAnders Persson ent->sofe_socktuple = NULL; 8293e95bd4aSAnders Persson ent->sofe_socktuple_cnt = 0; 8303e95bd4aSAnders Persson } 8313e95bd4aSAnders Persson sof_entry_kstat_destroy(ent); 8323e95bd4aSAnders Persson 8333e95bd4aSAnders Persson mutex_destroy(&ent->sofe_lock); 8343e95bd4aSAnders Persson kmem_free(ent, sizeof (sof_entry_t)); 8353e95bd4aSAnders Persson } 8363e95bd4aSAnders Persson 8373e95bd4aSAnders Persson static int 8383e95bd4aSAnders Persson sof_entry_kstat_update(kstat_t *ksp, int rw) 8393e95bd4aSAnders Persson { 8403e95bd4aSAnders Persson sof_entry_t *ent = ksp->ks_private; 8413e95bd4aSAnders Persson 8423e95bd4aSAnders Persson if (rw == KSTAT_WRITE) 8433e95bd4aSAnders Persson return (EACCES); 8443e95bd4aSAnders Persson 8453e95bd4aSAnders Persson ent->sofe_kstat.sofek_nactive.value.ui64 = ent->sofe_refcnt; 8463e95bd4aSAnders Persson 8473e95bd4aSAnders Persson return (0); 8483e95bd4aSAnders Persson } 8493e95bd4aSAnders Persson 8503e95bd4aSAnders Persson /* 8513e95bd4aSAnders Persson * Create the kstat for filter entry `ent'. 8523e95bd4aSAnders Persson */ 8533e95bd4aSAnders Persson static int 8543e95bd4aSAnders Persson sof_entry_kstat_create(sof_entry_t *ent) 8553e95bd4aSAnders Persson { 8563e95bd4aSAnders Persson char name[SOF_MAXNAMELEN + 7]; 8573e95bd4aSAnders Persson 8583e95bd4aSAnders Persson (void) snprintf(name, sizeof (name), "filter_%s", ent->sofe_name); 8593e95bd4aSAnders Persson ent->sofe_ksp = kstat_create("sockfs", 0, name, "misc", 8603e95bd4aSAnders Persson KSTAT_TYPE_NAMED, 8613e95bd4aSAnders Persson sizeof (sof_entry_kstat_t) / sizeof (kstat_named_t), 8623e95bd4aSAnders Persson KSTAT_FLAG_VIRTUAL); 8633e95bd4aSAnders Persson 8643e95bd4aSAnders Persson if (ent->sofe_ksp == NULL) 8653e95bd4aSAnders Persson return (ENOMEM); 8663e95bd4aSAnders Persson 8673e95bd4aSAnders Persson kstat_named_init(&ent->sofe_kstat.sofek_nactive, "nactive", 8683e95bd4aSAnders Persson KSTAT_DATA_UINT64); 8693e95bd4aSAnders Persson kstat_named_init(&ent->sofe_kstat.sofek_tot_active_attach, 8703e95bd4aSAnders Persson "tot_active_attach", KSTAT_DATA_UINT64); 8713e95bd4aSAnders Persson kstat_named_init(&ent->sofe_kstat.sofek_tot_passive_attach, 8723e95bd4aSAnders Persson "tot_passive_attach", KSTAT_DATA_UINT64); 8733e95bd4aSAnders Persson kstat_named_init(&ent->sofe_kstat.sofek_ndeferred, "ndeferred", 8743e95bd4aSAnders Persson KSTAT_DATA_UINT64); 8753e95bd4aSAnders Persson kstat_named_init(&ent->sofe_kstat.sofek_attach_failures, 8763e95bd4aSAnders Persson "attach_failures", KSTAT_DATA_UINT64); 8773e95bd4aSAnders Persson 8783e95bd4aSAnders Persson ent->sofe_ksp->ks_data = &ent->sofe_kstat; 8793e95bd4aSAnders Persson ent->sofe_ksp->ks_update = sof_entry_kstat_update; 8803e95bd4aSAnders Persson ent->sofe_ksp->ks_private = ent; 8813e95bd4aSAnders Persson kstat_install(ent->sofe_ksp); 8823e95bd4aSAnders Persson 8833e95bd4aSAnders Persson return (0); 8843e95bd4aSAnders Persson } 8853e95bd4aSAnders Persson 8863e95bd4aSAnders Persson /* 8873e95bd4aSAnders Persson * Destroys the kstat for filter entry `ent'. 8883e95bd4aSAnders Persson */ 8893e95bd4aSAnders Persson static void 8903e95bd4aSAnders Persson sof_entry_kstat_destroy(sof_entry_t *ent) 8913e95bd4aSAnders Persson { 8923e95bd4aSAnders Persson if (ent->sofe_ksp != NULL) { 8933e95bd4aSAnders Persson kstat_delete(ent->sofe_ksp); 8943e95bd4aSAnders Persson ent->sofe_ksp = NULL; 8953e95bd4aSAnders Persson } 8963e95bd4aSAnders Persson } 8973e95bd4aSAnders Persson 8983e95bd4aSAnders Persson static void 8993e95bd4aSAnders Persson sof_entry_hold(sof_entry_t *ent) 9003e95bd4aSAnders Persson { 9013e95bd4aSAnders Persson mutex_enter(&ent->sofe_lock); 9023e95bd4aSAnders Persson ent->sofe_refcnt++; 9033e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock); 9043e95bd4aSAnders Persson } 9053e95bd4aSAnders Persson 9063e95bd4aSAnders Persson /* 9073e95bd4aSAnders Persson * Decrement the reference count for `ent'. The entry will 9083e95bd4aSAnders Persson * drop its' reference on the filter module whenever its' 9093e95bd4aSAnders Persson * ref count reaches zero. 9103e95bd4aSAnders Persson */ 9113e95bd4aSAnders Persson static void 9123e95bd4aSAnders Persson sof_entry_rele(sof_entry_t *ent) 9133e95bd4aSAnders Persson { 9143e95bd4aSAnders Persson mutex_enter(&ent->sofe_lock); 9153e95bd4aSAnders Persson if (--ent->sofe_refcnt == 0) { 9163e95bd4aSAnders Persson sof_module_t *mod = ent->sofe_mod; 9173e95bd4aSAnders Persson ent->sofe_mod = NULL; 9183e95bd4aSAnders Persson if (ent->sofe_flags & SOFEF_CONDEMED) { 9193e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock); 9203e95bd4aSAnders Persson sof_entry_free(ent); 9213e95bd4aSAnders Persson } else { 9223e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock); 9233e95bd4aSAnders Persson } 9243e95bd4aSAnders Persson if (mod != NULL) 9253e95bd4aSAnders Persson sof_module_rele(mod); 9263e95bd4aSAnders Persson } else { 9273e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock); 9283e95bd4aSAnders Persson } 9293e95bd4aSAnders Persson } 9303e95bd4aSAnders Persson 9313e95bd4aSAnders Persson /* 9323e95bd4aSAnders Persson * Loads the module used by `ent' 9333e95bd4aSAnders Persson */ 9343e95bd4aSAnders Persson static int 9353e95bd4aSAnders Persson sof_entry_load_module(sof_entry_t *ent) 9363e95bd4aSAnders Persson { 9373e95bd4aSAnders Persson sof_module_t *mod = sof_module_hold_by_name(ent->sofe_name, 9383e95bd4aSAnders Persson ent->sofe_modname); 9393e95bd4aSAnders Persson 9403e95bd4aSAnders Persson if (mod == NULL) 9413e95bd4aSAnders Persson return (EINVAL); 9423e95bd4aSAnders Persson 9433e95bd4aSAnders Persson mutex_enter(&ent->sofe_lock); 9443e95bd4aSAnders Persson /* Another thread might have already loaded the module */ 9453e95bd4aSAnders Persson ASSERT(ent->sofe_mod == mod || ent->sofe_mod == NULL); 9463e95bd4aSAnders Persson if (ent->sofe_mod != NULL) { 9473e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock); 9483e95bd4aSAnders Persson sof_module_rele(mod); 9493e95bd4aSAnders Persson } else { 9503e95bd4aSAnders Persson ent->sofe_mod = mod; 9513e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock); 9523e95bd4aSAnders Persson } 9533e95bd4aSAnders Persson 9543e95bd4aSAnders Persson return (0); 9553e95bd4aSAnders Persson } 9563e95bd4aSAnders Persson 9573e95bd4aSAnders Persson /* 9583e95bd4aSAnders Persson * Add filter entry `ent' to the global list and attach it to all sockparam 9593e95bd4aSAnders Persson * entries which the filter is interested in. Upon successful return the filter 9603e95bd4aSAnders Persson * will be available for applications to use. 9613e95bd4aSAnders Persson */ 9623e95bd4aSAnders Persson int 9633e95bd4aSAnders Persson sof_entry_add(sof_entry_t *ent) 9643e95bd4aSAnders Persson { 9653e95bd4aSAnders Persson int error; 9663e95bd4aSAnders Persson 9673e95bd4aSAnders Persson /* 9683e95bd4aSAnders Persson * We hold sockconf_lock as a WRITER for the whole operation, 9693e95bd4aSAnders Persson * so all operations must be non-blocking. 9703e95bd4aSAnders Persson */ 9713e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 9723e95bd4aSAnders Persson if (sof_entry_find(ent->sofe_name) != NULL) { 9733e95bd4aSAnders Persson rw_exit(&sockconf_lock); 9743e95bd4aSAnders Persson return (EEXIST); 9753e95bd4aSAnders Persson } 9763e95bd4aSAnders Persson 9773e95bd4aSAnders Persson /* The entry is unique; create the kstats */ 9783e95bd4aSAnders Persson if (sof_entry_kstat_create(ent) != 0) { 9793e95bd4aSAnders Persson rw_exit(&sockconf_lock); 9803e95bd4aSAnders Persson return (ENOMEM); 9813e95bd4aSAnders Persson } 9823e95bd4aSAnders Persson 9833e95bd4aSAnders Persson /* 9843e95bd4aSAnders Persson * Attach the filter to sockparams of interest. 9853e95bd4aSAnders Persson */ 9863e95bd4aSAnders Persson if ((error = sockparams_new_filter(ent)) != 0) { 9873e95bd4aSAnders Persson sof_entry_kstat_destroy(ent); 9883e95bd4aSAnders Persson rw_exit(&sockconf_lock); 9893e95bd4aSAnders Persson return (error); 9903e95bd4aSAnders Persson } 9913e95bd4aSAnders Persson /* 9923e95bd4aSAnders Persson * Everything is OK; insert in global list. 9933e95bd4aSAnders Persson */ 9943e95bd4aSAnders Persson list_insert_tail(&sof_entry_list, ent); 9953e95bd4aSAnders Persson rw_exit(&sockconf_lock); 9963e95bd4aSAnders Persson 9973e95bd4aSAnders Persson return (0); 9983e95bd4aSAnders Persson } 9993e95bd4aSAnders Persson 10003e95bd4aSAnders Persson /* 10013e95bd4aSAnders Persson * Removes the filter entry `ent' from global list and all sockparams. 10023e95bd4aSAnders Persson */ 10033e95bd4aSAnders Persson sof_entry_t * 10043e95bd4aSAnders Persson sof_entry_remove_by_name(const char *name) 10053e95bd4aSAnders Persson { 10063e95bd4aSAnders Persson sof_entry_t *ent; 10073e95bd4aSAnders Persson 10083e95bd4aSAnders Persson rw_enter(&sockconf_lock, RW_WRITER); 10093e95bd4aSAnders Persson if ((ent = sof_entry_find(name)) == NULL) { 10103e95bd4aSAnders Persson rw_exit(&sockconf_lock); 10113e95bd4aSAnders Persson return (NULL); 10123e95bd4aSAnders Persson } 10133e95bd4aSAnders Persson list_remove(&sof_entry_list, ent); 10143e95bd4aSAnders Persson sockparams_filter_cleanup(ent); 10153e95bd4aSAnders Persson sof_entry_kstat_destroy(ent); 10163e95bd4aSAnders Persson rw_exit(&sockconf_lock); 10173e95bd4aSAnders Persson 10183e95bd4aSAnders Persson return (ent); 10193e95bd4aSAnders Persson } 10203e95bd4aSAnders Persson 10213e95bd4aSAnders Persson /* 10223e95bd4aSAnders Persson * Filter entry `ent' will process sockparams entry `sp' to determine whether 10233e95bd4aSAnders Persson * it should be attached to the sockparams. It should be called whenever a new 10243e95bd4aSAnders Persson * filter or sockparams is being added. Returns zero either if the filter is 10253e95bd4aSAnders Persson * not interested in the sockparams or if it successfully attached to the 10263e95bd4aSAnders Persson * sockparams. On failure an errno is returned. 10273e95bd4aSAnders Persson */ 10283e95bd4aSAnders Persson int 10293e95bd4aSAnders Persson sof_entry_proc_sockparams(sof_entry_t *ent, struct sockparams *sp) 10303e95bd4aSAnders Persson { 10313e95bd4aSAnders Persson uint_t i; 10323e95bd4aSAnders Persson sof_socktuple_t *t = ent->sofe_socktuple; 10333e95bd4aSAnders Persson sp_filter_t *new, *fil; 10343e95bd4aSAnders Persson 10353e95bd4aSAnders Persson /* Only interested in non-TPI sockets */ 10363e95bd4aSAnders Persson if (strcmp(sp->sp_smod_name, SOTPI_SMOD_NAME) == 0) 10373e95bd4aSAnders Persson return (0); 10383e95bd4aSAnders Persson 10393e95bd4aSAnders Persson for (i = 0; i < ent->sofe_socktuple_cnt; i++) { 10403e95bd4aSAnders Persson if (t[i].sofst_family == sp->sp_family && 10413e95bd4aSAnders Persson t[i].sofst_type == sp->sp_type && 10423e95bd4aSAnders Persson t[i].sofst_protocol == sp->sp_protocol) 10433e95bd4aSAnders Persson break; 10443e95bd4aSAnders Persson } 10453e95bd4aSAnders Persson /* This filter is not interested in the sockparams entry */ 10463e95bd4aSAnders Persson if (i == ent->sofe_socktuple_cnt) 10473e95bd4aSAnders Persson return (0); 10483e95bd4aSAnders Persson 10493e95bd4aSAnders Persson new = kmem_zalloc(sizeof (sp_filter_t), KM_NOSLEEP); 10503e95bd4aSAnders Persson if (new == NULL) 10513e95bd4aSAnders Persson return (ENOMEM); 10523e95bd4aSAnders Persson 10533e95bd4aSAnders Persson new->spf_filter = ent; 10543e95bd4aSAnders Persson if (ent->sofe_flags & SOFEF_PROG) { 10553e95bd4aSAnders Persson /* placement is irrelevant for programmatic filters */ 10563e95bd4aSAnders Persson list_insert_head(&sp->sp_prog_filters, new); 10573e95bd4aSAnders Persson return (0); 10583e95bd4aSAnders Persson } else { 10593e95bd4aSAnders Persson ASSERT(ent->sofe_flags & SOFEF_AUTO); 10603e95bd4aSAnders Persson /* 10613e95bd4aSAnders Persson * If the filter specifies a placement hint, then make sure 10623e95bd4aSAnders Persson * it can be satisfied. 10633e95bd4aSAnders Persson */ 10643e95bd4aSAnders Persson switch (ent->sofe_hint) { 10653e95bd4aSAnders Persson case SOF_HINT_TOP: 10663e95bd4aSAnders Persson if ((fil = list_head(&sp->sp_auto_filters)) != NULL && 10673e95bd4aSAnders Persson fil->spf_filter->sofe_hint == SOF_HINT_TOP) 10683e95bd4aSAnders Persson break; 10693e95bd4aSAnders Persson list_insert_head(&sp->sp_auto_filters, new); 10703e95bd4aSAnders Persson return (0); 10713e95bd4aSAnders Persson case SOF_HINT_BOTTOM: 10723e95bd4aSAnders Persson if ((fil = list_tail(&sp->sp_auto_filters)) != NULL && 10733e95bd4aSAnders Persson fil->spf_filter->sofe_hint == SOF_HINT_BOTTOM) 10743e95bd4aSAnders Persson break; 10753e95bd4aSAnders Persson list_insert_tail(&sp->sp_auto_filters, new); 10763e95bd4aSAnders Persson return (0); 10773e95bd4aSAnders Persson case SOF_HINT_BEFORE: 10783e95bd4aSAnders Persson case SOF_HINT_AFTER: 10793e95bd4aSAnders Persson for (fil = list_head(&sp->sp_auto_filters); 10803e95bd4aSAnders Persson fil != NULL; 10813e95bd4aSAnders Persson fil = list_next(&sp->sp_auto_filters, fil)) { 10823e95bd4aSAnders Persson if (strncmp(ent->sofe_hintarg, 10833e95bd4aSAnders Persson fil->spf_filter->sofe_name, 10843e95bd4aSAnders Persson SOF_MAXNAMELEN) == 0) 10853e95bd4aSAnders Persson break; 10863e95bd4aSAnders Persson } 10873e95bd4aSAnders Persson 10883e95bd4aSAnders Persson if (fil != NULL) { 10893e95bd4aSAnders Persson if (ent->sofe_hint == SOF_HINT_BEFORE) { 10903e95bd4aSAnders Persson if (fil->spf_filter->sofe_hint == 10913e95bd4aSAnders Persson SOF_HINT_TOP) 10923e95bd4aSAnders Persson break; 10933e95bd4aSAnders Persson list_insert_before(&sp->sp_auto_filters, 10943e95bd4aSAnders Persson fil, new); 10953e95bd4aSAnders Persson } else { 10963e95bd4aSAnders Persson if (fil->spf_filter->sofe_hint == 10973e95bd4aSAnders Persson SOF_HINT_BOTTOM) 10983e95bd4aSAnders Persson break; 10993e95bd4aSAnders Persson list_insert_after(&sp->sp_auto_filters, 11003e95bd4aSAnders Persson fil, new); 11013e95bd4aSAnders Persson } 11023e95bd4aSAnders Persson return (0); 11033e95bd4aSAnders Persson } 11043e95bd4aSAnders Persson /*FALLTHRU*/ 11053e95bd4aSAnders Persson case SOF_HINT_NONE: 11063e95bd4aSAnders Persson /* 11073e95bd4aSAnders Persson * Insert the new filter at the beginning as long as it 11083e95bd4aSAnders Persson * does not violate a TOP hint, otherwise insert in the 11093e95bd4aSAnders Persson * next suitable location. 11103e95bd4aSAnders Persson */ 11113e95bd4aSAnders Persson if ((fil = list_head(&sp->sp_auto_filters)) != NULL && 11123e95bd4aSAnders Persson fil->spf_filter->sofe_hint == SOF_HINT_TOP) { 11133e95bd4aSAnders Persson list_insert_after(&sp->sp_auto_filters, fil, 11143e95bd4aSAnders Persson new); 11153e95bd4aSAnders Persson } else { 11163e95bd4aSAnders Persson list_insert_head(&sp->sp_auto_filters, new); 11173e95bd4aSAnders Persson } 11183e95bd4aSAnders Persson return (0); 11193e95bd4aSAnders Persson } 11203e95bd4aSAnders Persson /* Failed to insert the filter */ 11213e95bd4aSAnders Persson kmem_free(new, sizeof (sp_filter_t)); 11223e95bd4aSAnders Persson return (ENOSPC); 11233e95bd4aSAnders Persson } 11243e95bd4aSAnders Persson } 11253e95bd4aSAnders Persson 11263e95bd4aSAnders Persson /* 11273e95bd4aSAnders Persson * Remove all filter entries attached to the sockparams entry `sp'. 11283e95bd4aSAnders Persson */ 11293e95bd4aSAnders Persson void 11303e95bd4aSAnders Persson sof_sockparams_fini(struct sockparams *sp) 11313e95bd4aSAnders Persson { 11323e95bd4aSAnders Persson sp_filter_t *fil; 11333e95bd4aSAnders Persson 11343e95bd4aSAnders Persson ASSERT(!list_link_active(&sp->sp_node)); 11353e95bd4aSAnders Persson 11363e95bd4aSAnders Persson while ((fil = list_remove_head(&sp->sp_auto_filters)) != NULL) 11373e95bd4aSAnders Persson kmem_free(fil, sizeof (sp_filter_t)); 11383e95bd4aSAnders Persson while ((fil = list_remove_head(&sp->sp_prog_filters)) != NULL) 11393e95bd4aSAnders Persson kmem_free(fil, sizeof (sp_filter_t)); 11403e95bd4aSAnders Persson } 11413e95bd4aSAnders Persson 11423e95bd4aSAnders Persson /* 11433e95bd4aSAnders Persson * A new sockparams is being added. Walk all filters and attach those that 11443e95bd4aSAnders Persson * are interested in the entry. 11453e95bd4aSAnders Persson * 11463e95bd4aSAnders Persson * It should be called when the sockparams entry is about to be made available 11473e95bd4aSAnders Persson * for use and while holding the sockconf_lock. 11483e95bd4aSAnders Persson */ 11493e95bd4aSAnders Persson int 11503e95bd4aSAnders Persson sof_sockparams_init(struct sockparams *sp) 11513e95bd4aSAnders Persson { 11523e95bd4aSAnders Persson sof_entry_t *ent; 11533e95bd4aSAnders Persson 11543e95bd4aSAnders Persson ASSERT(RW_WRITE_HELD(&sockconf_lock)); 11553e95bd4aSAnders Persson 11563e95bd4aSAnders Persson for (ent = list_head(&sof_entry_list); ent != NULL; 11573e95bd4aSAnders Persson ent = list_next(&sof_entry_list, ent)) { 11583e95bd4aSAnders Persson if (sof_entry_proc_sockparams(ent, sp) != 0) { 11593e95bd4aSAnders Persson sof_sockparams_fini(sp); 11603e95bd4aSAnders Persson return (ENOMEM); 11613e95bd4aSAnders Persson } 11623e95bd4aSAnders Persson } 11633e95bd4aSAnders Persson return (0); 11643e95bd4aSAnders Persson } 11653e95bd4aSAnders Persson 11663e95bd4aSAnders Persson static sof_module_t * 11673e95bd4aSAnders Persson sof_module_find(const char *name) 11683e95bd4aSAnders Persson { 11693e95bd4aSAnders Persson sof_module_t *ent; 11703e95bd4aSAnders Persson 11713e95bd4aSAnders Persson ASSERT(MUTEX_HELD(&sof_module_lock)); 11723e95bd4aSAnders Persson 11733e95bd4aSAnders Persson for (ent = list_head(&sof_module_list); ent != NULL; 11743e95bd4aSAnders Persson ent = list_next(&sof_module_list, ent)) 11753e95bd4aSAnders Persson if (strcmp(ent->sofm_name, name) == 0) 11763e95bd4aSAnders Persson return (ent); 11773e95bd4aSAnders Persson return (NULL); 11783e95bd4aSAnders Persson } 11793e95bd4aSAnders Persson 11803e95bd4aSAnders Persson /* 11813e95bd4aSAnders Persson * Returns a pointer to a module identified by `name' with its ref count 11823e95bd4aSAnders Persson * bumped. An attempt to load the module is done if it's not found in the 11833e95bd4aSAnders Persson * global list. 11843e95bd4aSAnders Persson */ 11853e95bd4aSAnders Persson sof_module_t * 11863e95bd4aSAnders Persson sof_module_hold_by_name(const char *name, const char *modname) 11873e95bd4aSAnders Persson { 11883e95bd4aSAnders Persson ddi_modhandle_t handle = NULL; 11893e95bd4aSAnders Persson sof_module_t *mod = NULL; 11903e95bd4aSAnders Persson char *modpath; 11913e95bd4aSAnders Persson int error; 11923e95bd4aSAnders Persson 11933e95bd4aSAnders Persson /* 11943e95bd4aSAnders Persson * We'll go through the loop at most two times, which will only 11953e95bd4aSAnders Persson * happen if the module needs to be loaded. 11963e95bd4aSAnders Persson */ 11973e95bd4aSAnders Persson for (;;) { 11983e95bd4aSAnders Persson mutex_enter(&sof_module_lock); 11993e95bd4aSAnders Persson mod = sof_module_find(name); 12003e95bd4aSAnders Persson if (mod != NULL || handle != NULL) 12013e95bd4aSAnders Persson break; 12023e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 12033e95bd4aSAnders Persson 12043e95bd4aSAnders Persson modpath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 12053e95bd4aSAnders Persson (void) snprintf(modpath, MAXPATHLEN, "%s/%s", SOF_MODPATH, 12063e95bd4aSAnders Persson modname); 12073e95bd4aSAnders Persson handle = ddi_modopen(modpath, KRTLD_MODE_FIRST, &error); 12083e95bd4aSAnders Persson kmem_free(modpath, MAXPATHLEN); 12093e95bd4aSAnders Persson /* Failed to load, then bail */ 12103e95bd4aSAnders Persson if (handle == NULL) { 12113e95bd4aSAnders Persson cmn_err(CE_WARN, 12123e95bd4aSAnders Persson "Failed to load socket filter module: %s (err %d)", 12133e95bd4aSAnders Persson modname, error); 12143e95bd4aSAnders Persson return (NULL); 12153e95bd4aSAnders Persson } 12163e95bd4aSAnders Persson } 12173e95bd4aSAnders Persson if (mod != NULL) 12183e95bd4aSAnders Persson mod->sofm_refcnt++; 12193e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 12203e95bd4aSAnders Persson 12213e95bd4aSAnders Persson if (handle != NULL) { 12223e95bd4aSAnders Persson (void) ddi_modclose(handle); 12233e95bd4aSAnders Persson /* 12243e95bd4aSAnders Persson * The module was loaded, but the filter module could not be 12253e95bd4aSAnders Persson * found. It's likely a misconfigured filter. 12263e95bd4aSAnders Persson */ 12273e95bd4aSAnders Persson if (mod == NULL) { 12283e95bd4aSAnders Persson cmn_err(CE_WARN, 12293e95bd4aSAnders Persson "Socket filter module %s was loaded, but did not" \ 12303e95bd4aSAnders Persson "register. Filter %s is likely misconfigured.", 12313e95bd4aSAnders Persson modname, name); 12323e95bd4aSAnders Persson } 12333e95bd4aSAnders Persson } 12343e95bd4aSAnders Persson 12353e95bd4aSAnders Persson return (mod); 12363e95bd4aSAnders Persson } 12373e95bd4aSAnders Persson 12383e95bd4aSAnders Persson void 12393e95bd4aSAnders Persson sof_module_rele(sof_module_t *mod) 12403e95bd4aSAnders Persson { 12413e95bd4aSAnders Persson mutex_enter(&sof_module_lock); 12423e95bd4aSAnders Persson mod->sofm_refcnt--; 12433e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 12443e95bd4aSAnders Persson } 12453e95bd4aSAnders Persson 12463e95bd4aSAnders Persson int 12473e95bd4aSAnders Persson sof_rval2errno(sof_rval_t rval) 12483e95bd4aSAnders Persson { 12493e95bd4aSAnders Persson if (rval > SOF_RVAL_CONTINUE) { 12503e95bd4aSAnders Persson return ((int)rval); 12513e95bd4aSAnders Persson } else { 12523e95bd4aSAnders Persson #ifdef DEBUG 12533e95bd4aSAnders Persson if (socket_filter_debug) 12543e95bd4aSAnders Persson printf("sof_rval2errno: invalid rval '%d'\n", rval); 12553e95bd4aSAnders Persson #endif 12563e95bd4aSAnders Persson return (EINVAL); 12573e95bd4aSAnders Persson } 12583e95bd4aSAnders Persson } 12593e95bd4aSAnders Persson 12603e95bd4aSAnders Persson /* 12613e95bd4aSAnders Persson * Walk through all the filters attached to `so' and allow each filter 12623e95bd4aSAnders Persson * to process the data using its data_out callback. `mp' is a b_cont chain. 12633e95bd4aSAnders Persson * 12643e95bd4aSAnders Persson * Returns the processed mblk, or NULL if mblk was consumed. The mblk might 12653e95bd4aSAnders Persson * have been consumed as a result of an error, in which case `errp' is set to 12663e95bd4aSAnders Persson * the appropriate errno. 12673e95bd4aSAnders Persson */ 12683e95bd4aSAnders Persson mblk_t * 12693e95bd4aSAnders Persson sof_filter_data_out_from(struct sonode *so, sof_instance_t *start, 12703e95bd4aSAnders Persson mblk_t *mp, struct nmsghdr *msg, cred_t *cr, int *errp) 12713e95bd4aSAnders Persson { 12723e95bd4aSAnders Persson sof_instance_t *inst; 12733e95bd4aSAnders Persson sof_rval_t rval; 12743e95bd4aSAnders Persson 12753e95bd4aSAnders Persson _NOTE(ARGUNUSED(so)); 12763e95bd4aSAnders Persson 12773e95bd4aSAnders Persson for (inst = start; inst != NULL; inst = inst->sofi_next) { 12783e95bd4aSAnders Persson if (!SOF_INTERESTED(inst, data_out)) 12793e95bd4aSAnders Persson continue; 12803e95bd4aSAnders Persson mp = (inst->sofi_ops->sofop_data_out)((sof_handle_t)inst, 12813e95bd4aSAnders Persson inst->sofi_cookie, mp, msg, cr, &rval); 12823e95bd4aSAnders Persson DTRACE_PROBE2(filter__data, (sof_instance_t), inst, 12833e95bd4aSAnders Persson (mblk_t *), mp); 12843e95bd4aSAnders Persson if (mp == NULL) { 12853e95bd4aSAnders Persson *errp = sof_rval2errno(rval); 12863e95bd4aSAnders Persson break; 12873e95bd4aSAnders Persson } 12883e95bd4aSAnders Persson } 12893e95bd4aSAnders Persson return (mp); 12903e95bd4aSAnders Persson } 12913e95bd4aSAnders Persson 12923e95bd4aSAnders Persson /* 12933e95bd4aSAnders Persson * Walk through all the filters attached to `so' and allow each filter 12943e95bd4aSAnders Persson * to process the data using its data_in_proc callback. `mp' is the start of 12953e95bd4aSAnders Persson * a possible b_next chain, and `lastmp' points to the last mblk in the chain. 12963e95bd4aSAnders Persson * 12973e95bd4aSAnders Persson * Returns the processed mblk, or NULL if all mblks in the chain were 12983e95bd4aSAnders Persson * consumed. `lastmp' is updated to point to the last mblk in the processed 12993e95bd4aSAnders Persson * chain. 13003e95bd4aSAnders Persson */ 13013e95bd4aSAnders Persson mblk_t * 13023e95bd4aSAnders Persson sof_filter_data_in_proc(struct sonode *so, mblk_t *mp, mblk_t **lastmp) 13033e95bd4aSAnders Persson { 13043e95bd4aSAnders Persson sof_instance_t *inst; 13053e95bd4aSAnders Persson size_t len = 0, orig = 0; 13063e95bd4aSAnders Persson ssize_t diff = 0; 13073e95bd4aSAnders Persson mblk_t *retmp = NULL, *tailmp, *nextmp; 13083e95bd4aSAnders Persson 13093e95bd4aSAnders Persson *lastmp = NULL; 13103e95bd4aSAnders Persson do { 13113e95bd4aSAnders Persson nextmp = mp->b_next; 13123e95bd4aSAnders Persson mp->b_next = mp->b_prev = NULL; 13133e95bd4aSAnders Persson len = orig = msgdsize(mp); 13143e95bd4aSAnders Persson for (inst = so->so_filter_bottom; inst != NULL; 13153e95bd4aSAnders Persson inst = inst->sofi_prev) { 13163e95bd4aSAnders Persson if (!SOF_INTERESTED(inst, data_in_proc)) 13173e95bd4aSAnders Persson continue; 13183e95bd4aSAnders Persson mp = (inst->sofi_ops->sofop_data_in_proc)( 13193e95bd4aSAnders Persson (sof_handle_t)inst, inst->sofi_cookie, mp, 13203e95bd4aSAnders Persson kcred, &len); 13213e95bd4aSAnders Persson if (mp == NULL) 13223e95bd4aSAnders Persson break; 13233e95bd4aSAnders Persson } 13243e95bd4aSAnders Persson DTRACE_PROBE2(filter__data, (sof_instance_t), inst, 13253e95bd4aSAnders Persson (mblk_t *), mp); 13263e95bd4aSAnders Persson diff += len - orig; 13273e95bd4aSAnders Persson if (mp == NULL) 13283e95bd4aSAnders Persson continue; 13293e95bd4aSAnders Persson 13303e95bd4aSAnders Persson for (tailmp = mp; tailmp->b_cont != NULL; 13313e95bd4aSAnders Persson tailmp = tailmp->b_cont) 13323e95bd4aSAnders Persson ; 13333e95bd4aSAnders Persson mp->b_prev = tailmp; 13343e95bd4aSAnders Persson 13353e95bd4aSAnders Persson if (*lastmp == NULL) 13363e95bd4aSAnders Persson retmp = mp; 13373e95bd4aSAnders Persson else 13383e95bd4aSAnders Persson (*lastmp)->b_next = mp; 13393e95bd4aSAnders Persson *lastmp = mp; 13403e95bd4aSAnders Persson } while ((mp = nextmp) != NULL); 13413e95bd4aSAnders Persson 13423e95bd4aSAnders Persson /* 13433e95bd4aSAnders Persson * The size of the chain has changed; make sure the rcv queue 13443e95bd4aSAnders Persson * stays consistent and check if the flow control state should 13453e95bd4aSAnders Persson * change. 13463e95bd4aSAnders Persson */ 13473e95bd4aSAnders Persson if (diff != 0) { 13483e95bd4aSAnders Persson DTRACE_PROBE2(filter__data__adjust__qlen, 13493e95bd4aSAnders Persson (struct sonode *), so, (size_t), diff); 13503e95bd4aSAnders Persson mutex_enter(&so->so_lock); 13513e95bd4aSAnders Persson so->so_rcv_queued += diff; 13523e95bd4aSAnders Persson /* so_check_flow_control drops so_lock */ 1353a215d4ebSKacheong Poon (void) so_check_flow_control(so); 13543e95bd4aSAnders Persson } 13553e95bd4aSAnders Persson 13563e95bd4aSAnders Persson return (retmp); 13573e95bd4aSAnders Persson } 13583e95bd4aSAnders Persson 13593e95bd4aSAnders Persson int 13603e95bd4aSAnders Persson sof_filter_bind(struct sonode *so, struct sockaddr *addr, 13613e95bd4aSAnders Persson socklen_t *addrlen, cred_t *cr) 13623e95bd4aSAnders Persson { 13633e95bd4aSAnders Persson __SOF_FILTER_OP(so, bind, cr, addr, addrlen) 13643e95bd4aSAnders Persson } 13653e95bd4aSAnders Persson 13663e95bd4aSAnders Persson int 13673e95bd4aSAnders Persson sof_filter_listen(struct sonode *so, int *backlogp, cred_t *cr) 13683e95bd4aSAnders Persson { 13693e95bd4aSAnders Persson __SOF_FILTER_OP(so, listen, cr, backlogp) 13703e95bd4aSAnders Persson } 13713e95bd4aSAnders Persson 13723e95bd4aSAnders Persson int 13733e95bd4aSAnders Persson sof_filter_connect(struct sonode *so, struct sockaddr *addr, 13743e95bd4aSAnders Persson socklen_t *addrlen, cred_t *cr) 13753e95bd4aSAnders Persson { 13763e95bd4aSAnders Persson __SOF_FILTER_OP(so, connect, cr, addr, addrlen) 13773e95bd4aSAnders Persson } 13783e95bd4aSAnders Persson 13793e95bd4aSAnders Persson int 13803e95bd4aSAnders Persson sof_filter_accept(struct sonode *so, cred_t *cr) 13813e95bd4aSAnders Persson { 13823e95bd4aSAnders Persson sof_instance_t *inst; 13833e95bd4aSAnders Persson sof_rval_t rval; 13843e95bd4aSAnders Persson 13853e95bd4aSAnders Persson for (inst = so->so_filter_top; inst != NULL; inst = inst->sofi_next) { 13863e95bd4aSAnders Persson if (!SOF_INTERESTED(inst, accept)) 13873e95bd4aSAnders Persson continue; 13883e95bd4aSAnders Persson rval = (inst->sofi_ops->sofop_accept)((sof_handle_t)inst, 13893e95bd4aSAnders Persson inst->sofi_cookie, cr); 13903e95bd4aSAnders Persson DTRACE_PROBE2(filter__action, (sof_instance_t), inst, 13913e95bd4aSAnders Persson (sof_rval_t), rval); 13923e95bd4aSAnders Persson if (rval != SOF_RVAL_CONTINUE) { 13933e95bd4aSAnders Persson ASSERT(rval != SOF_RVAL_RETURN); 13943e95bd4aSAnders Persson return (sof_rval2errno(rval)); 13953e95bd4aSAnders Persson } 13963e95bd4aSAnders Persson } 13973e95bd4aSAnders Persson return (-1); 13983e95bd4aSAnders Persson } 13993e95bd4aSAnders Persson 14003e95bd4aSAnders Persson int 14013e95bd4aSAnders Persson sof_filter_shutdown(struct sonode *so, int *howp, cred_t *cr) 14023e95bd4aSAnders Persson { 14033e95bd4aSAnders Persson __SOF_FILTER_OP(so, shutdown, cr, howp) 14043e95bd4aSAnders Persson } 14053e95bd4aSAnders Persson 14063e95bd4aSAnders Persson int 14073e95bd4aSAnders Persson sof_filter_getsockname(struct sonode *so, struct sockaddr *addr, 14083e95bd4aSAnders Persson socklen_t *addrlenp, cred_t *cr) 14093e95bd4aSAnders Persson { 14103e95bd4aSAnders Persson __SOF_FILTER_OP(so, getsockname, cr, addr, addrlenp) 14113e95bd4aSAnders Persson } 14123e95bd4aSAnders Persson 14133e95bd4aSAnders Persson int 14143e95bd4aSAnders Persson sof_filter_getpeername(struct sonode *so, struct sockaddr *addr, 14153e95bd4aSAnders Persson socklen_t *addrlenp, cred_t *cr) 14163e95bd4aSAnders Persson { 14173e95bd4aSAnders Persson __SOF_FILTER_OP(so, getpeername, cr, addr, addrlenp) 14183e95bd4aSAnders Persson } 14193e95bd4aSAnders Persson 14203e95bd4aSAnders Persson int 14213e95bd4aSAnders Persson sof_filter_setsockopt(struct sonode *so, int level, int option_name, 14223e95bd4aSAnders Persson void *optval, socklen_t *optlenp, cred_t *cr) 14233e95bd4aSAnders Persson { 14243e95bd4aSAnders Persson __SOF_FILTER_OP(so, setsockopt, cr, level, option_name, 14253e95bd4aSAnders Persson optval, optlenp) 14263e95bd4aSAnders Persson } 14273e95bd4aSAnders Persson 14283e95bd4aSAnders Persson int 14293e95bd4aSAnders Persson sof_filter_getsockopt(struct sonode *so, int level, int option_name, 14303e95bd4aSAnders Persson void *optval, socklen_t *optlenp, cred_t *cr) 14313e95bd4aSAnders Persson { 14323e95bd4aSAnders Persson __SOF_FILTER_OP(so, getsockopt, cr, level, option_name, 14333e95bd4aSAnders Persson optval, optlenp) 14343e95bd4aSAnders Persson } 14353e95bd4aSAnders Persson 14363e95bd4aSAnders Persson int 14373e95bd4aSAnders Persson sof_filter_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode, 14383e95bd4aSAnders Persson int32_t *rvalp, cred_t *cr) 14393e95bd4aSAnders Persson { 14403e95bd4aSAnders Persson __SOF_FILTER_OP(so, ioctl, cr, cmd, arg, mode, rvalp) 14413e95bd4aSAnders Persson } 14423e95bd4aSAnders Persson 14433e95bd4aSAnders Persson /* 14443e95bd4aSAnders Persson * sof_register(version, name, ops, flags) 14453e95bd4aSAnders Persson * 14463e95bd4aSAnders Persson * Register a socket filter identified by name `name' and which should use 14473e95bd4aSAnders Persson * the ops vector `ops' for event notification. `flags' should be set to 0. 14483e95bd4aSAnders Persson * On success 0 is returned, otherwise an errno is returned. 14493e95bd4aSAnders Persson */ 14503e95bd4aSAnders Persson int 14513e95bd4aSAnders Persson sof_register(int version, const char *name, const sof_ops_t *ops, int flags) 14523e95bd4aSAnders Persson { 14533e95bd4aSAnders Persson sof_module_t *mod; 14543e95bd4aSAnders Persson 14553e95bd4aSAnders Persson _NOTE(ARGUNUSED(flags)); 14563e95bd4aSAnders Persson 14573e95bd4aSAnders Persson if (version != SOF_VERSION) 14583e95bd4aSAnders Persson return (EINVAL); 14593e95bd4aSAnders Persson 14603e95bd4aSAnders Persson mod = kmem_zalloc(sizeof (sof_module_t), KM_SLEEP); 14613e95bd4aSAnders Persson mod->sofm_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 14623e95bd4aSAnders Persson (void) strcpy(mod->sofm_name, name); 14633e95bd4aSAnders Persson mod->sofm_ops = *ops; 14643e95bd4aSAnders Persson 14653e95bd4aSAnders Persson mutex_enter(&sof_module_lock); 14663e95bd4aSAnders Persson if (sof_module_find(name) != NULL) { 14673e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 14683e95bd4aSAnders Persson kmem_free(mod->sofm_name, strlen(mod->sofm_name) + 1); 14693e95bd4aSAnders Persson kmem_free(mod, sizeof (sof_module_t)); 14703e95bd4aSAnders Persson return (EEXIST); 14713e95bd4aSAnders Persson } 14723e95bd4aSAnders Persson list_insert_tail(&sof_module_list, mod); 14733e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 14743e95bd4aSAnders Persson 14753e95bd4aSAnders Persson return (0); 14763e95bd4aSAnders Persson } 14773e95bd4aSAnders Persson 14783e95bd4aSAnders Persson /* 14793e95bd4aSAnders Persson * sof_unregister(name) 14803e95bd4aSAnders Persson * 14813e95bd4aSAnders Persson * Try to unregister the socket filter identified by `name'. If the filter 14823e95bd4aSAnders Persson * is successfully unregistered, then 0 is returned, otherwise an errno is 14833e95bd4aSAnders Persson * returned. 14843e95bd4aSAnders Persson */ 14853e95bd4aSAnders Persson int 14863e95bd4aSAnders Persson sof_unregister(const char *name) 14873e95bd4aSAnders Persson { 14883e95bd4aSAnders Persson sof_module_t *mod; 14893e95bd4aSAnders Persson 14903e95bd4aSAnders Persson mutex_enter(&sof_module_lock); 14913e95bd4aSAnders Persson mod = sof_module_find(name); 14923e95bd4aSAnders Persson if (mod != NULL) { 14933e95bd4aSAnders Persson if (mod->sofm_refcnt == 0) { 14943e95bd4aSAnders Persson list_remove(&sof_module_list, mod); 14953e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 14963e95bd4aSAnders Persson 14973e95bd4aSAnders Persson kmem_free(mod->sofm_name, strlen(mod->sofm_name) + 1); 14983e95bd4aSAnders Persson kmem_free(mod, sizeof (sof_module_t)); 14993e95bd4aSAnders Persson return (0); 15003e95bd4aSAnders Persson } else { 15013e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 15023e95bd4aSAnders Persson return (EBUSY); 15033e95bd4aSAnders Persson } 15043e95bd4aSAnders Persson } 15053e95bd4aSAnders Persson mutex_exit(&sof_module_lock); 15063e95bd4aSAnders Persson 15073e95bd4aSAnders Persson return (ENXIO); 15083e95bd4aSAnders Persson } 15093e95bd4aSAnders Persson 15103e95bd4aSAnders Persson /* 15113e95bd4aSAnders Persson * sof_newconn_ready(handle) 15123e95bd4aSAnders Persson * 15133e95bd4aSAnders Persson * The filter `handle` no longer wants to defer the socket it is attached 15143e95bd4aSAnders Persson * to. A newconn notification will be generated if there is no other filter 15153e95bd4aSAnders Persson * that wants the socket deferred. 15163e95bd4aSAnders Persson */ 15173e95bd4aSAnders Persson void 15183e95bd4aSAnders Persson sof_newconn_ready(sof_handle_t handle) 15193e95bd4aSAnders Persson { 15203e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 15213e95bd4aSAnders Persson struct sonode *so = inst->sofi_sonode; 15223e95bd4aSAnders Persson struct sonode *pso = so->so_listener; 15233e95bd4aSAnders Persson 15243e95bd4aSAnders Persson mutex_enter(&so->so_lock); 15253e95bd4aSAnders Persson if (!(inst->sofi_flags & SOFIF_DEFER)) { 15263e95bd4aSAnders Persson mutex_exit(&so->so_lock); 15273e95bd4aSAnders Persson return; 15283e95bd4aSAnders Persson } 15293e95bd4aSAnders Persson ASSERT(so->so_state & SS_FIL_DEFER); 15303e95bd4aSAnders Persson inst->sofi_flags &= ~SOFIF_DEFER; 15313e95bd4aSAnders Persson SOF_STAT_ADD(inst, ndeferred, -1); 15323e95bd4aSAnders Persson 15333e95bd4aSAnders Persson /* 15343e95bd4aSAnders Persson * Check if any other filter has deferred the socket. The last 15353e95bd4aSAnders Persson * filter to remove its DEFER flag will be the one generating the 15363e95bd4aSAnders Persson * wakeup. 15373e95bd4aSAnders Persson */ 15383e95bd4aSAnders Persson for (inst = so->so_filter_top; inst != NULL; inst = inst->sofi_next) { 15393e95bd4aSAnders Persson /* Still deferred; nothing to do */ 15403e95bd4aSAnders Persson if (inst->sofi_flags & SOFIF_DEFER) { 15413e95bd4aSAnders Persson mutex_exit(&so->so_lock); 15423e95bd4aSAnders Persson return; 15433e95bd4aSAnders Persson } 15443e95bd4aSAnders Persson } 15453e95bd4aSAnders Persson so->so_state &= ~SS_FIL_DEFER; 15463e95bd4aSAnders Persson mutex_exit(&so->so_lock); 15473e95bd4aSAnders Persson 15483e95bd4aSAnders Persson /* 15493e95bd4aSAnders Persson * The socket is no longer deferred; move it over to the regular 15503e95bd4aSAnders Persson * accept list and notify the user. However, it is possible that 15513e95bd4aSAnders Persson * the socket is being dropped by sof_sonode_drop_deferred(), so 15523e95bd4aSAnders Persson * first make sure the socket is on the deferred list. 15533e95bd4aSAnders Persson */ 15543e95bd4aSAnders Persson mutex_enter(&pso->so_acceptq_lock); 15553e95bd4aSAnders Persson if (!list_link_active(&so->so_acceptq_node)) { 15563e95bd4aSAnders Persson mutex_exit(&pso->so_acceptq_lock); 15573e95bd4aSAnders Persson return; 15583e95bd4aSAnders Persson } 15593e95bd4aSAnders Persson list_remove(&pso->so_acceptq_defer, so); 15603e95bd4aSAnders Persson list_insert_tail(&pso->so_acceptq_list, so); 15613e95bd4aSAnders Persson cv_signal(&pso->so_acceptq_cv); 15623e95bd4aSAnders Persson mutex_exit(&pso->so_acceptq_lock); 15633e95bd4aSAnders Persson 15643e95bd4aSAnders Persson mutex_enter(&pso->so_lock); 15653e95bd4aSAnders Persson so_notify_newconn(pso); /* so_notify_newconn drops the lock */ 15663e95bd4aSAnders Persson } 15673e95bd4aSAnders Persson 15683e95bd4aSAnders Persson /* 15693e95bd4aSAnders Persson * sof_bypass(handle) 15703e95bd4aSAnders Persson * 15713e95bd4aSAnders Persson * Stop generating callbacks for `handle'. 15723e95bd4aSAnders Persson */ 15733e95bd4aSAnders Persson void 15743e95bd4aSAnders Persson sof_bypass(sof_handle_t handle) 15753e95bd4aSAnders Persson { 15763e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 15773e95bd4aSAnders Persson struct sonode *so = inst->sofi_sonode; 15783e95bd4aSAnders Persson 15793e95bd4aSAnders Persson mutex_enter(&so->so_lock); 15803e95bd4aSAnders Persson if (!(inst->sofi_flags & SOFIF_BYPASS)) { 15813e95bd4aSAnders Persson inst->sofi_flags |= SOFIF_BYPASS; 15823e95bd4aSAnders Persson ASSERT(so->so_filter_active > 0); 15833e95bd4aSAnders Persson so->so_filter_active--; 15843e95bd4aSAnders Persson } 15853e95bd4aSAnders Persson mutex_exit(&so->so_lock); 15863e95bd4aSAnders Persson } 15873e95bd4aSAnders Persson 15883e95bd4aSAnders Persson /* 15893e95bd4aSAnders Persson * sof_rcv_flowctrl(handle, enable) 15903e95bd4aSAnders Persson * 15913e95bd4aSAnders Persson * If `enable' is TRUE, then recv side flow control will be asserted for 15923e95bd4aSAnders Persson * the socket associated with `handle'. When `enable' is FALSE the filter 15933e95bd4aSAnders Persson * indicates that it no longer wants to assert flow control, however, the 15943e95bd4aSAnders Persson * condition will not be removed until there are no other filters asserting 15953e95bd4aSAnders Persson * flow control and there is space available in the receive buffer. 15963e95bd4aSAnders Persson */ 15973e95bd4aSAnders Persson void 15983e95bd4aSAnders Persson sof_rcv_flowctrl(sof_handle_t handle, boolean_t enable) 15993e95bd4aSAnders Persson { 16003e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 16013e95bd4aSAnders Persson struct sonode *so = inst->sofi_sonode; 16023e95bd4aSAnders Persson 16033e95bd4aSAnders Persson mutex_enter(&so->so_lock); 16043e95bd4aSAnders Persson if (enable) { 16053e95bd4aSAnders Persson inst->sofi_flags |= SOFIF_RCV_FLOWCTRL; 16063e95bd4aSAnders Persson so->so_flowctrld = B_TRUE; 16073e95bd4aSAnders Persson so->so_state |= SS_FIL_RCV_FLOWCTRL; 16083e95bd4aSAnders Persson mutex_exit(&so->so_lock); 16093e95bd4aSAnders Persson } else { 16103e95bd4aSAnders Persson inst->sofi_flags &= ~SOFIF_RCV_FLOWCTRL; 16113e95bd4aSAnders Persson for (inst = so->so_filter_top; inst != NULL; 16123e95bd4aSAnders Persson inst = inst->sofi_next) { 16133e95bd4aSAnders Persson /* another filter is asserting flow control */ 16143e95bd4aSAnders Persson if (inst->sofi_flags & SOFIF_RCV_FLOWCTRL) { 16153e95bd4aSAnders Persson mutex_exit(&so->so_lock); 16163e95bd4aSAnders Persson return; 16173e95bd4aSAnders Persson } 16183e95bd4aSAnders Persson } 16193e95bd4aSAnders Persson so->so_state &= ~SS_FIL_RCV_FLOWCTRL; 16203e95bd4aSAnders Persson /* so_check_flow_control drops so_lock */ 1621a215d4ebSKacheong Poon (void) so_check_flow_control(so); 16223e95bd4aSAnders Persson } 16233e95bd4aSAnders Persson ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 16243e95bd4aSAnders Persson } 16253e95bd4aSAnders Persson 16263e95bd4aSAnders Persson /* 16273e95bd4aSAnders Persson * sof_snd_flowctrl(handle, enable) 16283e95bd4aSAnders Persson * 16293e95bd4aSAnders Persson * If `enable' is TRUE, then send side flow control will be asserted for 16303e95bd4aSAnders Persson * the socket associated with `handle'. When `enable' is FALSE the filter 16313e95bd4aSAnders Persson * indicates that is no longer wants to assert flow control, however, the 16323e95bd4aSAnders Persson * condition will not be removed until there are no other filters asserting 16333e95bd4aSAnders Persson * flow control and there are tx buffers available. 16343e95bd4aSAnders Persson */ 16353e95bd4aSAnders Persson void 16363e95bd4aSAnders Persson sof_snd_flowctrl(sof_handle_t handle, boolean_t enable) 16373e95bd4aSAnders Persson { 16383e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 16393e95bd4aSAnders Persson struct sonode *so = inst->sofi_sonode; 16403e95bd4aSAnders Persson 16413e95bd4aSAnders Persson mutex_enter(&so->so_lock); 16423e95bd4aSAnders Persson if (enable) { 16433e95bd4aSAnders Persson inst->sofi_flags |= SOFIF_SND_FLOWCTRL; 16443e95bd4aSAnders Persson so->so_state |= SS_FIL_SND_FLOWCTRL; 16453e95bd4aSAnders Persson } else { 16463e95bd4aSAnders Persson inst->sofi_flags &= ~SOFIF_SND_FLOWCTRL; 16473e95bd4aSAnders Persson for (inst = so->so_filter_top; inst != NULL; 16483e95bd4aSAnders Persson inst = inst->sofi_next) { 16493e95bd4aSAnders Persson if (inst->sofi_flags & SOFIF_SND_FLOWCTRL) { 16503e95bd4aSAnders Persson mutex_exit(&so->so_lock); 16513e95bd4aSAnders Persson return; 16523e95bd4aSAnders Persson } 16533e95bd4aSAnders Persson } 16543e95bd4aSAnders Persson so->so_state &= ~SS_FIL_SND_FLOWCTRL; 16553e95bd4aSAnders Persson /* 16563e95bd4aSAnders Persson * Wake up writer if the socket is no longer flow controlled. 16573e95bd4aSAnders Persson */ 16583e95bd4aSAnders Persson if (!SO_SND_FLOWCTRLD(so)) { 16593e95bd4aSAnders Persson /* so_notify_writable drops so_lock */ 16603e95bd4aSAnders Persson so_notify_writable(so); 16613e95bd4aSAnders Persson return; 16623e95bd4aSAnders Persson } 16633e95bd4aSAnders Persson } 16643e95bd4aSAnders Persson mutex_exit(&so->so_lock); 16653e95bd4aSAnders Persson } 16663e95bd4aSAnders Persson 16673e95bd4aSAnders Persson /* 16683e95bd4aSAnders Persson * sof_get_cookie(handle) 16693e95bd4aSAnders Persson * 16703e95bd4aSAnders Persson * Returns the cookie used by `handle'. 16713e95bd4aSAnders Persson */ 16723e95bd4aSAnders Persson void * 16733e95bd4aSAnders Persson sof_get_cookie(sof_handle_t handle) 16743e95bd4aSAnders Persson { 16753e95bd4aSAnders Persson return (((sof_instance_t *)handle)->sofi_cookie); 16763e95bd4aSAnders Persson } 16773e95bd4aSAnders Persson 16783e95bd4aSAnders Persson /* 16793e95bd4aSAnders Persson * sof_cas_cookie(handle, old, new) 16803e95bd4aSAnders Persson * 16813e95bd4aSAnders Persson * Compare-and-swap the cookie used by `handle'. 16823e95bd4aSAnders Persson */ 16833e95bd4aSAnders Persson void * 16843e95bd4aSAnders Persson sof_cas_cookie(sof_handle_t handle, void *old, void *new) 16853e95bd4aSAnders Persson { 16863e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 16873e95bd4aSAnders Persson 16883e95bd4aSAnders Persson return (atomic_cas_ptr(&inst->sofi_cookie, old, new)); 16893e95bd4aSAnders Persson } 16903e95bd4aSAnders Persson 16913e95bd4aSAnders Persson /* 16923e95bd4aSAnders Persson * sof_inject_data_out(handle, mp, msg, flowctrld) 16933e95bd4aSAnders Persson * 16943e95bd4aSAnders Persson * Submit `mp' for transmission. `msg' cannot by NULL, and may contain 16953e95bd4aSAnders Persson * ancillary data and destination address. Returns 0 when successful 16963e95bd4aSAnders Persson * in which case `flowctrld' is updated. If flow controlled, no new data 16973e95bd4aSAnders Persson * should be injected until a SOF_EV_INJECT_DATA_OUT_OK event is observed. 16983e95bd4aSAnders Persson * In case of failure, an errno is returned. 16993e95bd4aSAnders Persson * 17003e95bd4aSAnders Persson * Filters that are lower in the stack than `handle' will see the data 17013e95bd4aSAnders Persson * before it is transmitted and may end up modifying or freeing the data. 17023e95bd4aSAnders Persson */ 17033e95bd4aSAnders Persson int 17043e95bd4aSAnders Persson sof_inject_data_out(sof_handle_t handle, mblk_t *mp, struct nmsghdr *msg, 17053e95bd4aSAnders Persson boolean_t *flowctrld) 17063e95bd4aSAnders Persson { 17073e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 17083e95bd4aSAnders Persson struct sonode *so = inst->sofi_sonode; 17093e95bd4aSAnders Persson int error; 17103e95bd4aSAnders Persson 17113e95bd4aSAnders Persson mutex_enter(&so->so_lock); 1712*e82bc0baSAnders Persson if (so->so_state & SS_FIL_STOP) { 17133e95bd4aSAnders Persson mutex_exit(&so->so_lock); 17143e95bd4aSAnders Persson freemsg(mp); 17153e95bd4aSAnders Persson return (EPIPE); 17163e95bd4aSAnders Persson } 17173e95bd4aSAnders Persson so->so_filter_tx++; 17183e95bd4aSAnders Persson mutex_exit(&so->so_lock); 17193e95bd4aSAnders Persson 17203e95bd4aSAnders Persson error = so_sendmblk_impl(inst->sofi_sonode, msg, FNONBLOCK, 17213e95bd4aSAnders Persson kcred, &mp, inst->sofi_next, B_TRUE); 17223e95bd4aSAnders Persson 17233e95bd4aSAnders Persson mutex_enter(&so->so_lock); 17243e95bd4aSAnders Persson ASSERT(so->so_filter_tx > 0); 17253e95bd4aSAnders Persson so->so_filter_tx--; 17263e95bd4aSAnders Persson if (so->so_state & SS_CLOSING) 17273e95bd4aSAnders Persson cv_signal(&so->so_closing_cv); 17283e95bd4aSAnders Persson mutex_exit(&so->so_lock); 17293e95bd4aSAnders Persson 17303e95bd4aSAnders Persson if (mp != NULL) 17313e95bd4aSAnders Persson freemsg(mp); 17323e95bd4aSAnders Persson 17333e95bd4aSAnders Persson if (error == ENOSPC) { 17343e95bd4aSAnders Persson *flowctrld = B_TRUE; 17353e95bd4aSAnders Persson error = 0; 17363e95bd4aSAnders Persson } else { 17373e95bd4aSAnders Persson *flowctrld = B_FALSE; 17383e95bd4aSAnders Persson } 17393e95bd4aSAnders Persson 17403e95bd4aSAnders Persson return (error); 17413e95bd4aSAnders Persson } 17423e95bd4aSAnders Persson 17433e95bd4aSAnders Persson /* 17443e95bd4aSAnders Persson * sof_inject_data_in(handle, mp, len, flag, flowctrld) 17453e95bd4aSAnders Persson * 17463e95bd4aSAnders Persson * Enqueue `mp' which contains `len' bytes of M_DATA onto the socket 17473e95bd4aSAnders Persson * associated with `handle'. `flags' should be set to 0. Returns 0 when 17483e95bd4aSAnders Persson * successful in which case `flowctrld' is updated. If flow controlled, 17493e95bd4aSAnders Persson * no new data should be injected until a SOF_EV_INJECT_DATA_IN_OK event 17503e95bd4aSAnders Persson * is observed. In case of failure, an errno is returned. 17513e95bd4aSAnders Persson * 17523e95bd4aSAnders Persson * Filters that are higher in the stack than `handle' will see the data 17533e95bd4aSAnders Persson * before it is enqueued on the receive queue and may end up modifying or 17543e95bd4aSAnders Persson * freeing the data. 17553e95bd4aSAnders Persson */ 17563e95bd4aSAnders Persson int 17573e95bd4aSAnders Persson sof_inject_data_in(sof_handle_t handle, mblk_t *mp, size_t len, int flags, 17583e95bd4aSAnders Persson boolean_t *flowctrld) 17593e95bd4aSAnders Persson { 17603e95bd4aSAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 17613e95bd4aSAnders Persson ssize_t avail; 17623e95bd4aSAnders Persson int error = 0; 17633e95bd4aSAnders Persson 17643e95bd4aSAnders Persson ASSERT(flags == 0); 17653e95bd4aSAnders Persson avail = so_queue_msg_impl(inst->sofi_sonode, mp, len, flags, &error, 17663e95bd4aSAnders Persson NULL, inst->sofi_prev); 17673e95bd4aSAnders Persson /* fallback should never happen when there is an active filter */ 17683e95bd4aSAnders Persson ASSERT(error != EOPNOTSUPP); 17693e95bd4aSAnders Persson 17703e95bd4aSAnders Persson *flowctrld = (avail > 0) ? B_FALSE : B_TRUE; 17713e95bd4aSAnders Persson return (error); 17723e95bd4aSAnders Persson } 1773dd49f125SAnders Persson 1774dd49f125SAnders Persson /* 1775dd49f125SAnders Persson * sof_newconn_move(handle, newparent) 1776dd49f125SAnders Persson * 1777dd49f125SAnders Persson * Private interface only to be used by KSSL. 1778dd49f125SAnders Persson * 1779dd49f125SAnders Persson * Moves the socket associated with `handle' from its current listening 1780dd49f125SAnders Persson * socket to the listener associated with `newparent'. The socket being 1781dd49f125SAnders Persson * moved must be in a deferred state and it is up to the consumer of the 1782dd49f125SAnders Persson * interface to ensure that the `newparent' does not go away while this 1783dd49f125SAnders Persson * operation is pending. 1784dd49f125SAnders Persson */ 1785dd49f125SAnders Persson boolean_t 1786dd49f125SAnders Persson sof_newconn_move(sof_handle_t handle, sof_handle_t newparent) 1787dd49f125SAnders Persson { 1788dd49f125SAnders Persson sof_instance_t *inst = (sof_instance_t *)handle; 1789dd49f125SAnders Persson sof_instance_t *newpinst = (sof_instance_t *)newparent; 1790dd49f125SAnders Persson struct sonode *so, *old, *new; 1791dd49f125SAnders Persson 1792dd49f125SAnders Persson so = inst->sofi_sonode; 1793dd49f125SAnders Persson ASSERT(so->so_state & SS_FIL_DEFER); 1794dd49f125SAnders Persson 1795dd49f125SAnders Persson if (inst->sofi_next != NULL || inst->sofi_prev != NULL || 1796dd49f125SAnders Persson !(so->so_state & SS_FIL_DEFER)) 1797dd49f125SAnders Persson return (B_FALSE); 1798dd49f125SAnders Persson 1799dd49f125SAnders Persson old = so->so_listener; 1800dd49f125SAnders Persson mutex_enter(&old->so_acceptq_lock); 1801dd49f125SAnders Persson list_remove(&old->so_acceptq_defer, so); 1802dd49f125SAnders Persson old->so_acceptq_len--; 1803dd49f125SAnders Persson mutex_exit(&old->so_acceptq_lock); 1804dd49f125SAnders Persson 1805dd49f125SAnders Persson new = newpinst->sofi_sonode; 1806dd49f125SAnders Persson mutex_enter(&new->so_acceptq_lock); 1807dd49f125SAnders Persson list_insert_tail(&new->so_acceptq_defer, so); 1808dd49f125SAnders Persson new->so_acceptq_len++; 1809dd49f125SAnders Persson mutex_exit(&new->so_acceptq_lock); 1810dd49f125SAnders Persson 1811dd49f125SAnders Persson so->so_listener = new; 1812dd49f125SAnders Persson 1813dd49f125SAnders Persson return (B_TRUE); 1814dd49f125SAnders Persson } 1815