4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/systm.h>
26 #include <sys/sysmacros.h>
27 #include <sys/cmn_err.h>
30 #include <sys/mutex.h>
32 #include <sys/rwlock.h>
33 #include <sys/stropts.h>
34 #include <sys/taskq.h>
35 #include <sys/socketvar.h>
36 #include "sockcommon.h"
37 #include "sockfilter_impl.h"
40 * Socket Filter Framework
42 * Socket filter entry (sof_entry_t):
44 * There exists one entry for each configured filter (done via soconfig(1M)),
45 * and they are all in sof_entry_list. In addition to the global list, each
46 * sockparams entry maintains a list of filters that is interested in that
47 * particular socket type. So the filter entry may be referenced by multiple
48 * sockparams. The set of sockparams referencing a filter may change as
49 * socket types are added and/or removed from the system. Both sof_entry_list
50 * and the sockparams list is protected by sockconf_lock.
52 * Each filter entry has a ref count which is incremented whenever a filter
53 * is attached to a socket. An entry is marked SOFEF_CONDEMED when it is
54 * unconfigured, which will result in the entry being freed when its ref
57 * Socket filter module (sof_module_t):
59 * Modules are created by sof_register() and placed in sof_module_list,
60 * which is protected by sof_module_lock. Each module has a reference count
61 * that is incremented when a filter entry is using the module. A module
62 * can be destroyed by sof_unregister() only when its ref count is zero.
64 * Socket filter instance (sof_instance_t):
66 * Whenever a filter is attached to a socket (sonode), a new instance is
67 * created. The socket is guaranteed to be single threaded when filters are
68 * being attached/detached. The instance uses the sonode's so_lock for
71 * The lifetime of an instance is the same as the socket it's attached to.
73 * How things link together:
75 * sockparams.sp_{auto,prog}_filters -> sp_filter_t -> sp_filter_t
78 * sonode.so_filter_top -> sof_instance_t | |
81 * sof_entry_list -> sof_entry_t -> sof_entry -> ... -> sof_entry_t
84 * sof_module_list -> sof_module_t -> ... -> sof_module_t
87 static list_t sof_entry_list
; /* list of configured filters */
89 static list_t sof_module_list
; /* list of loaded filter modules */
90 static kmutex_t sof_module_lock
; /* protect the module list */
92 static sof_kstat_t sof_stat
;
93 static kstat_t
*sof_stat_ksp
;
96 static int socket_filter_debug
= 0;
100 * A connection that has been deferred for more than `sof_defer_drop_time'
101 * ticks can be dropped to make room for new connections. A connection that
102 * is to be dropped is moved over to `sof_close_deferred_list' where it will
103 * be closed by sof_close_deferred() (which is running on a taskq). Connections
104 * will not be moved over to the close list if it grows larger than
105 * `sof_close_deferred_max_backlog'.
107 clock_t sof_defer_drop_time
= 3000;
108 uint_t sof_close_deferred_max_backlog
= 1000;
110 taskq_t
*sof_close_deferred_taskq
;
111 boolean_t sof_close_deferred_running
;
112 uint_t sof_close_deferred_backlog
;
113 list_t sof_close_deferred_list
;
114 kmutex_t sof_close_deferred_lock
;
116 static void sof_close_deferred(void *);
118 static void sof_module_rele(sof_module_t
*);
119 static sof_module_t
*sof_module_hold_by_name(const char *, const char *);
121 static int sof_entry_load_module(sof_entry_t
*);
122 static void sof_entry_hold(sof_entry_t
*);
123 static void sof_entry_rele(sof_entry_t
*);
124 static int sof_entry_kstat_create(sof_entry_t
*);
125 static void sof_entry_kstat_destroy(sof_entry_t
*);
127 static sof_instance_t
*sof_instance_create(sof_entry_t
*, struct sonode
*);
128 static void sof_instance_destroy(sof_instance_t
*);
131 sof_kstat_update(kstat_t
*ksp
, int rw
)
133 _NOTE(ARGUNUSED(ksp
));
135 if (rw
== KSTAT_WRITE
)
138 sof_stat
.sofks_defer_close_backlog
.value
.ui64
=
139 sof_close_deferred_backlog
;
147 list_create(&sof_entry_list
, sizeof (sof_entry_t
),
148 offsetof(sof_entry_t
, sofe_node
));
149 list_create(&sof_module_list
, sizeof (sof_module_t
),
150 offsetof(sof_module_t
, sofm_node
));
151 list_create(&sof_close_deferred_list
, sizeof (struct sonode
),
152 offsetof(struct sonode
, so_acceptq_node
));
154 sof_close_deferred_taskq
= taskq_create("sof_close_deferred_taskq",
155 1, minclsyspri
, 1, INT_MAX
, TASKQ_PREPOPULATE
);
156 sof_close_deferred_running
= B_FALSE
;
157 sof_close_deferred_backlog
= 0;
159 mutex_init(&sof_close_deferred_lock
, NULL
, MUTEX_DEFAULT
, 0);
160 mutex_init(&sof_module_lock
, NULL
, MUTEX_DEFAULT
, 0);
162 sof_stat_ksp
= kstat_create("sockfs", 0, "sockfilter", "misc",
163 KSTAT_TYPE_NAMED
, sizeof (sof_kstat_t
) / sizeof (kstat_named_t
),
166 if (sof_stat_ksp
== NULL
)
169 kstat_named_init(&sof_stat
.sofks_defer_closed
, "defer_closed",
171 kstat_named_init(&sof_stat
.sofks_defer_close_backlog
,
172 "defer_close_backlog", KSTAT_DATA_UINT64
);
173 kstat_named_init(&sof_stat
.sofks_defer_close_failed_backlog_too_big
,
174 "defer_close_failed_backlog_too_big", KSTAT_DATA_UINT64
);
176 sof_stat_ksp
->ks_data
= &sof_stat
;
177 sof_stat_ksp
->ks_update
= sof_kstat_update
;
178 kstat_install(sof_stat_ksp
);
182 * Process filter options.
185 sof_setsockopt_impl(struct sonode
*so
, int option_name
,
186 const void *optval
, socklen_t optlen
, struct cred
*cr
)
188 struct sockparams
*sp
= so
->so_sockparams
;
189 sof_entry_t
*ent
= NULL
;
191 sof_instance_t
*inst
;
195 _NOTE(ARGUNUSED(optlen
));
198 * Is the filter in a state where filters can be attached?
200 if (!(so
->so_state
& SS_FILOP_OK
))
203 if (option_name
== FIL_ATTACH
) {
205 * Make sure there isn't already another instance of the
206 * same filter attached to the socket.
208 for (inst
= so
->so_filter_top
; inst
!= NULL
;
209 inst
= inst
->sofi_next
) {
210 if (strncmp(inst
->sofi_filter
->sofe_name
,
211 (const char *)optval
, SOF_MAXNAMELEN
) == 0)
214 /* Look up the filter. */
215 rw_enter(&sockconf_lock
, RW_READER
);
216 for (fil
= list_head(&sp
->sp_prog_filters
); fil
!= NULL
;
217 fil
= list_next(&sp
->sp_prog_filters
, fil
)) {
218 ent
= fil
->spf_filter
;
219 ASSERT(ent
->sofe_flags
& SOFEF_PROG
);
221 if (strncmp(ent
->sofe_name
, (const char *)optval
,
222 SOF_MAXNAMELEN
) == 0)
227 rw_exit(&sockconf_lock
);
230 inst
= sof_instance_create(ent
, so
);
231 rw_exit(&sockconf_lock
);
233 /* Failed to create an instance; must be out of memory */
238 * This might be the first time the filter is being used,
239 * so try to load the module if it's not already registered.
241 if (ent
->sofe_mod
== NULL
&&
242 (error
= sof_entry_load_module(ent
)) != 0) {
243 sof_instance_destroy(inst
);
247 /* Module loaded OK, so there must be an ops vector */
248 ASSERT(ent
->sofe_mod
!= NULL
);
249 inst
->sofi_ops
= &ent
->sofe_mod
->sofm_ops
;
251 SOF_STAT_ADD(inst
, tot_active_attach
, 1);
252 if (inst
->sofi_ops
->sofop_attach_active
!= NULL
) {
253 rval
= inst
->sofi_ops
->sofop_attach_active(
254 (sof_handle_t
)inst
, so
->so_family
, so
->so_type
,
255 so
->so_protocol
, cr
, &inst
->sofi_cookie
);
256 if (rval
!= SOF_RVAL_CONTINUE
) {
258 case SOF_RVAL_DETACH
:
260 * Filter does not want to to attach.
261 * An error is returned so the user
262 * knows the request did not go
268 SOF_STAT_ADD(inst
, attach_failures
, 1);
269 /* Not a valid rval for active attach */
270 ASSERT(rval
!= SOF_RVAL_DEFER
);
271 error
= sof_rval2errno(rval
);
274 sof_instance_destroy(inst
);
279 } else if (option_name
== FIL_DETACH
) {
280 for (inst
= so
->so_filter_top
; inst
!= NULL
;
281 inst
= inst
->sofi_next
) {
283 ent
= inst
->sofi_filter
;
284 if (strncmp(ent
->sofe_name
, (const char *)optval
,
285 SOF_MAXNAMELEN
) == 0)
291 /* automatic filters cannot be detached */
292 if (inst
->sofi_filter
->sofe_flags
& SOFEF_AUTO
)
295 if (inst
->sofi_ops
->sofop_detach
!= NULL
)
296 inst
->sofi_ops
->sofop_detach((sof_handle_t
)inst
,
297 inst
->sofi_cookie
, cr
);
298 sof_instance_destroy(inst
);
307 sof_setsockopt(struct sonode
*so
, int option_name
,
308 const void *optval
, socklen_t optlen
, struct cred
*cr
)
313 * By grabbing the lock as a writer we ensure that no other socket
314 * operations can start while the filter stack is being manipulated.
316 * We do a tryenter so that in case there is an active thread we
317 * ask the caller to try again instead of blocking here until the
318 * other thread is done (which could be indefinitely in case of recv).
320 if (!rw_tryenter(&so
->so_fallback_rwlock
, RW_WRITER
)) {
324 /* Bail out if a fallback has taken place */
325 if (so
->so_state
& SS_FALLBACK_COMP
)
328 error
= sof_setsockopt_impl(so
, option_name
, optval
,
330 rw_exit(&so
->so_fallback_rwlock
);
336 * Get filter socket options.
339 sof_getsockopt_impl(struct sonode
*so
, int option_name
,
340 void *optval
, socklen_t
*optlenp
, struct cred
*cr
)
342 sof_instance_t
*inst
;
344 socklen_t maxsz
= *optlenp
;
348 _NOTE(ARGUNUSED(cr
));
350 if (option_name
== FIL_LIST
) {
351 fi
= (struct fil_info
*)optval
;
353 if (maxsz
< sizeof (*fi
))
356 for (inst
= so
->so_filter_top
, cnt
= 0; inst
!= NULL
;
357 inst
= inst
->sofi_next
)
359 for (inst
= so
->so_filter_top
, i
= 0;
360 inst
!= NULL
&& (i
+1) * sizeof (*fi
) <= maxsz
;
361 inst
= inst
->sofi_next
, i
++) {
363 (inst
->sofi_filter
->sofe_flags
& SOFEF_AUTO
) ?
364 FILF_AUTO
: FILF_PROG
;
365 if (inst
->sofi_flags
& SOFIF_BYPASS
)
366 fi
[i
].fi_flags
|= FILF_BYPASS
;
367 (void) strncpy(fi
[i
].fi_name
,
368 inst
->sofi_filter
->sofe_name
, FILNAME_MAX
);
370 fi
[i
].fi_pos
= --cnt
;
372 *optlenp
= i
* sizeof (*fi
);
380 sof_getsockopt(struct sonode
*so
, int option_name
,
381 void *optval
, socklen_t
*optlenp
, struct cred
*cr
)
386 * The fallback lock is used here to serialize set and get
389 rw_enter(&so
->so_fallback_rwlock
, RW_READER
);
390 if (so
->so_state
& SS_FALLBACK_COMP
)
393 error
= sof_getsockopt_impl(so
, option_name
, optval
, optlenp
,
395 rw_exit(&so
->so_fallback_rwlock
);
401 * The socket `so' wants to inherit the filter stack from `pso'.
402 * Returns 0 if all went well or an errno otherwise.
405 sof_sonode_inherit_filters(struct sonode
*so
, struct sonode
*pso
)
407 sof_instance_t
*inst
, *pinst
;
410 struct sockaddr_in6 laddrbuf
, faddrbuf
;
411 struct sockaddr_in6
*laddr
, *faddr
;
412 socklen_t laddrlen
, faddrlen
;
415 * Make sure there is enough room to retrieve the addresses
417 if (so
->so_proto_props
.sopp_maxaddrlen
> sizeof (laddrbuf
)) {
418 laddr
= kmem_zalloc(so
->so_proto_props
.sopp_maxaddrlen
,
422 faddr
= kmem_zalloc(so
->so_proto_props
.sopp_maxaddrlen
,
425 kmem_free(laddr
, so
->so_proto_props
.sopp_maxaddrlen
);
428 laddrlen
= faddrlen
= so
->so_proto_props
.sopp_maxaddrlen
;
430 laddrlen
= faddrlen
= sizeof (laddrbuf
);
435 error
= (*so
->so_downcalls
->sd_getpeername
)
436 (so
->so_proto_handle
, (struct sockaddr
*)faddr
, &faddrlen
, kcred
);
439 error
= (*so
->so_downcalls
->sd_getsockname
)
440 (so
->so_proto_handle
, (struct sockaddr
*)laddr
, &laddrlen
, kcred
);
445 * The stack is built bottom up. Filters are allowed to modify the
446 * the foreign and local addresses during attach.
448 for (pinst
= pso
->so_filter_bottom
;
449 pinst
!= NULL
&& !(pinst
->sofi_flags
& SOFIF_BYPASS
);
450 pinst
= pinst
->sofi_prev
) {
451 inst
= sof_instance_create(pinst
->sofi_filter
, so
);
457 * The filter module must be loaded since it's already
458 * attached to the listener.
460 ASSERT(pinst
->sofi_ops
!= NULL
);
461 inst
->sofi_ops
= pinst
->sofi_ops
;
463 SOF_STAT_ADD(inst
, tot_passive_attach
, 1);
464 if (inst
->sofi_ops
->sofop_attach_passive
!= NULL
) {
465 rval
= inst
->sofi_ops
->sofop_attach_passive(
467 (sof_handle_t
)pinst
, pinst
->sofi_cookie
,
468 (struct sockaddr
*)laddr
, laddrlen
,
469 (struct sockaddr
*)faddr
, faddrlen
,
471 if (rval
!= SOF_RVAL_CONTINUE
) {
472 if (rval
== SOF_RVAL_DEFER
) {
473 mutex_enter(&so
->so_lock
);
474 inst
->sofi_flags
|= SOFIF_DEFER
;
475 so
->so_state
|= SS_FIL_DEFER
;
476 mutex_exit(&so
->so_lock
);
477 so
->so_filter_defertime
=
479 SOF_STAT_ADD(inst
, ndeferred
, 1);
480 } else if (rval
== SOF_RVAL_DETACH
) {
481 sof_instance_destroy(inst
);
483 SOF_STAT_ADD(inst
, attach_failures
, 1);
484 error
= sof_rval2errno(rval
);
486 * Filters that called attached will be
487 * destroyed when the socket goes away,
488 * after detach is called.
497 if (laddr
!= &laddrbuf
) {
498 kmem_free(laddr
, so
->so_proto_props
.sopp_maxaddrlen
);
499 kmem_free(faddr
, so
->so_proto_props
.sopp_maxaddrlen
);
505 * Attach any automatic filters to sonode `so'. Returns 0 if all went well
506 * and an errno otherwise.
509 sof_sonode_autoattach_filters(struct sonode
*so
, cred_t
*cr
)
511 struct sockparams
*sp
= so
->so_sockparams
;
513 sof_instance_t
*inst
;
518 * A created instance is added to the top of the sonode's filter
519 * stack, so traverse the config list in reverse order.
521 rw_enter(&sockconf_lock
, RW_READER
);
522 for (fil
= list_tail(&sp
->sp_auto_filters
);
523 fil
!= NULL
; fil
= list_prev(&sp
->sp_auto_filters
, fil
)) {
524 ASSERT(fil
->spf_filter
->sofe_flags
& SOFEF_AUTO
);
525 if (!sof_instance_create(fil
->spf_filter
, so
)) {
526 rw_exit(&sockconf_lock
);
527 error
= ENOMEM
; /* must have run out of memory */
531 rw_exit(&sockconf_lock
);
534 * Notify each filter that it's being attached.
536 inst
= so
->so_filter_top
;
537 while (inst
!= NULL
) {
538 sof_entry_t
*ent
= inst
->sofi_filter
;
539 sof_instance_t
*ninst
= inst
->sofi_next
;
542 * This might be the first time the filter is being used,
543 * so try to load the module if it's not already registered.
545 if (ent
->sofe_mod
== NULL
&&
546 (error
= sof_entry_load_module(ent
)) != 0)
549 /* Module loaded OK, so there must be an ops vector */
550 ASSERT(ent
->sofe_mod
!= NULL
);
551 inst
->sofi_ops
= &ent
->sofe_mod
->sofm_ops
;
553 SOF_STAT_ADD(inst
, tot_active_attach
, 1);
554 if (inst
->sofi_ops
->sofop_attach_active
!= NULL
) {
555 rval
= inst
->sofi_ops
->sofop_attach_active(
556 (sof_handle_t
)inst
, so
->so_family
, so
->so_type
,
557 so
->so_protocol
, cr
, &inst
->sofi_cookie
);
558 if (rval
!= SOF_RVAL_CONTINUE
) {
560 case SOF_RVAL_DETACH
:
561 /* filter does not want to attach */
562 sof_instance_destroy(inst
);
565 SOF_STAT_ADD(inst
, attach_failures
, 1);
566 /* Not a valid rval for active attach */
567 ASSERT(rval
!= SOF_RVAL_DEFER
);
568 error
= sof_rval2errno(rval
);
578 inst
= so
->so_filter_top
;
580 ASSERT(inst
!= NULL
);
582 * Destroy all filters for which attach was not called. The other
583 * filters will be destroyed (and detach called) when the socket
587 sof_instance_t
*t
= inst
->sofi_next
;
588 sof_instance_destroy(inst
);
590 } while (inst
!= NULL
);
596 * Detaches and frees all filters attached to sonode `so'.
599 sof_sonode_cleanup(struct sonode
*so
)
601 sof_instance_t
*inst
;
603 while ((inst
= so
->so_filter_top
) != NULL
) {
604 (inst
->sofi_ops
->sofop_detach
)((sof_handle_t
)inst
,
605 inst
->sofi_cookie
, kcred
);
606 sof_instance_destroy(inst
);
611 * Notifies all active filters attached to `so' about the `event' and
612 * where `arg' is an event specific argument.
615 sof_sonode_notify_filters(struct sonode
*so
, sof_event_t event
, uintptr_t arg
)
617 sof_instance_t
*inst
;
619 for (inst
= so
->so_filter_bottom
; inst
!= NULL
;
620 inst
= inst
->sofi_prev
) {
621 if (SOF_INTERESTED(inst
, notify
))
622 (inst
->sofi_ops
->sofop_notify
)((sof_handle_t
)inst
,
623 inst
->sofi_cookie
, event
, arg
);
628 * The socket `so' is closing. Notify filters and make sure that there
629 * are no pending tx operations.
632 sof_sonode_closing(struct sonode
*so
)
635 * Notify filters that the socket is being closed. It's OK for
636 * filters to inject data.
638 sof_sonode_notify_filters(so
, SOF_EV_CLOSING
, (uintptr_t)B_TRUE
);
641 * Stop any future attempts to inject data, and wait for any
642 * pending operations to complete. This has to be done to ensure
643 * that no data is sent down to the protocol once a close
644 * downcall has been made.
646 mutex_enter(&so
->so_lock
);
647 so
->so_state
|= SS_FIL_STOP
;
648 while (so
->so_filter_tx
> 0)
649 cv_wait(&so
->so_closing_cv
, &so
->so_lock
);
650 mutex_exit(&so
->so_lock
);
654 * Called when socket `so' wants to get rid of a deferred connection.
655 * Returns TRUE if a connection was dropped.
658 sof_sonode_drop_deferred(struct sonode
*so
)
661 clock_t now
= ddi_get_lbolt();
663 if (sof_close_deferred_backlog
> sof_close_deferred_max_backlog
) {
664 SOF_GLOBAL_STAT_BUMP(defer_close_failed_backlog_too_big
);
667 mutex_enter(&so
->so_acceptq_lock
);
668 if ((def
= list_head(&so
->so_acceptq_defer
)) != NULL
&&
669 (now
- def
->so_filter_defertime
) > sof_defer_drop_time
) {
670 list_remove(&so
->so_acceptq_defer
, def
);
671 so
->so_acceptq_len
--;
672 mutex_exit(&so
->so_acceptq_lock
);
673 def
->so_listener
= NULL
;
675 mutex_exit(&so
->so_acceptq_lock
);
679 mutex_enter(&sof_close_deferred_lock
);
680 list_insert_tail(&sof_close_deferred_list
, def
);
681 sof_close_deferred_backlog
++;
682 if (!sof_close_deferred_running
) {
683 mutex_exit(&sof_close_deferred_lock
);
684 (void) taskq_dispatch(sof_close_deferred_taskq
,
685 sof_close_deferred
, NULL
, TQ_NOSLEEP
);
687 mutex_exit(&sof_close_deferred_lock
);
693 * Called from a taskq to close connections that have been deferred for
697 sof_close_deferred(void *unused
)
701 _NOTE(ARGUNUSED(unused
));
703 mutex_enter(&sof_close_deferred_lock
);
704 if (!sof_close_deferred_running
) {
705 sof_close_deferred_running
= B_TRUE
;
707 list_remove_head(&sof_close_deferred_list
)) != NULL
) {
708 sof_close_deferred_backlog
--;
709 mutex_exit(&sof_close_deferred_lock
);
711 SOF_GLOBAL_STAT_BUMP(defer_closed
);
712 (void) socket_close(drop
, 0, kcred
);
713 socket_destroy(drop
);
715 mutex_enter(&sof_close_deferred_lock
);
717 sof_close_deferred_running
= B_FALSE
;
718 ASSERT(sof_close_deferred_backlog
== 0);
720 mutex_exit(&sof_close_deferred_lock
);
724 * Creates a new filter instance from the entry `ent' and attaches
725 * it to the sonode `so'. On success, return a pointer to the created
728 * The new instance will be placed on the top of the filter stack.
730 * The caller is responsible for assigning the instance's ops vector and
731 * calling the filter's attach callback.
733 * No locks are held while manipulating the sonode fields because we are
734 * guaranteed that this operation is serialized.
736 * We can be sure that the entry `ent' will not disappear, because the
737 * caller is either holding sockconf_lock (in case of an active open), or is
738 * already holding a reference (in case of a passive open, the listener has
741 static sof_instance_t
*
742 sof_instance_create(sof_entry_t
*ent
, struct sonode
*so
)
744 sof_instance_t
*inst
;
746 inst
= kmem_zalloc(sizeof (sof_instance_t
), KM_NOSLEEP
);
750 inst
->sofi_filter
= ent
;
751 inst
->sofi_sonode
= so
;
753 inst
->sofi_next
= so
->so_filter_top
;
754 if (so
->so_filter_top
!= NULL
)
755 so
->so_filter_top
->sofi_prev
= inst
;
757 so
->so_filter_bottom
= inst
;
758 so
->so_filter_top
= inst
;
759 so
->so_filter_active
++;
764 * Destroys the filter instance `inst' and unlinks it from the sonode.
766 * Any filter private state must be destroyed (via the detach callback)
767 * before the instance is destroyed.
770 sof_instance_destroy(sof_instance_t
*inst
)
772 struct sonode
*so
= inst
->sofi_sonode
;
774 ASSERT(inst
->sofi_sonode
!= NULL
);
775 ASSERT(inst
->sofi_filter
!= NULL
);
776 ASSERT(inst
->sofi_prev
!= NULL
|| so
->so_filter_top
== inst
);
777 ASSERT(inst
->sofi_next
!= NULL
|| so
->so_filter_bottom
== inst
);
779 if (inst
->sofi_prev
!= NULL
)
780 inst
->sofi_prev
->sofi_next
= inst
->sofi_next
;
782 so
->so_filter_top
= inst
->sofi_next
;
784 if (inst
->sofi_next
!= NULL
)
785 inst
->sofi_next
->sofi_prev
= inst
->sofi_prev
;
787 so
->so_filter_bottom
= inst
->sofi_prev
;
789 if (!(inst
->sofi_flags
& SOFIF_BYPASS
)) {
790 ASSERT(so
->so_filter_active
> 0);
791 so
->so_filter_active
--;
793 if (inst
->sofi_flags
& SOFIF_DEFER
)
794 SOF_STAT_ADD(inst
, ndeferred
, -1);
795 sof_entry_rele(inst
->sofi_filter
);
796 kmem_free(inst
, sizeof (sof_instance_t
));
800 sof_entry_find(const char *name
)
804 for (ent
= list_head(&sof_entry_list
); ent
!= NULL
;
805 ent
= list_next(&sof_entry_list
, ent
)) {
806 if (strncmp(ent
->sofe_name
, name
, SOF_MAXNAMELEN
) == 0)
813 sof_entry_free(sof_entry_t
*ent
)
815 ASSERT(ent
->sofe_refcnt
== 0);
816 ASSERT(!list_link_active(&ent
->sofe_node
));
818 if (ent
->sofe_hintarg
!= NULL
) {
819 ASSERT(ent
->sofe_hint
== SOF_HINT_BEFORE
||
820 ent
->sofe_hint
== SOF_HINT_AFTER
);
821 kmem_free(ent
->sofe_hintarg
, strlen(ent
->sofe_hintarg
) + 1);
822 ent
->sofe_hintarg
= NULL
;
824 if (ent
->sofe_socktuple_cnt
> 0) {
825 ASSERT(ent
->sofe_socktuple
!= NULL
);
826 kmem_free(ent
->sofe_socktuple
,
827 sizeof (sof_socktuple_t
) * ent
->sofe_socktuple_cnt
);
828 ent
->sofe_socktuple
= NULL
;
829 ent
->sofe_socktuple_cnt
= 0;
831 sof_entry_kstat_destroy(ent
);
833 mutex_destroy(&ent
->sofe_lock
);
834 kmem_free(ent
, sizeof (sof_entry_t
));
838 sof_entry_kstat_update(kstat_t
*ksp
, int rw
)
840 sof_entry_t
*ent
= ksp
->ks_private
;
842 if (rw
== KSTAT_WRITE
)
845 ent
->sofe_kstat
.sofek_nactive
.value
.ui64
= ent
->sofe_refcnt
;
851 * Create the kstat for filter entry `ent'.
854 sof_entry_kstat_create(sof_entry_t
*ent
)
856 char name
[SOF_MAXNAMELEN
+ 7];
858 (void) snprintf(name
, sizeof (name
), "filter_%s", ent
->sofe_name
);
859 ent
->sofe_ksp
= kstat_create("sockfs", 0, name
, "misc",
861 sizeof (sof_entry_kstat_t
) / sizeof (kstat_named_t
),
864 if (ent
->sofe_ksp
== NULL
)
867 kstat_named_init(&ent
->sofe_kstat
.sofek_nactive
, "nactive",
869 kstat_named_init(&ent
->sofe_kstat
.sofek_tot_active_attach
,
870 "tot_active_attach", KSTAT_DATA_UINT64
);
871 kstat_named_init(&ent
->sofe_kstat
.sofek_tot_passive_attach
,
872 "tot_passive_attach", KSTAT_DATA_UINT64
);
873 kstat_named_init(&ent
->sofe_kstat
.sofek_ndeferred
, "ndeferred",
875 kstat_named_init(&ent
->sofe_kstat
.sofek_attach_failures
,
876 "attach_failures", KSTAT_DATA_UINT64
);
878 ent
->sofe_ksp
->ks_data
= &ent
->sofe_kstat
;
879 ent
->sofe_ksp
->ks_update
= sof_entry_kstat_update
;
880 ent
->sofe_ksp
->ks_private
= ent
;
881 kstat_install(ent
->sofe_ksp
);
887 * Destroys the kstat for filter entry `ent'.
890 sof_entry_kstat_destroy(sof_entry_t
*ent
)
892 if (ent
->sofe_ksp
!= NULL
) {
893 kstat_delete(ent
->sofe_ksp
);
894 ent
->sofe_ksp
= NULL
;
899 sof_entry_hold(sof_entry_t
*ent
)
901 mutex_enter(&ent
->sofe_lock
);
903 mutex_exit(&ent
->sofe_lock
);
907 * Decrement the reference count for `ent'. The entry will
908 * drop its' reference on the filter module whenever its'
909 * ref count reaches zero.
912 sof_entry_rele(sof_entry_t
*ent
)
914 mutex_enter(&ent
->sofe_lock
);
915 if (--ent
->sofe_refcnt
== 0) {
916 sof_module_t
*mod
= ent
->sofe_mod
;
917 ent
->sofe_mod
= NULL
;
918 if (ent
->sofe_flags
& SOFEF_CONDEMED
) {
919 mutex_exit(&ent
->sofe_lock
);
922 mutex_exit(&ent
->sofe_lock
);
925 sof_module_rele(mod
);
927 mutex_exit(&ent
->sofe_lock
);
932 * Loads the module used by `ent'
935 sof_entry_load_module(sof_entry_t
*ent
)
937 sof_module_t
*mod
= sof_module_hold_by_name(ent
->sofe_name
,
943 mutex_enter(&ent
->sofe_lock
);
944 /* Another thread might have already loaded the module */
945 ASSERT(ent
->sofe_mod
== mod
|| ent
->sofe_mod
== NULL
);
946 if (ent
->sofe_mod
!= NULL
) {
947 mutex_exit(&ent
->sofe_lock
);
948 sof_module_rele(mod
);
951 mutex_exit(&ent
->sofe_lock
);
958 * Add filter entry `ent' to the global list and attach it to all sockparam
959 * entries which the filter is interested in. Upon successful return the filter
960 * will be available for applications to use.
963 sof_entry_add(sof_entry_t
*ent
)
968 * We hold sockconf_lock as a WRITER for the whole operation,
969 * so all operations must be non-blocking.
971 rw_enter(&sockconf_lock
, RW_WRITER
);
972 if (sof_entry_find(ent
->sofe_name
) != NULL
) {
973 rw_exit(&sockconf_lock
);
977 /* The entry is unique; create the kstats */
978 if (sof_entry_kstat_create(ent
) != 0) {
979 rw_exit(&sockconf_lock
);
984 * Attach the filter to sockparams of interest.
986 if ((error
= sockparams_new_filter(ent
)) != 0) {
987 sof_entry_kstat_destroy(ent
);
988 rw_exit(&sockconf_lock
);
992 * Everything is OK; insert in global list.
994 list_insert_tail(&sof_entry_list
, ent
);
995 rw_exit(&sockconf_lock
);
1001 * Removes the filter entry `ent' from global list and all sockparams.
1004 sof_entry_remove_by_name(const char *name
)
1008 rw_enter(&sockconf_lock
, RW_WRITER
);
1009 if ((ent
= sof_entry_find(name
)) == NULL
) {
1010 rw_exit(&sockconf_lock
);
1013 list_remove(&sof_entry_list
, ent
);
1014 sockparams_filter_cleanup(ent
);
1015 sof_entry_kstat_destroy(ent
);
1016 rw_exit(&sockconf_lock
);
1022 * Filter entry `ent' will process sockparams entry `sp' to determine whether
1023 * it should be attached to the sockparams. It should be called whenever a new
1024 * filter or sockparams is being added. Returns zero either if the filter is
1025 * not interested in the sockparams or if it successfully attached to the
1026 * sockparams. On failure an errno is returned.
1029 sof_entry_proc_sockparams(sof_entry_t
*ent
, struct sockparams
*sp
)
1032 sof_socktuple_t
*t
= ent
->sofe_socktuple
;
1033 sp_filter_t
*new, *fil
;
1035 /* Only interested in non-TPI sockets */
1036 if (strcmp(sp
->sp_smod_name
, SOTPI_SMOD_NAME
) == 0)
1039 for (i
= 0; i
< ent
->sofe_socktuple_cnt
; i
++) {
1040 if (t
[i
].sofst_family
== sp
->sp_family
&&
1041 t
[i
].sofst_type
== sp
->sp_type
&&
1042 t
[i
].sofst_protocol
== sp
->sp_protocol
)
1045 /* This filter is not interested in the sockparams entry */
1046 if (i
== ent
->sofe_socktuple_cnt
)
1049 new = kmem_zalloc(sizeof (sp_filter_t
), KM_NOSLEEP
);
1053 new->spf_filter
= ent
;
1054 if (ent
->sofe_flags
& SOFEF_PROG
) {
1055 /* placement is irrelevant for programmatic filters */
1056 list_insert_head(&sp
->sp_prog_filters
, new);
1059 ASSERT(ent
->sofe_flags
& SOFEF_AUTO
);
1061 * If the filter specifies a placement hint, then make sure
1062 * it can be satisfied.
1064 switch (ent
->sofe_hint
) {
1066 if ((fil
= list_head(&sp
->sp_auto_filters
)) != NULL
&&
1067 fil
->spf_filter
->sofe_hint
== SOF_HINT_TOP
)
1069 list_insert_head(&sp
->sp_auto_filters
, new);
1071 case SOF_HINT_BOTTOM
:
1072 if ((fil
= list_tail(&sp
->sp_auto_filters
)) != NULL
&&
1073 fil
->spf_filter
->sofe_hint
== SOF_HINT_BOTTOM
)
1075 list_insert_tail(&sp
->sp_auto_filters
, new);
1077 case SOF_HINT_BEFORE
:
1078 case SOF_HINT_AFTER
:
1079 for (fil
= list_head(&sp
->sp_auto_filters
);
1081 fil
= list_next(&sp
->sp_auto_filters
, fil
)) {
1082 if (strncmp(ent
->sofe_hintarg
,
1083 fil
->spf_filter
->sofe_name
,
1084 SOF_MAXNAMELEN
) == 0)
1089 if (ent
->sofe_hint
== SOF_HINT_BEFORE
) {
1090 if (fil
->spf_filter
->sofe_hint
==
1093 list_insert_before(&sp
->sp_auto_filters
,
1096 if (fil
->spf_filter
->sofe_hint
==
1099 list_insert_after(&sp
->sp_auto_filters
,
1107 * Insert the new filter at the beginning as long as it
1108 * does not violate a TOP hint, otherwise insert in the
1109 * next suitable location.
1111 if ((fil
= list_head(&sp
->sp_auto_filters
)) != NULL
&&
1112 fil
->spf_filter
->sofe_hint
== SOF_HINT_TOP
) {
1113 list_insert_after(&sp
->sp_auto_filters
, fil
,
1116 list_insert_head(&sp
->sp_auto_filters
, new);
1120 /* Failed to insert the filter */
1121 kmem_free(new, sizeof (sp_filter_t
));
1127 * Remove all filter entries attached to the sockparams entry `sp'.
1130 sof_sockparams_fini(struct sockparams
*sp
)
1134 ASSERT(!list_link_active(&sp
->sp_node
));
1136 while ((fil
= list_remove_head(&sp
->sp_auto_filters
)) != NULL
)
1137 kmem_free(fil
, sizeof (sp_filter_t
));
1138 while ((fil
= list_remove_head(&sp
->sp_prog_filters
)) != NULL
)
1139 kmem_free(fil
, sizeof (sp_filter_t
));
1143 * A new sockparams is being added. Walk all filters and attach those that
1144 * are interested in the entry.
1146 * It should be called when the sockparams entry is about to be made available
1147 * for use and while holding the sockconf_lock.
1150 sof_sockparams_init(struct sockparams
*sp
)
1154 ASSERT(RW_WRITE_HELD(&sockconf_lock
));
1156 for (ent
= list_head(&sof_entry_list
); ent
!= NULL
;
1157 ent
= list_next(&sof_entry_list
, ent
)) {
1158 if (sof_entry_proc_sockparams(ent
, sp
) != 0) {
1159 sof_sockparams_fini(sp
);
1166 static sof_module_t
*
1167 sof_module_find(const char *name
)
1171 ASSERT(MUTEX_HELD(&sof_module_lock
));
1173 for (ent
= list_head(&sof_module_list
); ent
!= NULL
;
1174 ent
= list_next(&sof_module_list
, ent
))
1175 if (strcmp(ent
->sofm_name
, name
) == 0)
1181 * Returns a pointer to a module identified by `name' with its ref count
1182 * bumped. An attempt to load the module is done if it's not found in the
1186 sof_module_hold_by_name(const char *name
, const char *modname
)
1188 ddi_modhandle_t handle
= NULL
;
1189 sof_module_t
*mod
= NULL
;
1194 * We'll go through the loop at most two times, which will only
1195 * happen if the module needs to be loaded.
1198 mutex_enter(&sof_module_lock
);
1199 mod
= sof_module_find(name
);
1200 if (mod
!= NULL
|| handle
!= NULL
)
1202 mutex_exit(&sof_module_lock
);
1204 modpath
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1205 (void) snprintf(modpath
, MAXPATHLEN
, "%s/%s", SOF_MODPATH
,
1207 handle
= ddi_modopen(modpath
, KRTLD_MODE_FIRST
, &error
);
1208 kmem_free(modpath
, MAXPATHLEN
);
1209 /* Failed to load, then bail */
1210 if (handle
== NULL
) {
1212 "Failed to load socket filter module: %s (err %d)",
1219 mutex_exit(&sof_module_lock
);
1221 if (handle
!= NULL
) {
1222 (void) ddi_modclose(handle
);
1224 * The module was loaded, but the filter module could not be
1225 * found. It's likely a misconfigured filter.
1229 "Socket filter module %s was loaded, but did not" \
1230 "register. Filter %s is likely misconfigured.",
1239 sof_module_rele(sof_module_t
*mod
)
1241 mutex_enter(&sof_module_lock
);
1243 mutex_exit(&sof_module_lock
);
1247 sof_rval2errno(sof_rval_t rval
)
1249 if (rval
> SOF_RVAL_CONTINUE
) {
1253 if (socket_filter_debug
)
1254 printf("sof_rval2errno: invalid rval '%d'\n", rval
);
1261 * Walk through all the filters attached to `so' and allow each filter
1262 * to process the data using its data_out callback. `mp' is a b_cont chain.
1264 * Returns the processed mblk, or NULL if mblk was consumed. The mblk might
1265 * have been consumed as a result of an error, in which case `errp' is set to
1266 * the appropriate errno.
1269 sof_filter_data_out_from(struct sonode
*so
, sof_instance_t
*start
,
1270 mblk_t
*mp
, struct msghdr
*msg
, cred_t
*cr
, int *errp
)
1272 sof_instance_t
*inst
;
1275 _NOTE(ARGUNUSED(so
));
1277 for (inst
= start
; inst
!= NULL
; inst
= inst
->sofi_next
) {
1278 if (!SOF_INTERESTED(inst
, data_out
))
1280 mp
= (inst
->sofi_ops
->sofop_data_out
)((sof_handle_t
)inst
,
1281 inst
->sofi_cookie
, mp
, msg
, cr
, &rval
);
1282 DTRACE_PROBE2(filter__data
, (sof_instance_t
), inst
,
1285 *errp
= sof_rval2errno(rval
);
1293 * Walk through all the filters attached to `so' and allow each filter
1294 * to process the data using its data_in_proc callback. `mp' is the start of
1295 * a possible b_next chain, and `lastmp' points to the last mblk in the chain.
1297 * Returns the processed mblk, or NULL if all mblks in the chain were
1298 * consumed. `lastmp' is updated to point to the last mblk in the processed
1302 sof_filter_data_in_proc(struct sonode
*so
, mblk_t
*mp
, mblk_t
**lastmp
)
1304 sof_instance_t
*inst
;
1305 size_t len
= 0, orig
= 0;
1307 mblk_t
*retmp
= NULL
, *tailmp
, *nextmp
;
1311 nextmp
= mp
->b_next
;
1312 mp
->b_next
= mp
->b_prev
= NULL
;
1313 len
= orig
= msgdsize(mp
);
1314 for (inst
= so
->so_filter_bottom
; inst
!= NULL
;
1315 inst
= inst
->sofi_prev
) {
1316 if (!SOF_INTERESTED(inst
, data_in_proc
))
1318 mp
= (inst
->sofi_ops
->sofop_data_in_proc
)(
1319 (sof_handle_t
)inst
, inst
->sofi_cookie
, mp
,
1324 DTRACE_PROBE2(filter__data
, (sof_instance_t
), inst
,
1330 for (tailmp
= mp
; tailmp
->b_cont
!= NULL
;
1331 tailmp
= tailmp
->b_cont
)
1333 mp
->b_prev
= tailmp
;
1335 if (*lastmp
== NULL
)
1338 (*lastmp
)->b_next
= mp
;
1340 } while ((mp
= nextmp
) != NULL
);
1343 * The size of the chain has changed; make sure the rcv queue
1344 * stays consistent and check if the flow control state should
1348 DTRACE_PROBE2(filter__data__adjust__qlen
,
1349 (struct sonode
*), so
, (size_t), diff
);
1350 mutex_enter(&so
->so_lock
);
1351 so
->so_rcv_queued
+= diff
;
1352 /* so_check_flow_control drops so_lock */
1353 (void) so_check_flow_control(so
);
1360 sof_filter_bind(struct sonode
*so
, struct sockaddr
*addr
,
1361 socklen_t
*addrlen
, cred_t
*cr
)
1363 __SOF_FILTER_OP(so
, bind
, cr
, addr
, addrlen
)
1367 sof_filter_listen(struct sonode
*so
, int *backlogp
, cred_t
*cr
)
1369 __SOF_FILTER_OP(so
, listen
, cr
, backlogp
)
1373 sof_filter_connect(struct sonode
*so
, struct sockaddr
*addr
,
1374 socklen_t
*addrlen
, cred_t
*cr
)
1376 __SOF_FILTER_OP(so
, connect
, cr
, addr
, addrlen
)
1380 sof_filter_accept(struct sonode
*so
, cred_t
*cr
)
1382 sof_instance_t
*inst
;
1385 for (inst
= so
->so_filter_top
; inst
!= NULL
; inst
= inst
->sofi_next
) {
1386 if (!SOF_INTERESTED(inst
, accept
))
1388 rval
= (inst
->sofi_ops
->sofop_accept
)((sof_handle_t
)inst
,
1389 inst
->sofi_cookie
, cr
);
1390 DTRACE_PROBE2(filter__action
, (sof_instance_t
), inst
,
1391 (sof_rval_t
), rval
);
1392 if (rval
!= SOF_RVAL_CONTINUE
) {
1393 ASSERT(rval
!= SOF_RVAL_RETURN
);
1394 return (sof_rval2errno(rval
));
1401 sof_filter_shutdown(struct sonode
*so
, int *howp
, cred_t
*cr
)
1403 __SOF_FILTER_OP(so
, shutdown
, cr
, howp
)
1407 sof_filter_getsockname(struct sonode
*so
, struct sockaddr
*addr
,
1408 socklen_t
*addrlenp
, cred_t
*cr
)
1410 __SOF_FILTER_OP(so
, getsockname
, cr
, addr
, addrlenp
)
1414 sof_filter_getpeername(struct sonode
*so
, struct sockaddr
*addr
,
1415 socklen_t
*addrlenp
, cred_t
*cr
)
1417 __SOF_FILTER_OP(so
, getpeername
, cr
, addr
, addrlenp
)
1421 sof_filter_setsockopt(struct sonode
*so
, int level
, int option_name
,
1422 void *optval
, socklen_t
*optlenp
, cred_t
*cr
)
1424 __SOF_FILTER_OP(so
, setsockopt
, cr
, level
, option_name
,
1429 sof_filter_getsockopt(struct sonode
*so
, int level
, int option_name
,
1430 void *optval
, socklen_t
*optlenp
, cred_t
*cr
)
1432 __SOF_FILTER_OP(so
, getsockopt
, cr
, level
, option_name
,
1437 sof_filter_ioctl(struct sonode
*so
, int cmd
, intptr_t arg
, int mode
,
1438 int32_t *rvalp
, cred_t
*cr
)
1440 __SOF_FILTER_OP(so
, ioctl
, cr
, cmd
, arg
, mode
, rvalp
)
1444 * sof_register(version, name, ops, flags)
1446 * Register a socket filter identified by name `name' and which should use
1447 * the ops vector `ops' for event notification. `flags' should be set to 0.
1448 * On success 0 is returned, otherwise an errno is returned.
1451 sof_register(int version
, const char *name
, const sof_ops_t
*ops
, int flags
)
1455 _NOTE(ARGUNUSED(flags
));
1457 if (version
!= SOF_VERSION
)
1460 mod
= kmem_zalloc(sizeof (sof_module_t
), KM_SLEEP
);
1461 mod
->sofm_name
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
1462 (void) strcpy(mod
->sofm_name
, name
);
1463 mod
->sofm_ops
= *ops
;
1465 mutex_enter(&sof_module_lock
);
1466 if (sof_module_find(name
) != NULL
) {
1467 mutex_exit(&sof_module_lock
);
1468 kmem_free(mod
->sofm_name
, strlen(mod
->sofm_name
) + 1);
1469 kmem_free(mod
, sizeof (sof_module_t
));
1472 list_insert_tail(&sof_module_list
, mod
);
1473 mutex_exit(&sof_module_lock
);
1479 * sof_unregister(name)
1481 * Try to unregister the socket filter identified by `name'. If the filter
1482 * is successfully unregistered, then 0 is returned, otherwise an errno is
1486 sof_unregister(const char *name
)
1490 mutex_enter(&sof_module_lock
);
1491 mod
= sof_module_find(name
);
1493 if (mod
->sofm_refcnt
== 0) {
1494 list_remove(&sof_module_list
, mod
);
1495 mutex_exit(&sof_module_lock
);
1497 kmem_free(mod
->sofm_name
, strlen(mod
->sofm_name
) + 1);
1498 kmem_free(mod
, sizeof (sof_module_t
));
1501 mutex_exit(&sof_module_lock
);
1505 mutex_exit(&sof_module_lock
);
1511 * sof_newconn_ready(handle)
1513 * The filter `handle` no longer wants to defer the socket it is attached
1514 * to. A newconn notification will be generated if there is no other filter
1515 * that wants the socket deferred.
1518 sof_newconn_ready(sof_handle_t handle
)
1520 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1521 struct sonode
*so
= inst
->sofi_sonode
;
1522 struct sonode
*pso
= so
->so_listener
;
1524 mutex_enter(&so
->so_lock
);
1525 if (!(inst
->sofi_flags
& SOFIF_DEFER
)) {
1526 mutex_exit(&so
->so_lock
);
1529 ASSERT(so
->so_state
& SS_FIL_DEFER
);
1530 inst
->sofi_flags
&= ~SOFIF_DEFER
;
1531 SOF_STAT_ADD(inst
, ndeferred
, -1);
1534 * Check if any other filter has deferred the socket. The last
1535 * filter to remove its DEFER flag will be the one generating the
1538 for (inst
= so
->so_filter_top
; inst
!= NULL
; inst
= inst
->sofi_next
) {
1539 /* Still deferred; nothing to do */
1540 if (inst
->sofi_flags
& SOFIF_DEFER
) {
1541 mutex_exit(&so
->so_lock
);
1545 so
->so_state
&= ~SS_FIL_DEFER
;
1546 mutex_exit(&so
->so_lock
);
1549 * The socket is no longer deferred; move it over to the regular
1550 * accept list and notify the user. However, it is possible that
1551 * the socket is being dropped by sof_sonode_drop_deferred(), so
1552 * first make sure the socket is on the deferred list.
1554 mutex_enter(&pso
->so_acceptq_lock
);
1555 if (!list_link_active(&so
->so_acceptq_node
)) {
1556 mutex_exit(&pso
->so_acceptq_lock
);
1559 list_remove(&pso
->so_acceptq_defer
, so
);
1560 list_insert_tail(&pso
->so_acceptq_list
, so
);
1561 cv_signal(&pso
->so_acceptq_cv
);
1562 mutex_exit(&pso
->so_acceptq_lock
);
1564 mutex_enter(&pso
->so_lock
);
1565 so_notify_newconn(pso
); /* so_notify_newconn drops the lock */
1569 * sof_bypass(handle)
1571 * Stop generating callbacks for `handle'.
1574 sof_bypass(sof_handle_t handle
)
1576 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1577 struct sonode
*so
= inst
->sofi_sonode
;
1579 mutex_enter(&so
->so_lock
);
1580 if (!(inst
->sofi_flags
& SOFIF_BYPASS
)) {
1581 inst
->sofi_flags
|= SOFIF_BYPASS
;
1582 ASSERT(so
->so_filter_active
> 0);
1583 so
->so_filter_active
--;
1585 mutex_exit(&so
->so_lock
);
1589 * sof_rcv_flowctrl(handle, enable)
1591 * If `enable' is TRUE, then recv side flow control will be asserted for
1592 * the socket associated with `handle'. When `enable' is FALSE the filter
1593 * indicates that it no longer wants to assert flow control, however, the
1594 * condition will not be removed until there are no other filters asserting
1595 * flow control and there is space available in the receive buffer.
1598 sof_rcv_flowctrl(sof_handle_t handle
, boolean_t enable
)
1600 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1601 struct sonode
*so
= inst
->sofi_sonode
;
1603 mutex_enter(&so
->so_lock
);
1605 inst
->sofi_flags
|= SOFIF_RCV_FLOWCTRL
;
1606 so
->so_flowctrld
= B_TRUE
;
1607 so
->so_state
|= SS_FIL_RCV_FLOWCTRL
;
1608 mutex_exit(&so
->so_lock
);
1610 inst
->sofi_flags
&= ~SOFIF_RCV_FLOWCTRL
;
1611 for (inst
= so
->so_filter_top
; inst
!= NULL
;
1612 inst
= inst
->sofi_next
) {
1613 /* another filter is asserting flow control */
1614 if (inst
->sofi_flags
& SOFIF_RCV_FLOWCTRL
) {
1615 mutex_exit(&so
->so_lock
);
1619 so
->so_state
&= ~SS_FIL_RCV_FLOWCTRL
;
1620 /* so_check_flow_control drops so_lock */
1621 (void) so_check_flow_control(so
);
1623 ASSERT(MUTEX_NOT_HELD(&so
->so_lock
));
1627 * sof_snd_flowctrl(handle, enable)
1629 * If `enable' is TRUE, then send side flow control will be asserted for
1630 * the socket associated with `handle'. When `enable' is FALSE the filter
1631 * indicates that is no longer wants to assert flow control, however, the
1632 * condition will not be removed until there are no other filters asserting
1633 * flow control and there are tx buffers available.
1636 sof_snd_flowctrl(sof_handle_t handle
, boolean_t enable
)
1638 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1639 struct sonode
*so
= inst
->sofi_sonode
;
1641 mutex_enter(&so
->so_lock
);
1643 inst
->sofi_flags
|= SOFIF_SND_FLOWCTRL
;
1644 so
->so_state
|= SS_FIL_SND_FLOWCTRL
;
1646 inst
->sofi_flags
&= ~SOFIF_SND_FLOWCTRL
;
1647 for (inst
= so
->so_filter_top
; inst
!= NULL
;
1648 inst
= inst
->sofi_next
) {
1649 if (inst
->sofi_flags
& SOFIF_SND_FLOWCTRL
) {
1650 mutex_exit(&so
->so_lock
);
1654 so
->so_state
&= ~SS_FIL_SND_FLOWCTRL
;
1656 * Wake up writer if the socket is no longer flow controlled.
1658 if (!SO_SND_FLOWCTRLD(so
)) {
1659 /* so_notify_writable drops so_lock */
1660 so_notify_writable(so
);
1664 mutex_exit(&so
->so_lock
);
1668 * sof_get_cookie(handle)
1670 * Returns the cookie used by `handle'.
1673 sof_get_cookie(sof_handle_t handle
)
1675 return (((sof_instance_t
*)handle
)->sofi_cookie
);
1679 * sof_cas_cookie(handle, old, new)
1681 * Compare-and-swap the cookie used by `handle'.
1684 sof_cas_cookie(sof_handle_t handle
, void *old
, void *new)
1686 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1688 return (atomic_cas_ptr(&inst
->sofi_cookie
, old
, new));
1692 * sof_inject_data_out(handle, mp, msg, flowctrld)
1694 * Submit `mp' for transmission. `msg' cannot by NULL, and may contain
1695 * ancillary data and destination address. Returns 0 when successful
1696 * in which case `flowctrld' is updated. If flow controlled, no new data
1697 * should be injected until a SOF_EV_INJECT_DATA_OUT_OK event is observed.
1698 * In case of failure, an errno is returned.
1700 * Filters that are lower in the stack than `handle' will see the data
1701 * before it is transmitted and may end up modifying or freeing the data.
1704 sof_inject_data_out(sof_handle_t handle
, mblk_t
*mp
, struct msghdr
*msg
,
1705 boolean_t
*flowctrld
)
1707 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1708 struct sonode
*so
= inst
->sofi_sonode
;
1711 mutex_enter(&so
->so_lock
);
1712 if (so
->so_state
& SS_FIL_STOP
) {
1713 mutex_exit(&so
->so_lock
);
1718 mutex_exit(&so
->so_lock
);
1720 error
= so_sendmblk_impl(inst
->sofi_sonode
, msg
, FNONBLOCK
,
1721 kcred
, &mp
, inst
->sofi_next
, B_TRUE
);
1723 mutex_enter(&so
->so_lock
);
1724 ASSERT(so
->so_filter_tx
> 0);
1726 if (so
->so_state
& SS_CLOSING
)
1727 cv_signal(&so
->so_closing_cv
);
1728 mutex_exit(&so
->so_lock
);
1733 if (error
== ENOSPC
) {
1734 *flowctrld
= B_TRUE
;
1737 *flowctrld
= B_FALSE
;
1744 * sof_inject_data_in(handle, mp, len, flag, flowctrld)
1746 * Enqueue `mp' which contains `len' bytes of M_DATA onto the socket
1747 * associated with `handle'. `flags' should be set to 0. Returns 0 when
1748 * successful in which case `flowctrld' is updated. If flow controlled,
1749 * no new data should be injected until a SOF_EV_INJECT_DATA_IN_OK event
1750 * is observed. In case of failure, an errno is returned.
1752 * Filters that are higher in the stack than `handle' will see the data
1753 * before it is enqueued on the receive queue and may end up modifying or
1757 sof_inject_data_in(sof_handle_t handle
, mblk_t
*mp
, size_t len
, int flags
,
1758 boolean_t
*flowctrld
)
1760 sof_instance_t
*inst
= (sof_instance_t
*)handle
;
1765 avail
= so_queue_msg_impl(inst
->sofi_sonode
, mp
, len
, flags
, &error
,
1766 NULL
, inst
->sofi_prev
);
1767 /* fallback should never happen when there is an active filter */
1768 ASSERT(error
!= EOPNOTSUPP
);
1770 *flowctrld
= (avail
> 0) ? B_FALSE
: B_TRUE
;