if_llatbl.c revision 1.22.2.2 1 /* $NetBSD: if_llatbl.c,v 1.22.2.2 2017/12/03 11:39:02 jdolecek Exp $ */
2 /*
3 * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
4 * Copyright (c) 2004-2008 Qing Li. All rights reserved.
5 * Copyright (c) 2008 Kip Macy. All rights reserved.
6 * Copyright (c) 2015 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30 #include <sys/cdefs.h>
31
32 #ifdef _KERNEL_OPT
33 #include "opt_ddb.h"
34 #include "opt_inet.h"
35 #include "opt_inet6.h"
36 #include "opt_net_mpsafe.h"
37 #endif
38
39 #include "arp.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/syslog.h>
46 #include <sys/sysctl.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/mutex.h>
52 #include <sys/rwlock.h>
53
54 #ifdef DDB
55 #include <ddb/ddb.h>
56 #endif
57
58 #include <netinet/in.h>
59 #include <net/if_llatbl.h>
60 #include <net/if.h>
61 #include <net/if_dl.h>
62 #include <net/route.h>
63 #include <netinet/if_inarp.h>
64 #include <netinet/in_var.h>
65 #include <netinet6/in6_var.h>
66 #include <netinet6/nd6.h>
67
68 static SLIST_HEAD(, lltable) lltables;
69 krwlock_t lltable_rwlock;
70
71 static void lltable_unlink(struct lltable *llt);
72 static void llentries_unlink(struct lltable *llt, struct llentries *head);
73
74 static void htable_unlink_entry(struct llentry *lle);
75 static void htable_link_entry(struct lltable *llt, struct llentry *lle);
76 static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
77 void *farg);
78
79 int
80 lltable_dump_entry(struct lltable *llt, struct llentry *lle,
81 struct rt_walkarg *w, struct sockaddr *sa)
82 {
83 #define RTF_LLINFO 0x400
84 #define RTF_CLONED 0x2000
85 struct ifnet *ifp = llt->llt_ifp;
86 int error;
87 void *a;
88 struct sockaddr_dl sdl;
89 int size;
90 struct rt_addrinfo info;
91
92 memset(&info, 0, sizeof(info));
93 info.rti_info[RTAX_DST] = sa;
94
95 a = (lle->la_flags & LLE_VALID) == LLE_VALID ? &lle->ll_addr : NULL;
96 if (sockaddr_dl_init(&sdl, sizeof(sdl), ifp->if_index, ifp->if_type,
97 NULL, 0, a, ifp->if_addrlen) == NULL)
98 return EINVAL;
99
100 info.rti_info[RTAX_GATEWAY] = sstocsa(&sdl);
101 if (sa->sa_family == AF_INET && lle->la_flags & LLE_PUB) {
102 struct sockaddr_inarp *sin;
103 sin = (struct sockaddr_inarp *)sa;
104 sin->sin_other = SIN_PROXY;
105 }
106 if ((error = rt_msg3(RTM_GET, &info, 0, w, &size)))
107 return error;
108 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
109 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
110
111 /* Need to copy by myself */
112 rtm->rtm_index = ifp->if_index;
113 rtm->rtm_rmx.rmx_mtu = 0;
114 rtm->rtm_rmx.rmx_expire =
115 (lle->la_flags & LLE_STATIC) ? 0 : lle->la_expire;
116 rtm->rtm_flags = RTF_UP;
117 rtm->rtm_flags |= RTF_HOST; /* For ndp */
118 /* For backward compatibility */
119 rtm->rtm_flags |= RTF_LLINFO | RTF_CLONED;
120 rtm->rtm_flags |= (lle->la_flags & LLE_STATIC) ? RTF_STATIC : 0;
121 if (lle->la_flags & LLE_PUB)
122 rtm->rtm_flags |= RTF_ANNOUNCE;
123 rtm->rtm_addrs = info.rti_addrs;
124 if ((error = copyout(rtm, w->w_where, size)) != 0)
125 w->w_where = NULL;
126 else
127 w->w_where = (char *)w->w_where + size;
128 }
129
130 return error;
131 #undef RTF_LLINFO
132 #undef RTF_CLONED
133 }
134
135 /*
136 * Dump lle state for a specific address family.
137 */
138 static int
139 lltable_dump_af(struct lltable *llt, struct rt_walkarg *w)
140 {
141 int error;
142
143 LLTABLE_LOCK_ASSERT();
144
145 if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
146 return (0);
147 error = 0;
148
149 IF_AFDATA_RLOCK(llt->llt_ifp);
150 error = lltable_foreach_lle(llt,
151 (llt_foreach_cb_t *)llt->llt_dump_entry, w);
152 IF_AFDATA_RUNLOCK(llt->llt_ifp);
153
154 return (error);
155 }
156
157 /*
158 * Dump arp state for a specific address family.
159 */
160 int
161 lltable_sysctl_dump(int af, struct rt_walkarg *w)
162 {
163 struct lltable *llt;
164 int error = 0;
165
166 LLTABLE_RLOCK();
167 SLIST_FOREACH(llt, &lltables, llt_link) {
168 if (llt->llt_af == af) {
169 error = lltable_dump_af(llt, w);
170 if (error != 0)
171 goto done;
172 }
173 }
174 done:
175 LLTABLE_RUNLOCK();
176 return (error);
177 }
178
179 /*
180 * Common function helpers for chained hash table.
181 */
182
183 /*
184 * Runs specified callback for each entry in @llt.
185 * Caller does the locking.
186 *
187 */
188 static int
189 htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
190 {
191 struct llentry *lle, *next;
192 int i, error;
193
194 error = 0;
195
196 for (i = 0; i < llt->llt_hsize; i++) {
197 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
198 error = f(llt, lle, farg);
199 if (error != 0)
200 break;
201 }
202 }
203
204 return (error);
205 }
206
207 static void
208 htable_link_entry(struct lltable *llt, struct llentry *lle)
209 {
210 struct llentries *lleh;
211 uint32_t hashidx;
212
213 if ((lle->la_flags & LLE_LINKED) != 0)
214 return;
215
216 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
217
218 hashidx = llt->llt_hash(lle, llt->llt_hsize);
219 lleh = &llt->lle_head[hashidx];
220
221 lle->lle_tbl = llt;
222 lle->lle_head = lleh;
223 lle->la_flags |= LLE_LINKED;
224 LIST_INSERT_HEAD(lleh, lle, lle_next);
225
226 llt->llt_lle_count++;
227 }
228
229 static void
230 htable_unlink_entry(struct llentry *lle)
231 {
232
233 if ((lle->la_flags & LLE_LINKED) != 0) {
234 IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
235 LIST_REMOVE(lle, lle_next);
236 lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
237 #if 0
238 lle->lle_tbl = NULL;
239 lle->lle_head = NULL;
240 #endif
241 KASSERT(lle->lle_tbl->llt_lle_count != 0);
242 lle->lle_tbl->llt_lle_count--;
243 }
244 }
245
246 struct prefix_match_data {
247 const struct sockaddr *prefix;
248 const struct sockaddr *mask;
249 struct llentries dchain;
250 u_int flags;
251 };
252
253 static int
254 htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
255 {
256 struct prefix_match_data *pmd;
257
258 pmd = (struct prefix_match_data *)farg;
259
260 if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
261 LLE_WLOCK(lle);
262 LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
263 }
264
265 return (0);
266 }
267
268 static void
269 htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
270 const struct sockaddr *mask, u_int flags)
271 {
272 struct llentry *lle, *next;
273 struct prefix_match_data pmd;
274
275 memset(&pmd, 0, sizeof(pmd));
276 pmd.prefix = prefix;
277 pmd.mask = mask;
278 pmd.flags = flags;
279 LIST_INIT(&pmd.dchain);
280
281 IF_AFDATA_WLOCK(llt->llt_ifp);
282 /* Push matching lles to chain */
283 lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
284
285 llentries_unlink(llt, &pmd.dchain);
286 IF_AFDATA_WUNLOCK(llt->llt_ifp);
287
288 LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
289 llt->llt_free_entry(llt, lle);
290 }
291
292 static void
293 htable_free_tbl(struct lltable *llt)
294 {
295
296 free(llt->lle_head, M_LLTABLE);
297 free(llt, M_LLTABLE);
298 }
299
300 static void
301 llentries_unlink(struct lltable *llt, struct llentries *head)
302 {
303 struct llentry *lle, *next;
304
305 LIST_FOREACH_SAFE(lle, head, lle_chain, next)
306 llt->llt_unlink_entry(lle);
307 }
308
309 /*
310 * Helper function used to drop all mbufs in hold queue.
311 *
312 * Returns the number of held packets, if any, that were dropped.
313 */
314 size_t
315 lltable_drop_entry_queue(struct llentry *lle)
316 {
317 size_t pkts_dropped;
318 struct mbuf *next;
319
320 LLE_WLOCK_ASSERT(lle);
321
322 pkts_dropped = 0;
323 while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
324 next = lle->la_hold->m_nextpkt;
325 m_freem(lle->la_hold);
326 lle->la_hold = next;
327 lle->la_numheld--;
328 pkts_dropped++;
329 }
330
331 KASSERTMSG(lle->la_numheld == 0,
332 "la_numheld %d > 0, pkts_droped %zd",
333 lle->la_numheld, pkts_dropped);
334
335 return (pkts_dropped);
336 }
337
338 /*
339 * Deletes an address from the address table.
340 * This function is called by the timer functions
341 * such as arptimer() and nd6_llinfo_timer(), and
342 * the caller does the locking.
343 *
344 * Returns the number of held packets, if any, that were dropped.
345 */
346 size_t
347 llentry_free(struct llentry *lle)
348 {
349 struct lltable *llt;
350 size_t pkts_dropped;
351
352 LLE_WLOCK_ASSERT(lle);
353
354 if ((lle->la_flags & LLE_LINKED) != 0) {
355 llt = lle->lle_tbl;
356
357 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
358 llt->llt_unlink_entry(lle);
359 }
360
361 pkts_dropped = lltable_drop_entry_queue(lle);
362
363 LLE_FREE_LOCKED(lle);
364
365 return (pkts_dropped);
366 }
367
368 /*
369 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
370 *
371 * If found the llentry * is returned referenced and unlocked.
372 */
373 struct llentry *
374 llentry_alloc(struct ifnet *ifp, struct lltable *lt,
375 struct sockaddr_storage *dst)
376 {
377 struct llentry *la;
378
379 IF_AFDATA_RLOCK(ifp);
380 la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
381 IF_AFDATA_RUNLOCK(ifp);
382 if ((la == NULL) &&
383 #ifdef __FreeBSD__
384 (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
385 #else /* XXX */
386 (ifp->if_flags & IFF_NOARP) == 0) {
387 #endif
388 IF_AFDATA_WLOCK(ifp);
389 la = lla_create(lt, 0, (struct sockaddr *)dst, NULL /* XXX */);
390 IF_AFDATA_WUNLOCK(ifp);
391 }
392
393 if (la != NULL) {
394 LLE_ADDREF(la);
395 LLE_WUNLOCK(la);
396 }
397
398 return (la);
399 }
400
401 /*
402 * Free all entries from given table and free itself.
403 */
404
405 static int
406 lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
407 {
408 struct llentries *dchain;
409
410 dchain = (struct llentries *)farg;
411
412 LLE_WLOCK(lle);
413 LIST_INSERT_HEAD(dchain, lle, lle_chain);
414
415 return (0);
416 }
417
418 /*
419 * Free all entries from given table.
420 */
421 void
422 lltable_purge_entries(struct lltable *llt)
423 {
424 struct llentry *lle, *next;
425 struct llentries dchain;
426
427 KASSERTMSG(llt != NULL, "llt is NULL");
428
429 LIST_INIT(&dchain);
430 IF_AFDATA_WLOCK(llt->llt_ifp);
431 /* Push all lles to @dchain */
432 lltable_foreach_lle(llt, lltable_free_cb, &dchain);
433 llentries_unlink(llt, &dchain);
434 IF_AFDATA_WUNLOCK(llt->llt_ifp);
435
436 LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
437 /*
438 * We need to release the lock here to lle_timer proceeds;
439 * lle_timer should stop immediately if LLE_LINKED isn't set.
440 * Note that we cannot pass lle->lle_lock to callout_halt
441 * because it's a rwlock.
442 */
443 LLE_ADDREF(lle);
444 LLE_WUNLOCK(lle);
445 #ifdef NET_MPSAFE
446 callout_halt(&lle->la_timer, NULL);
447 #else
448 if (mutex_owned(softnet_lock))
449 callout_halt(&lle->la_timer, softnet_lock);
450 else
451 callout_halt(&lle->la_timer, NULL);
452 #endif
453 LLE_WLOCK(lle);
454 LLE_REMREF(lle);
455 llentry_free(lle);
456 }
457
458 }
459
460 /*
461 * Free all entries from given table and free itself.
462 */
463 void
464 lltable_free(struct lltable *llt)
465 {
466
467 KASSERTMSG(llt != NULL, "llt is NULL");
468
469 lltable_unlink(llt);
470 lltable_purge_entries(llt);
471 llt->llt_free_tbl(llt);
472 }
473
474 void
475 lltable_drain(int af)
476 {
477 struct lltable *llt;
478 struct llentry *lle;
479 register int i;
480
481 LLTABLE_RLOCK();
482 SLIST_FOREACH(llt, &lltables, llt_link) {
483 if (llt->llt_af != af)
484 continue;
485
486 for (i=0; i < llt->llt_hsize; i++) {
487 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
488 LLE_WLOCK(lle);
489 lltable_drop_entry_queue(lle);
490 LLE_WUNLOCK(lle);
491 }
492 }
493 }
494 LLTABLE_RUNLOCK();
495 }
496
497 void
498 lltable_prefix_free(const int af, const struct sockaddr *prefix,
499 const struct sockaddr *mask, const u_int flags)
500 {
501 struct lltable *llt;
502
503 LLTABLE_RLOCK();
504 SLIST_FOREACH(llt, &lltables, llt_link) {
505 if (llt->llt_af != af)
506 continue;
507
508 llt->llt_prefix_free(llt, prefix, mask, flags);
509 }
510 LLTABLE_RUNLOCK();
511 }
512
513 struct lltable *
514 lltable_allocate_htbl(uint32_t hsize)
515 {
516 struct lltable *llt;
517 int i;
518
519 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
520 llt->llt_hsize = hsize;
521 llt->lle_head = malloc(sizeof(struct llentries) * hsize,
522 M_LLTABLE, M_WAITOK | M_ZERO);
523
524 for (i = 0; i < llt->llt_hsize; i++)
525 LIST_INIT(&llt->lle_head[i]);
526
527 /* Set some default callbacks */
528 llt->llt_link_entry = htable_link_entry;
529 llt->llt_unlink_entry = htable_unlink_entry;
530 llt->llt_prefix_free = htable_prefix_free;
531 llt->llt_foreach_entry = htable_foreach_lle;
532
533 llt->llt_free_tbl = htable_free_tbl;
534
535 return (llt);
536 }
537
538 /*
539 * Links lltable to global llt list.
540 */
541 void
542 lltable_link(struct lltable *llt)
543 {
544
545 LLTABLE_WLOCK();
546 SLIST_INSERT_HEAD(&lltables, llt, llt_link);
547 LLTABLE_WUNLOCK();
548 }
549
550 static void
551 lltable_unlink(struct lltable *llt)
552 {
553
554 LLTABLE_WLOCK();
555 SLIST_REMOVE(&lltables, llt, lltable, llt_link);
556 LLTABLE_WUNLOCK();
557
558 }
559
560 /*
561 * External methods used by lltable consumers
562 */
563
564 int
565 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
566 {
567
568 return (llt->llt_foreach_entry(llt, f, farg));
569 }
570
571 void
572 lltable_link_entry(struct lltable *llt, struct llentry *lle)
573 {
574
575 llt->llt_link_entry(llt, lle);
576 }
577
578 void
579 lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
580 {
581
582 llt->llt_unlink_entry(lle);
583 }
584
585 void
586 lltable_free_entry(struct lltable *llt, struct llentry *lle)
587 {
588
589 llt->llt_free_entry(llt, lle);
590 }
591
592 void
593 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
594 {
595 struct lltable *llt;
596
597 llt = lle->lle_tbl;
598 llt->llt_fill_sa_entry(lle, sa);
599 }
600
601 struct ifnet *
602 lltable_get_ifp(const struct lltable *llt)
603 {
604
605 return (llt->llt_ifp);
606 }
607
608 int
609 lltable_get_af(const struct lltable *llt)
610 {
611
612 return (llt->llt_af);
613 }
614
615 /*
616 * Called in route_output when rtm_flags contains RTF_LLDATA.
617 */
618 int
619 lla_rt_output(const u_char rtm_type, const int rtm_flags, const time_t rtm_expire,
620 struct rt_addrinfo *info, int sdl_index)
621 {
622 const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]);
623 const struct sockaddr *dst = info->rti_info[RTAX_DST];
624 struct ifnet *ifp;
625 struct lltable *llt;
626 struct llentry *lle;
627 u_int laflags;
628 int error;
629 struct psref psref;
630 int bound;
631
632 KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl");
633
634 bound = curlwp_bind();
635 if (sdl_index != 0)
636 ifp = if_get_byindex(sdl_index, &psref);
637 else
638 ifp = if_get_byindex(dl->sdl_index, &psref);
639 if (ifp == NULL) {
640 curlwp_bindx(bound);
641 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
642 __func__, sdl_index != 0 ? sdl_index : dl->sdl_index);
643 return EINVAL;
644 }
645
646 /* XXX linked list may be too expensive */
647 LLTABLE_RLOCK();
648 SLIST_FOREACH(llt, &lltables, llt_link) {
649 if (llt->llt_af == dst->sa_family &&
650 llt->llt_ifp == ifp)
651 break;
652 }
653 LLTABLE_RUNLOCK();
654 KASSERTMSG(llt != NULL, "Yep, ugly hacks are bad");
655
656 error = 0;
657
658 switch (rtm_type) {
659 case RTM_ADD: {
660 struct rtentry *rt;
661
662 /* Never call rtalloc1 with IF_AFDATA_WLOCK */
663 rt = rtalloc1(dst, 0);
664
665 /* Add static LLE */
666 IF_AFDATA_WLOCK(ifp);
667 lle = lla_lookup(llt, 0, dst);
668
669 /* Cannot overwrite an existing static entry */
670 if (lle != NULL &&
671 (lle->la_flags & LLE_STATIC || lle->la_expire == 0)) {
672 LLE_RUNLOCK(lle);
673 IF_AFDATA_WUNLOCK(ifp);
674 if (rt != NULL)
675 rt_unref(rt);
676 error = EEXIST;
677 goto out;
678 }
679 if (lle != NULL)
680 LLE_RUNLOCK(lle);
681
682 lle = lla_create(llt, 0, dst, rt);
683 if (lle == NULL) {
684 IF_AFDATA_WUNLOCK(ifp);
685 if (rt != NULL)
686 rt_unref(rt);
687 error = ENOMEM;
688 goto out;
689 }
690
691 KASSERT(ifp->if_addrlen <= sizeof(lle->ll_addr));
692 memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen);
693 if ((rtm_flags & RTF_ANNOUNCE))
694 lle->la_flags |= LLE_PUB;
695 lle->la_flags |= LLE_VALID;
696 #ifdef INET6
697 /*
698 * ND6
699 */
700 if (dst->sa_family == AF_INET6)
701 lle->ln_state = ND6_LLINFO_REACHABLE;
702 #endif
703 /*
704 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
705 */
706
707 if (rtm_expire == 0) {
708 lle->la_flags |= LLE_STATIC;
709 lle->la_expire = 0;
710 } else
711 lle->la_expire = rtm_expire;
712 laflags = lle->la_flags;
713 LLE_WUNLOCK(lle);
714 IF_AFDATA_WUNLOCK(ifp);
715 if (rt != NULL)
716 rt_unref(rt);
717 #if defined(INET) && NARP > 0
718 /* gratuitous ARP */
719 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) {
720 const struct sockaddr_in *sin;
721 struct in_ifaddr *ia;
722 struct psref _psref;
723
724 sin = satocsin(dst);
725 ia = in_get_ia_on_iface_psref(sin->sin_addr,
726 ifp, &_psref);
727 if (ia != NULL) {
728 arpannounce(ifp, &ia->ia_ifa, CLLADDR(dl));
729 ia4_release(ia, &_psref);
730 }
731 }
732 #else
733 (void)laflags;
734 #endif
735 break;
736 }
737
738 case RTM_DELETE:
739 IF_AFDATA_WLOCK(ifp);
740 error = lla_delete(llt, 0, dst);
741 IF_AFDATA_WUNLOCK(ifp);
742 error = (error == 0 ? 0 : ENOENT);
743 break;
744
745 default:
746 error = EINVAL;
747 }
748
749 out:
750 if_put(ifp, &psref);
751 curlwp_bindx(bound);
752 return (error);
753 }
754
755 void
756 lltableinit(void)
757 {
758
759 SLIST_INIT(&lltables);
760 rw_init(&lltable_rwlock);
761 }
762
763 #ifdef __FreeBSD__
764 #ifdef DDB
765 struct llentry_sa {
766 struct llentry base;
767 struct sockaddr l3_addr;
768 };
769
770 static void
771 llatbl_lle_show(struct llentry_sa *la)
772 {
773 struct llentry *lle;
774 uint8_t octet[6];
775
776 lle = &la->base;
777 db_printf("lle=%p\n", lle);
778 db_printf(" lle_next=%p\n", lle->lle_next.le_next);
779 db_printf(" lle_lock=%p\n", &lle->lle_lock);
780 db_printf(" lle_tbl=%p\n", lle->lle_tbl);
781 db_printf(" lle_head=%p\n", lle->lle_head);
782 db_printf(" la_hold=%p\n", lle->la_hold);
783 db_printf(" la_numheld=%d\n", lle->la_numheld);
784 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
785 db_printf(" la_flags=0x%04x\n", lle->la_flags);
786 db_printf(" la_asked=%u\n", lle->la_asked);
787 db_printf(" la_preempt=%u\n", lle->la_preempt);
788 db_printf(" ln_byhint=%u\n", lle->ln_byhint);
789 db_printf(" ln_state=%d\n", lle->ln_state);
790 db_printf(" ln_router=%u\n", lle->ln_router);
791 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
792 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
793 memcopy(octet, &lle->ll_addr.mac16, sizeof(octet));
794 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
795 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
796 db_printf(" lle_timer=%p\n", &lle->lle_timer);
797
798 switch (la->l3_addr.sa_family) {
799 #ifdef INET
800 case AF_INET:
801 {
802 struct sockaddr_in *sin;
803 char l3s[INET_ADDRSTRLEN];
804
805 sin = (struct sockaddr_in *)&la->l3_addr;
806 inet_ntoa_r(sin->sin_addr, l3s);
807 db_printf(" l3_addr=%s\n", l3s);
808 break;
809 }
810 #endif
811 #ifdef INET6
812 case AF_INET6:
813 {
814 struct sockaddr_in6 *sin6;
815 char l3s[INET6_ADDRSTRLEN];
816
817 sin6 = (struct sockaddr_in6 *)&la->l3_addr;
818 IN6_PRINT(l3s, &sin6->sin6_addr);
819 db_printf(" l3_addr=%s\n", l3s);
820 break;
821 }
822 #endif
823 default:
824 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
825 break;
826 }
827 }
828
829 DB_SHOW_COMMAND(llentry, db_show_llentry)
830 {
831
832 if (!have_addr) {
833 db_printf("usage: show llentry <struct llentry *>\n");
834 return;
835 }
836
837 llatbl_lle_show((struct llentry_sa *)addr);
838 }
839
840 static void
841 llatbl_llt_show(struct lltable *llt)
842 {
843 int i;
844 struct llentry *lle;
845
846 db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
847 llt, llt->llt_af, llt->llt_ifp);
848
849 for (i = 0; i < llt->llt_hsize; i++) {
850 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
851
852 llatbl_lle_show((struct llentry_sa *)lle);
853 if (db_pager_quit)
854 return;
855 }
856 }
857 }
858
859 DB_SHOW_COMMAND(lltable, db_show_lltable)
860 {
861
862 if (!have_addr) {
863 db_printf("usage: show lltable <struct lltable *>\n");
864 return;
865 }
866
867 llatbl_llt_show((struct lltable *)addr);
868 }
869
870 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
871 {
872 VNET_ITERATOR_DECL(vnet_iter);
873 struct lltable *llt;
874
875 VNET_FOREACH(vnet_iter) {
876 CURVNET_SET_QUIET(vnet_iter);
877 #ifdef VIMAGE
878 db_printf("vnet=%p\n", curvnet);
879 #endif
880 SLIST_FOREACH(llt, &lltables, llt_link) {
881 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
882 llt, llt->llt_af, llt->llt_ifp,
883 (llt->llt_ifp != NULL) ?
884 llt->llt_ifp->if_xname : "?");
885 if (have_addr && addr != 0) /* verbose */
886 llatbl_llt_show(llt);
887 if (db_pager_quit) {
888 CURVNET_RESTORE();
889 return;
890 }
891 }
892 CURVNET_RESTORE();
893 }
894 }
895 #endif /* DDB */
896 #endif /* __FreeBSD__ */
897