1 /* $NetBSD: if_llatbl.c,v 1.22 2017/11/10 07:24:28 ozaki-r 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