]>
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
) {
132 IF_AFDATA_RLOCK(llt
->llt_ifp
, llt
->llt_af
);
133 error
= lltable_foreach_lle(llt
,
134 (llt_foreach_cb_t
*)llt
->llt_dump_entry
, wr
);
135 IF_AFDATA_RUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
141 * Dump arp state for a specific address family.
144 lltable_sysctl_dumparp(int af
, struct sysctl_req
*wr
)
146 struct lltable
*llt
= NULL
;
150 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
151 if (llt
->llt_af
== af
) {
152 error
= lltable_dump_af(llt
, wr
);
164 * Common function helpers for chained hash table.
168 * Runs specified callback for each entry in @llt.
169 * Caller does the locking.
173 htable_foreach_lle(struct lltable
*llt
, llt_foreach_cb_t
*f
, void *farg
)
175 struct llentry
*lle
, *next
;
180 for (i
= 0; i
< llt
->llt_hsize
; i
++) {
181 LIST_FOREACH_SAFE(lle
, &llt
->lle_head
[i
], lle_next
, next
) {
182 error
= f(llt
, lle
, farg
);
193 htable_link_entry(struct lltable
*llt
, struct llentry
*lle
)
195 struct llentries
*lleh
;
198 if ((lle
->la_flags
& LLE_LINKED
) != 0) {
202 IF_AFDATA_WLOCK_ASSERT(llt
->llt_ifp
, llt
->llt_af
);
204 hashidx
= llt
->llt_hash(lle
, llt
->llt_hsize
);
205 lleh
= &llt
->lle_head
[hashidx
];
208 lle
->lle_head
= lleh
;
209 lle
->la_flags
|= LLE_LINKED
;
210 LIST_INSERT_HEAD(lleh
, lle
, lle_next
);
214 htable_unlink_entry(struct llentry
*lle
)
216 if ((lle
->la_flags
& LLE_LINKED
) != 0) {
217 IF_AFDATA_WLOCK_ASSERT(lle
->lle_tbl
->llt_ifp
, lle
->lle_tbl
->llt_af
);
218 LIST_REMOVE(lle
, lle_next
);
219 lle
->la_flags
&= ~(LLE_VALID
| LLE_LINKED
);
222 lle
->lle_head
= NULL
;
227 struct prefix_match_data
{
228 const struct sockaddr
*addr
;
229 const struct sockaddr
*mask
;
230 struct llentries dchain
;
235 htable_prefix_free_cb(struct lltable
*llt
, struct llentry
*lle
, void *farg
)
237 struct prefix_match_data
*pmd
;
239 pmd
= (struct prefix_match_data
*)farg
;
241 if (llt
->llt_match_prefix(pmd
->addr
, pmd
->mask
, pmd
->flags
, lle
)) {
243 LIST_INSERT_HEAD(&pmd
->dchain
, lle
, lle_chain
);
250 htable_prefix_free(struct lltable
*llt
, const struct sockaddr
*addr
,
251 const struct sockaddr
*mask
, u_int flags
)
253 struct llentry
*lle
, *next
;
254 struct prefix_match_data pmd
;
256 bzero(&pmd
, sizeof(pmd
));
260 LIST_INIT(&pmd
.dchain
);
262 IF_AFDATA_WLOCK(llt
->llt_ifp
, llt
->llt_af
);
263 /* Push matching lles to chain */
264 lltable_foreach_lle(llt
, htable_prefix_free_cb
, &pmd
);
266 llentries_unlink(llt
, &pmd
.dchain
);
267 IF_AFDATA_WUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
269 LIST_FOREACH_SAFE(lle
, &pmd
.dchain
, lle_chain
, next
)
270 lltable_free_entry(llt
, lle
);
274 htable_free_tbl(struct lltable
*llt
)
276 FREE(llt
->lle_head
, M_LLTABLE
);
277 FREE(llt
, M_LLTABLE
);
281 llentries_unlink(struct lltable
*llt
, struct llentries
*head
)
283 struct llentry
*lle
, *next
;
285 LIST_FOREACH_SAFE(lle
, head
, lle_chain
, next
)
286 llt
->llt_unlink_entry(lle
);
290 * Helper function used to drop all mbufs in hold queue.
292 * Returns the number of held packets, if any, that were dropped.
295 lltable_drop_entry_queue(struct llentry
*lle
)
300 LLE_WLOCK_ASSERT(lle
);
303 while ((lle
->la_numheld
> 0) && (lle
->la_hold
!= NULL
)) {
304 next
= lle
->la_hold
->m_nextpkt
;
305 m_freem(lle
->la_hold
);
311 KASSERT(lle
->la_numheld
== 0,
312 ("%s: la_numheld %d > 0, pkts_droped %zd", __func__
,
313 lle
->la_numheld
, pkts_dropped
));
319 lltable_set_entry_addr(struct ifnet
*ifp
, struct llentry
*lle
,
322 bcopy(ll_addr
, &lle
->ll_addr
, ifp
->if_addrlen
);
323 lle
->la_flags
|= LLE_VALID
;
324 lle
->r_flags
|= RLLE_VALID
;
329 * XXX The following is related to a change to cache destination layer 2
330 * header cached in the entry instead of just the destination mac address
331 * Right now leaving this code out and just storing the destination's mac
335 * Tries to update @lle link-level address.
336 * Since update requires AFDATA WLOCK, function
337 * drops @lle lock, acquires AFDATA lock and then acquires
338 * @lle lock to maintain lock order.
340 * Returns 1 on success.
343 lltable_try_set_entry_addr(struct ifnet
*ifp
, struct llentry
*lle
,
344 const char *linkhdr
, size_t linkhdrsize
, int lladdr_off
)
346 /* Perform real LLE update */
347 /* use afdata WLOCK to update fields */
348 LLE_WLOCK_ASSERT(lle
);
351 IF_AFDATA_WLOCK(ifp
, lle
->lle_tbl
->llt_af
);
355 * Since we droppped LLE lock, other thread might have deleted
356 * this lle. Check and return
358 if ((lle
->la_flags
& LLE_DELETED
) != 0) {
359 IF_AFDATA_WUNLOCK(ifp
, lle
->lle_tbl
->llt_af
);
360 LLE_FREE_LOCKED(lle
);
365 lltable_set_entry_addr(ifp
, lle
, linkhdr
, linkhdrsize
, lladdr_off
);
367 IF_AFDATA_WUNLOCK(ifp
, lle
->lle_tbl
->llt_af
);
375 * Helper function used to pre-compute full/partial link-layer
376 * header data suitable for feeding into if_output().
379 lltable_calc_llheader(struct ifnet
*ifp
, int family
, char *lladdr
,
380 char *buf
, size_t *bufsize
, int *lladdr_off
)
382 struct if_encap_req ereq
;
385 bzero(buf
, *bufsize
);
386 bzero(&ereq
, sizeof(ereq
));
388 ereq
.bufsize
= *bufsize
;
389 ereq
.rtype
= IFENCAP_LL
;
390 ereq
.family
= family
;
391 ereq
.lladdr
= lladdr
;
392 ereq
.lladdr_len
= ifp
->if_addrlen
;
393 error
= ifp
->if_requestencap(ifp
, &ereq
);
395 *bufsize
= ereq
.bufsize
;
396 *lladdr_off
= ereq
.lladdr_off
;
403 * Update link-layer header for given @lle after
404 * interface lladdr was changed.
407 llentry_update_ifaddr(struct lltable
*llt
, struct llentry
*lle
, void *farg
)
410 u_char linkhdr
[LLE_MAX_LINKHDR
];
415 ifp
= (struct ifnet
*)farg
;
417 lladdr
= (void *)lle
->ll_addr
;
420 if ((lle
->la_flags
& LLE_VALID
) == 0) {
425 if ((lle
->la_flags
& LLE_IFADDR
) != 0) {
426 lladdr
= (void *)IF_LLADDR(ifp
);
429 linkhdrsize
= sizeof(linkhdr
);
430 lltable_calc_llheader(ifp
, llt
->llt_af
, (void *)lladdr
, (void *)linkhdr
, &linkhdrsize
,
432 memcpy(lle
->r_linkdata
, linkhdr
, linkhdrsize
);
439 * Update all calculated headers for given @llt
442 lltable_update_ifaddr(struct lltable
*llt
)
444 if (llt
->llt_ifp
->if_flags
& IFF_LOOPBACK
) {
448 IF_AFDATA_WLOCK(llt
->llt_ifp
, llt
->llt_af
);
449 lltable_foreach_lle(llt
, llentry_update_ifaddr
, llt
->llt_ifp
);
450 IF_AFDATA_WUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
456 * Performs generic cleanup routines and frees lle.
458 * Called for non-linked entries, with callouts and
459 * other AF-specific cleanups performed.
461 * @lle must be passed WLOCK'ed
463 * Returns the number of held packets, if any, that were dropped.
466 llentry_free(struct llentry
*lle
)
470 LLE_WLOCK_ASSERT(lle
);
472 KASSERT((lle
->la_flags
& LLE_LINKED
) == 0, ("freeing linked lle"));
474 pkts_dropped
= lltable_drop_entry_queue(lle
);
476 LLE_FREE_LOCKED(lle
);
482 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
484 * If found the llentry * is returned referenced and unlocked.
487 llentry_alloc(struct ifnet
*ifp
, struct lltable
*lt
,
488 struct sockaddr_storage
*dst
)
490 struct llentry
*la
, *la_tmp
;
492 IF_AFDATA_RLOCK(ifp
, lt
->llt_af
);
493 la
= lla_lookup(lt
, LLE_EXCLUSIVE
, (struct sockaddr
*)dst
);
494 IF_AFDATA_RUNLOCK(ifp
, lt
->llt_af
);
502 if ((ifp
->if_flags
& IFF_NOARP
) == 0) {
503 la
= lltable_alloc_entry(lt
, 0, (struct sockaddr
*)dst
);
507 IF_AFDATA_WLOCK(ifp
, lt
->llt_af
);
509 /* Prefer any existing LLE over newly-created one */
510 la_tmp
= lla_lookup(lt
, LLE_EXCLUSIVE
, (struct sockaddr
*)dst
);
511 if (la_tmp
== NULL
) {
512 lltable_link_entry(lt
, la
);
514 IF_AFDATA_WUNLOCK(ifp
, lt
->llt_af
);
515 if (la_tmp
!= NULL
) {
516 lltable_free_entry(lt
, la
);
527 * Free all entries from given table and free itself.
531 lltable_free_cb(struct lltable
*llt
, struct llentry
*lle
, void *farg
)
534 struct llentries
*dchain
;
536 dchain
= (struct llentries
*)farg
;
539 LIST_INSERT_HEAD(dchain
, lle
, lle_chain
);
545 * Free all entries from given table and free itself.
548 lltable_free(struct lltable
*llt
)
550 struct llentry
*lle
, *next
;
551 struct llentries dchain
;
553 KASSERT(llt
!= NULL
, ("%s: llt is NULL", __func__
));
555 //lltable_unlink(llt);
558 IF_AFDATA_WLOCK(llt
->llt_ifp
, llt
->llt_af
);
559 /* Push all lles to @dchain */
560 lltable_foreach_lle(llt
, lltable_free_cb
, &dchain
);
561 llentries_unlink(llt
, &dchain
);
562 IF_AFDATA_WUNLOCK(llt
->llt_ifp
, llt
->llt_af
);
564 LIST_FOREACH_SAFE(lle
, &dchain
, lle_chain
, next
) {
566 if (thread_call_cancel(lle
->lle_timer
) == TRUE
) {
573 /* XXX We recycle network interfaces so we only purge */
574 /* llt->llt_free_tbl(llt); */
579 lltable_drain(int af
)
586 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
587 if (llt
->llt_af
!= af
) {
591 for (i
= 0; i
< llt
->llt_hsize
; i
++) {
592 LIST_FOREACH(lle
, &llt
->lle_head
[i
], lle_next
) {
595 m_freem(lle
->la_hold
);
607 * Deletes an address from given lltable.
608 * Used for userland interaction to remove
609 * individual entries. Skips entries added by OS.
612 lltable_delete_addr(struct lltable
*llt
, u_int flags
,
613 const struct sockaddr
*l3addr
)
619 IF_AFDATA_WLOCK(ifp
, llt
->llt_af
);
620 lle
= lla_lookup(llt
, LLE_EXCLUSIVE
, l3addr
);
623 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
626 if ((lle
->la_flags
& LLE_IFADDR
) != 0 && (flags
& LLE_IFADDR
) == 0) {
627 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
632 lltable_unlink_entry(llt
, lle
);
633 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
635 llt
->llt_delete_entry(llt
, lle
);
641 lltable_prefix_free(int af
, struct sockaddr
*addr
, struct sockaddr
*mask
,
647 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
648 if (llt
->llt_af
!= af
) {
652 llt
->llt_prefix_free(llt
, addr
, mask
, flags
);
658 lltable_allocate_htbl(uint32_t hsize
)
663 MALLOC(llt
, struct lltable
*, sizeof(struct lltable
), M_LLTABLE
, M_WAITOK
| M_ZERO
);
664 llt
->llt_hsize
= hsize
;
665 MALLOC(llt
->lle_head
, struct llentries
*, sizeof(struct llentries
) * hsize
,
666 M_LLTABLE
, M_WAITOK
| M_ZERO
);
668 for (i
= 0; i
< llt
->llt_hsize
; i
++) {
669 LIST_INIT(&llt
->lle_head
[i
]);
672 /* Set some default callbacks */
673 llt
->llt_link_entry
= htable_link_entry
;
674 llt
->llt_unlink_entry
= htable_unlink_entry
;
675 llt
->llt_prefix_free
= htable_prefix_free
;
676 llt
->llt_foreach_entry
= htable_foreach_lle
;
677 llt
->llt_free_tbl
= htable_free_tbl
;
683 * Links lltable to global llt list.
686 lltable_link(struct lltable
*llt
)
689 SLIST_INSERT_HEAD(&lltables
, llt
, llt_link
);
695 lltable_unlink(struct lltable
*llt
)
698 SLIST_REMOVE(&lltables
, llt
, lltable
, llt_link
);
704 * External methods used by lltable consumers
708 lltable_foreach_lle(struct lltable
*llt
, llt_foreach_cb_t
*f
, void *farg
)
710 return llt
->llt_foreach_entry(llt
, f
, farg
);
714 lltable_alloc_entry(struct lltable
*llt
, u_int flags
,
715 const struct sockaddr
*l3addr
)
717 return llt
->llt_alloc_entry(llt
, flags
, l3addr
);
721 lltable_free_entry(struct lltable
*llt
, struct llentry
*lle
)
723 llt
->llt_free_entry(llt
, lle
);
727 lltable_link_entry(struct lltable
*llt
, struct llentry
*lle
)
729 llt
->llt_link_entry(llt
, lle
);
733 lltable_unlink_entry(struct lltable
*llt
, struct llentry
*lle
)
735 llt
->llt_unlink_entry(lle
);
739 lltable_fill_sa_entry(const struct llentry
*lle
, struct sockaddr
*sa
)
744 llt
->llt_fill_sa_entry(lle
, sa
);
748 lltable_get_ifp(const struct lltable
*llt
)
754 lltable_get_af(const struct lltable
*llt
)
759 #define ifnet_byindex(index) ifindex2ifnet[(index)]
762 * Called in route_output when rtm_flags contains RTF_LLDATA.
765 lla_rt_output(struct rt_msghdr
*rtm
, struct rt_addrinfo
*info
)
767 struct sockaddr_dl
*dl
=
768 (struct sockaddr_dl
*)(void *)info
->rti_info
[RTAX_GATEWAY
];
769 struct sockaddr
*dst
= (struct sockaddr
*)info
->rti_info
[RTAX_DST
];
772 struct llentry
*lle
, *lle_tmp
;
776 KASSERT(dl
!= NULL
&& dl
->sdl_family
== AF_LINK
,
777 ("%s: invalid dl\n", __func__
));
779 ifp
= ifnet_byindex(dl
->sdl_index
);
781 log(LOG_INFO
, "%s: invalid ifp (sdl_index %d)\n",
782 __func__
, dl
->sdl_index
);
786 /* XXX linked list may be too expensive */
788 SLIST_FOREACH(llt
, &lltables
, llt_link
) {
789 if (llt
->llt_af
== dst
->sa_family
&&
790 llt
->llt_ifp
== ifp
) {
795 KASSERT(llt
!= NULL
, ("Yep, ugly hacks are bad\n"));
799 switch (rtm
->rtm_type
) {
803 if (rtm
->rtm_rmx
.rmx_expire
== 0) {
804 laflags
= LLE_STATIC
;
806 lle
= lltable_alloc_entry(llt
, laflags
, dst
);
811 linkhdrsize
= sizeof(linkhdr
);
812 if (lltable_calc_llheader(ifp
, dst
->sa_family
, LLADDR(dl
),
813 (void *)linkhdr
, &linkhdrsize
, &lladdr_off
) != 0) {
817 lltable_set_entry_addr(ifp
, lle
, LLADDR(dl
));
819 if (rtm
->rtm_flags
& RTF_ANNOUNCE
) {
820 lle
->la_flags
|= LLE_PUB
;
822 lle
->la_expire
= rtm
->rtm_rmx
.rmx_expire
;
824 laflags
= lle
->la_flags
;
826 /* Try to link new entry */
828 IF_AFDATA_WLOCK(ifp
, llt
->llt_af
);
830 lle_tmp
= lla_lookup(llt
, LLE_EXCLUSIVE
, dst
);
831 if (lle_tmp
!= NULL
) {
832 /* Check if we are trying to replace immutable entry */
833 if ((lle_tmp
->la_flags
& LLE_IFADDR
) != 0) {
834 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
835 LLE_WUNLOCK(lle_tmp
);
836 lltable_free_entry(llt
, lle
);
839 /* Unlink existing entry from table */
840 lltable_unlink_entry(llt
, lle_tmp
);
842 lltable_link_entry(llt
, lle
);
843 IF_AFDATA_WUNLOCK(ifp
, llt
->llt_af
);
845 if (lle_tmp
!= NULL
) {
846 EVENTHANDLER_INVOKE(NULL
, lle_event
, lle_tmp
, LLENTRY_EXPIRED
);
847 lltable_free_entry(llt
, lle_tmp
);
851 * By invoking LLE handler here we might get
852 * two events on static LLE entry insertion
853 * in routing socket. However, since we might have
854 * other subscribers we need to generate this event.
856 EVENTHANDLER_INVOKE(NULL
, lle_event
, lle
, LLENTRY_RESOLVED
);
860 if ((laflags
& LLE_PUB
) && dst
->sa_family
== AF_INET
) {
861 dlil_send_arp(ifp
, ARPOP_REQUEST
, NULL
, dst
, NULL
, dst
, 0);
868 return lltable_delete_addr(llt
, 0, dst
);