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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2017 Joyent, Inc.
28 * Data-Link Services Module
31 #include <sys/sysmacros.h>
32 #include <sys/strsubr.h>
33 #include <sys/strsun.h>
35 #include <sys/dld_impl.h>
37 #include <sys/atomic.h>
39 static kmem_cache_t
*i_dls_link_cachep
;
40 mod_hash_t
*i_dls_link_hash
;
41 static uint_t i_dls_link_count
;
43 #define LINK_HASHSZ 67 /* prime */
44 #define IMPL_HASHSZ 67 /* prime */
47 * Construct a hash key from the DLSAP value.
49 #define MAKE_KEY(_sap) \
50 ((mod_hash_key_t)(uintptr_t)((_sap) << VLAN_ID_SIZE))
52 #define DLS_STRIP_PADDING(pktsize, p) { \
54 ssize_t delta = pktsize - msgdsize(p); \
57 (void) adjmsg(p, delta); \
67 i_dls_link_constructor(void *buf
, void *arg
, int kmflag
)
69 dls_link_t
*dlp
= buf
;
70 char name
[MAXNAMELEN
];
72 bzero(buf
, sizeof (dls_link_t
));
74 (void) snprintf(name
, MAXNAMELEN
, "dls_link_t_%p_hash", buf
);
75 dlp
->dl_str_hash
= mod_hash_create_idhash(name
, IMPL_HASHSZ
,
76 mod_hash_null_valdtor
);
83 i_dls_link_destructor(void *buf
, void *arg
)
85 dls_link_t
*dlp
= buf
;
87 ASSERT(dlp
->dl_ref
== 0);
88 ASSERT(dlp
->dl_mh
== NULL
);
89 ASSERT(dlp
->dl_mah
== NULL
);
90 ASSERT(dlp
->dl_unknowns
== 0);
92 mod_hash_destroy_idhash(dlp
->dl_str_hash
);
93 dlp
->dl_str_hash
= NULL
;
98 * - Parse the mac header information of the given packet.
99 * - Strip the padding and skip over the header. Note that because some
100 * DLS consumers only check the db_ref count of the first mblk, we
101 * pullup the message into a single mblk. Because the original message
102 * is freed as the result of message pulling up, mac_vlan_header_info()
103 * is called again to update the mhi_saddr and mhi_daddr pointers in the
104 * mhip. Further, the mac_vlan_header_info() function ensures that the
105 * size of the pulled message is greater than the MAC header size,
106 * therefore we can directly advance b_rptr to point at the payload.
108 * We choose to use a macro for performance reasons.
110 #define DLS_PREPARE_PKT(mh, mp, mhip, err) { \
111 mblk_t *nextp = (mp)->b_next; \
112 if (((err) = mac_vlan_header_info((mh), (mp), (mhip))) == 0) { \
113 DLS_STRIP_PADDING((mhip)->mhi_pktsize, (mp)); \
114 if (MBLKL((mp)) < (mhip)->mhi_hdrsize) { \
116 if ((newmp = msgpullup((mp), -1)) == NULL) { \
119 (mp)->b_next = NULL; \
122 VERIFY(mac_vlan_header_info((mh), \
123 (mp), (mhip)) == 0); \
124 (mp)->b_next = nextp; \
125 (mp)->b_rptr += (mhip)->mhi_hdrsize; \
128 (mp)->b_rptr += (mhip)->mhi_hdrsize; \
134 * Truncate the chain starting at mp such that all packets in the chain
135 * have identical source and destination addresses, saps, and tag types
136 * (see below). It returns a pointer to the mblk following the chain,
137 * NULL if there is no further packet following the processed chain.
138 * The countp argument is set to the number of valid packets in the chain.
139 * Note that the whole MAC header (including the VLAN tag if any) in each
140 * packet will be stripped.
143 i_dls_link_subchain(dls_link_t
*dlp
, mblk_t
*mp
, const mac_header_info_t
*mhip
,
148 size_t addr_size
= dlp
->dl_mip
->mi_addr_length
;
149 uint16_t vid
= VLAN_ID(mhip
->mhi_tci
);
150 uint16_t pri
= VLAN_PRI(mhip
->mhi_tci
);
153 * Compare with subsequent headers until we find one that has
154 * differing header information. After checking each packet
155 * strip padding and skip over the header.
157 for (prevp
= mp
; (mp
= mp
->b_next
) != NULL
; prevp
= mp
) {
158 mac_header_info_t cmhi
;
162 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &cmhi
, err
);
169 * The source, destination, sap, vlan tag must all match in
172 if (mhip
->mhi_saddr
== NULL
|| cmhi
.mhi_saddr
== NULL
||
173 memcmp(mhip
->mhi_daddr
, cmhi
.mhi_daddr
, addr_size
) != 0 ||
174 memcmp(mhip
->mhi_saddr
, cmhi
.mhi_saddr
, addr_size
) != 0 ||
175 mhip
->mhi_bindsap
!= cmhi
.mhi_bindsap
) {
177 * Note that we don't need to restore the padding.
179 mp
->b_rptr
-= cmhi
.mhi_hdrsize
;
183 cvid
= VLAN_ID(cmhi
.mhi_tci
);
184 cpri
= VLAN_PRI(cmhi
.mhi_tci
);
187 * There are several types of packets. Packets don't match
188 * if they are classified to different type or if they are
189 * VLAN packets but belong to different VLANs:
191 * packet type tagged vid pri
192 * ---------------------------------------------------------
193 * untagged No zero zero
194 * VLAN packets Yes non-zero -
195 * priority tagged Yes zero non-zero
196 * 0 tagged Yes zero zero
198 if ((mhip
->mhi_istagged
!= cmhi
.mhi_istagged
) ||
199 (vid
!= cvid
) || ((vid
== VLAN_ID_NONE
) &&
200 (((pri
== 0) && (cpri
!= 0)) ||
201 ((pri
!= 0) && (cpri
== 0))))) {
202 mp
->b_rptr
-= cmhi
.mhi_hdrsize
;
210 * Break the chain at this point and return a pointer to the next
213 prevp
->b_next
= NULL
;
220 i_dls_head_hold(mod_hash_key_t key
, mod_hash_val_t val
)
222 dls_head_t
*dhp
= (dls_head_t
*)val
;
225 * The lock order is mod_hash's internal lock -> dh_lock as in the
226 * call to i_dls_link_rx -> mod_hash_find_cb_rval -> i_dls_head_hold
228 mutex_enter(&dhp
->dh_lock
);
229 if (dhp
->dh_removing
) {
230 mutex_exit(&dhp
->dh_lock
);
234 mutex_exit(&dhp
->dh_lock
);
239 i_dls_head_rele(dls_head_t
*dhp
)
241 mutex_enter(&dhp
->dh_lock
);
243 if (dhp
->dh_ref
== 0 && dhp
->dh_removing
!= 0)
244 cv_broadcast(&dhp
->dh_cv
);
245 mutex_exit(&dhp
->dh_lock
);
249 i_dls_head_alloc(mod_hash_key_t key
)
253 dhp
= kmem_zalloc(sizeof (dls_head_t
), KM_SLEEP
);
259 i_dls_head_free(dls_head_t
*dhp
)
261 ASSERT(dhp
->dh_ref
== 0);
262 kmem_free(dhp
, sizeof (dls_head_t
));
266 * Try to send mp up to the streams of the given sap. Return the
267 * number of streams which accepted this message, or 0 if no streams
268 * accepted the message.
270 * Note that this function copies the message chain and the original
271 * mp remains valid after this function returns.
274 i_dls_link_rx_func(dls_link_t
*dlp
, mac_resource_handle_t mrh
,
275 mac_header_info_t
*mhip
, mblk_t
*mp
, uint32_t sap
,
276 boolean_t (*acceptfunc
)())
278 mod_hash_t
*hash
= dlp
->dl_str_hash
;
285 uint_t naccepted
= 0;
289 * Construct a hash key from the DLSAP.
294 * Search the hash table for a dld_str_t eligible to receive a
295 * packet chain for this DLSAP. The mod hash's internal lock
296 * serializes find/insert/remove from the mod hash list.
297 * Incrementing the dh_ref (while holding the mod hash lock)
298 * ensures dls_link_remove will wait for the upcall to finish.
300 if (mod_hash_find_cb_rval(hash
, key
, (mod_hash_val_t
*)&dhp
,
301 i_dls_head_hold
, &rval
) != 0 || (rval
!= 0)) {
306 * Find all dld_str_t that will accept the sub-chain.
308 for (dsp
= dhp
->dh_list
; dsp
!= NULL
; dsp
= dsp
->ds_next
) {
309 if (!acceptfunc(dsp
, mhip
, &ds_rx
, &ds_rx_arg
))
313 * We have at least one acceptor.
318 * There will normally be at least one more dld_str_t
319 * (since we've yet to check for non-promiscuous
320 * dld_str_t) so dup the sub-chain.
322 if ((nmp
= copymsgchain(mp
)) != NULL
)
323 ds_rx(ds_rx_arg
, mrh
, nmp
, mhip
);
327 * Release the hold on the dld_str_t chain now that we have
328 * finished walking it.
330 i_dls_head_rele(dhp
);
336 i_dls_link_rx(void *arg
, mac_resource_handle_t mrh
, mblk_t
*mp
,
339 dls_link_t
*dlp
= arg
;
340 mod_hash_t
*hash
= dlp
->dl_str_hash
;
342 mac_header_info_t mhi
;
350 dls_rx_t ds_rx
, nds_rx
;
351 void *ds_rx_arg
, *nds_rx_arg
;
356 * Walk the packet chain.
358 for (; mp
!= NULL
; mp
= nextp
) {
360 * Wipe the accepted state.
364 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &mhi
, err
);
366 atomic_inc_32(&(dlp
->dl_unknowns
));
374 * Grab the longest sub-chain we can process as a single
377 nextp
= i_dls_link_subchain(dlp
, mp
, &mhi
, &npacket
);
378 ASSERT(npacket
!= 0);
380 vid
= VLAN_ID(mhi
.mhi_tci
);
382 if (mhi
.mhi_istagged
) {
384 * If it is tagged traffic, send it upstream to
385 * all dld_str_t which are attached to the physical
386 * link and bound to SAP 0x8100.
388 if (i_dls_link_rx_func(dlp
, mrh
, &mhi
, mp
,
389 ETHERTYPE_VLAN
, dls_accept
) > 0) {
394 * Don't pass the packets up if they are tagged
396 * - their VID and priority are both zero and the
397 * original packet isn't using the PVID (invalid
399 * - their sap is ETHERTYPE_VLAN and their VID is
400 * zero as they have already been sent upstreams.
402 if ((vid
== VLAN_ID_NONE
&& !mhi
.mhi_ispvid
&&
403 VLAN_PRI(mhi
.mhi_tci
) == 0) ||
404 (mhi
.mhi_bindsap
== ETHERTYPE_VLAN
&&
405 vid
== VLAN_ID_NONE
)) {
412 * Construct a hash key from the DLSAP.
414 key
= MAKE_KEY(mhi
.mhi_bindsap
);
417 * Search the hash table for dld_str_t eligible to receive
418 * a packet chain for this DLSAP.
420 if (mod_hash_find_cb_rval(hash
, key
, (mod_hash_val_t
*)&dhp
,
421 i_dls_head_hold
, &rval
) != 0 || (rval
!= 0)) {
427 * Find the first dld_str_t that will accept the sub-chain.
429 for (dsp
= dhp
->dh_list
; dsp
!= NULL
; dsp
= dsp
->ds_next
)
430 if (dls_accept(dsp
, &mhi
, &ds_rx
, &ds_rx_arg
))
434 * If we did not find any dld_str_t willing to accept the
435 * sub-chain then throw it away.
438 i_dls_head_rele(dhp
);
444 * We have at least one acceptor.
449 * Find the next dld_str_t that will accept the
452 for (ndsp
= dsp
->ds_next
; ndsp
!= NULL
;
453 ndsp
= ndsp
->ds_next
)
454 if (dls_accept(ndsp
, &mhi
, &nds_rx
,
459 * If there are no more dld_str_t that are willing
460 * to accept the sub-chain then we don't need to dup
461 * it before handing it to the current one.
464 ds_rx(ds_rx_arg
, mrh
, mp
, &mhi
);
467 * Since there are no more dld_str_t, we're
474 * There are more dld_str_t so dup the sub-chain.
476 if ((nmp
= copymsgchain(mp
)) != NULL
)
477 ds_rx(ds_rx_arg
, mrh
, nmp
, &mhi
);
481 ds_rx_arg
= nds_rx_arg
;
485 * Release the hold on the dld_str_t chain now that we have
486 * finished walking it.
488 i_dls_head_rele(dhp
);
492 * If there were no acceptors then add the packet count to the
496 atomic_add_32(&(dlp
->dl_unknowns
), npacket
);
502 dls_rx_vlan_promisc(void *arg
, mac_resource_handle_t mrh
, mblk_t
*mp
,
505 dld_str_t
*dsp
= arg
;
506 dls_link_t
*dlp
= dsp
->ds_dlp
;
507 mac_header_info_t mhi
;
512 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &mhi
, err
);
517 * If there is promiscuous handle for vlan, we filter out the untagged
518 * pkts and pkts that are not for the primary unicast address.
520 if (dsp
->ds_vlan_mph
!= NULL
) {
521 uint8_t prim_addr
[MAXMACADDRLEN
];
522 size_t addr_length
= dsp
->ds_mip
->mi_addr_length
;
524 if (!(mhi
.mhi_istagged
))
526 ASSERT(dsp
->ds_mh
!= NULL
);
527 mac_unicast_primary_get(dsp
->ds_mh
, (uint8_t *)prim_addr
);
528 if (memcmp(mhi
.mhi_daddr
, prim_addr
, addr_length
) != 0)
531 if (!dls_accept(dsp
, &mhi
, &ds_rx
, &ds_rx_arg
))
534 ds_rx(ds_rx_arg
, NULL
, mp
, &mhi
);
539 atomic_inc_32(&dlp
->dl_unknowns
);
545 dls_rx_promisc(void *arg
, mac_resource_handle_t mrh
, mblk_t
*mp
,
548 dld_str_t
*dsp
= arg
;
549 dls_link_t
*dlp
= dsp
->ds_dlp
;
550 mac_header_info_t mhi
;
557 DLS_PREPARE_PKT(dlp
->dl_mh
, mp
, &mhi
, err
);
562 * In order to filter out sap pkt that no dls channel listens, search
563 * the hash table trying to find a dld_str_t eligible to receive the pkt
565 if ((dsp
->ds_promisc
& DLS_PROMISC_SAP
) == 0) {
566 key
= MAKE_KEY(mhi
.mhi_bindsap
);
567 if (mod_hash_find(dsp
->ds_dlp
->dl_str_hash
, key
,
568 (mod_hash_val_t
*)&dhp
) != 0)
572 if (!dls_accept_promisc(dsp
, &mhi
, &ds_rx
, &ds_rx_arg
, loopback
))
575 ds_rx(ds_rx_arg
, NULL
, mp
, &mhi
);
579 atomic_inc_32(&dlp
->dl_unknowns
);
584 i_dls_link_destroy(dls_link_t
*dlp
)
586 ASSERT(dlp
->dl_nactive
== 0);
587 ASSERT(dlp
->dl_impl_count
== 0);
588 ASSERT(dlp
->dl_zone_ref
== 0);
591 * Free the structure back to the cache.
593 if (dlp
->dl_mch
!= NULL
)
594 mac_client_close(dlp
->dl_mch
, 0);
596 if (dlp
->dl_mh
!= NULL
) {
597 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
598 mac_close(dlp
->dl_mh
);
604 dlp
->dl_unknowns
= 0;
605 dlp
->dl_nonip_cnt
= 0;
606 kmem_cache_free(i_dls_link_cachep
, dlp
);
610 i_dls_link_create(const char *name
, dls_link_t
**dlpp
)
616 * Allocate a new dls_link_t structure.
618 dlp
= kmem_cache_alloc(i_dls_link_cachep
, KM_SLEEP
);
621 * Name the dls_link_t after the MAC interface it represents.
623 (void) strlcpy(dlp
->dl_name
, name
, sizeof (dlp
->dl_name
));
626 * First reference; hold open the MAC interface.
628 ASSERT(dlp
->dl_mh
== NULL
);
629 err
= mac_open(dlp
->dl_name
, &dlp
->dl_mh
);
633 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
634 dlp
->dl_mip
= mac_info(dlp
->dl_mh
);
636 /* DLS is the "primary" MAC client */
637 ASSERT(dlp
->dl_mch
== NULL
);
639 err
= mac_client_open(dlp
->dl_mh
, &dlp
->dl_mch
, NULL
,
640 MAC_OPEN_FLAGS_USE_DATALINK_NAME
);
644 DTRACE_PROBE2(dls__primary__client
, char *, dlp
->dl_name
, void *,
651 i_dls_link_destroy(dlp
);
656 * Module initialization functions.
663 * Create a kmem_cache of dls_link_t structures.
665 i_dls_link_cachep
= kmem_cache_create("dls_link_cache",
666 sizeof (dls_link_t
), 0, i_dls_link_constructor
,
667 i_dls_link_destructor
, NULL
, NULL
, NULL
, 0);
668 ASSERT(i_dls_link_cachep
!= NULL
);
671 * Create a dls_link_t hash table and associated lock.
673 i_dls_link_hash
= mod_hash_create_extended("dls_link_hash",
674 IMPL_HASHSZ
, mod_hash_null_keydtor
, mod_hash_null_valdtor
,
675 mod_hash_bystr
, NULL
, mod_hash_strkey_cmp
, KM_SLEEP
);
676 i_dls_link_count
= 0;
682 if (i_dls_link_count
> 0)
686 * Destroy the kmem_cache.
688 kmem_cache_destroy(i_dls_link_cachep
);
691 * Destroy the hash table and associated lock.
693 mod_hash_destroy_hash(i_dls_link_hash
);
698 * Exported functions.
702 dls_link_hold_common(const char *name
, dls_link_t
**dlpp
, boolean_t create
)
708 * Look up a dls_link_t corresponding to the given macname in the
709 * global hash table. The i_dls_link_hash itself is protected by the
710 * mod_hash package's internal lock which synchronizes
711 * find/insert/remove into the global mod_hash list. Assumes that
712 * inserts and removes are single threaded on a per mac end point
713 * by the mac perimeter.
715 if ((err
= mod_hash_find(i_dls_link_hash
, (mod_hash_key_t
)name
,
716 (mod_hash_val_t
*)&dlp
)) == 0)
719 ASSERT(err
== MH_ERR_NOTFOUND
);
724 * We didn't find anything so we need to create one.
726 if ((err
= i_dls_link_create(name
, &dlp
)) != 0)
730 * Insert the dls_link_t.
732 err
= mod_hash_insert(i_dls_link_hash
, (mod_hash_key_t
)dlp
->dl_name
,
733 (mod_hash_val_t
)dlp
);
736 atomic_inc_32(&i_dls_link_count
);
737 ASSERT(i_dls_link_count
!= 0);
740 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
742 * Bump the reference count and hand back the reference.
750 dls_link_hold_create(const char *name
, dls_link_t
**dlpp
)
752 return (dls_link_hold_common(name
, dlpp
, B_TRUE
));
756 dls_link_hold(const char *name
, dls_link_t
**dlpp
)
758 return (dls_link_hold_common(name
, dlpp
, B_FALSE
));
762 dls_link_devinfo(dev_t dev
)
766 char macname
[MAXNAMELEN
];
768 mac_perim_handle_t mph
;
770 if ((drv
= ddi_major_to_name(getmajor(dev
))) == NULL
)
772 (void) snprintf(macname
, MAXNAMELEN
, "%s%d", drv
,
773 DLS_MINOR2INST(getminor(dev
)));
776 * The code below assumes that the name constructed above is the
777 * macname. This is not the case for legacy devices. Currently this
778 * is ok because this function is only called in the getinfo(9e) path,
779 * which for a legacy device would directly end up in the driver's
780 * getinfo, rather than here
782 if (mac_perim_enter_by_macname(macname
, &mph
) != 0)
785 if (dls_link_hold(macname
, &dlp
) != 0) {
790 dip
= mac_devinfo_get(dlp
->dl_mh
);
798 dls_link_dev(dls_link_t
*dlp
)
800 return (makedevice(ddi_driver_major(mac_devinfo_get(dlp
->dl_mh
)),
801 mac_minor(dlp
->dl_mh
)));
805 dls_link_rele(dls_link_t
*dlp
)
809 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
811 * Check if there are any more references.
813 if (--dlp
->dl_ref
== 0) {
814 (void) mod_hash_remove(i_dls_link_hash
,
815 (mod_hash_key_t
)dlp
->dl_name
, &val
);
816 ASSERT(dlp
== (dls_link_t
*)val
);
819 * Destroy the dls_link_t.
821 i_dls_link_destroy(dlp
);
822 ASSERT(i_dls_link_count
> 0);
823 atomic_dec_32(&i_dls_link_count
);
828 dls_link_rele_by_name(const char *name
)
832 if (mod_hash_find(i_dls_link_hash
, (mod_hash_key_t
)name
,
833 (mod_hash_val_t
*)&dlp
) != 0)
836 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
839 * Must fail detach if mac client is busy.
841 ASSERT(dlp
->dl_ref
> 0 && dlp
->dl_mch
!= NULL
);
842 if (mac_link_has_flows(dlp
->dl_mch
))
850 dls_link_setzid(const char *name
, zoneid_t zid
)
856 if ((err
= dls_link_hold_create(name
, &dlp
)) != 0)
859 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
861 if ((old_zid
= dlp
->dl_zid
) == zid
)
865 * Check whether this dlp is used by its own zone. If yes, we cannot
868 if (dlp
->dl_zone_ref
!= 0) {
875 if (zid
== GLOBAL_ZONEID
) {
877 * The link is moving from a non-global zone to the global
878 * zone, so we need to release the reference that was held
879 * when the link was originally assigned to the non-global
887 * We only keep the reference to this link open if the link has
888 * successfully moved from the global zone to a non-global zone.
890 if (err
!= 0 || old_zid
!= GLOBAL_ZONEID
)
896 dls_link_getzid(const char *name
, zoneid_t
*zidp
)
901 if ((err
= dls_link_hold(name
, &dlp
)) != 0)
904 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
913 dls_link_add(dls_link_t
*dlp
, uint32_t sap
, dld_str_t
*dsp
)
915 mod_hash_t
*hash
= dlp
->dl_str_hash
;
921 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
924 * Generate a hash key based on the sap.
929 * Search the table for a list head with this key.
931 if ((err
= mod_hash_find(hash
, key
, (mod_hash_val_t
*)&dhp
)) != 0) {
932 ASSERT(err
== MH_ERR_NOTFOUND
);
934 dhp
= i_dls_head_alloc(key
);
935 err
= mod_hash_insert(hash
, key
, (mod_hash_val_t
)dhp
);
940 * Add the dld_str_t to the head of the list. List walkers in
941 * i_dls_link_rx_* bump up dh_ref to ensure the list does not change
942 * while they walk the list. The membar below ensures that list walkers
943 * see exactly the old list or the new list.
945 ASSERT(dsp
->ds_next
== NULL
);
954 * Save a pointer to the list head.
957 dlp
->dl_impl_count
++;
961 dls_link_remove(dls_link_t
*dlp
, dld_str_t
*dsp
)
963 mod_hash_t
*hash
= dlp
->dl_str_hash
;
968 ASSERT(MAC_PERIM_HELD(dlp
->dl_mh
));
971 * We set dh_removing here to tell the receive callbacks not to pass
972 * up packets anymore. Then wait till the current callbacks are done.
973 * This happens either in the close path or in processing the
974 * DL_UNBIND_REQ via a taskq thread, and it is ok to cv_wait in either.
975 * The dh_ref ensures there aren't and there won't be any upcalls
976 * walking or using the dh_list. The mod hash internal lock ensures
977 * that the insert/remove of the dls_head_t itself synchronizes with
978 * any i_dls_link_rx trying to locate it. The perimeter ensures that
979 * there isn't another simultaneous dls_link_add/remove.
983 mutex_enter(&dhp
->dh_lock
);
984 dhp
->dh_removing
= B_TRUE
;
985 while (dhp
->dh_ref
!= 0)
986 cv_wait(&dhp
->dh_cv
, &dhp
->dh_lock
);
987 mutex_exit(&dhp
->dh_lock
);
990 * Walk the list and remove the dld_str_t.
992 for (pp
= &dhp
->dh_list
; (p
= *pp
) != NULL
; pp
= &(p
->ds_next
)) {
1001 ASSERT(dlp
->dl_impl_count
!= 0);
1002 dlp
->dl_impl_count
--;
1004 if (dhp
->dh_list
== NULL
) {
1005 mod_hash_val_t val
= NULL
;
1008 * The list is empty so remove the hash table entry.
1010 (void) mod_hash_remove(hash
, dhp
->dh_key
, &val
);
1011 ASSERT(dhp
== (dls_head_t
*)val
);
1012 i_dls_head_free(dhp
);
1014 mutex_enter(&dhp
->dh_lock
);
1015 dhp
->dh_removing
= B_FALSE
;
1016 mutex_exit(&dhp
->dh_lock
);