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]
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>
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"
47 * Socket parameter (struct sockparams) entries represent the socket types
48 * available on the system.
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.
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)).
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
;
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",
96 kstat_named_init(&sp_g_stats
.spgs_ephem_nreuse
, "ephemeral_nreuse",
99 sp_g_kstat
= kstat_create("sockfs", 0, "sockparams", "misc",
100 KSTAT_TYPE_NAMED
, sizeof (sp_g_stats
) / sizeof (kstat_named_t
),
102 if (sp_g_kstat
== NULL
)
105 sp_g_kstat
->ks_data
= &sp_g_stats
;
107 kstat_install(sp_g_kstat
);
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
)
119 sps
->sps_nactive
.value
.ui64
= sp
->sp_refcnt
;
125 * Setup kstats for the given sockparams entry.
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
),
139 if (sp
->sp_kstat
== NULL
)
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
);
149 sockparams_kstat_fini(struct sockparams
*sp
)
151 if (sp
->sp_kstat
!= NULL
) {
152 kstat_delete(sp
->sp_kstat
);
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.
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
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.
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.
184 * devpath and modname are freed upon failure.
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
;
193 ASSERT((flags
& ~SOCKPARAMS_EPHEMERAL
) == 0);
194 if (flags
& ~SOCKPARAMS_EPHEMERAL
) {
199 /* either a module or device must be given, but not both */
200 if (modname
== NULL
&& devpath
== NULL
) {
205 sp
= kmem_zalloc(sizeof (*sp
), kmflags
);
210 sp
->sp_family
= family
;
212 sp
->sp_protocol
= protocol
;
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",
223 kstat_named_init(&sp
->sp_stats
.sps_nactive
, "nactive",
225 kstat_named_init(&sp
->sp_stats
.sps_ncreate
, "ncreate",
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
;
237 size
= strlen(SOTPI_SMOD_NAME
) + 1;
238 modname
= kmem_zalloc(size
, kmflags
);
239 if (modname
== NULL
) {
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
);
254 mutex_init(&sp
->sp_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
258 ASSERT(*errorp
!= 0);
260 kmem_free(modname
, strlen(modname
) + 1);
262 kmem_free(devpath
, devpathlen
);
264 kmem_free(sp
, sizeof (*sp
));
269 * Initialize the STREAMS device aspect of the sockparams entry.
272 sockparams_sdev_init(struct sockparams
*sp
, char *devpath
, int devpathlen
)
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",
286 sp
->sp_sdev_info
.sd_vnode
= vp
;
287 sp
->sp_sdev_info
.sd_devpath
= devpath
;
288 sp
->sp_sdev_info
.sd_devpathlen
= devpathlen
;
294 * sockparams_destroy(struct sockparams *sp)
296 * Releases all the resources associated with the sockparams entry,
297 * and frees the sockparams entry.
300 * sp: the sockparams entry to destroy.
306 * The sp_lock of the entry can not be held.
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.
335 sockparams_sdev_fini(struct sockparams
*sp
)
340 * if the entry does not have a STREAMS device, then there
343 if (!SOCKPARAMS_HAS_DEVICE(sp
))
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
) {
371 else if (by_devpath
&&
372 sp
->sp_sdev_info
.sd_devpath
!= NULL
&&
373 strcmp(sp
->sp_sdev_info
.sd_devpath
,
376 else if (strcmp(sp
->sp_smod_name
, name
) == 0)
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
397 * The tpi flag is used to determine whether name refers to a device or
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
;
408 * First look for an existing entry
410 rw_enter(&sockconf_lock
, RW_READER
);
411 sp
= sockparams_find(&sp_ephem_list
, family
, type
, protocol
,
414 SOCKPARAMS_INC_REF(sp
);
415 rw_exit(&sockconf_lock
);
416 sp_g_stats
.spgs_ephem_nreuse
.value
.ui64
++;
420 struct sockparams
*newsp
= NULL
;
421 char *namebuf
= NULL
;
424 rw_exit(&sockconf_lock
);
426 namelen
= strlen(name
) + 1;
427 namebuf
= kmem_alloc(namelen
, kmflag
);
428 if (namebuf
== NULL
) {
433 (void *)strncpy(namebuf
, name
, namelen
);
435 newsp
= sockparams_create(family
, type
,
436 protocol
, NULL
, namebuf
, namelen
,
437 SOCKPARAMS_EPHEMERAL
, kmflag
, errorp
);
439 newsp
= sockparams_create(family
, type
,
440 protocol
, namebuf
, NULL
, 0,
441 SOCKPARAMS_EPHEMERAL
, kmflag
, errorp
);
445 ASSERT(*errorp
!= 0);
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
) {
457 sockparams_destroy(newsp
);
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
,
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
);
479 *errorp
= sof_sockparams_init(newsp
);
481 rw_exit(&sockconf_lock
);
482 sockparams_destroy(newsp
);
485 SOCKPARAMS_INC_REF(newsp
);
486 list_insert_tail(&sp_ephem_list
, newsp
);
487 rw_exit(&sockconf_lock
);
491 ASSERT(*errorp
== 0);
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
,
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
,
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.
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
);
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.
547 * sp: the sockparms entry to add
550 * On success 0, but if an entry already exists, then EEXIST
554 * The caller can not be holding sockconf_lock.
557 sockparams_add(struct sockparams
*sp
)
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
);
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
);
580 rw_exit(&sockconf_lock
);
583 list_insert_tail(&sphead
, sp
);
584 rw_exit(&sockconf_lock
);
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.
597 * family, type, protocol: the socket type that should be removed.
600 * On success 0, otherwise ENXIO.
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
);
616 * If no one is holding a reference to the entry, then
617 * we go ahead and remove it from the list and then
620 mutex_enter(&sp
->sp_lock
);
621 if (sp
->sp_refcnt
!= 0) {
622 mutex_exit(&sp
->sp_lock
);
623 rw_exit(&sockconf_lock
);
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
);
634 rw_exit(&sockconf_lock
);
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
649 * family, type, protocol: tuple to search for
650 * spp: Value-return argument
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
;
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
);
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)
689 if (sp
->sp_family
== family
&&
690 sp
->sp_protocol
== protocol
&& found
< 2)
693 rw_exit(&sockconf_lock
);
696 error
= EAFNOSUPPORT
;
699 error
= EPROTONOSUPPORT
;
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
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
);
726 * We put a hold on the sockparams entry
727 * earlier, hoping everything would work out.
728 * That obviously did not happen, so release
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(...))
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
;
750 SMOD_DEC_REF(smod
, sp
->sp_smod_name
);
751 mutex_exit(&sp
->sp_lock
);
755 * Alright, we have a valid sockparams entry.
762 * Called when filter entry `ent' is going away. All sockparams remove
763 * their references to `ent'.
766 sockparams_filter_cleanup_impl(sof_entry_t
*ent
, list_t
*list
)
768 struct sockparams
*sp
;
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
));
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.
800 sockparams_new_filter_impl(sof_entry_t
*ent
, list_t
*list
)
802 struct sockparams
*sp
;
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
);
818 sockparams_new_filter(sof_entry_t
*ent
)
822 if ((error
= sockparams_new_filter_impl(ent
, &sphead
)) != 0)
825 if ((error
= sockparams_new_filter_impl(ent
, &sp_ephem_list
)) != 0)
826 sockparams_filter_cleanup_impl(ent
, &sphead
);
831 * Setup and return socket configuration table.
834 sockparams_copyout_socktable(uintptr_t socktable
)
836 STRUCT_DECL(sockconfig_socktable
, st
);
837 struct sockparams
*sp
;
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)
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.
855 for (sp
= list_head(&sphead
); sp
!= NULL
;
856 sp
= list_next(&sphead
, sp
)) {
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)
869 se
= kmem_alloc(count
* sizeof (sockconfig_socktable_entry_t
),
871 for (sp
= list_head(&sphead
); sp
!= NULL
;
872 sp
= list_next(&sphead
, sp
)) {
875 * Return if the number of entries has changed.
877 rw_exit(&sockconf_lock
);
879 count
* sizeof (sockconfig_socktable_entry_t
));
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
,
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
;
894 rw_exit(&sockconf_lock
);
895 if (ddi_copyout(se
, STRUCT_FGETP(st
, st_entries
),
896 i
* sizeof (sockconfig_socktable_entry_t
), 0) != 0)
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)