1 /* $NetBSD: aarp.c,v 1.34 2009/09/12 20:43:18 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1990,1991 Regents of The University of Michigan. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby granted, 9 * provided that the above copyright notice appears in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation, and that the name of The University 12 * of Michigan not be used in advertising or publicity pertaining to 13 * distribution of the software without specific, written prior 14 * permission. This software is supplied as is without expressed or 15 * implied warranties of any kind. 16 * 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 20 * Research Systems Unix Group 21 * The University of Michigan 22 * c/o Wesley Craig 23 * 535 W. William Street 24 * Ann Arbor, Michigan 25 * +1-313-764-2278 26 * netatalk@umich.edu 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: aarp.c,v 1.34 2009/09/12 20:43:18 tsutsui Exp $"); 31 32 #include "opt_mbuftrace.h" 33 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/syslog.h> 37 #include <sys/systm.h> 38 #include <sys/callout.h> 39 #include <sys/proc.h> 40 #include <sys/mbuf.h> 41 #include <sys/time.h> 42 #include <sys/kernel.h> 43 #include <sys/socketvar.h> 44 #include <net/if.h> 45 #include <net/route.h> 46 #include <net/if_ether.h> 47 #include <net/if_dl.h> 48 #include <netinet/in.h> 49 #undef s_net 50 51 #include <netatalk/at.h> 52 #include <netatalk/at_var.h> 53 #include <netatalk/aarp.h> 54 #include <netatalk/ddp_var.h> 55 #include <netatalk/phase2.h> 56 #include <netatalk/at_extern.h> 57 58 static struct aarptab *aarptnew(const struct at_addr *); 59 static void aarptfree(struct aarptab *); 60 static void at_aarpinput(struct ifnet *, struct mbuf *); 61 static void aarptimer(void *); 62 static void aarpwhohas(struct ifnet *, const struct sockaddr_at *); 63 64 #define AARPTAB_BSIZ 9 65 #define AARPTAB_NB 19 66 #define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) 67 struct aarptab aarptab[AARPTAB_SIZE]; 68 69 #define AARPTAB_HASH(a) \ 70 ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB ) 71 72 #define AARPTAB_LOOK(aat,addr) { \ 73 int n; \ 74 aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \ 75 for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \ 76 if ( aat->aat_ataddr.s_net == (addr).s_net && \ 77 aat->aat_ataddr.s_node == (addr).s_node ) \ 78 break; \ 79 if ( n >= AARPTAB_BSIZ ) \ 80 aat = 0; \ 81 } 82 83 #define AARPT_AGE (60 * 1) 84 #define AARPT_KILLC 20 85 #define AARPT_KILLI 3 86 87 const u_char atmulticastaddr[6] = { 88 0x09, 0x00, 0x07, 0xff, 0xff, 0xff 89 }; 90 91 const u_char at_org_code[3] = { 92 0x08, 0x00, 0x07 93 }; 94 const u_char aarp_org_code[3] = { 95 0x00, 0x00, 0x00 96 }; 97 98 struct callout aarptimer_callout; 99 #ifdef MBUFTRACE 100 struct mowner aarp_mowner = MOWNER_INIT("atalk", "arp"); 101 #endif 102 103 /*ARGSUSED*/ 104 static void 105 aarptimer(void *ignored) 106 { 107 struct aarptab *aat; 108 int i, s; 109 110 mutex_enter(softnet_lock); 111 callout_reset(&aarptimer_callout, AARPT_AGE * hz, aarptimer, NULL); 112 aat = aarptab; 113 for (i = 0; i < AARPTAB_SIZE; i++, aat++) { 114 int killtime = (aat->aat_flags & ATF_COM) ? AARPT_KILLC : 115 AARPT_KILLI; 116 if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM)) 117 continue; 118 if (++aat->aat_timer < killtime) 119 continue; 120 s = splnet(); 121 aarptfree(aat); 122 splx(s); 123 } 124 mutex_exit(softnet_lock); 125 } 126 127 /* 128 * search through the network addresses to find one that includes the given 129 * network.. remember to take netranges into consideration. 130 */ 131 struct ifaddr * 132 at_ifawithnet(const struct sockaddr_at *sat, struct ifnet *ifp) 133 { 134 struct ifaddr *ifa; 135 struct sockaddr_at *sat2; 136 struct netrange *nr; 137 138 IFADDR_FOREACH(ifa, ifp) { 139 if (ifa->ifa_addr->sa_family != AF_APPLETALK) 140 continue; 141 142 sat2 = satosat(ifa->ifa_addr); 143 if (sat2->sat_addr.s_net == sat->sat_addr.s_net) 144 break; 145 146 nr = (struct netrange *) (sat2->sat_zero); 147 if ((nr->nr_phase == 2) 148 && (ntohs(nr->nr_firstnet) <= ntohs(sat->sat_addr.s_net)) 149 && (ntohs(nr->nr_lastnet) >= ntohs(sat->sat_addr.s_net))) 150 break; 151 } 152 return ifa; 153 } 154 155 static void 156 aarpwhohas(struct ifnet *ifp, const struct sockaddr_at *sat) 157 { 158 struct mbuf *m; 159 struct ether_header *eh; 160 struct ether_aarp *ea; 161 struct at_ifaddr *aa; 162 struct llc *llc; 163 struct sockaddr sa; 164 165 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 166 return; 167 168 MCLAIM(m, &aarp_mowner); 169 m->m_len = sizeof(*ea); 170 m->m_pkthdr.len = sizeof(*ea); 171 MH_ALIGN(m, sizeof(*ea)); 172 173 ea = mtod(m, struct ether_aarp *); 174 memset(ea, 0, sizeof(*ea)); 175 176 ea->aarp_hrd = htons(AARPHRD_ETHER); 177 ea->aarp_pro = htons(ETHERTYPE_ATALK); 178 ea->aarp_hln = sizeof(ea->aarp_sha); 179 ea->aarp_pln = sizeof(ea->aarp_spu); 180 ea->aarp_op = htons(AARPOP_REQUEST); 181 memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha)); 182 183 /* 184 * We need to check whether the output ethernet type should 185 * be phase 1 or 2. We have the interface that we'll be sending 186 * the aarp out. We need to find an AppleTalk network on that 187 * interface with the same address as we're looking for. If the 188 * net is phase 2, generate an 802.2 and SNAP header. 189 */ 190 if ((aa = (struct at_ifaddr *) at_ifawithnet(sat, ifp)) == NULL) { 191 m_freem(m); 192 return; 193 } 194 eh = (struct ether_header *) sa.sa_data; 195 196 if (aa->aa_flags & AFA_PHASE2) { 197 memcpy(eh->ether_dhost, atmulticastaddr, 198 sizeof(eh->ether_dhost)); 199 eh->ether_type = 0; /* if_output will treat as 802 */ 200 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 201 if (!m) 202 return; 203 204 llc = mtod(m, struct llc *); 205 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 206 llc->llc_control = LLC_UI; 207 memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code)); 208 llc->llc_ether_type = htons(ETHERTYPE_AARP); 209 210 memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net, 211 sizeof(ea->aarp_spnet)); 212 memcpy(ea->aarp_tpnet, &sat->sat_addr.s_net, 213 sizeof(ea->aarp_tpnet)); 214 ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node; 215 ea->aarp_tpnode = sat->sat_addr.s_node; 216 } else { 217 memcpy(eh->ether_dhost, etherbroadcastaddr, 218 sizeof(eh->ether_dhost)); 219 eh->ether_type = htons(ETHERTYPE_AARP); 220 221 ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node; 222 ea->aarp_tpa = sat->sat_addr.s_node; 223 } 224 225 #ifdef NETATALKDEBUG 226 printf("aarp: sending request via %u.%u seaking %u.%u\n", 227 ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node, 228 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 229 #endif /* NETATALKDEBUG */ 230 231 sa.sa_len = sizeof(struct sockaddr); 232 sa.sa_family = AF_UNSPEC; 233 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX NULL should be routing */ 234 /* information */ 235 } 236 237 int 238 aarpresolve(struct ifnet *ifp, struct mbuf *m, 239 const struct sockaddr_at *destsat, u_char *desten) 240 { 241 struct at_ifaddr *aa; 242 struct aarptab *aat; 243 int s; 244 245 if (at_broadcast(destsat)) { 246 aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp); 247 if (aa == NULL) { 248 m_freem(m); 249 return (0); 250 } 251 if (aa->aa_flags & AFA_PHASE2) 252 memcpy(desten, atmulticastaddr, 253 sizeof(atmulticastaddr)); 254 else 255 memcpy(desten, etherbroadcastaddr, 256 sizeof(etherbroadcastaddr)); 257 return 1; 258 } 259 s = splnet(); 260 AARPTAB_LOOK(aat, destsat->sat_addr); 261 if (aat == 0) { /* No entry */ 262 aat = aarptnew(&destsat->sat_addr); 263 if (aat == 0) 264 panic("aarpresolve: no free entry"); 265 266 aat->aat_hold = m; 267 aarpwhohas(ifp, destsat); 268 splx(s); 269 return 0; 270 } 271 272 /* found an entry */ 273 aat->aat_timer = 0; 274 if (aat->aat_flags & ATF_COM) { /* entry is COMplete */ 275 memcpy(desten, aat->aat_enaddr, sizeof(aat->aat_enaddr)); 276 splx(s); 277 return 1; 278 } 279 280 /* entry has not completed */ 281 if (aat->aat_hold) 282 m_freem(aat->aat_hold); 283 aat->aat_hold = m; 284 aarpwhohas(ifp, destsat); 285 splx(s); 286 287 return 0; 288 } 289 290 void 291 aarpinput(struct ifnet *ifp, struct mbuf *m) 292 { 293 struct arphdr *ar; 294 295 if (ifp->if_flags & IFF_NOARP) 296 goto out; 297 298 if (m->m_len < sizeof(struct arphdr)) 299 goto out; 300 301 ar = mtod(m, struct arphdr *); 302 if (ntohs(ar->ar_hrd) != AARPHRD_ETHER) 303 goto out; 304 305 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 306 goto out; 307 308 switch (ntohs(ar->ar_pro)) { 309 case ETHERTYPE_ATALK: 310 at_aarpinput(ifp, m); 311 return; 312 313 default: 314 break; 315 } 316 317 out: 318 m_freem(m); 319 } 320 321 static void 322 at_aarpinput(struct ifnet *ifp, struct mbuf *m) 323 { 324 struct ether_aarp *ea; 325 struct at_ifaddr *aa; 326 struct ifaddr *ia; 327 struct aarptab *aat; 328 struct ether_header *eh; 329 struct llc *llc; 330 struct sockaddr_at sat; 331 struct sockaddr sa; 332 struct at_addr spa, tpa, ma; 333 int op; 334 u_int16_t net; 335 336 ea = mtod(m, struct ether_aarp *); 337 338 /* Check to see if from my hardware address */ 339 if (!memcmp(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha))) { 340 m_freem(m); 341 return; 342 } 343 op = ntohs(ea->aarp_op); 344 memcpy(&net, ea->aarp_tpnet, sizeof(net)); 345 346 if (net != 0) { /* should be ATADDR_ANYNET? */ 347 sat.sat_len = sizeof(struct sockaddr_at); 348 sat.sat_family = AF_APPLETALK; 349 sat.sat_addr.s_net = net; 350 aa = (struct at_ifaddr *) at_ifawithnet(&sat, ifp); 351 if (aa == NULL) { 352 m_freem(m); 353 return; 354 } 355 memcpy(&spa.s_net, ea->aarp_spnet, sizeof(spa.s_net)); 356 memcpy(&tpa.s_net, ea->aarp_tpnet, sizeof(tpa.s_net)); 357 } else { 358 /* 359 * Since we don't know the net, we just look for the first 360 * phase 1 address on the interface. 361 */ 362 IFADDR_FOREACH(ia, ifp) { 363 aa = (struct at_ifaddr *)ia; 364 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 365 (aa->aa_flags & AFA_PHASE2) == 0) 366 break; 367 } 368 if (ia == NULL) { 369 m_freem(m); 370 return; 371 } 372 tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net; 373 } 374 375 spa.s_node = ea->aarp_spnode; 376 tpa.s_node = ea->aarp_tpnode; 377 ma.s_net = AA_SAT(aa)->sat_addr.s_net; 378 ma.s_node = AA_SAT(aa)->sat_addr.s_node; 379 380 /* 381 * This looks like it's from us. 382 */ 383 if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) { 384 if (aa->aa_flags & AFA_PROBING) { 385 /* 386 * We're probing, someone either responded to our 387 * probe, or probed for the same address we'd like 388 * to use. Change the address we're probing for. 389 */ 390 callout_stop(&aa->aa_probe_ch); 391 wakeup(aa); 392 m_freem(m); 393 return; 394 } else if (op != AARPOP_PROBE) { 395 /* 396 * This is not a probe, and we're not probing. 397 * This means that someone's saying they have the same 398 * source address as the one we're using. Get upset... 399 */ 400 log(LOG_ERR, "aarp: duplicate AT address!! %s\n", 401 ether_sprintf(ea->aarp_sha)); 402 m_freem(m); 403 return; 404 } 405 } 406 AARPTAB_LOOK(aat, spa); 407 if (aat) { 408 if (op == AARPOP_PROBE) { 409 /* 410 * Someone's probing for spa, deallocate the one we've 411 * got, so that if the prober keeps the address, we'll 412 * be able to arp for him. 413 */ 414 aarptfree(aat); 415 m_freem(m); 416 return; 417 } 418 memcpy(aat->aat_enaddr, ea->aarp_sha, sizeof(ea->aarp_sha)); 419 aat->aat_flags |= ATF_COM; 420 if (aat->aat_hold) { 421 sat.sat_len = sizeof(struct sockaddr_at); 422 sat.sat_family = AF_APPLETALK; 423 sat.sat_addr = spa; 424 (*ifp->if_output)(ifp, aat->aat_hold, 425 (struct sockaddr *) & sat, NULL); /* XXX */ 426 aat->aat_hold = 0; 427 } 428 } 429 if (aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node 430 && op != AARPOP_PROBE) { 431 if ((aat = aarptnew(&spa)) != NULL) { 432 memcpy(aat->aat_enaddr, ea->aarp_sha, 433 sizeof(ea->aarp_sha)); 434 aat->aat_flags |= ATF_COM; 435 } 436 } 437 /* 438 * Don't respond to responses, and never respond if we're 439 * still probing. 440 */ 441 if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node || 442 op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) { 443 m_freem(m); 444 return; 445 } 446 447 /* 448 * Prepare and send AARP-response. 449 */ 450 m->m_len = sizeof(*ea); 451 m->m_pkthdr.len = sizeof(*ea); 452 memcpy(ea->aarp_tha, ea->aarp_sha, sizeof(ea->aarp_sha)); 453 memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha)); 454 455 /* XXX */ 456 eh = (struct ether_header *) sa.sa_data; 457 memcpy(eh->ether_dhost, ea->aarp_tha, sizeof(eh->ether_dhost)); 458 459 if (aa->aa_flags & AFA_PHASE2) { 460 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 461 if (m == NULL) 462 return; 463 464 llc = mtod(m, struct llc *); 465 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 466 llc->llc_control = LLC_UI; 467 memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code)); 468 llc->llc_ether_type = htons(ETHERTYPE_AARP); 469 470 memcpy(ea->aarp_tpnet, ea->aarp_spnet, sizeof(ea->aarp_tpnet)); 471 memcpy(ea->aarp_spnet, &ma.s_net, sizeof(ea->aarp_spnet)); 472 eh->ether_type = 0; /* if_output will treat as 802 */ 473 } else { 474 eh->ether_type = htons(ETHERTYPE_AARP); 475 } 476 477 ea->aarp_tpnode = ea->aarp_spnode; 478 ea->aarp_spnode = ma.s_node; 479 ea->aarp_op = htons(AARPOP_RESPONSE); 480 481 sa.sa_len = sizeof(struct sockaddr); 482 sa.sa_family = AF_UNSPEC; 483 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 484 return; 485 } 486 487 static void 488 aarptfree(struct aarptab *aat) 489 { 490 491 if (aat->aat_hold) 492 m_freem(aat->aat_hold); 493 aat->aat_hold = 0; 494 aat->aat_timer = aat->aat_flags = 0; 495 aat->aat_ataddr.s_net = 0; 496 aat->aat_ataddr.s_node = 0; 497 } 498 499 static struct aarptab * 500 aarptnew(const struct at_addr *addr) 501 { 502 int n; 503 int oldest = -1; 504 struct aarptab *aat, *aato = NULL; 505 static int first = 1; 506 507 if (first) { 508 first = 0; 509 callout_init(&aarptimer_callout, 0); 510 callout_reset(&aarptimer_callout, hz, aarptimer, NULL); 511 MOWNER_ATTACH(&aarp_mowner); 512 } 513 aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ]; 514 for (n = 0; n < AARPTAB_BSIZ; n++, aat++) { 515 if (aat->aat_flags == 0) 516 goto out; 517 if (aat->aat_flags & ATF_PERM) 518 continue; 519 if ((int) aat->aat_timer > oldest) { 520 oldest = aat->aat_timer; 521 aato = aat; 522 } 523 } 524 if (aato == NULL) 525 return (NULL); 526 aat = aato; 527 aarptfree(aat); 528 out: 529 aat->aat_ataddr = *addr; 530 aat->aat_flags = ATF_INUSE; 531 return (aat); 532 } 533 534 535 void 536 aarpprobe(void *arp) 537 { 538 struct mbuf *m; 539 struct ether_header *eh; 540 struct ether_aarp *ea; 541 struct ifaddr *ia; 542 struct at_ifaddr *aa; 543 struct llc *llc; 544 struct sockaddr sa; 545 struct ifnet *ifp = arp; 546 547 mutex_enter(softnet_lock); 548 549 /* 550 * We need to check whether the output ethernet type should 551 * be phase 1 or 2. We have the interface that we'll be sending 552 * the aarp out. We need to find an AppleTalk network on that 553 * interface with the same address as we're looking for. If the 554 * net is phase 2, generate an 802.2 and SNAP header. 555 */ 556 IFADDR_FOREACH(ia, ifp) { 557 aa = (struct at_ifaddr *)ia; 558 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 559 (aa->aa_flags & AFA_PROBING)) 560 break; 561 } 562 if (ia == NULL) { /* serious error XXX */ 563 printf("aarpprobe why did this happen?!\n"); 564 mutex_exit(softnet_lock); 565 return; 566 } 567 if (aa->aa_probcnt <= 0) { 568 aa->aa_flags &= ~AFA_PROBING; 569 wakeup(aa); 570 mutex_exit(softnet_lock); 571 return; 572 } else { 573 callout_reset(&aa->aa_probe_ch, hz / 5, aarpprobe, arp); 574 } 575 576 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) { 577 mutex_exit(softnet_lock); 578 return; 579 } 580 581 MCLAIM(m, &aarp_mowner); 582 m->m_len = sizeof(*ea); 583 m->m_pkthdr.len = sizeof(*ea); 584 MH_ALIGN(m, sizeof(*ea)); 585 586 ea = mtod(m, struct ether_aarp *); 587 memset(ea, 0, sizeof(*ea)); 588 589 ea->aarp_hrd = htons(AARPHRD_ETHER); 590 ea->aarp_pro = htons(ETHERTYPE_ATALK); 591 ea->aarp_hln = sizeof(ea->aarp_sha); 592 ea->aarp_pln = sizeof(ea->aarp_spu); 593 ea->aarp_op = htons(AARPOP_PROBE); 594 memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha)); 595 596 eh = (struct ether_header *) sa.sa_data; 597 598 if (aa->aa_flags & AFA_PHASE2) { 599 memcpy(eh->ether_dhost, atmulticastaddr, 600 sizeof(eh->ether_dhost)); 601 eh->ether_type = 0; /* if_output will treat as 802 */ 602 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 603 if (!m) { 604 mutex_exit(softnet_lock); 605 return; 606 } 607 608 llc = mtod(m, struct llc *); 609 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 610 llc->llc_control = LLC_UI; 611 memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code)); 612 llc->llc_ether_type = htons(ETHERTYPE_AARP); 613 614 memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net, 615 sizeof(ea->aarp_spnet)); 616 memcpy(ea->aarp_tpnet, &AA_SAT(aa)->sat_addr.s_net, 617 sizeof(ea->aarp_tpnet)); 618 ea->aarp_spnode = ea->aarp_tpnode = 619 AA_SAT(aa)->sat_addr.s_node; 620 } else { 621 memcpy(eh->ether_dhost, etherbroadcastaddr, 622 sizeof(eh->ether_dhost)); 623 eh->ether_type = htons(ETHERTYPE_AARP); 624 ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node; 625 } 626 627 #ifdef NETATALKDEBUG 628 printf("aarp: sending probe for %u.%u\n", 629 ntohs(AA_SAT(aa)->sat_addr.s_net), 630 AA_SAT(aa)->sat_addr.s_node); 631 #endif /* NETATALKDEBUG */ 632 633 sa.sa_len = sizeof(struct sockaddr); 634 sa.sa_family = AF_UNSPEC; 635 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 636 aa->aa_probcnt--; 637 mutex_exit(softnet_lock); 638 } 639 640 void 641 aarp_clean(void) 642 { 643 struct aarptab *aat; 644 int i; 645 646 callout_stop(&aarptimer_callout); 647 for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) 648 if (aat->aat_hold) 649 m_freem(aat->aat_hold); 650 } 651