]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_llatbl.c
2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
30 * Copyright (c) 2004-2008 Qing Li. All rights reserved.
31 * Copyright (c) 2008 Kip Macy. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
42 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 #include <sys/cdefs.h>
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/malloc.h>
59 #include <sys/syslog.h>
60 #include <sys/sysctl.h>
61 #include <sys/socket.h>
62 #include <sys/kernel.h>
63 #include <kern/queue.h>
64 #include <kern/locks.h>
66 #include <netinet/in.h>
67 #include <net/if_llatbl.h>
69 #include <net/if_dl.h>
70 #include <net/if_var.h>
72 #include <net/route.h>
73 #include <netinet/if_ether.h>
74 #include <netinet6/in6_var.h>
75 #include <netinet6/nd6.h>
77 MALLOC_DEFINE(M_LLTABLE
, "lltable", "link level address tables");
79 static SLIST_HEAD(, lltable
) lltables
= SLIST_HEAD_INITIALIZER(lltables
);
81 static lck_grp_attr_t
*lltable_rwlock_grp_attr
;
82 static lck_grp_t
*lltable_rwlock_grp
;
83 static lck_attr_t
*lltable_rwlock_attr
;
85 static lck_grp_attr_t
*lle_lock_grp_attr
= NULL
;
86 lck_grp_t
*lle_lock_grp
= NULL
;
87 lck_attr_t
*lle_lock_attr
= NULL
;
89 decl_lck_rw_data(, lltable_rwlock_data
);
90 lck_rw_t
*lltable_rwlock
= &lltable_rwlock_data
;
93 static void lltable_unlink(struct lltable
*llt
);
95 static void llentries_unlink(struct lltable
*llt
, struct llentries
*head
);
97 static void htable_unlink_entry(struct llentry
*lle
);
98 static void htable_link_entry(struct lltable
*llt
, struct llentry
*lle
);
99 static int htable_foreach_lle(struct lltable
*llt
, llt_foreach_cb_t
*f
,
105 lltable_rwlock_grp_attr
= lck_grp_attr_alloc_init();
106 lltable_rwlock_grp
= lck_grp_alloc_init("lltable_rwlock",
107 lltable_rwlock_grp_attr
);
108 lltable_rwlock_attr
= lck_attr_alloc_init();
109 lck_rw_init(lltable_rwlock
, lltable_rwlock_grp
,
110 lltable_rwlock_attr
);
112 lle_lock_grp_attr
= lck_grp_attr_alloc_init();
113 lle_lock_grp
= lck_grp_alloc_init("lle locks", lle_lock_grp_attr
);
114 lle_lock_attr
= lck_attr_alloc_init();
118 * Dump lle state for a specific address family.
121 lltable_dump_af(struct lltable
*llt
, struct sysctl_req
*wr
)
125 LLTABLE_LOCK_ASSERT();
127 if (llt
->llt_ifp
->if_flags
& IFF_LOOPBACK
)
131 IF_AFDATA_RLOCK(llt
->llt_ifp
, llt
->llt_af
);
132 error
= lltable_foreach_lle(llt
,
133 (llt_foreach_cb_t
*)llt
->llt_dump_entry
, wr
);
134 IF_AFDATA_RUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
140 * Dump arp state for a specific address family.
143 lltable_sysctl_dumparp(int af
, struct sysctl_req
*wr
)
145 struct lltable
*llt
= NULL
;
149 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
150 if (llt
->llt_af
== af
) {
151 error
= lltable_dump_af(llt
, wr
);
162 * Common function helpers for chained hash table.
166 * Runs specified callback for each entry in @llt.
167 * Caller does the locking.
171 htable_foreach_lle(struct lltable
*llt
, llt_foreach_cb_t
*f
, void *farg
)
173 struct llentry
*lle
, *next
;
178 for (i
= 0; i
< llt
->llt_hsize
; i
++) {
179 LIST_FOREACH_SAFE(lle
, &llt
->lle_head
[i
], lle_next
, next
) {
180 error
= f(llt
, lle
, farg
);
190 htable_link_entry(struct lltable
*llt
, struct llentry
*lle
)
192 struct llentries
*lleh
;
195 if ((lle
->la_flags
& LLE_LINKED
) != 0)
198 IF_AFDATA_WLOCK_ASSERT(llt
->llt_ifp
, llt
->llt_af
);
200 hashidx
= llt
->llt_hash(lle
, llt
->llt_hsize
);
201 lleh
= &llt
->lle_head
[hashidx
];
204 lle
->lle_head
= lleh
;
205 lle
->la_flags
|= LLE_LINKED
;
206 LIST_INSERT_HEAD(lleh
, lle
, lle_next
);
210 htable_unlink_entry(struct llentry
*lle
)
212 if ((lle
->la_flags
& LLE_LINKED
) != 0) {
213 IF_AFDATA_WLOCK_ASSERT(lle
->lle_tbl
->llt_ifp
, lle
->lle_tbl
->llt_af
);
214 LIST_REMOVE(lle
, lle_next
);
215 lle
->la_flags
&= ~(LLE_VALID
| LLE_LINKED
);
218 lle
->lle_head
= NULL
;
223 struct prefix_match_data
{
224 const struct sockaddr
*addr
;
225 const struct sockaddr
*mask
;
226 struct llentries dchain
;
231 htable_prefix_free_cb(struct lltable
*llt
, struct llentry
*lle
, void *farg
)
233 struct prefix_match_data
*pmd
;
235 pmd
= (struct prefix_match_data
*)farg
;
237 if (llt
->llt_match_prefix(pmd
->addr
, pmd
->mask
, pmd
->flags
, lle
)) {
239 LIST_INSERT_HEAD(&pmd
->dchain
, lle
, lle_chain
);
246 htable_prefix_free(struct lltable
*llt
, const struct sockaddr
*addr
,
247 const struct sockaddr
*mask
, u_int flags
)
249 struct llentry
*lle
, *next
;
250 struct prefix_match_data pmd
;
252 bzero(&pmd
, sizeof(pmd
));
256 LIST_INIT(&pmd
.dchain
);
258 IF_AFDATA_WLOCK(llt
->llt_ifp
, llt
->llt_af
);
259 /* Push matching lles to chain */
260 lltable_foreach_lle(llt
, htable_prefix_free_cb
, &pmd
);
262 llentries_unlink(llt
, &pmd
.dchain
);
263 IF_AFDATA_WUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
265 LIST_FOREACH_SAFE(lle
, &pmd
.dchain
, lle_chain
, next
)
266 lltable_free_entry(llt
, lle
);
270 htable_free_tbl(struct lltable
*llt
)
273 FREE(llt
->lle_head
, M_LLTABLE
);
274 FREE(llt
, M_LLTABLE
);
278 llentries_unlink(struct lltable
*llt
, struct llentries
*head
)
280 struct llentry
*lle
, *next
;
282 LIST_FOREACH_SAFE(lle
, head
, lle_chain
, next
)
283 llt
->llt_unlink_entry(lle
);
287 * Helper function used to drop all mbufs in hold queue.
289 * Returns the number of held packets, if any, that were dropped.
292 lltable_drop_entry_queue(struct llentry
*lle
)
297 LLE_WLOCK_ASSERT(lle
);
300 while ((lle
->la_numheld
> 0) && (lle
->la_hold
!= NULL
)) {
301 next
= lle
->la_hold
->m_nextpkt
;
302 m_freem(lle
->la_hold
);
308 KASSERT(lle
->la_numheld
== 0,
309 ("%s: la_numheld %d > 0, pkts_droped %zd", __func__
,
310 lle
->la_numheld
, pkts_dropped
));
312 return (pkts_dropped
);
316 lltable_set_entry_addr(struct ifnet
*ifp
, struct llentry
*lle
,
319 bcopy(ll_addr
, &lle
->ll_addr
, ifp
->if_addrlen
);
320 lle
->la_flags
|= LLE_VALID
;
321 lle
->r_flags
|= RLLE_VALID
;
326 * XXX The following is related to a change to cache destination layer 2
327 * header cached in the entry instead of just the destination mac address
328 * Right now leaving this code out and just storing the destination's mac
332 * Tries to update @lle link-level address.
333 * Since update requires AFDATA WLOCK, function
334 * drops @lle lock, acquires AFDATA lock and then acquires
335 * @lle lock to maintain lock order.
337 * Returns 1 on success.
340 lltable_try_set_entry_addr(struct ifnet
*ifp
, struct llentry
*lle
,
341 const char *linkhdr
, size_t linkhdrsize
, int lladdr_off
)
343 /* Perform real LLE update */
344 /* use afdata WLOCK to update fields */
345 LLE_WLOCK_ASSERT(lle
);
348 IF_AFDATA_WLOCK(ifp
, lle
->lle_tbl
->llt_af
);
352 * Since we droppped LLE lock, other thread might have deleted
353 * this lle. Check and return
355 if ((lle
->la_flags
& LLE_DELETED
) != 0) {
356 IF_AFDATA_WUNLOCK(ifp
, lle
->lle_tbl
->llt_af
);
357 LLE_FREE_LOCKED(lle
);
362 lltable_set_entry_addr(ifp
, lle
, linkhdr
, linkhdrsize
, lladdr_off
);
364 IF_AFDATA_WUNLOCK(ifp
, lle
->lle_tbl
->llt_af
);
372 * Helper function used to pre-compute full/partial link-layer
373 * header data suitable for feeding into if_output().
376 lltable_calc_llheader(struct ifnet
*ifp
, int family
, char *lladdr
,
377 char *buf
, size_t *bufsize
, int *lladdr_off
)
379 struct if_encap_req ereq
;
382 bzero(buf
, *bufsize
);
383 bzero(&ereq
, sizeof(ereq
));
385 ereq
.bufsize
= *bufsize
;
386 ereq
.rtype
= IFENCAP_LL
;
387 ereq
.family
= family
;
388 ereq
.lladdr
= lladdr
;
389 ereq
.lladdr_len
= ifp
->if_addrlen
;
390 error
= ifp
->if_requestencap(ifp
, &ereq
);
392 *bufsize
= ereq
.bufsize
;
393 *lladdr_off
= ereq
.lladdr_off
;
400 * Update link-layer header for given @lle after
401 * interface lladdr was changed.
404 llentry_update_ifaddr(struct lltable
*llt
, struct llentry
*lle
, void *farg
)
407 u_char linkhdr
[LLE_MAX_LINKHDR
];
412 ifp
= (struct ifnet
*)farg
;
414 lladdr
= (void *)lle
->ll_addr
;
417 if ((lle
->la_flags
& LLE_VALID
) == 0) {
422 if ((lle
->la_flags
& LLE_IFADDR
) != 0)
423 lladdr
= (void *)IF_LLADDR(ifp
);
425 linkhdrsize
= sizeof(linkhdr
);
426 lltable_calc_llheader(ifp
, llt
->llt_af
, (void *)lladdr
, (void *)linkhdr
, &linkhdrsize
,
428 memcpy(lle
->r_linkdata
, linkhdr
, linkhdrsize
);
435 * Update all calculated headers for given @llt
438 lltable_update_ifaddr(struct lltable
*llt
)
441 if (llt
->llt_ifp
->if_flags
& IFF_LOOPBACK
)
444 IF_AFDATA_WLOCK(llt
->llt_ifp
, llt
->llt_af
);
445 lltable_foreach_lle(llt
, llentry_update_ifaddr
, llt
->llt_ifp
);
446 IF_AFDATA_WUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
452 * Performs generic cleanup routines and frees lle.
454 * Called for non-linked entries, with callouts and
455 * other AF-specific cleanups performed.
457 * @lle must be passed WLOCK'ed
459 * Returns the number of held packets, if any, that were dropped.
462 llentry_free(struct llentry
*lle
)
466 LLE_WLOCK_ASSERT(lle
);
468 KASSERT((lle
->la_flags
& LLE_LINKED
) == 0, ("freeing linked lle"));
470 pkts_dropped
= lltable_drop_entry_queue(lle
);
472 LLE_FREE_LOCKED(lle
);
474 return (pkts_dropped
);
478 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
480 * If found the llentry * is returned referenced and unlocked.
483 llentry_alloc(struct ifnet
*ifp
, struct lltable
*lt
,
484 struct sockaddr_storage
*dst
)
486 struct llentry
*la
, *la_tmp
;
488 IF_AFDATA_RLOCK(ifp
, lt
->llt_af
);
489 la
= lla_lookup(lt
, LLE_EXCLUSIVE
, (struct sockaddr
*)dst
);
490 IF_AFDATA_RUNLOCK(ifp
, lt
->llt_af
);
498 if ((ifp
->if_flags
& IFF_NOARP
) == 0) {
499 la
= lltable_alloc_entry(lt
, 0, (struct sockaddr
*)dst
);
502 IF_AFDATA_WLOCK(ifp
, lt
->llt_af
);
504 /* Prefer any existing LLE over newly-created one */
505 la_tmp
= lla_lookup(lt
, LLE_EXCLUSIVE
, (struct sockaddr
*)dst
);
507 lltable_link_entry(lt
, la
);
508 IF_AFDATA_WUNLOCK(ifp
, lt
->llt_af
);
509 if (la_tmp
!= NULL
) {
510 lltable_free_entry(lt
, la
);
521 * Free all entries from given table and free itself.
525 lltable_free_cb(struct lltable
*llt
, struct llentry
*lle
, void *farg
)
528 struct llentries
*dchain
;
530 dchain
= (struct llentries
*)farg
;
533 LIST_INSERT_HEAD(dchain
, lle
, lle_chain
);
539 * Free all entries from given table and free itself.
542 lltable_free(struct lltable
*llt
)
544 struct llentry
*lle
, *next
;
545 struct llentries dchain
;
547 KASSERT(llt
!= NULL
, ("%s: llt is NULL", __func__
));
549 //lltable_unlink(llt);
552 IF_AFDATA_WLOCK(llt
->llt_ifp
, llt
->llt_af
);
553 /* Push all lles to @dchain */
554 lltable_foreach_lle(llt
, lltable_free_cb
, &dchain
);
555 llentries_unlink(llt
, &dchain
);
556 IF_AFDATA_WUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
558 LIST_FOREACH_SAFE(lle
, &dchain
, lle_chain
, next
) {
560 if (thread_call_cancel(lle
->lle_timer
) == TRUE
)
566 /* XXX We recycle network interfaces so we only purge */
567 /* llt->llt_free_tbl(llt); */
572 lltable_drain(int af
)
579 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
580 if (llt
->llt_af
!= af
)
583 for (i
=0; i
< llt
->llt_hsize
; i
++) {
584 LIST_FOREACH(lle
, &llt
->lle_head
[i
], lle_next
) {
587 m_freem(lle
->la_hold
);
599 * Deletes an address from given lltable.
600 * Used for userland interaction to remove
601 * individual entries. Skips entries added by OS.
604 lltable_delete_addr(struct lltable
*llt
, u_int flags
,
605 const struct sockaddr
*l3addr
)
611 IF_AFDATA_WLOCK(ifp
, llt
->llt_af
);
612 lle
= lla_lookup(llt
, LLE_EXCLUSIVE
, l3addr
);
615 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
618 if ((lle
->la_flags
& LLE_IFADDR
) != 0 && (flags
& LLE_IFADDR
) == 0) {
619 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
624 lltable_unlink_entry(llt
, lle
);
625 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
627 llt
->llt_delete_entry(llt
, lle
);
633 lltable_prefix_free(int af
, struct sockaddr
*addr
, struct sockaddr
*mask
,
639 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
640 if (llt
->llt_af
!= af
)
643 llt
->llt_prefix_free(llt
, addr
, mask
, flags
);
649 lltable_allocate_htbl(uint32_t hsize
)
654 MALLOC(llt
, struct lltable
*, sizeof(struct lltable
), M_LLTABLE
, M_WAITOK
| M_ZERO
);
655 llt
->llt_hsize
= hsize
;
656 MALLOC(llt
->lle_head
, struct llentries
*, sizeof(struct llentries
) * hsize
,
657 M_LLTABLE
, M_WAITOK
| M_ZERO
);
659 for (i
= 0; i
< llt
->llt_hsize
; i
++)
660 LIST_INIT(&llt
->lle_head
[i
]);
662 /* Set some default callbacks */
663 llt
->llt_link_entry
= htable_link_entry
;
664 llt
->llt_unlink_entry
= htable_unlink_entry
;
665 llt
->llt_prefix_free
= htable_prefix_free
;
666 llt
->llt_foreach_entry
= htable_foreach_lle
;
667 llt
->llt_free_tbl
= htable_free_tbl
;
673 * Links lltable to global llt list.
676 lltable_link(struct lltable
*llt
)
679 SLIST_INSERT_HEAD(&lltables
, llt
, llt_link
);
685 lltable_unlink(struct lltable
*llt
)
688 SLIST_REMOVE(&lltables
, llt
, lltable
, llt_link
);
694 * External methods used by lltable consumers
698 lltable_foreach_lle(struct lltable
*llt
, llt_foreach_cb_t
*f
, void *farg
)
700 return (llt
->llt_foreach_entry(llt
, f
, farg
));
704 lltable_alloc_entry(struct lltable
*llt
, u_int flags
,
705 const struct sockaddr
*l3addr
)
707 return (llt
->llt_alloc_entry(llt
, flags
, l3addr
));
711 lltable_free_entry(struct lltable
*llt
, struct llentry
*lle
)
713 llt
->llt_free_entry(llt
, lle
);
717 lltable_link_entry(struct lltable
*llt
, struct llentry
*lle
)
719 llt
->llt_link_entry(llt
, lle
);
723 lltable_unlink_entry(struct lltable
*llt
, struct llentry
*lle
)
725 llt
->llt_unlink_entry(lle
);
729 lltable_fill_sa_entry(const struct llentry
*lle
, struct sockaddr
*sa
)
734 llt
->llt_fill_sa_entry(lle
, sa
);
738 lltable_get_ifp(const struct lltable
*llt
)
740 return (llt
->llt_ifp
);
744 lltable_get_af(const struct lltable
*llt
)
746 return (llt
->llt_af
);
749 #define ifnet_byindex(index) ifindex2ifnet[(index)]
752 * Called in route_output when rtm_flags contains RTF_LLDATA.
755 lla_rt_output(struct rt_msghdr
*rtm
, struct rt_addrinfo
*info
)
757 struct sockaddr_dl
*dl
=
758 (struct sockaddr_dl
*)(void *)info
->rti_info
[RTAX_GATEWAY
];
759 struct sockaddr
*dst
= (struct sockaddr
*)info
->rti_info
[RTAX_DST
];
762 struct llentry
*lle
, *lle_tmp
;
766 KASSERT(dl
!= NULL
&& dl
->sdl_family
== AF_LINK
,
767 ("%s: invalid dl\n", __func__
));
769 ifp
= ifnet_byindex(dl
->sdl_index
);
771 log(LOG_INFO
, "%s: invalid ifp (sdl_index %d)\n",
772 __func__
, dl
->sdl_index
);
776 /* XXX linked list may be too expensive */
778 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
779 if (llt
->llt_af
== dst
->sa_family
&&
784 KASSERT(llt
!= NULL
, ("Yep, ugly hacks are bad\n"));
788 switch (rtm
->rtm_type
) {
792 if (rtm
->rtm_rmx
.rmx_expire
== 0)
793 laflags
= LLE_STATIC
;
794 lle
= lltable_alloc_entry(llt
, laflags
, dst
);
798 linkhdrsize
= sizeof(linkhdr
);
799 if (lltable_calc_llheader(ifp
, dst
->sa_family
, LLADDR(dl
),
800 (void *)linkhdr
, &linkhdrsize
, &lladdr_off
) != 0)
803 lltable_set_entry_addr(ifp
, lle
, LLADDR(dl
));
805 if (rtm
->rtm_flags
& RTF_ANNOUNCE
)
806 lle
->la_flags
|= LLE_PUB
;
807 lle
->la_expire
= rtm
->rtm_rmx
.rmx_expire
;
809 laflags
= lle
->la_flags
;
811 /* Try to link new entry */
813 IF_AFDATA_WLOCK(ifp
, llt
->llt_af
);
815 lle_tmp
= lla_lookup(llt
, LLE_EXCLUSIVE
, dst
);
816 if (lle_tmp
!= NULL
) {
817 /* Check if we are trying to replace immutable entry */
818 if ((lle_tmp
->la_flags
& LLE_IFADDR
) != 0) {
819 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
820 LLE_WUNLOCK(lle_tmp
);
821 lltable_free_entry(llt
, lle
);
824 /* Unlink existing entry from table */
825 lltable_unlink_entry(llt
, lle_tmp
);
827 lltable_link_entry(llt
, lle
);
828 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
830 if (lle_tmp
!= NULL
) {
831 EVENTHANDLER_INVOKE(NULL
, lle_event
, lle_tmp
, LLENTRY_EXPIRED
);
832 lltable_free_entry(llt
, lle_tmp
);
836 * By invoking LLE handler here we might get
837 * two events on static LLE entry insertion
838 * in routing socket. However, since we might have
839 * other subscribers we need to generate this event.
841 EVENTHANDLER_INVOKE(NULL
, lle_event
, lle
, LLENTRY_RESOLVED
);
845 if ((laflags
& LLE_PUB
) && dst
->sa_family
== AF_INET
)
846 dlil_send_arp(ifp
, ARPOP_REQUEST
, NULL
, dst
, NULL
, dst
, 0);
852 return (lltable_delete_addr(llt
, 0, dst
));