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  *
44*bbf21555SRichard Lowe  *   There exists one entry for each configured filter (done via soconfig(8)),
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
62e82bc0baSAnders 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 
8752aec5b9SDan McDonald 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;
9352aec5b9SDan McDonald 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 *);
11952aec5b9SDan McDonald 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 *);
12252aec5b9SDan McDonald static void		sof_entry_hold(sof_entry_t *);
12352aec5b9SDan McDonald static void		sof_entry_rele(sof_entry_t *);
12452aec5b9SDan McDonald static int		sof_entry_kstat_create(sof_entry_t *);
12552aec5b9SDan McDonald static void		sof_entry_kstat_destroy(sof_entry_t *);
1263e95bd4aSAnders Persson 
12752aec5b9SDan McDonald 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
sof_kstat_update(kstat_t * ksp,int rw)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
sof_init(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
sof_setsockopt_impl(struct sonode * so,int option_name,const void * optval,socklen_t optlen,struct cred * cr)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
sof_setsockopt(struct sonode * so,int option_name,const void * optval,socklen_t optlen,struct cred * cr)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
sof_getsockopt_impl(struct sonode * so,int option_name,void * optval,socklen_t * optlenp,struct cred * cr)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
sof_getsockopt(struct sonode * so,int option_name,void * optval,socklen_t * optlenp,struct cred * cr)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
sof_sonode_inherit_filters(struct sonode * so,struct sonode * pso)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
sof_sonode_autoattach_filters(struct sonode * so,cred_t * cr)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
sof_sonode_cleanup(struct sonode * so)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
sof_sonode_notify_filters(struct sonode * so,sof_event_t event,uintptr_t arg)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
sof_sonode_closing(struct sonode * so)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 
640e82bc0baSAnders Persson 	/*
641e82bc0baSAnders Persson 	 * Stop any future attempts to inject data, and wait for any
642e82bc0baSAnders Persson 	 * pending operations to complete. This has to be done to ensure
643e82bc0baSAnders Persson 	 * that no data is sent down to the protocol once a close
644e82bc0baSAnders Persson 	 * downcall has been made.
645e82bc0baSAnders Persson 	 */
6463e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
647e82bc0baSAnders 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
sof_sonode_drop_deferred(struct sonode * so)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
sof_close_deferred(void * unused)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 *
sof_instance_create(sof_entry_t * ent,struct sonode * so)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
sof_instance_destroy(sof_instance_t * inst)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 *
sof_entry_find(const char * name)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
sof_entry_free(sof_entry_t * ent)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
sof_entry_kstat_update(kstat_t * ksp,int rw)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
sof_entry_kstat_create(sof_entry_t * ent)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
sof_entry_kstat_destroy(sof_entry_t * ent)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
sof_entry_hold(sof_entry_t * ent)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
sof_entry_rele(sof_entry_t * ent)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
sof_entry_load_module(sof_entry_t * ent)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
sof_entry_add(sof_entry_t * ent)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 *
sof_entry_remove_by_name(const char * name)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
sof_entry_proc_sockparams(sof_entry_t * ent,struct sockparams * sp)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,
108352aec5b9SDan McDonald 				    fil->spf_filter->sofe_name, SOF_MAXNAMELEN)
108452aec5b9SDan McDonald 				    == 0) {
108552aec5b9SDan McDonald 					break;
108652aec5b9SDan McDonald 				}
10873e95bd4aSAnders Persson 			}
10883e95bd4aSAnders Persson 
10893e95bd4aSAnders Persson 			if (fil != NULL) {
10903e95bd4aSAnders Persson 				if (ent->sofe_hint == SOF_HINT_BEFORE) {
10913e95bd4aSAnders Persson 					if (fil->spf_filter->sofe_hint ==
10923e95bd4aSAnders Persson 					    SOF_HINT_TOP)
10933e95bd4aSAnders Persson 						break;
10943e95bd4aSAnders Persson 					list_insert_before(&sp->sp_auto_filters,
10953e95bd4aSAnders Persson 					    fil, new);
10963e95bd4aSAnders Persson 				} else {
10973e95bd4aSAnders Persson 					if (fil->spf_filter->sofe_hint ==
10983e95bd4aSAnders Persson 					    SOF_HINT_BOTTOM)
10993e95bd4aSAnders Persson 						break;
11003e95bd4aSAnders Persson 					list_insert_after(&sp->sp_auto_filters,
11013e95bd4aSAnders Persson 					    fil, new);
11023e95bd4aSAnders Persson 				}
11033e95bd4aSAnders Persson 				return (0);
11043e95bd4aSAnders Persson 			}
11053e95bd4aSAnders Persson 			/*FALLTHRU*/
11063e95bd4aSAnders Persson 		case SOF_HINT_NONE:
11073e95bd4aSAnders Persson 			/*
11083e95bd4aSAnders Persson 			 * Insert the new filter at the beginning as long as it
11093e95bd4aSAnders Persson 			 * does not violate a TOP hint, otherwise insert in the
11103e95bd4aSAnders Persson 			 * next suitable location.
11113e95bd4aSAnders Persson 			 */
11123e95bd4aSAnders Persson 			if ((fil = list_head(&sp->sp_auto_filters)) != NULL &&
11133e95bd4aSAnders Persson 			    fil->spf_filter->sofe_hint == SOF_HINT_TOP) {
11143e95bd4aSAnders Persson 				list_insert_after(&sp->sp_auto_filters, fil,
11153e95bd4aSAnders Persson 				    new);
11163e95bd4aSAnders Persson 			} else {
11173e95bd4aSAnders Persson 				list_insert_head(&sp->sp_auto_filters, new);
11183e95bd4aSAnders Persson 			}
11193e95bd4aSAnders Persson 			return (0);
11203e95bd4aSAnders Persson 		}
11213e95bd4aSAnders Persson 		/* Failed to insert the filter */
11223e95bd4aSAnders Persson 		kmem_free(new, sizeof (sp_filter_t));
11233e95bd4aSAnders Persson 		return (ENOSPC);
11243e95bd4aSAnders Persson 	}
11253e95bd4aSAnders Persson }
11263e95bd4aSAnders Persson 
11273e95bd4aSAnders Persson /*
11283e95bd4aSAnders Persson  * Remove all filter entries attached to the sockparams entry `sp'.
11293e95bd4aSAnders Persson  */
11303e95bd4aSAnders Persson void
sof_sockparams_fini(struct sockparams * sp)11313e95bd4aSAnders Persson sof_sockparams_fini(struct sockparams *sp)
11323e95bd4aSAnders Persson {
11333e95bd4aSAnders Persson 	sp_filter_t *fil;
11343e95bd4aSAnders Persson 
11353e95bd4aSAnders Persson 	ASSERT(!list_link_active(&sp->sp_node));
11363e95bd4aSAnders Persson 
11373e95bd4aSAnders Persson 	while ((fil = list_remove_head(&sp->sp_auto_filters)) != NULL)
11383e95bd4aSAnders Persson 		kmem_free(fil, sizeof (sp_filter_t));
11393e95bd4aSAnders Persson 	while ((fil = list_remove_head(&sp->sp_prog_filters)) != NULL)
11403e95bd4aSAnders Persson 		kmem_free(fil, sizeof (sp_filter_t));
11413e95bd4aSAnders Persson }
11423e95bd4aSAnders Persson 
11433e95bd4aSAnders Persson /*
11443e95bd4aSAnders Persson  * A new sockparams is being added. Walk all filters and attach those that
11453e95bd4aSAnders Persson  * are interested in the entry.
11463e95bd4aSAnders Persson  *
11473e95bd4aSAnders Persson  * It should be called when the sockparams entry is about to be made available
11483e95bd4aSAnders Persson  * for use and while holding the sockconf_lock.
11493e95bd4aSAnders Persson  */
11503e95bd4aSAnders Persson int
sof_sockparams_init(struct sockparams * sp)11513e95bd4aSAnders Persson sof_sockparams_init(struct sockparams *sp)
11523e95bd4aSAnders Persson {
11533e95bd4aSAnders Persson 	sof_entry_t *ent;
11543e95bd4aSAnders Persson 
11553e95bd4aSAnders Persson 	ASSERT(RW_WRITE_HELD(&sockconf_lock));
11563e95bd4aSAnders Persson 
11573e95bd4aSAnders Persson 	for (ent = list_head(&sof_entry_list); ent != NULL;
11583e95bd4aSAnders Persson 	    ent = list_next(&sof_entry_list, ent)) {
11593e95bd4aSAnders Persson 		if (sof_entry_proc_sockparams(ent, sp) != 0) {
11603e95bd4aSAnders Persson 			sof_sockparams_fini(sp);
11613e95bd4aSAnders Persson 			return (ENOMEM);
11623e95bd4aSAnders Persson 		}
11633e95bd4aSAnders Persson 	}
11643e95bd4aSAnders Persson 	return (0);
11653e95bd4aSAnders Persson }
11663e95bd4aSAnders Persson 
11673e95bd4aSAnders Persson static sof_module_t *
sof_module_find(const char * name)11683e95bd4aSAnders Persson sof_module_find(const char *name)
11693e95bd4aSAnders Persson {
11703e95bd4aSAnders Persson 	sof_module_t *ent;
11713e95bd4aSAnders Persson 
11723e95bd4aSAnders Persson 	ASSERT(MUTEX_HELD(&sof_module_lock));
11733e95bd4aSAnders Persson 
11743e95bd4aSAnders Persson 	for (ent = list_head(&sof_module_list); ent != NULL;
11753e95bd4aSAnders Persson 	    ent = list_next(&sof_module_list, ent))
11763e95bd4aSAnders Persson 		if (strcmp(ent->sofm_name, name) == 0)
11773e95bd4aSAnders Persson 			return (ent);
11783e95bd4aSAnders Persson 	return (NULL);
11793e95bd4aSAnders Persson }
11803e95bd4aSAnders Persson 
11813e95bd4aSAnders Persson /*
11823e95bd4aSAnders Persson  * Returns a pointer to a module identified by `name' with its ref count
11833e95bd4aSAnders Persson  * bumped. An attempt to load the module is done if it's not found in the
11843e95bd4aSAnders Persson  * global list.
11853e95bd4aSAnders Persson  */
11863e95bd4aSAnders Persson sof_module_t *
sof_module_hold_by_name(const char * name,const char * modname)11873e95bd4aSAnders Persson sof_module_hold_by_name(const char *name, const char *modname)
11883e95bd4aSAnders Persson {
11893e95bd4aSAnders Persson 	ddi_modhandle_t handle = NULL;
11903e95bd4aSAnders Persson 	sof_module_t *mod = NULL;
11913e95bd4aSAnders Persson 	char *modpath;
11923e95bd4aSAnders Persson 	int error;
11933e95bd4aSAnders Persson 
11943e95bd4aSAnders Persson 	/*
11953e95bd4aSAnders Persson 	 * We'll go through the loop at most two times, which will only
11963e95bd4aSAnders Persson 	 * happen if the module needs to be loaded.
11973e95bd4aSAnders Persson 	 */
11983e95bd4aSAnders Persson 	for (;;) {
11993e95bd4aSAnders Persson 		mutex_enter(&sof_module_lock);
12003e95bd4aSAnders Persson 		mod = sof_module_find(name);
12013e95bd4aSAnders Persson 		if (mod != NULL || handle != NULL)
12023e95bd4aSAnders Persson 			break;
12033e95bd4aSAnders Persson 		mutex_exit(&sof_module_lock);
12043e95bd4aSAnders Persson 
12053e95bd4aSAnders Persson 		modpath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
12063e95bd4aSAnders Persson 		(void) snprintf(modpath, MAXPATHLEN, "%s/%s", SOF_MODPATH,
12073e95bd4aSAnders Persson 		    modname);
12083e95bd4aSAnders Persson 		handle = ddi_modopen(modpath, KRTLD_MODE_FIRST, &error);
12093e95bd4aSAnders Persson 		kmem_free(modpath, MAXPATHLEN);
12103e95bd4aSAnders Persson 		/* Failed to load, then bail */
12113e95bd4aSAnders Persson 		if (handle == NULL) {
12123e95bd4aSAnders Persson 			cmn_err(CE_WARN,
12133e95bd4aSAnders Persson 			    "Failed to load socket filter module: %s (err %d)",
12143e95bd4aSAnders Persson 			    modname, error);
12153e95bd4aSAnders Persson 			return (NULL);
12163e95bd4aSAnders Persson 		}
12173e95bd4aSAnders Persson 	}
12183e95bd4aSAnders Persson 	if (mod != NULL)
12193e95bd4aSAnders Persson 		mod->sofm_refcnt++;
12203e95bd4aSAnders Persson 	mutex_exit(&sof_module_lock);
12213e95bd4aSAnders Persson 
12223e95bd4aSAnders Persson 	if (handle != NULL) {
12233e95bd4aSAnders Persson 		(void) ddi_modclose(handle);
12243e95bd4aSAnders Persson 		/*
12253e95bd4aSAnders Persson 		 * The module was loaded, but the filter module could not be
12263e95bd4aSAnders Persson 		 * found. It's likely a misconfigured filter.
12273e95bd4aSAnders Persson 		 */
12283e95bd4aSAnders Persson 		if (mod == NULL) {
12293e95bd4aSAnders Persson 			cmn_err(CE_WARN,
12303e95bd4aSAnders Persson 			    "Socket filter module %s was loaded, but did not" \
12313e95bd4aSAnders Persson 			    "register. Filter %s is likely misconfigured.",
12323e95bd4aSAnders Persson 			    modname, name);
12333e95bd4aSAnders Persson 		}
12343e95bd4aSAnders Persson 	}
12353e95bd4aSAnders Persson 
12363e95bd4aSAnders Persson 	return (mod);
12373e95bd4aSAnders Persson }
12383e95bd4aSAnders Persson 
12393e95bd4aSAnders Persson void
sof_module_rele(sof_module_t * mod)12403e95bd4aSAnders Persson sof_module_rele(sof_module_t *mod)
12413e95bd4aSAnders Persson {
12423e95bd4aSAnders Persson 	mutex_enter(&sof_module_lock);
12433e95bd4aSAnders Persson 	mod->sofm_refcnt--;
12443e95bd4aSAnders Persson 	mutex_exit(&sof_module_lock);
12453e95bd4aSAnders Persson }
12463e95bd4aSAnders Persson 
12473e95bd4aSAnders Persson int
sof_rval2errno(sof_rval_t rval)12483e95bd4aSAnders Persson sof_rval2errno(sof_rval_t rval)
12493e95bd4aSAnders Persson {
12503e95bd4aSAnders Persson 	if (rval > SOF_RVAL_CONTINUE) {
12513e95bd4aSAnders Persson 		return ((int)rval);
12523e95bd4aSAnders Persson 	} else {
12533e95bd4aSAnders Persson #ifdef DEBUG
12543e95bd4aSAnders Persson 		if (socket_filter_debug)
12553e95bd4aSAnders Persson 			printf("sof_rval2errno: invalid rval '%d'\n", rval);
12563e95bd4aSAnders Persson #endif
12573e95bd4aSAnders Persson 		return (EINVAL);
12583e95bd4aSAnders Persson 	}
12593e95bd4aSAnders Persson }
12603e95bd4aSAnders Persson 
12613e95bd4aSAnders Persson /*
12623e95bd4aSAnders Persson  * Walk through all the filters attached to `so' and allow each filter
12633e95bd4aSAnders Persson  * to process the data using its data_out callback. `mp' is a b_cont chain.
12643e95bd4aSAnders Persson  *
12653e95bd4aSAnders Persson  * Returns the processed mblk, or NULL if mblk was consumed. The mblk might
12663e95bd4aSAnders Persson  * have been consumed as a result of an error, in which case `errp' is set to
12673e95bd4aSAnders Persson  * the appropriate errno.
12683e95bd4aSAnders Persson  */
12693e95bd4aSAnders Persson mblk_t *
sof_filter_data_out_from(struct sonode * so,sof_instance_t * start,mblk_t * mp,struct nmsghdr * msg,cred_t * cr,int * errp)12703e95bd4aSAnders Persson sof_filter_data_out_from(struct sonode *so, sof_instance_t *start,
12713e95bd4aSAnders Persson     mblk_t *mp, struct nmsghdr *msg, cred_t *cr, int *errp)
12723e95bd4aSAnders Persson {
12733e95bd4aSAnders Persson 	sof_instance_t *inst;
12743e95bd4aSAnders Persson 	sof_rval_t rval;
12753e95bd4aSAnders Persson 
12763e95bd4aSAnders Persson 	_NOTE(ARGUNUSED(so));
12773e95bd4aSAnders Persson 
12783e95bd4aSAnders Persson 	for (inst = start; inst != NULL; inst = inst->sofi_next) {
12793e95bd4aSAnders Persson 		if (!SOF_INTERESTED(inst, data_out))
12803e95bd4aSAnders Persson 			continue;
12813e95bd4aSAnders Persson 		mp = (inst->sofi_ops->sofop_data_out)((sof_handle_t)inst,
12823e95bd4aSAnders Persson 		    inst->sofi_cookie, mp, msg, cr, &rval);
12833e95bd4aSAnders Persson 		DTRACE_PROBE2(filter__data, (sof_instance_t), inst,
12843e95bd4aSAnders Persson 		    (mblk_t *), mp);
12853e95bd4aSAnders Persson 		if (mp == NULL) {
12863e95bd4aSAnders Persson 			*errp = sof_rval2errno(rval);
12873e95bd4aSAnders Persson 			break;
12883e95bd4aSAnders Persson 		}
12893e95bd4aSAnders Persson 	}
12903e95bd4aSAnders Persson 	return (mp);
12913e95bd4aSAnders Persson }
12923e95bd4aSAnders Persson 
12933e95bd4aSAnders Persson /*
12943e95bd4aSAnders Persson  * Walk through all the filters attached to `so' and allow each filter
12953e95bd4aSAnders Persson  * to process the data using its data_in_proc callback. `mp' is the start of
12963e95bd4aSAnders Persson  * a possible b_next chain, and `lastmp' points to the last mblk in the chain.
12973e95bd4aSAnders Persson  *
12983e95bd4aSAnders Persson  * Returns the processed mblk, or NULL if all mblks in the chain were
12993e95bd4aSAnders Persson  * consumed. `lastmp' is updated to point to the last mblk in the processed
13003e95bd4aSAnders Persson  * chain.
13013e95bd4aSAnders Persson  */
13023e95bd4aSAnders Persson mblk_t *
sof_filter_data_in_proc(struct sonode * so,mblk_t * mp,mblk_t ** lastmp)13033e95bd4aSAnders Persson sof_filter_data_in_proc(struct sonode *so, mblk_t *mp, mblk_t **lastmp)
13043e95bd4aSAnders Persson {
13053e95bd4aSAnders Persson 	sof_instance_t *inst;
13063e95bd4aSAnders Persson 	size_t len = 0, orig = 0;
13073e95bd4aSAnders Persson 	ssize_t diff = 0;
13083e95bd4aSAnders Persson 	mblk_t *retmp = NULL, *tailmp, *nextmp;
13093e95bd4aSAnders Persson 
13103e95bd4aSAnders Persson 	*lastmp = NULL;
13113e95bd4aSAnders Persson 	do {
13123e95bd4aSAnders Persson 		nextmp = mp->b_next;
13133e95bd4aSAnders Persson 		mp->b_next = mp->b_prev = NULL;
13143e95bd4aSAnders Persson 		len = orig = msgdsize(mp);
13153e95bd4aSAnders Persson 		for (inst = so->so_filter_bottom; inst != NULL;
13163e95bd4aSAnders Persson 		    inst = inst->sofi_prev) {
13173e95bd4aSAnders Persson 			if (!SOF_INTERESTED(inst, data_in_proc))
13183e95bd4aSAnders Persson 				continue;
13193e95bd4aSAnders Persson 			mp = (inst->sofi_ops->sofop_data_in_proc)(
13203e95bd4aSAnders Persson 			    (sof_handle_t)inst, inst->sofi_cookie, mp,
13213e95bd4aSAnders Persson 			    kcred, &len);
13223e95bd4aSAnders Persson 			if (mp == NULL)
13233e95bd4aSAnders Persson 				break;
13243e95bd4aSAnders Persson 		}
13253e95bd4aSAnders Persson 		DTRACE_PROBE2(filter__data, (sof_instance_t), inst,
13263e95bd4aSAnders Persson 		    (mblk_t *), mp);
13273e95bd4aSAnders Persson 		diff += len - orig;
13283e95bd4aSAnders Persson 		if (mp == NULL)
13293e95bd4aSAnders Persson 			continue;
13303e95bd4aSAnders Persson 
13313e95bd4aSAnders Persson 		for (tailmp = mp; tailmp->b_cont != NULL;
13323e95bd4aSAnders Persson 		    tailmp = tailmp->b_cont)
13333e95bd4aSAnders Persson 			;
13343e95bd4aSAnders Persson 		mp->b_prev = tailmp;
13353e95bd4aSAnders Persson 
13363e95bd4aSAnders Persson 		if (*lastmp == NULL)
13373e95bd4aSAnders Persson 			retmp = mp;
13383e95bd4aSAnders Persson 		else
13393e95bd4aSAnders Persson 			(*lastmp)->b_next = mp;
13403e95bd4aSAnders Persson 		*lastmp = mp;
13413e95bd4aSAnders Persson 	} while ((mp = nextmp) != NULL);
13423e95bd4aSAnders Persson 
13433e95bd4aSAnders Persson 	/*
13443e95bd4aSAnders Persson 	 * The size of the chain has changed; make sure the rcv queue
13453e95bd4aSAnders Persson 	 * stays consistent and check if the flow control state should
13463e95bd4aSAnders Persson 	 * change.
13473e95bd4aSAnders Persson 	 */
13483e95bd4aSAnders Persson 	if (diff != 0) {
13493e95bd4aSAnders Persson 		DTRACE_PROBE2(filter__data__adjust__qlen,
13503e95bd4aSAnders Persson 		    (struct sonode *), so, (size_t), diff);
13513e95bd4aSAnders Persson 		mutex_enter(&so->so_lock);
13523e95bd4aSAnders Persson 		so->so_rcv_queued += diff;
13533e95bd4aSAnders Persson 		/* so_check_flow_control drops so_lock */
1354a215d4ebSKacheong Poon 		(void) so_check_flow_control(so);
13553e95bd4aSAnders Persson 	}
13563e95bd4aSAnders Persson 
13573e95bd4aSAnders Persson 	return (retmp);
13583e95bd4aSAnders Persson }
13593e95bd4aSAnders Persson 
13603e95bd4aSAnders Persson int
sof_filter_bind(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,cred_t * cr)13613e95bd4aSAnders Persson sof_filter_bind(struct sonode *so, struct sockaddr *addr,
13623e95bd4aSAnders Persson     socklen_t *addrlen, cred_t *cr)
13633e95bd4aSAnders Persson {
13643e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, bind, cr, addr, addrlen)
13653e95bd4aSAnders Persson }
13663e95bd4aSAnders Persson 
13673e95bd4aSAnders Persson int
sof_filter_listen(struct sonode * so,int * backlogp,cred_t * cr)13683e95bd4aSAnders Persson sof_filter_listen(struct sonode *so, int *backlogp, cred_t *cr)
13693e95bd4aSAnders Persson {
13703e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, listen, cr, backlogp)
13713e95bd4aSAnders Persson }
13723e95bd4aSAnders Persson 
13733e95bd4aSAnders Persson int
sof_filter_connect(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,cred_t * cr)13743e95bd4aSAnders Persson sof_filter_connect(struct sonode *so, struct sockaddr *addr,
13753e95bd4aSAnders Persson     socklen_t *addrlen, cred_t *cr)
13763e95bd4aSAnders Persson {
13773e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, connect, cr, addr, addrlen)
13783e95bd4aSAnders Persson }
13793e95bd4aSAnders Persson 
13803e95bd4aSAnders Persson int
sof_filter_accept(struct sonode * so,cred_t * cr)13813e95bd4aSAnders Persson sof_filter_accept(struct sonode *so, cred_t *cr)
13823e95bd4aSAnders Persson {
13833e95bd4aSAnders Persson 	sof_instance_t *inst;
13843e95bd4aSAnders Persson 	sof_rval_t rval;
13853e95bd4aSAnders Persson 
13863e95bd4aSAnders Persson 	for (inst = so->so_filter_top; inst != NULL; inst = inst->sofi_next) {
13873e95bd4aSAnders Persson 		if (!SOF_INTERESTED(inst, accept))
13883e95bd4aSAnders Persson 			continue;
13893e95bd4aSAnders Persson 		rval = (inst->sofi_ops->sofop_accept)((sof_handle_t)inst,
13903e95bd4aSAnders Persson 		    inst->sofi_cookie, cr);
13913e95bd4aSAnders Persson 		DTRACE_PROBE2(filter__action, (sof_instance_t), inst,
13923e95bd4aSAnders Persson 		    (sof_rval_t), rval);
13933e95bd4aSAnders Persson 		if (rval != SOF_RVAL_CONTINUE) {
13943e95bd4aSAnders Persson 			ASSERT(rval != SOF_RVAL_RETURN);
13953e95bd4aSAnders Persson 			return (sof_rval2errno(rval));
13963e95bd4aSAnders Persson 		}
13973e95bd4aSAnders Persson 	}
13983e95bd4aSAnders Persson 	return (-1);
13993e95bd4aSAnders Persson }
14003e95bd4aSAnders Persson 
14013e95bd4aSAnders Persson int
sof_filter_shutdown(struct sonode * so,int * howp,cred_t * cr)14023e95bd4aSAnders Persson sof_filter_shutdown(struct sonode *so, int *howp, cred_t *cr)
14033e95bd4aSAnders Persson {
14043e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, shutdown, cr, howp)
14053e95bd4aSAnders Persson }
14063e95bd4aSAnders Persson 
14073e95bd4aSAnders Persson int
sof_filter_getsockname(struct sonode * so,struct sockaddr * addr,socklen_t * addrlenp,cred_t * cr)14083e95bd4aSAnders Persson sof_filter_getsockname(struct sonode *so, struct sockaddr *addr,
14093e95bd4aSAnders Persson     socklen_t *addrlenp, cred_t *cr)
14103e95bd4aSAnders Persson {
14113e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, getsockname, cr, addr, addrlenp)
14123e95bd4aSAnders Persson }
14133e95bd4aSAnders Persson 
14143e95bd4aSAnders Persson int
sof_filter_getpeername(struct sonode * so,struct sockaddr * addr,socklen_t * addrlenp,cred_t * cr)14153e95bd4aSAnders Persson sof_filter_getpeername(struct sonode *so, struct sockaddr *addr,
14163e95bd4aSAnders Persson     socklen_t *addrlenp, cred_t *cr)
14173e95bd4aSAnders Persson {
14183e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, getpeername, cr, addr, addrlenp)
14193e95bd4aSAnders Persson }
14203e95bd4aSAnders Persson 
14213e95bd4aSAnders Persson int
sof_filter_setsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,cred_t * cr)14223e95bd4aSAnders Persson sof_filter_setsockopt(struct sonode *so, int level, int option_name,
14233e95bd4aSAnders Persson     void *optval, socklen_t *optlenp, cred_t *cr)
14243e95bd4aSAnders Persson {
14253e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, setsockopt, cr, level, option_name,
14263e95bd4aSAnders Persson 	    optval, optlenp)
14273e95bd4aSAnders Persson }
14283e95bd4aSAnders Persson 
14293e95bd4aSAnders Persson int
sof_filter_getsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,cred_t * cr)14303e95bd4aSAnders Persson sof_filter_getsockopt(struct sonode *so, int level, int option_name,
14313e95bd4aSAnders Persson     void *optval, socklen_t *optlenp, cred_t *cr)
14323e95bd4aSAnders Persson {
14333e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, getsockopt, cr, level, option_name,
14343e95bd4aSAnders Persson 	    optval, optlenp)
14353e95bd4aSAnders Persson }
14363e95bd4aSAnders Persson 
14373e95bd4aSAnders Persson int
sof_filter_ioctl(struct sonode * so,int cmd,intptr_t arg,int mode,int32_t * rvalp,cred_t * cr)14383e95bd4aSAnders Persson sof_filter_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
14393e95bd4aSAnders Persson     int32_t *rvalp, cred_t *cr)
14403e95bd4aSAnders Persson {
14413e95bd4aSAnders Persson 	__SOF_FILTER_OP(so, ioctl, cr, cmd, arg, mode, rvalp)
14423e95bd4aSAnders Persson }
14433e95bd4aSAnders Persson 
14443e95bd4aSAnders Persson /*
14453e95bd4aSAnders Persson  * sof_register(version, name, ops, flags)
14463e95bd4aSAnders Persson  *
14473e95bd4aSAnders Persson  * Register a socket filter identified by name `name' and which should use
14483e95bd4aSAnders Persson  * the ops vector `ops' for event notification. `flags' should be set to 0.
14493e95bd4aSAnders Persson  * On success 0 is returned, otherwise an errno is returned.
14503e95bd4aSAnders Persson  */
14513e95bd4aSAnders Persson int
sof_register(int version,const char * name,const sof_ops_t * ops,int flags)14523e95bd4aSAnders Persson sof_register(int version, const char *name, const sof_ops_t *ops, int flags)
14533e95bd4aSAnders Persson {
14543e95bd4aSAnders Persson 	sof_module_t *mod;
14553e95bd4aSAnders Persson 
14563e95bd4aSAnders Persson 	_NOTE(ARGUNUSED(flags));
14573e95bd4aSAnders Persson 
14583e95bd4aSAnders Persson 	if (version != SOF_VERSION)
14593e95bd4aSAnders Persson 		return (EINVAL);
14603e95bd4aSAnders Persson 
14613e95bd4aSAnders Persson 	mod = kmem_zalloc(sizeof (sof_module_t), KM_SLEEP);
14623e95bd4aSAnders Persson 	mod->sofm_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
14633e95bd4aSAnders Persson 	(void) strcpy(mod->sofm_name, name);
14643e95bd4aSAnders Persson 	mod->sofm_ops = *ops;
14653e95bd4aSAnders Persson 
14663e95bd4aSAnders Persson 	mutex_enter(&sof_module_lock);
14673e95bd4aSAnders Persson 	if (sof_module_find(name) != NULL) {
14683e95bd4aSAnders Persson 		mutex_exit(&sof_module_lock);
14693e95bd4aSAnders Persson 		kmem_free(mod->sofm_name, strlen(mod->sofm_name) + 1);
14703e95bd4aSAnders Persson 		kmem_free(mod, sizeof (sof_module_t));
14713e95bd4aSAnders Persson 		return (EEXIST);
14723e95bd4aSAnders Persson 	}
14733e95bd4aSAnders Persson 	list_insert_tail(&sof_module_list, mod);
14743e95bd4aSAnders Persson 	mutex_exit(&sof_module_lock);
14753e95bd4aSAnders Persson 
14763e95bd4aSAnders Persson 	return (0);
14773e95bd4aSAnders Persson }
14783e95bd4aSAnders Persson 
14793e95bd4aSAnders Persson /*
14803e95bd4aSAnders Persson  * sof_unregister(name)
14813e95bd4aSAnders Persson  *
14823e95bd4aSAnders Persson  * Try to unregister the socket filter identified by `name'. If the filter
14833e95bd4aSAnders Persson  * is successfully unregistered, then 0 is returned, otherwise an errno is
14843e95bd4aSAnders Persson  * returned.
14853e95bd4aSAnders Persson  */
14863e95bd4aSAnders Persson int
sof_unregister(const char * name)14873e95bd4aSAnders Persson sof_unregister(const char *name)
14883e95bd4aSAnders Persson {
14893e95bd4aSAnders Persson 	sof_module_t *mod;
14903e95bd4aSAnders Persson 
14913e95bd4aSAnders Persson 	mutex_enter(&sof_module_lock);
14923e95bd4aSAnders Persson 	mod = sof_module_find(name);
14933e95bd4aSAnders Persson 	if (mod != NULL) {
14943e95bd4aSAnders Persson 		if (mod->sofm_refcnt == 0) {
14953e95bd4aSAnders Persson 			list_remove(&sof_module_list, mod);
14963e95bd4aSAnders Persson 			mutex_exit(&sof_module_lock);
14973e95bd4aSAnders Persson 
14983e95bd4aSAnders Persson 			kmem_free(mod->sofm_name, strlen(mod->sofm_name) + 1);
14993e95bd4aSAnders Persson 			kmem_free(mod, sizeof (sof_module_t));
15003e95bd4aSAnders Persson 			return (0);
15013e95bd4aSAnders Persson 		} else {
15023e95bd4aSAnders Persson 			mutex_exit(&sof_module_lock);
15033e95bd4aSAnders Persson 			return (EBUSY);
15043e95bd4aSAnders Persson 		}
15053e95bd4aSAnders Persson 	}
15063e95bd4aSAnders Persson 	mutex_exit(&sof_module_lock);
15073e95bd4aSAnders Persson 
15083e95bd4aSAnders Persson 	return (ENXIO);
15093e95bd4aSAnders Persson }
15103e95bd4aSAnders Persson 
15113e95bd4aSAnders Persson /*
15123e95bd4aSAnders Persson  * sof_newconn_ready(handle)
15133e95bd4aSAnders Persson  *
15143e95bd4aSAnders Persson  * The filter `handle` no longer wants to defer the socket it is attached
15153e95bd4aSAnders Persson  * to. A newconn notification will be generated if there is no other filter
15163e95bd4aSAnders Persson  * that wants the socket deferred.
15173e95bd4aSAnders Persson  */
15183e95bd4aSAnders Persson void
sof_newconn_ready(sof_handle_t handle)15193e95bd4aSAnders Persson sof_newconn_ready(sof_handle_t handle)
15203e95bd4aSAnders Persson {
15213e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
15223e95bd4aSAnders Persson 	struct sonode *so = inst->sofi_sonode;
15233e95bd4aSAnders Persson 	struct sonode *pso = so->so_listener;
15243e95bd4aSAnders Persson 
15253e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
15263e95bd4aSAnders Persson 	if (!(inst->sofi_flags & SOFIF_DEFER)) {
15273e95bd4aSAnders Persson 		mutex_exit(&so->so_lock);
15283e95bd4aSAnders Persson 		return;
15293e95bd4aSAnders Persson 	}
15303e95bd4aSAnders Persson 	ASSERT(so->so_state & SS_FIL_DEFER);
15313e95bd4aSAnders Persson 	inst->sofi_flags &= ~SOFIF_DEFER;
15323e95bd4aSAnders Persson 	SOF_STAT_ADD(inst, ndeferred, -1);
15333e95bd4aSAnders Persson 
15343e95bd4aSAnders Persson 	/*
15353e95bd4aSAnders Persson 	 * Check if any other filter has deferred the socket. The last
15363e95bd4aSAnders Persson 	 * filter to remove its DEFER flag will be the one generating the
15373e95bd4aSAnders Persson 	 * wakeup.
15383e95bd4aSAnders Persson 	 */
15393e95bd4aSAnders Persson 	for (inst = so->so_filter_top; inst != NULL; inst = inst->sofi_next) {
15403e95bd4aSAnders Persson 		/* Still deferred; nothing to do */
15413e95bd4aSAnders Persson 		if (inst->sofi_flags & SOFIF_DEFER) {
15423e95bd4aSAnders Persson 			mutex_exit(&so->so_lock);
15433e95bd4aSAnders Persson 			return;
15443e95bd4aSAnders Persson 		}
15453e95bd4aSAnders Persson 	}
15463e95bd4aSAnders Persson 	so->so_state &= ~SS_FIL_DEFER;
15473e95bd4aSAnders Persson 	mutex_exit(&so->so_lock);
15483e95bd4aSAnders Persson 
15493e95bd4aSAnders Persson 	/*
15503e95bd4aSAnders Persson 	 * The socket is no longer deferred; move it over to the regular
15513e95bd4aSAnders Persson 	 * accept list and notify the user. However, it is possible that
15523e95bd4aSAnders Persson 	 * the socket is being dropped by sof_sonode_drop_deferred(), so
15533e95bd4aSAnders Persson 	 * first make sure the socket is on the deferred list.
15543e95bd4aSAnders Persson 	 */
15553e95bd4aSAnders Persson 	mutex_enter(&pso->so_acceptq_lock);
15563e95bd4aSAnders Persson 	if (!list_link_active(&so->so_acceptq_node)) {
15573e95bd4aSAnders Persson 		mutex_exit(&pso->so_acceptq_lock);
15583e95bd4aSAnders Persson 		return;
15593e95bd4aSAnders Persson 	}
15603e95bd4aSAnders Persson 	list_remove(&pso->so_acceptq_defer, so);
15613e95bd4aSAnders Persson 	list_insert_tail(&pso->so_acceptq_list, so);
15623e95bd4aSAnders Persson 	cv_signal(&pso->so_acceptq_cv);
15633e95bd4aSAnders Persson 	mutex_exit(&pso->so_acceptq_lock);
15643e95bd4aSAnders Persson 
15653e95bd4aSAnders Persson 	mutex_enter(&pso->so_lock);
15663e95bd4aSAnders Persson 	so_notify_newconn(pso);		/* so_notify_newconn drops the lock */
15673e95bd4aSAnders Persson }
15683e95bd4aSAnders Persson 
15693e95bd4aSAnders Persson /*
15703e95bd4aSAnders Persson  * sof_bypass(handle)
15713e95bd4aSAnders Persson  *
15723e95bd4aSAnders Persson  * Stop generating callbacks for `handle'.
15733e95bd4aSAnders Persson  */
15743e95bd4aSAnders Persson void
sof_bypass(sof_handle_t handle)15753e95bd4aSAnders Persson sof_bypass(sof_handle_t handle)
15763e95bd4aSAnders Persson {
15773e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
15783e95bd4aSAnders Persson 	struct sonode *so = inst->sofi_sonode;
15793e95bd4aSAnders Persson 
15803e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
15813e95bd4aSAnders Persson 	if (!(inst->sofi_flags & SOFIF_BYPASS)) {
15823e95bd4aSAnders Persson 		inst->sofi_flags |= SOFIF_BYPASS;
15833e95bd4aSAnders Persson 		ASSERT(so->so_filter_active > 0);
15843e95bd4aSAnders Persson 		so->so_filter_active--;
15853e95bd4aSAnders Persson 	}
15863e95bd4aSAnders Persson 	mutex_exit(&so->so_lock);
15873e95bd4aSAnders Persson }
15883e95bd4aSAnders Persson 
15893e95bd4aSAnders Persson /*
15903e95bd4aSAnders Persson  * sof_rcv_flowctrl(handle, enable)
15913e95bd4aSAnders Persson  *
15923e95bd4aSAnders Persson  * If `enable' is TRUE, then recv side flow control will be asserted for
15933e95bd4aSAnders Persson  * the socket associated with `handle'. When `enable' is FALSE the filter
15943e95bd4aSAnders Persson  * indicates that it no longer wants to assert flow control, however, the
15953e95bd4aSAnders Persson  * condition will not be removed until there are no other filters asserting
15963e95bd4aSAnders Persson  * flow control and there is space available in the receive buffer.
15973e95bd4aSAnders Persson  */
15983e95bd4aSAnders Persson void
sof_rcv_flowctrl(sof_handle_t handle,boolean_t enable)15993e95bd4aSAnders Persson sof_rcv_flowctrl(sof_handle_t handle, boolean_t enable)
16003e95bd4aSAnders Persson {
16013e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
16023e95bd4aSAnders Persson 	struct sonode *so = inst->sofi_sonode;
16033e95bd4aSAnders Persson 
16043e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
16053e95bd4aSAnders Persson 	if (enable) {
16063e95bd4aSAnders Persson 		inst->sofi_flags |= SOFIF_RCV_FLOWCTRL;
16073e95bd4aSAnders Persson 		so->so_flowctrld = B_TRUE;
16083e95bd4aSAnders Persson 		so->so_state |= SS_FIL_RCV_FLOWCTRL;
16093e95bd4aSAnders Persson 		mutex_exit(&so->so_lock);
16103e95bd4aSAnders Persson 	} else {
16113e95bd4aSAnders Persson 		inst->sofi_flags &= ~SOFIF_RCV_FLOWCTRL;
16123e95bd4aSAnders Persson 		for (inst = so->so_filter_top; inst != NULL;
16133e95bd4aSAnders Persson 		    inst = inst->sofi_next) {
16143e95bd4aSAnders Persson 			/* another filter is asserting flow control */
16153e95bd4aSAnders Persson 			if (inst->sofi_flags & SOFIF_RCV_FLOWCTRL) {
16163e95bd4aSAnders Persson 				mutex_exit(&so->so_lock);
16173e95bd4aSAnders Persson 				return;
16183e95bd4aSAnders Persson 			}
16193e95bd4aSAnders Persson 		}
16203e95bd4aSAnders Persson 		so->so_state &= ~SS_FIL_RCV_FLOWCTRL;
16213e95bd4aSAnders Persson 		/* so_check_flow_control drops so_lock */
1622a215d4ebSKacheong Poon 		(void) so_check_flow_control(so);
16233e95bd4aSAnders Persson 	}
16243e95bd4aSAnders Persson 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
16253e95bd4aSAnders Persson }
16263e95bd4aSAnders Persson 
16273e95bd4aSAnders Persson /*
16283e95bd4aSAnders Persson  * sof_snd_flowctrl(handle, enable)
16293e95bd4aSAnders Persson  *
16303e95bd4aSAnders Persson  * If `enable' is TRUE, then send side flow control will be asserted for
16313e95bd4aSAnders Persson  * the socket associated with `handle'. When `enable' is FALSE the filter
16323e95bd4aSAnders Persson  * indicates that is no longer wants to assert flow control, however, the
16333e95bd4aSAnders Persson  * condition will not be removed until there are no other filters asserting
16343e95bd4aSAnders Persson  * flow control and there are tx buffers available.
16353e95bd4aSAnders Persson  */
16363e95bd4aSAnders Persson void
sof_snd_flowctrl(sof_handle_t handle,boolean_t enable)16373e95bd4aSAnders Persson sof_snd_flowctrl(sof_handle_t handle, boolean_t enable)
16383e95bd4aSAnders Persson {
16393e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
16403e95bd4aSAnders Persson 	struct sonode *so = inst->sofi_sonode;
16413e95bd4aSAnders Persson 
16423e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
16433e95bd4aSAnders Persson 	if (enable) {
16443e95bd4aSAnders Persson 		inst->sofi_flags |= SOFIF_SND_FLOWCTRL;
16453e95bd4aSAnders Persson 		so->so_state |= SS_FIL_SND_FLOWCTRL;
16463e95bd4aSAnders Persson 	} else {
16473e95bd4aSAnders Persson 		inst->sofi_flags &= ~SOFIF_SND_FLOWCTRL;
16483e95bd4aSAnders Persson 		for (inst = so->so_filter_top; inst != NULL;
16493e95bd4aSAnders Persson 		    inst = inst->sofi_next) {
16503e95bd4aSAnders Persson 			if (inst->sofi_flags & SOFIF_SND_FLOWCTRL) {
16513e95bd4aSAnders Persson 				mutex_exit(&so->so_lock);
16523e95bd4aSAnders Persson 				return;
16533e95bd4aSAnders Persson 			}
16543e95bd4aSAnders Persson 		}
16553e95bd4aSAnders Persson 		so->so_state &= ~SS_FIL_SND_FLOWCTRL;
16563e95bd4aSAnders Persson 		/*
16573e95bd4aSAnders Persson 		 * Wake up writer if the socket is no longer flow controlled.
16583e95bd4aSAnders Persson 		 */
16593e95bd4aSAnders Persson 		if (!SO_SND_FLOWCTRLD(so)) {
16603e95bd4aSAnders Persson 			/* so_notify_writable drops so_lock */
16613e95bd4aSAnders Persson 			so_notify_writable(so);
16623e95bd4aSAnders Persson 			return;
16633e95bd4aSAnders Persson 		}
16643e95bd4aSAnders Persson 	}
16653e95bd4aSAnders Persson 	mutex_exit(&so->so_lock);
16663e95bd4aSAnders Persson }
16673e95bd4aSAnders Persson 
16683e95bd4aSAnders Persson /*
16693e95bd4aSAnders Persson  * sof_get_cookie(handle)
16703e95bd4aSAnders Persson  *
16713e95bd4aSAnders Persson  * Returns the cookie used by `handle'.
16723e95bd4aSAnders Persson  */
16733e95bd4aSAnders Persson void *
sof_get_cookie(sof_handle_t handle)16743e95bd4aSAnders Persson sof_get_cookie(sof_handle_t handle)
16753e95bd4aSAnders Persson {
16763e95bd4aSAnders Persson 	return (((sof_instance_t *)handle)->sofi_cookie);
16773e95bd4aSAnders Persson }
16783e95bd4aSAnders Persson 
16793e95bd4aSAnders Persson /*
16803e95bd4aSAnders Persson  * sof_cas_cookie(handle, old, new)
16813e95bd4aSAnders Persson  *
16823e95bd4aSAnders Persson  * Compare-and-swap the cookie used by `handle'.
16833e95bd4aSAnders Persson  */
16843e95bd4aSAnders Persson void *
sof_cas_cookie(sof_handle_t handle,void * old,void * new)16853e95bd4aSAnders Persson sof_cas_cookie(sof_handle_t handle, void *old, void *new)
16863e95bd4aSAnders Persson {
16873e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
16883e95bd4aSAnders Persson 
16893e95bd4aSAnders Persson 	return (atomic_cas_ptr(&inst->sofi_cookie, old, new));
16903e95bd4aSAnders Persson }
16913e95bd4aSAnders Persson 
16923e95bd4aSAnders Persson /*
16933e95bd4aSAnders Persson  * sof_inject_data_out(handle, mp, msg, flowctrld)
16943e95bd4aSAnders Persson  *
16953e95bd4aSAnders Persson  * Submit `mp' for transmission. `msg' cannot by NULL, and may contain
16963e95bd4aSAnders Persson  * ancillary data and destination address. Returns 0 when successful
16973e95bd4aSAnders Persson  * in which case `flowctrld' is updated. If flow controlled, no new data
16983e95bd4aSAnders Persson  * should be injected until a SOF_EV_INJECT_DATA_OUT_OK event is observed.
16993e95bd4aSAnders Persson  * In case of failure, an errno is returned.
17003e95bd4aSAnders Persson  *
17013e95bd4aSAnders Persson  * Filters that are lower in the stack than `handle' will see the data
17023e95bd4aSAnders Persson  * before it is transmitted and may end up modifying or freeing the data.
17033e95bd4aSAnders Persson  */
17043e95bd4aSAnders Persson int
sof_inject_data_out(sof_handle_t handle,mblk_t * mp,struct nmsghdr * msg,boolean_t * flowctrld)17053e95bd4aSAnders Persson sof_inject_data_out(sof_handle_t handle, mblk_t *mp, struct nmsghdr *msg,
17063e95bd4aSAnders Persson     boolean_t *flowctrld)
17073e95bd4aSAnders Persson {
17083e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
17093e95bd4aSAnders Persson 	struct sonode *so = inst->sofi_sonode;
17103e95bd4aSAnders Persson 	int error;
17113e95bd4aSAnders Persson 
17123e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
1713e82bc0baSAnders Persson 	if (so->so_state & SS_FIL_STOP) {
17143e95bd4aSAnders Persson 		mutex_exit(&so->so_lock);
17153e95bd4aSAnders Persson 		freemsg(mp);
17163e95bd4aSAnders Persson 		return (EPIPE);
17173e95bd4aSAnders Persson 	}
17183e95bd4aSAnders Persson 	so->so_filter_tx++;
17193e95bd4aSAnders Persson 	mutex_exit(&so->so_lock);
17203e95bd4aSAnders Persson 
17213e95bd4aSAnders Persson 	error = so_sendmblk_impl(inst->sofi_sonode, msg, FNONBLOCK,
17223e95bd4aSAnders Persson 	    kcred, &mp, inst->sofi_next, B_TRUE);
17233e95bd4aSAnders Persson 
17243e95bd4aSAnders Persson 	mutex_enter(&so->so_lock);
17253e95bd4aSAnders Persson 	ASSERT(so->so_filter_tx > 0);
17263e95bd4aSAnders Persson 	so->so_filter_tx--;
17273e95bd4aSAnders Persson 	if (so->so_state & SS_CLOSING)
17283e95bd4aSAnders Persson 		cv_signal(&so->so_closing_cv);
17293e95bd4aSAnders Persson 	mutex_exit(&so->so_lock);
17303e95bd4aSAnders Persson 
17313e95bd4aSAnders Persson 	if (mp != NULL)
17323e95bd4aSAnders Persson 		freemsg(mp);
17333e95bd4aSAnders Persson 
17343e95bd4aSAnders Persson 	if (error == ENOSPC) {
17353e95bd4aSAnders Persson 		*flowctrld = B_TRUE;
17363e95bd4aSAnders Persson 		error = 0;
17373e95bd4aSAnders Persson 	} else {
17383e95bd4aSAnders Persson 		*flowctrld = B_FALSE;
17393e95bd4aSAnders Persson 	}
17403e95bd4aSAnders Persson 
17413e95bd4aSAnders Persson 	return (error);
17423e95bd4aSAnders Persson }
17433e95bd4aSAnders Persson 
17443e95bd4aSAnders Persson /*
17453e95bd4aSAnders Persson  * sof_inject_data_in(handle, mp, len, flag, flowctrld)
17463e95bd4aSAnders Persson  *
17473e95bd4aSAnders Persson  * Enqueue `mp' which contains `len' bytes of M_DATA onto the socket
17483e95bd4aSAnders Persson  * associated with `handle'. `flags' should be set to 0. Returns 0 when
17493e95bd4aSAnders Persson  * successful in which case `flowctrld' is updated. If flow controlled,
17503e95bd4aSAnders Persson  * no new data should be injected until a SOF_EV_INJECT_DATA_IN_OK event
17513e95bd4aSAnders Persson  * is observed.  In case of failure, an errno is returned.
17523e95bd4aSAnders Persson  *
17533e95bd4aSAnders Persson  * Filters that are higher in the stack than `handle' will see the data
17543e95bd4aSAnders Persson  * before it is enqueued on the receive queue and may end up modifying or
17553e95bd4aSAnders Persson  * freeing the data.
17563e95bd4aSAnders Persson  */
17573e95bd4aSAnders Persson int
sof_inject_data_in(sof_handle_t handle,mblk_t * mp,size_t len,int flags,boolean_t * flowctrld)17583e95bd4aSAnders Persson sof_inject_data_in(sof_handle_t handle, mblk_t *mp, size_t len, int flags,
17593e95bd4aSAnders Persson     boolean_t *flowctrld)
17603e95bd4aSAnders Persson {
17613e95bd4aSAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
17623e95bd4aSAnders Persson 	ssize_t avail;
17633e95bd4aSAnders Persson 	int error = 0;
17643e95bd4aSAnders Persson 
17653e95bd4aSAnders Persson 	ASSERT(flags == 0);
17663e95bd4aSAnders Persson 	avail = so_queue_msg_impl(inst->sofi_sonode, mp, len, flags, &error,
17673e95bd4aSAnders Persson 	    NULL, inst->sofi_prev);
17683e95bd4aSAnders Persson 	/* fallback should never happen when there is an active filter */
17693e95bd4aSAnders Persson 	ASSERT(error != EOPNOTSUPP);
17703e95bd4aSAnders Persson 
17713e95bd4aSAnders Persson 	*flowctrld = (avail > 0) ? B_FALSE : B_TRUE;
17723e95bd4aSAnders Persson 	return (error);
17733e95bd4aSAnders Persson }
1774dd49f125SAnders Persson 
1775dd49f125SAnders Persson /*
1776dd49f125SAnders Persson  * sof_newconn_move(handle, newparent)
1777dd49f125SAnders Persson  *
1778dd49f125SAnders Persson  * Private interface only to be used by KSSL.
1779dd49f125SAnders Persson  *
1780dd49f125SAnders Persson  * Moves the socket associated with `handle' from its current listening
1781dd49f125SAnders Persson  * socket to the listener associated with `newparent'. The socket being
1782dd49f125SAnders Persson  * moved must be in a deferred state and it is up to the consumer of the
1783dd49f125SAnders Persson  * interface to ensure that the `newparent' does not go away while this
1784dd49f125SAnders Persson  * operation is pending.
1785dd49f125SAnders Persson  */
1786dd49f125SAnders Persson boolean_t
sof_newconn_move(sof_handle_t handle,sof_handle_t newparent)1787dd49f125SAnders Persson sof_newconn_move(sof_handle_t handle, sof_handle_t newparent)
1788dd49f125SAnders Persson {
1789dd49f125SAnders Persson 	sof_instance_t *inst = (sof_instance_t *)handle;
1790dd49f125SAnders Persson 	sof_instance_t *newpinst = (sof_instance_t *)newparent;
1791dd49f125SAnders Persson 	struct sonode *so, *old, *new;
1792dd49f125SAnders Persson 
1793dd49f125SAnders Persson 	so = inst->sofi_sonode;
1794dd49f125SAnders Persson 	ASSERT(so->so_state & SS_FIL_DEFER);
1795dd49f125SAnders Persson 
1796dd49f125SAnders Persson 	if (inst->sofi_next != NULL || inst->sofi_prev != NULL ||
1797dd49f125SAnders Persson 	    !(so->so_state & SS_FIL_DEFER))
1798dd49f125SAnders Persson 		return (B_FALSE);
1799dd49f125SAnders Persson 
1800dd49f125SAnders Persson 	old = so->so_listener;
1801dd49f125SAnders Persson 	mutex_enter(&old->so_acceptq_lock);
1802dd49f125SAnders Persson 	list_remove(&old->so_acceptq_defer, so);
1803dd49f125SAnders Persson 	old->so_acceptq_len--;
1804dd49f125SAnders Persson 	mutex_exit(&old->so_acceptq_lock);
1805dd49f125SAnders Persson 
1806dd49f125SAnders Persson 	new = newpinst->sofi_sonode;
1807dd49f125SAnders Persson 	mutex_enter(&new->so_acceptq_lock);
1808dd49f125SAnders Persson 	list_insert_tail(&new->so_acceptq_defer, so);
1809dd49f125SAnders Persson 	new->so_acceptq_len++;
1810dd49f125SAnders Persson 	mutex_exit(&new->so_acceptq_lock);
1811dd49f125SAnders Persson 
1812dd49f125SAnders Persson 	so->so_listener = new;
1813dd49f125SAnders Persson 
1814dd49f125SAnders Persson 	return (B_TRUE);
1815dd49f125SAnders Persson }
1816