1 /* 2 * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. 3 * Copyright (c) 2004-2008 Qing Li. All rights reserved. 4 * Copyright (c) 2008 Kip Macy. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "opt_ddb.h" 31 #include "opt_inet.h" 32 #include "opt_inet6.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/malloc.h> 37 #include <sys/mbuf.h> 38 #include <sys/syslog.h> 39 #include <sys/sysctl.h> 40 #include <sys/socket.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/mutex.h> 44 #include <sys/rwlock.h> 45 46 #ifdef DDB 47 #include <ddb/ddb.h> 48 #endif 49 50 #include <vm/uma.h> 51 52 #include <netinet/in.h> 53 #include <net/if_llatbl.h> 54 #include <net/if.h> 55 #include <net/if_dl.h> 56 #include <net/if_var.h> 57 #include <net/route.h> 58 #include <net/vnet.h> 59 #include <netinet/if_ether.h> 60 #include <netinet6/in6_var.h> 61 #include <netinet6/nd6.h> 62 63 MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 64 65 static VNET_DEFINE(SLIST_HEAD(, lltable), lltables); 66 #define V_lltables VNET(lltables) 67 68 extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, 69 u_char *); 70 71 static void vnet_lltable_init(void); 72 73 struct rwlock lltable_rwlock; 74 RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock"); 75 76 /* 77 * Dump arp state for a specific address family. 78 */ 79 int 80 lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 81 { 82 struct lltable *llt; 83 int error = 0; 84 85 LLTABLE_RLOCK(); 86 SLIST_FOREACH(llt, &V_lltables, llt_link) { 87 if (llt->llt_af == af) { 88 error = llt->llt_dump(llt, wr); 89 if (error != 0) 90 goto done; 91 } 92 } 93 done: 94 LLTABLE_RUNLOCK(); 95 return (error); 96 } 97 98 /* 99 * Deletes an address from the address table. 100 * This function is called by the timer functions 101 * such as arptimer() and nd6_llinfo_timer(), and 102 * the caller does the locking. 103 */ 104 void 105 llentry_free(struct llentry *lle) 106 { 107 108 LLE_WLOCK_ASSERT(lle); 109 LIST_REMOVE(lle, lle_next); 110 111 if (lle->la_hold != NULL) 112 m_freem(lle->la_hold); 113 114 LLE_FREE_LOCKED(lle); 115 } 116 117 /* 118 * Update an llentry for address dst (equivalent to rtalloc for new-arp) 119 * Caller must pass in a valid struct llentry * (or NULL) 120 * 121 * if found the llentry * is returned referenced and unlocked 122 */ 123 int 124 llentry_update(struct llentry **llep, struct lltable *lt, 125 struct sockaddr_storage *dst, struct ifnet *ifp) 126 { 127 struct llentry *la; 128 129 IF_AFDATA_RLOCK(ifp); 130 la = lla_lookup(lt, LLE_EXCLUSIVE, 131 (struct sockaddr *)dst); 132 IF_AFDATA_RUNLOCK(ifp); 133 if ((la == NULL) && 134 (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 135 IF_AFDATA_WLOCK(ifp); 136 la = lla_lookup(lt, 137 (LLE_CREATE | LLE_EXCLUSIVE), 138 (struct sockaddr *)dst); 139 IF_AFDATA_WUNLOCK(ifp); 140 } 141 if (la != NULL && (*llep != la)) { 142 if (*llep != NULL) 143 LLE_FREE(*llep); 144 LLE_ADDREF(la); 145 LLE_WUNLOCK(la); 146 *llep = la; 147 } else if (la != NULL) 148 LLE_WUNLOCK(la); 149 150 if (la == NULL) 151 return (ENOENT); 152 153 return (0); 154 } 155 156 /* 157 * Free all entries from given table and free itself. 158 */ 159 void 160 lltable_free(struct lltable *llt) 161 { 162 struct llentry *lle, *next; 163 int i; 164 165 KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 166 167 LLTABLE_WLOCK(); 168 SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 169 LLTABLE_WUNLOCK(); 170 171 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 172 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 173 174 callout_drain(&lle->la_timer); 175 LLE_WLOCK(lle); 176 llentry_free(lle); 177 } 178 } 179 180 free(llt, M_LLTABLE); 181 } 182 183 void 184 lltable_drain(int af) 185 { 186 struct lltable *llt; 187 struct llentry *lle; 188 register int i; 189 190 LLTABLE_RLOCK(); 191 SLIST_FOREACH(llt, &V_lltables, llt_link) { 192 if (llt->llt_af != af) 193 continue; 194 195 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 196 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 197 if (lle->la_hold) { 198 m_freem(lle->la_hold); 199 lle->la_hold = NULL; 200 } 201 } 202 } 203 } 204 LLTABLE_RUNLOCK(); 205 } 206 207 void 208 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask) 209 { 210 struct lltable *llt; 211 212 LLTABLE_RLOCK(); 213 SLIST_FOREACH(llt, &V_lltables, llt_link) { 214 if (llt->llt_af != af) 215 continue; 216 217 llt->llt_prefix_free(llt, prefix, mask); 218 } 219 LLTABLE_RUNLOCK(); 220 } 221 222 223 224 /* 225 * Create a new lltable. 226 */ 227 struct lltable * 228 lltable_init(struct ifnet *ifp, int af) 229 { 230 struct lltable *llt; 231 register int i; 232 233 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK); 234 if (llt == NULL) 235 return (NULL); 236 237 llt->llt_af = af; 238 llt->llt_ifp = ifp; 239 for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) 240 LIST_INIT(&llt->lle_head[i]); 241 242 LLTABLE_WLOCK(); 243 SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 244 LLTABLE_WUNLOCK(); 245 246 return (llt); 247 } 248 249 /* 250 * Called in route_output when adding/deleting a route to an interface. 251 */ 252 int 253 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 254 { 255 struct sockaddr_dl *dl = 256 (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 257 struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 258 struct ifnet *ifp; 259 struct lltable *llt; 260 struct llentry *lle; 261 u_int laflags = 0, flags = 0; 262 int error = 0; 263 264 if (dl == NULL || dl->sdl_family != AF_LINK) { 265 log(LOG_INFO, "%s: invalid dl\n", __func__); 266 return EINVAL; 267 } 268 ifp = ifnet_byindex(dl->sdl_index); 269 if (ifp == NULL) { 270 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 271 __func__, dl->sdl_index); 272 return EINVAL; 273 } 274 275 switch (rtm->rtm_type) { 276 case RTM_ADD: 277 if (rtm->rtm_flags & RTF_ANNOUNCE) { 278 flags |= LLE_PUB; 279 #ifdef INET 280 if (dst->sa_family == AF_INET && 281 ((struct sockaddr_inarp *)dst)->sin_other != 0) { 282 struct rtentry *rt; 283 ((struct sockaddr_inarp *)dst)->sin_other = 0; 284 rt = rtalloc1(dst, 0, 0); 285 if (rt == NULL || !(rt->rt_flags & RTF_HOST)) { 286 log(LOG_INFO, "%s: RTM_ADD publish " 287 "(proxy only) is invalid\n", 288 __func__); 289 if (rt) 290 RTFREE_LOCKED(rt); 291 return EINVAL; 292 } 293 RTFREE_LOCKED(rt); 294 295 flags |= LLE_PROXY; 296 } 297 #endif 298 } 299 flags |= LLE_CREATE; 300 break; 301 302 case RTM_DELETE: 303 flags |= LLE_DELETE; 304 break; 305 306 case RTM_CHANGE: 307 break; 308 309 default: 310 return EINVAL; /* XXX not implemented yet */ 311 } 312 313 /* XXX linked list may be too expensive */ 314 LLTABLE_RLOCK(); 315 SLIST_FOREACH(llt, &V_lltables, llt_link) { 316 if (llt->llt_af == dst->sa_family && 317 llt->llt_ifp == ifp) 318 break; 319 } 320 LLTABLE_RUNLOCK(); 321 KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); 322 323 if (flags && LLE_CREATE) 324 flags |= LLE_EXCLUSIVE; 325 326 IF_AFDATA_LOCK(ifp); 327 lle = lla_lookup(llt, flags, dst); 328 IF_AFDATA_UNLOCK(ifp); 329 if (LLE_IS_VALID(lle)) { 330 if (flags & LLE_CREATE) { 331 /* 332 * If we delay the delete, then a subsequent 333 * "arp add" should look up this entry, reset the 334 * LLE_DELETED flag, and reset the expiration timer 335 */ 336 bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); 337 lle->la_flags |= LLE_VALID; 338 lle->la_flags &= ~LLE_DELETED; 339 #ifdef INET6 340 /* 341 * ND6 342 */ 343 if (dst->sa_family == AF_INET6) 344 lle->ln_state = ND6_LLINFO_REACHABLE; 345 #endif 346 /* 347 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) 348 */ 349 350 if (rtm->rtm_rmx.rmx_expire == 0) { 351 lle->la_flags |= LLE_STATIC; 352 lle->la_expire = 0; 353 } else 354 lle->la_expire = rtm->rtm_rmx.rmx_expire; 355 laflags = lle->la_flags; 356 LLE_WUNLOCK(lle); 357 #ifdef INET 358 /* gratuitous ARP */ 359 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { 360 arprequest(ifp, 361 &((struct sockaddr_in *)dst)->sin_addr, 362 &((struct sockaddr_in *)dst)->sin_addr, 363 ((laflags & LLE_PROXY) ? 364 (u_char *)IF_LLADDR(ifp) : 365 (u_char *)LLADDR(dl))); 366 } 367 #endif 368 } else { 369 if (flags & LLE_EXCLUSIVE) 370 LLE_WUNLOCK(lle); 371 else 372 LLE_RUNLOCK(lle); 373 } 374 } else if ((lle == NULL) && (flags & LLE_DELETE)) 375 error = EINVAL; 376 377 378 return (error); 379 } 380 381 static void 382 vnet_lltable_init() 383 { 384 385 SLIST_INIT(&V_lltables); 386 } 387 VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST, 388 vnet_lltable_init, NULL); 389 390 #ifdef DDB 391 struct llentry_sa { 392 struct llentry base; 393 struct sockaddr l3_addr; 394 }; 395 396 static void 397 llatbl_lle_show(struct llentry_sa *la) 398 { 399 struct llentry *lle; 400 uint8_t octet[6]; 401 402 lle = &la->base; 403 db_printf("lle=%p\n", lle); 404 db_printf(" lle_next=%p\n", lle->lle_next.le_next); 405 db_printf(" lle_lock=%p\n", &lle->lle_lock); 406 db_printf(" lle_tbl=%p\n", lle->lle_tbl); 407 db_printf(" lle_head=%p\n", lle->lle_head); 408 db_printf(" la_hold=%p\n", lle->la_hold); 409 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 410 db_printf(" la_flags=0x%04x\n", lle->la_flags); 411 db_printf(" la_asked=%u\n", lle->la_asked); 412 db_printf(" la_preempt=%u\n", lle->la_preempt); 413 db_printf(" ln_byhint=%u\n", lle->ln_byhint); 414 db_printf(" ln_state=%d\n", lle->ln_state); 415 db_printf(" ln_router=%u\n", lle->ln_router); 416 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 417 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 418 bcopy(&lle->ll_addr.mac16, octet, sizeof(octet)); 419 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 420 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 421 db_printf(" la_timer=%p\n", &lle->la_timer); 422 423 switch (la->l3_addr.sa_family) { 424 #ifdef INET 425 case AF_INET: 426 { 427 struct sockaddr_in *sin; 428 char l3s[INET_ADDRSTRLEN]; 429 430 sin = (struct sockaddr_in *)&la->l3_addr; 431 inet_ntoa_r(sin->sin_addr, l3s); 432 db_printf(" l3_addr=%s\n", l3s); 433 break; 434 } 435 #endif 436 #ifdef INET6 437 case AF_INET6: 438 { 439 struct sockaddr_in6 *sin6; 440 char l3s[INET6_ADDRSTRLEN]; 441 442 sin6 = (struct sockaddr_in6 *)&la->l3_addr; 443 ip6_sprintf(l3s, &sin6->sin6_addr); 444 db_printf(" l3_addr=%s\n", l3s); 445 break; 446 } 447 #endif 448 default: 449 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 450 break; 451 } 452 } 453 454 DB_SHOW_COMMAND(llentry, db_show_llentry) 455 { 456 457 if (!have_addr) { 458 db_printf("usage: show llentry <struct llentry *>\n"); 459 return; 460 } 461 462 llatbl_lle_show((struct llentry_sa *)addr); 463 } 464 465 static void 466 llatbl_llt_show(struct lltable *llt) 467 { 468 int i; 469 struct llentry *lle; 470 471 db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 472 llt, llt->llt_af, llt->llt_ifp); 473 474 for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 475 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 476 477 llatbl_lle_show((struct llentry_sa *)lle); 478 if (db_pager_quit) 479 return; 480 } 481 } 482 } 483 484 DB_SHOW_COMMAND(lltable, db_show_lltable) 485 { 486 487 if (!have_addr) { 488 db_printf("usage: show lltable <struct lltable *>\n"); 489 return; 490 } 491 492 llatbl_llt_show((struct lltable *)addr); 493 } 494 495 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 496 { 497 VNET_ITERATOR_DECL(vnet_iter); 498 struct lltable *llt; 499 500 VNET_FOREACH(vnet_iter) { 501 CURVNET_SET_QUIET(vnet_iter); 502 #ifdef VIMAGE 503 db_printf("vnet=%p\n", curvnet); 504 #endif 505 SLIST_FOREACH(llt, &V_lltables, llt_link) { 506 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 507 llt, llt->llt_af, llt->llt_ifp, 508 (llt->llt_ifp != NULL) ? 509 llt->llt_ifp->if_xname : "?"); 510 if (have_addr && addr != 0) /* verbose */ 511 llatbl_llt_show(llt); 512 if (db_pager_quit) { 513 CURVNET_RESTORE(); 514 return; 515 } 516 } 517 CURVNET_RESTORE(); 518 } 519 } 520 #endif 521