dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / kernel / fs / sockfs / sockparams.c
blobfe987ab2a496b0a37f345d510e01438be7d22743
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/t_lock.h>
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/sysmacros.h>
32 #include <sys/cmn_err.h>
33 #include <sys/list.h>
34 #include <sys/sunddi.h>
36 #include <sys/stropts.h>
37 #include <sys/socket.h>
38 #include <sys/socketvar.h>
40 #include "sockcommon.h"
41 #include "sockfilter_impl.h"
42 #include "socktpi.h"
45 * Socket Parameters
47 * Socket parameter (struct sockparams) entries represent the socket types
48 * available on the system.
50 * Flags (sp_flags):
52 * SOCKPARAMS_EPHEMERAL: A temporary sockparams entry that will be deleted
53 * as soon as its' ref count drops to zero. In addition, ephemeral entries will
54 * never be hooked onto the global sockparams list. Ephemeral entries are
55 * created when application requests to create a socket using an application
56 * supplied device path, or when a socket is falling back to TPI.
58 * Lock order:
59 * The lock order is sockconf_lock -> sp_lock.
61 extern int kobj_path_exists(char *, int);
63 static int sockparams_sdev_init(struct sockparams *, char *, int);
64 static void sockparams_sdev_fini(struct sockparams *);
67 * Global sockparams list (populated via soconfig(1M)).
69 static list_t sphead;
72 * List of ephemeral sockparams.
74 static list_t sp_ephem_list;
76 /* Global kstats for sockparams */
77 typedef struct sockparams_g_stats {
78 kstat_named_t spgs_ephem_nalloc;
79 kstat_named_t spgs_ephem_nreuse;
80 } sockparams_g_stats_t;
82 static sockparams_g_stats_t sp_g_stats;
83 static kstat_t *sp_g_kstat;
86 void
87 sockparams_init(void)
89 list_create(&sphead, sizeof (struct sockparams),
90 offsetof(struct sockparams, sp_node));
91 list_create(&sp_ephem_list, sizeof (struct sockparams),
92 offsetof(struct sockparams, sp_node));
94 kstat_named_init(&sp_g_stats.spgs_ephem_nalloc, "ephemeral_nalloc",
95 KSTAT_DATA_UINT64);
96 kstat_named_init(&sp_g_stats.spgs_ephem_nreuse, "ephemeral_nreuse",
97 KSTAT_DATA_UINT64);
99 sp_g_kstat = kstat_create("sockfs", 0, "sockparams", "misc",
100 KSTAT_TYPE_NAMED, sizeof (sp_g_stats) / sizeof (kstat_named_t),
101 KSTAT_FLAG_VIRTUAL);
102 if (sp_g_kstat == NULL)
103 return;
105 sp_g_kstat->ks_data = &sp_g_stats;
107 kstat_install(sp_g_kstat);
110 static int
111 sockparams_kstat_update(kstat_t *ksp, int rw)
113 struct sockparams *sp = ksp->ks_private;
114 sockparams_stats_t *sps = ksp->ks_data;
116 if (rw == KSTAT_WRITE)
117 return (EACCES);
119 sps->sps_nactive.value.ui64 = sp->sp_refcnt;
121 return (0);
125 * Setup kstats for the given sockparams entry.
127 static void
128 sockparams_kstat_init(struct sockparams *sp)
130 char name[KSTAT_STRLEN];
132 (void) snprintf(name, KSTAT_STRLEN, "socket_%d_%d_%d", sp->sp_family,
133 sp->sp_type, sp->sp_protocol);
135 sp->sp_kstat = kstat_create("sockfs", 0, name, "misc", KSTAT_TYPE_NAMED,
136 sizeof (sockparams_stats_t) / sizeof (kstat_named_t),
137 KSTAT_FLAG_VIRTUAL);
139 if (sp->sp_kstat == NULL)
140 return;
142 sp->sp_kstat->ks_data = &sp->sp_stats;
143 sp->sp_kstat->ks_update = sockparams_kstat_update;
144 sp->sp_kstat->ks_private = sp;
145 kstat_install(sp->sp_kstat);
148 static void
149 sockparams_kstat_fini(struct sockparams *sp)
151 if (sp->sp_kstat != NULL) {
152 kstat_delete(sp->sp_kstat);
153 sp->sp_kstat = NULL;
158 * sockparams_create(int family, int type, int protocol, char *modname,
159 * char *devpath, int devpathlen, int flags, int kmflags, int *errorp)
161 * Create a new sockparams entry.
163 * Arguments:
164 * family, type, protocol: specifies the socket type
165 * modname: Name of the module associated with the socket type. The
166 * module can be NULL if a device path is given, in which
167 * case the TPI module is used.
168 * devpath: Path to the STREAMS device. Must be NULL for non-STREAMS
169 * based transports.
170 * devpathlen: Length of the devpath string. The argument can be 0,
171 * indicating that devpath was allocated statically, and should
172 * not be freed when the sockparams entry is destroyed.
174 * flags : SOCKPARAMS_EPHEMERAL is the only flag that is allowed.
175 * kmflags: KM_{NO,}SLEEP
176 * errorp : Value-return argument, set when an error occurs.
178 * Returns:
179 * On success a new sockparams entry is returned, and *errorp is set
180 * to 0. On failure NULL is returned and *errorp is set to indicate the
181 * type of error that occured.
183 * Notes:
184 * devpath and modname are freed upon failure.
186 struct sockparams *
187 sockparams_create(int family, int type, int protocol, char *modname,
188 char *devpath, int devpathlen, int flags, int kmflags, int *errorp)
190 struct sockparams *sp = NULL;
191 size_t size;
193 ASSERT((flags & ~SOCKPARAMS_EPHEMERAL) == 0);
194 if (flags & ~SOCKPARAMS_EPHEMERAL) {
195 *errorp = EINVAL;
196 goto error;
199 /* either a module or device must be given, but not both */
200 if (modname == NULL && devpath == NULL) {
201 *errorp = EINVAL;
202 goto error;
205 sp = kmem_zalloc(sizeof (*sp), kmflags);
206 if (sp == NULL) {
207 *errorp = ENOMEM;
208 goto error;
210 sp->sp_family = family;
211 sp->sp_type = type;
212 sp->sp_protocol = protocol;
213 sp->sp_refcnt = 0;
214 sp->sp_flags = flags;
216 list_create(&sp->sp_auto_filters, sizeof (sp_filter_t),
217 offsetof(sp_filter_t, spf_node));
218 list_create(&sp->sp_prog_filters, sizeof (sp_filter_t),
219 offsetof(sp_filter_t, spf_node));
221 kstat_named_init(&sp->sp_stats.sps_nfallback, "nfallback",
222 KSTAT_DATA_UINT64);
223 kstat_named_init(&sp->sp_stats.sps_nactive, "nactive",
224 KSTAT_DATA_UINT64);
225 kstat_named_init(&sp->sp_stats.sps_ncreate, "ncreate",
226 KSTAT_DATA_UINT64);
229 * Track how many ephemeral entries we have created.
231 if (sp->sp_flags & SOCKPARAMS_EPHEMERAL)
232 sp_g_stats.spgs_ephem_nalloc.value.ui64++;
234 if (modname != NULL) {
235 sp->sp_smod_name = modname;
236 } else {
237 size = strlen(SOTPI_SMOD_NAME) + 1;
238 modname = kmem_zalloc(size, kmflags);
239 if (modname == NULL) {
240 *errorp = ENOMEM;
241 goto error;
243 sp->sp_smod_name = modname;
244 (void) sprintf(sp->sp_smod_name, "%s", SOTPI_SMOD_NAME);
247 if (devpath != NULL) {
248 /* Set up the device entry. */
249 *errorp = sockparams_sdev_init(sp, devpath, devpathlen);
250 if (*errorp != 0)
251 goto error;
254 mutex_init(&sp->sp_lock, NULL, MUTEX_DEFAULT, NULL);
255 *errorp = 0;
256 return (sp);
257 error:
258 ASSERT(*errorp != 0);
259 if (modname != NULL)
260 kmem_free(modname, strlen(modname) + 1);
261 if (devpathlen != 0)
262 kmem_free(devpath, devpathlen);
263 if (sp != NULL)
264 kmem_free(sp, sizeof (*sp));
265 return (NULL);
269 * Initialize the STREAMS device aspect of the sockparams entry.
271 static int
272 sockparams_sdev_init(struct sockparams *sp, char *devpath, int devpathlen)
274 vnode_t *vp = NULL;
275 int error;
277 ASSERT(devpath != NULL);
279 if ((error = sogetvp(devpath, &vp, UIO_SYSSPACE)) != 0) {
280 dprint(0, ("sockparams_sdev_init: vp %s failed with %d\n",
281 devpath, error));
282 return (error);
285 ASSERT(vp != NULL);
286 sp->sp_sdev_info.sd_vnode = vp;
287 sp->sp_sdev_info.sd_devpath = devpath;
288 sp->sp_sdev_info.sd_devpathlen = devpathlen;
290 return (0);
294 * sockparams_destroy(struct sockparams *sp)
296 * Releases all the resources associated with the sockparams entry,
297 * and frees the sockparams entry.
299 * Arguments:
300 * sp: the sockparams entry to destroy.
302 * Returns:
303 * Nothing.
305 * Locking:
306 * The sp_lock of the entry can not be held.
308 void
309 sockparams_destroy(struct sockparams *sp)
311 ASSERT(sp->sp_refcnt == 0);
312 ASSERT(!list_link_active(&sp->sp_node));
314 sockparams_sdev_fini(sp);
316 if (sp->sp_smod_info != NULL)
317 SMOD_DEC_REF(sp->sp_smod_info, sp->sp_smod_name);
318 kmem_free(sp->sp_smod_name, strlen(sp->sp_smod_name) + 1);
319 sp->sp_smod_name = NULL;
320 sp->sp_smod_info = NULL;
321 mutex_destroy(&sp->sp_lock);
322 sockparams_kstat_fini(sp);
324 sof_sockparams_fini(sp);
325 list_destroy(&sp->sp_auto_filters);
326 list_destroy(&sp->sp_prog_filters);
328 kmem_free(sp, sizeof (*sp));
332 * Clean up the STREAMS device part of the sockparams entry.
334 static void
335 sockparams_sdev_fini(struct sockparams *sp)
337 sdev_info_t sd;
340 * if the entry does not have a STREAMS device, then there
341 * is nothing to do.
343 if (!SOCKPARAMS_HAS_DEVICE(sp))
344 return;
346 sd = sp->sp_sdev_info;
347 if (sd.sd_vnode != NULL)
348 VN_RELE(sd.sd_vnode);
349 if (sd.sd_devpathlen != 0)
350 kmem_free(sd.sd_devpath, sd.sd_devpathlen);
352 sp->sp_sdev_info.sd_vnode = NULL;
353 sp->sp_sdev_info.sd_devpath = NULL;
357 * Look for a matching sockparams entry on the given list.
358 * The caller must hold the associated list lock.
360 static struct sockparams *
361 sockparams_find(list_t *list, int family, int type, int protocol,
362 boolean_t by_devpath, const char *name)
364 struct sockparams *sp;
366 for (sp = list_head(list); sp != NULL; sp = list_next(list, sp)) {
367 if (sp->sp_family == family && sp->sp_type == type) {
368 if (sp->sp_protocol == protocol) {
369 if (name == NULL)
370 break;
371 else if (by_devpath &&
372 sp->sp_sdev_info.sd_devpath != NULL &&
373 strcmp(sp->sp_sdev_info.sd_devpath,
374 name) == 0)
375 break;
376 else if (strcmp(sp->sp_smod_name, name) == 0)
377 break;
381 return (sp);
385 * sockparams_hold_ephemeral()
387 * Returns an ephemeral sockparams entry of the requested family, type and
388 * protocol. The entry is returned held, and the caller is responsible for
389 * dropping the reference using SOCKPARAMS_DEC_REF() once done.
391 * All ephemeral entries are on list (sp_ephem_list). If there is an
392 * entry on the list that match the search criteria, then a reference is
393 * placed on that entry. Otherwise, a new entry is created and inserted
394 * in the list. The entry is removed from the list when the last reference
395 * is dropped.
397 * The tpi flag is used to determine whether name refers to a device or
398 * module name.
400 static struct sockparams *
401 sockparams_hold_ephemeral(int family, int type, int protocol,
402 const char *name, boolean_t by_devpath, int kmflag, int *errorp)
404 struct sockparams *sp = NULL;
405 *errorp = 0;
408 * First look for an existing entry
410 rw_enter(&sockconf_lock, RW_READER);
411 sp = sockparams_find(&sp_ephem_list, family, type, protocol,
412 by_devpath, name);
413 if (sp != NULL) {
414 SOCKPARAMS_INC_REF(sp);
415 rw_exit(&sockconf_lock);
416 sp_g_stats.spgs_ephem_nreuse.value.ui64++;
418 return (sp);
419 } else {
420 struct sockparams *newsp = NULL;
421 char *namebuf = NULL;
422 int namelen = 0;
424 rw_exit(&sockconf_lock);
426 namelen = strlen(name) + 1;
427 namebuf = kmem_alloc(namelen, kmflag);
428 if (namebuf == NULL) {
429 *errorp = ENOMEM;
430 return (NULL);
433 (void *)strncpy(namebuf, name, namelen);
434 if (by_devpath) {
435 newsp = sockparams_create(family, type,
436 protocol, NULL, namebuf, namelen,
437 SOCKPARAMS_EPHEMERAL, kmflag, errorp);
438 } else {
439 newsp = sockparams_create(family, type,
440 protocol, namebuf, NULL, 0,
441 SOCKPARAMS_EPHEMERAL, kmflag, errorp);
444 if (newsp == NULL) {
445 ASSERT(*errorp != 0);
446 return (NULL);
450 * Time to load the socket module.
452 ASSERT(newsp->sp_smod_info == NULL);
453 newsp->sp_smod_info =
454 smod_lookup_byname(newsp->sp_smod_name);
455 if (newsp->sp_smod_info == NULL) {
456 /* Failed to load */
457 sockparams_destroy(newsp);
458 *errorp = ENXIO;
459 return (NULL);
463 * The sockparams entry was created, now try to add it
464 * to the list. We need to hold the lock as a WRITER.
466 rw_enter(&sockconf_lock, RW_WRITER);
467 sp = sockparams_find(&sp_ephem_list, family, type, protocol,
468 by_devpath, name);
469 if (sp != NULL) {
471 * Someone has requested a matching entry, so just
472 * place a hold on it and release the entry we alloc'ed.
474 SOCKPARAMS_INC_REF(sp);
475 rw_exit(&sockconf_lock);
477 sockparams_destroy(newsp);
478 } else {
479 *errorp = sof_sockparams_init(newsp);
480 if (*errorp != 0) {
481 rw_exit(&sockconf_lock);
482 sockparams_destroy(newsp);
483 return (NULL);
485 SOCKPARAMS_INC_REF(newsp);
486 list_insert_tail(&sp_ephem_list, newsp);
487 rw_exit(&sockconf_lock);
489 sp = newsp;
491 ASSERT(*errorp == 0);
493 return (sp);
497 struct sockparams *
498 sockparams_hold_ephemeral_bydev(int family, int type, int protocol,
499 const char *dev, int kmflag, int *errorp)
501 return (sockparams_hold_ephemeral(family, type, protocol, dev, B_TRUE,
502 kmflag, errorp));
505 struct sockparams *
506 sockparams_hold_ephemeral_bymod(int family, int type, int protocol,
507 const char *mod, int kmflag, int *errorp)
509 return (sockparams_hold_ephemeral(family, type, protocol, mod, B_FALSE,
510 kmflag, errorp));
514 * Called when the last socket using the ephemeral entry is dropping
515 * its' reference. To maintain lock order we must drop the sockparams
516 * lock before calling this function. As a result, a new reference
517 * might be placed on the entry, in which case there is nothing to
518 * do. However, if ref count goes to zero, we delete the entry.
520 void
521 sockparams_ephemeral_drop_last_ref(struct sockparams *sp)
523 ASSERT(sp->sp_flags & SOCKPARAMS_EPHEMERAL);
524 ASSERT(MUTEX_NOT_HELD(&sp->sp_lock));
526 rw_enter(&sockconf_lock, RW_WRITER);
527 mutex_enter(&sp->sp_lock);
529 if (--sp->sp_refcnt == 0) {
530 list_remove(&sp_ephem_list, sp);
531 mutex_exit(&sp->sp_lock);
532 rw_exit(&sockconf_lock);
534 sockparams_destroy(sp);
535 } else {
536 mutex_exit(&sp->sp_lock);
537 rw_exit(&sockconf_lock);
542 * sockparams_add(struct sockparams *sp)
544 * Tries to add the given sockparams entry to the global list.
546 * Arguments:
547 * sp: the sockparms entry to add
549 * Returns:
550 * On success 0, but if an entry already exists, then EEXIST
551 * is returned.
553 * Locking:
554 * The caller can not be holding sockconf_lock.
557 sockparams_add(struct sockparams *sp)
559 int error;
561 ASSERT(!(sp->sp_flags & SOCKPARAMS_EPHEMERAL));
563 rw_enter(&sockconf_lock, RW_WRITER);
564 if (sockparams_find(&sphead, sp->sp_family, sp->sp_type,
565 sp->sp_protocol, B_TRUE, NULL) != 0) {
566 rw_exit(&sockconf_lock);
567 return (EEXIST);
568 } else {
570 * Unique sockparams entry, so init the kstats.
572 sockparams_kstat_init(sp);
575 * Before making the socket type available we must make
576 * sure that interested socket filters are aware of it.
578 error = sof_sockparams_init(sp);
579 if (error != 0) {
580 rw_exit(&sockconf_lock);
581 return (error);
583 list_insert_tail(&sphead, sp);
584 rw_exit(&sockconf_lock);
585 return (0);
590 * sockparams_delete(int family, int type, int protocol)
592 * Marks the sockparams entry for a specific family, type and protocol
593 * for deletion. The entry is removed from the list and destroyed
594 * if no one is holding a reference to it.
596 * Arguments:
597 * family, type, protocol: the socket type that should be removed.
599 * Returns:
600 * On success 0, otherwise ENXIO.
602 * Locking:
603 * Caller can not be holding sockconf_lock or the sp_lock of
604 * any sockparams entry.
607 sockparams_delete(int family, int type, int protocol)
609 struct sockparams *sp;
611 rw_enter(&sockconf_lock, RW_WRITER);
612 sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL);
614 if (sp != NULL) {
616 * If no one is holding a reference to the entry, then
617 * we go ahead and remove it from the list and then
618 * destroy it.
620 mutex_enter(&sp->sp_lock);
621 if (sp->sp_refcnt != 0) {
622 mutex_exit(&sp->sp_lock);
623 rw_exit(&sockconf_lock);
624 return (EBUSY);
626 mutex_exit(&sp->sp_lock);
627 /* Delete the sockparams entry. */
628 list_remove(&sphead, sp);
629 rw_exit(&sockconf_lock);
631 sockparams_destroy(sp);
632 return (0);
633 } else {
634 rw_exit(&sockconf_lock);
635 return (ENXIO);
641 * solookup(int family, int type, int protocol, struct sockparams **spp)
643 * Lookup an entry in the sockparams list based on the triple. The returned
644 * entry either exactly match the given tuple, or it is the 'default' entry
645 * for the given <family, type>. A default entry is on with a protocol
646 * value of zero.
648 * Arguments:
649 * family, type, protocol: tuple to search for
650 * spp: Value-return argument
652 * Returns:
653 * If an entry is found, 0 is returned and *spp is set to point to the
654 * entry. In case an entry is not found, *spp is set to NULL, and an
655 * error code is returned. The errors are (in decreasing precedence):
656 * EAFNOSUPPORT - address family not in list
657 * EPROTONOSUPPORT - address family supported but not protocol.
658 * EPROTOTYPE - address family and protocol supported but not socket type.
660 * TODO: should use ddi_modopen()/ddi_modclose()
663 solookup(int family, int type, int protocol, struct sockparams **spp)
665 struct sockparams *sp = NULL;
666 int error = 0;
668 *spp = NULL;
669 rw_enter(&sockconf_lock, RW_READER);
672 * Search the sockparams list for an appropiate entry.
673 * Hopefully we find an entry that match the exact family,
674 * type and protocol specified by the user, in which case
675 * we return that entry. However, we also keep track of
676 * the default entry for a specific family and type, the
677 * entry of which would have a protocol value of 0.
679 sp = sockparams_find(&sphead, family, type, protocol, B_TRUE, NULL);
681 if (sp == NULL) {
682 int found = 0;
684 /* Determine correct error code */
685 for (sp = list_head(&sphead); sp != NULL;
686 sp = list_next(&sphead, sp)) {
687 if (sp->sp_family == family && found < 1)
688 found = 1;
689 if (sp->sp_family == family &&
690 sp->sp_protocol == protocol && found < 2)
691 found = 2;
693 rw_exit(&sockconf_lock);
694 switch (found) {
695 case 0:
696 error = EAFNOSUPPORT;
697 break;
698 case 1:
699 error = EPROTONOSUPPORT;
700 break;
701 case 2:
702 error = EPROTOTYPE;
703 break;
705 return (error);
709 * An entry was found.
711 * We put a hold on the entry early on, so if the
712 * sockmod is not loaded, and we have to exit
713 * sockconf_lock to call modload(), we know that the
714 * sockparams entry wont go away. That way we don't
715 * have to look up the entry once we come back from
716 * modload().
718 SOCKPARAMS_INC_REF(sp);
719 rw_exit(&sockconf_lock);
721 if (sp->sp_smod_info == NULL) {
722 smod_info_t *smod = smod_lookup_byname(sp->sp_smod_name);
724 if (smod == NULL) {
726 * We put a hold on the sockparams entry
727 * earlier, hoping everything would work out.
728 * That obviously did not happen, so release
729 * the hold here.
731 SOCKPARAMS_DEC_REF(sp);
733 * We should probably mark the sockparams as
734 * "bad", and redo the lookup skipping the
735 * "bad" entries. I.e., sp->sp_mod_state |= BAD,
736 * return (solookup(...))
738 return (ENXIO);
741 * Another thread might have already looked up the socket
742 * module for this entry. In that case we need to drop our
743 * reference to `smod' to ensure that the sockparams entry
744 * only holds one reference.
746 mutex_enter(&sp->sp_lock);
747 if (sp->sp_smod_info == NULL)
748 sp->sp_smod_info = smod;
749 else
750 SMOD_DEC_REF(smod, sp->sp_smod_name);
751 mutex_exit(&sp->sp_lock);
755 * Alright, we have a valid sockparams entry.
757 *spp = sp;
758 return (0);
762 * Called when filter entry `ent' is going away. All sockparams remove
763 * their references to `ent'.
765 static void
766 sockparams_filter_cleanup_impl(sof_entry_t *ent, list_t *list)
768 struct sockparams *sp;
769 sp_filter_t *fil;
770 list_t *flist;
772 ASSERT(RW_WRITE_HELD(&sockconf_lock));
774 for (sp = list_head(list); sp != NULL;
775 sp = list_next(list, sp)) {
776 flist = (ent->sofe_flags & SOFEF_AUTO) ?
777 &sp->sp_auto_filters : &sp->sp_prog_filters;
778 for (fil = list_head(flist); fil != NULL;
779 fil = list_next(flist, fil)) {
780 if (fil->spf_filter == ent) {
781 list_remove(flist, fil);
782 kmem_free(fil, sizeof (sp_filter_t));
783 break;
788 void
789 sockparams_filter_cleanup(sof_entry_t *ent)
791 sockparams_filter_cleanup_impl(ent, &sphead);
792 sockparams_filter_cleanup_impl(ent, &sp_ephem_list);
796 * New filter is being added; walk the list of sockparams to see if
797 * the filter is interested in any of the sockparams.
799 static int
800 sockparams_new_filter_impl(sof_entry_t *ent, list_t *list)
802 struct sockparams *sp;
803 int err;
805 ASSERT(RW_WRITE_HELD(&sockconf_lock));
807 for (sp = list_head(list); sp != NULL;
808 sp = list_next(list, sp)) {
809 if ((err = sof_entry_proc_sockparams(ent, sp)) != 0) {
810 sockparams_filter_cleanup(ent);
811 return (err);
814 return (0);
818 sockparams_new_filter(sof_entry_t *ent)
820 int error;
822 if ((error = sockparams_new_filter_impl(ent, &sphead)) != 0)
823 return (error);
825 if ((error = sockparams_new_filter_impl(ent, &sp_ephem_list)) != 0)
826 sockparams_filter_cleanup_impl(ent, &sphead);
827 return (error);
831 * Setup and return socket configuration table.
834 sockparams_copyout_socktable(uintptr_t socktable)
836 STRUCT_DECL(sockconfig_socktable, st);
837 struct sockparams *sp;
838 uint_t count;
839 uint_t i = 0;
840 int ret = 0;
841 sockconfig_socktable_entry_t *se;
843 STRUCT_INIT(st, get_udatamodel());
844 if (ddi_copyin((void *)socktable, STRUCT_BUF(st),
845 STRUCT_SIZE(st), 0) != 0)
846 return (EFAULT);
848 rw_enter(&sockconf_lock, RW_READER);
850 count = STRUCT_FGET(st, num_of_entries);
852 * If the output buffer is size zero, just copy out the count.
854 if (count == 0) {
855 for (sp = list_head(&sphead); sp != NULL;
856 sp = list_next(&sphead, sp)) {
857 count++;
859 STRUCT_FSET(st, num_of_entries, count);
861 rw_exit(&sockconf_lock);
862 if (ddi_copyout(STRUCT_BUF(st), (void *)socktable,
863 STRUCT_SIZE(st), 0) != 0)
864 return (EFAULT);
866 return (0);
869 se = kmem_alloc(count * sizeof (sockconfig_socktable_entry_t),
870 KM_SLEEP);
871 for (sp = list_head(&sphead); sp != NULL;
872 sp = list_next(&sphead, sp)) {
873 if (i >= count) {
875 * Return if the number of entries has changed.
877 rw_exit(&sockconf_lock);
878 kmem_free(se,
879 count * sizeof (sockconfig_socktable_entry_t));
880 return (EAGAIN);
882 se[i].se_family = sp->sp_family;
883 se[i].se_type = sp->sp_type;
884 se[i].se_protocol = sp->sp_protocol;
885 (void) strncpy(se[i].se_modname, sp->sp_smod_name,
886 MODMAXNAMELEN);
887 if (sp->sp_sdev_info.sd_devpath != NULL)
888 (void) strncpy(se[i].se_strdev,
889 sp->sp_sdev_info.sd_devpath, MAXPATHLEN);
890 se[i].se_refcnt = sp->sp_refcnt;
891 se[i].se_flags = sp->sp_flags;
892 i++;
894 rw_exit(&sockconf_lock);
895 if (ddi_copyout(se, STRUCT_FGETP(st, st_entries),
896 i * sizeof (sockconfig_socktable_entry_t), 0) != 0)
897 ret = EFAULT;
899 STRUCT_FSET(st, num_of_entries, i);
900 kmem_free(se, count * sizeof (sockconfig_socktable_entry_t));
902 if (ddi_copyout(STRUCT_BUF(st), (void *)socktable,
903 STRUCT_SIZE(st), 0) != 0)
904 ret = EFAULT;
906 return (ret);