1 /* $NetBSD: aarp.c,v 1.27 2008/04/24 11:38:37 ad 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.27 2008/04/24 11:38:37 ad 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(sat, ifp) 133 const struct sockaddr_at *sat; 134 struct ifnet *ifp; 135 { 136 struct ifaddr *ifa; 137 struct sockaddr_at *sat2; 138 struct netrange *nr; 139 140 IFADDR_FOREACH(ifa, ifp) { 141 if (ifa->ifa_addr->sa_family != AF_APPLETALK) 142 continue; 143 144 sat2 = satosat(ifa->ifa_addr); 145 if (sat2->sat_addr.s_net == sat->sat_addr.s_net) 146 break; 147 148 nr = (struct netrange *) (sat2->sat_zero); 149 if ((nr->nr_phase == 2) 150 && (ntohs(nr->nr_firstnet) <= ntohs(sat->sat_addr.s_net)) 151 && (ntohs(nr->nr_lastnet) >= ntohs(sat->sat_addr.s_net))) 152 break; 153 } 154 return ifa; 155 } 156 157 static void 158 aarpwhohas(ifp, sat) 159 struct ifnet *ifp; 160 const struct sockaddr_at *sat; 161 { 162 struct mbuf *m; 163 struct ether_header *eh; 164 struct ether_aarp *ea; 165 struct at_ifaddr *aa; 166 struct llc *llc; 167 struct sockaddr sa; 168 169 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 170 return; 171 172 MCLAIM(m, &aarp_mowner); 173 m->m_len = sizeof(*ea); 174 m->m_pkthdr.len = sizeof(*ea); 175 MH_ALIGN(m, sizeof(*ea)); 176 177 ea = mtod(m, struct ether_aarp *); 178 bzero(ea, sizeof(*ea)); 179 180 ea->aarp_hrd = htons(AARPHRD_ETHER); 181 ea->aarp_pro = htons(ETHERTYPE_ATALK); 182 ea->aarp_hln = sizeof(ea->aarp_sha); 183 ea->aarp_pln = sizeof(ea->aarp_spu); 184 ea->aarp_op = htons(AARPOP_REQUEST); 185 bcopy(CLLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha)); 186 187 /* 188 * We need to check whether the output ethernet type should 189 * be phase 1 or 2. We have the interface that we'll be sending 190 * the aarp out. We need to find an AppleTalk network on that 191 * interface with the same address as we're looking for. If the 192 * net is phase 2, generate an 802.2 and SNAP header. 193 */ 194 if ((aa = (struct at_ifaddr *) at_ifawithnet(sat, ifp)) == NULL) { 195 m_freem(m); 196 return; 197 } 198 eh = (struct ether_header *) sa.sa_data; 199 200 if (aa->aa_flags & AFA_PHASE2) { 201 bcopy(atmulticastaddr, eh->ether_dhost, 202 sizeof(eh->ether_dhost)); 203 eh->ether_type = 0; /* if_output will treat as 802 */ 204 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 205 if (!m) 206 return; 207 208 llc = mtod(m, struct llc *); 209 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 210 llc->llc_control = LLC_UI; 211 bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code)); 212 llc->llc_ether_type = htons(ETHERTYPE_AARP); 213 214 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, 215 sizeof(ea->aarp_spnet)); 216 bcopy(&sat->sat_addr.s_net, ea->aarp_tpnet, 217 sizeof(ea->aarp_tpnet)); 218 ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node; 219 ea->aarp_tpnode = sat->sat_addr.s_node; 220 } else { 221 bcopy(etherbroadcastaddr, eh->ether_dhost, 222 sizeof(eh->ether_dhost)); 223 eh->ether_type = htons(ETHERTYPE_AARP); 224 225 ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node; 226 ea->aarp_tpa = sat->sat_addr.s_node; 227 } 228 229 #ifdef NETATALKDEBUG 230 printf("aarp: sending request via %u.%u seaking %u.%u\n", 231 ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node, 232 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 233 #endif /* NETATALKDEBUG */ 234 235 sa.sa_len = sizeof(struct sockaddr); 236 sa.sa_family = AF_UNSPEC; 237 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX NULL should be routing */ 238 /* information */ 239 } 240 241 int 242 aarpresolve(struct ifnet *ifp, struct mbuf *m, 243 const struct sockaddr_at *destsat, u_char *desten) 244 { 245 struct at_ifaddr *aa; 246 struct aarptab *aat; 247 int s; 248 249 if (at_broadcast(destsat)) { 250 aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp); 251 if (aa == NULL) { 252 m_freem(m); 253 return (0); 254 } 255 if (aa->aa_flags & AFA_PHASE2) 256 bcopy(atmulticastaddr, desten, 257 sizeof(atmulticastaddr)); 258 else 259 bcopy(etherbroadcastaddr, desten, 260 sizeof(etherbroadcastaddr)); 261 return 1; 262 } 263 s = splnet(); 264 AARPTAB_LOOK(aat, destsat->sat_addr); 265 if (aat == 0) { /* No entry */ 266 aat = aarptnew(&destsat->sat_addr); 267 if (aat == 0) 268 panic("aarpresolve: no free entry"); 269 270 aat->aat_hold = m; 271 aarpwhohas(ifp, destsat); 272 splx(s); 273 return 0; 274 } 275 276 /* found an entry */ 277 aat->aat_timer = 0; 278 if (aat->aat_flags & ATF_COM) { /* entry is COMplete */ 279 bcopy(aat->aat_enaddr, desten, sizeof(aat->aat_enaddr)); 280 splx(s); 281 return 1; 282 } 283 284 /* entry has not completed */ 285 if (aat->aat_hold) 286 m_freem(aat->aat_hold); 287 aat->aat_hold = m; 288 aarpwhohas(ifp, destsat); 289 splx(s); 290 291 return 0; 292 } 293 294 void 295 aarpinput(ifp, m) 296 struct ifnet *ifp; 297 struct mbuf *m; 298 { 299 struct arphdr *ar; 300 301 if (ifp->if_flags & IFF_NOARP) 302 goto out; 303 304 if (m->m_len < sizeof(struct arphdr)) 305 goto out; 306 307 ar = mtod(m, struct arphdr *); 308 if (ntohs(ar->ar_hrd) != AARPHRD_ETHER) 309 goto out; 310 311 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 312 goto out; 313 314 switch (ntohs(ar->ar_pro)) { 315 case ETHERTYPE_ATALK: 316 at_aarpinput(ifp, m); 317 return; 318 319 default: 320 break; 321 } 322 323 out: 324 m_freem(m); 325 } 326 327 static void 328 at_aarpinput(ifp, m) 329 struct ifnet *ifp; 330 struct mbuf *m; 331 { 332 struct ether_aarp *ea; 333 struct at_ifaddr *aa; 334 struct ifaddr *ia; 335 struct aarptab *aat; 336 struct ether_header *eh; 337 struct llc *llc; 338 struct sockaddr_at sat; 339 struct sockaddr sa; 340 struct at_addr spa, tpa, ma; 341 int op; 342 u_int16_t net; 343 344 ea = mtod(m, struct ether_aarp *); 345 346 /* Check to see if from my hardware address */ 347 if (!bcmp(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha))) { 348 m_freem(m); 349 return; 350 } 351 op = ntohs(ea->aarp_op); 352 bcopy(ea->aarp_tpnet, &net, sizeof(net)); 353 354 if (net != 0) { /* should be ATADDR_ANYNET? */ 355 sat.sat_len = sizeof(struct sockaddr_at); 356 sat.sat_family = AF_APPLETALK; 357 sat.sat_addr.s_net = net; 358 aa = (struct at_ifaddr *) at_ifawithnet(&sat, ifp); 359 if (aa == NULL) { 360 m_freem(m); 361 return; 362 } 363 bcopy(ea->aarp_spnet, &spa.s_net, sizeof(spa.s_net)); 364 bcopy(ea->aarp_tpnet, &tpa.s_net, sizeof(tpa.s_net)); 365 } else { 366 /* 367 * Since we don't know the net, we just look for the first 368 * phase 1 address on the interface. 369 */ 370 IFADDR_FOREACH(ia, ifp) { 371 aa = (struct at_ifaddr *)ia; 372 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 373 (aa->aa_flags & AFA_PHASE2) == 0) 374 break; 375 } 376 if (ia == NULL) { 377 m_freem(m); 378 return; 379 } 380 tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net; 381 } 382 383 spa.s_node = ea->aarp_spnode; 384 tpa.s_node = ea->aarp_tpnode; 385 ma.s_net = AA_SAT(aa)->sat_addr.s_net; 386 ma.s_node = AA_SAT(aa)->sat_addr.s_node; 387 388 /* 389 * This looks like it's from us. 390 */ 391 if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) { 392 if (aa->aa_flags & AFA_PROBING) { 393 /* 394 * We're probing, someone either responded to our 395 * probe, or probed for the same address we'd like 396 * to use. Change the address we're probing for. 397 */ 398 callout_stop(&aa->aa_probe_ch); 399 wakeup(aa); 400 m_freem(m); 401 return; 402 } else if (op != AARPOP_PROBE) { 403 /* 404 * This is not a probe, and we're not probing. 405 * This means that someone's saying they have the same 406 * source address as the one we're using. Get upset... 407 */ 408 log(LOG_ERR, "aarp: duplicate AT address!! %s\n", 409 ether_sprintf(ea->aarp_sha)); 410 m_freem(m); 411 return; 412 } 413 } 414 AARPTAB_LOOK(aat, spa); 415 if (aat) { 416 if (op == AARPOP_PROBE) { 417 /* 418 * Someone's probing for spa, deallocate the one we've 419 * got, so that if the prober keeps the address, we'll 420 * be able to arp for him. 421 */ 422 aarptfree(aat); 423 m_freem(m); 424 return; 425 } 426 bcopy(ea->aarp_sha, aat->aat_enaddr, sizeof(ea->aarp_sha)); 427 aat->aat_flags |= ATF_COM; 428 if (aat->aat_hold) { 429 sat.sat_len = sizeof(struct sockaddr_at); 430 sat.sat_family = AF_APPLETALK; 431 sat.sat_addr = spa; 432 (*ifp->if_output)(ifp, aat->aat_hold, 433 (struct sockaddr *) & sat, NULL); /* XXX */ 434 aat->aat_hold = 0; 435 } 436 } 437 if (aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node 438 && op != AARPOP_PROBE) { 439 if ((aat = aarptnew(&spa)) != NULL) { 440 bcopy(ea->aarp_sha, aat->aat_enaddr, 441 sizeof(ea->aarp_sha)); 442 aat->aat_flags |= ATF_COM; 443 } 444 } 445 /* 446 * Don't respond to responses, and never respond if we're 447 * still probing. 448 */ 449 if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node || 450 op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) { 451 m_freem(m); 452 return; 453 } 454 bcopy(ea->aarp_sha, ea->aarp_tha, sizeof(ea->aarp_sha)); 455 bcopy(CLLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha)); 456 457 /* XXX */ 458 eh = (struct ether_header *) sa.sa_data; 459 bcopy(ea->aarp_tha, eh->ether_dhost, sizeof(eh->ether_dhost)); 460 461 if (aa->aa_flags & AFA_PHASE2) { 462 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 463 if (m == NULL) 464 return; 465 466 llc = mtod(m, struct llc *); 467 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 468 llc->llc_control = LLC_UI; 469 bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code)); 470 llc->llc_ether_type = htons(ETHERTYPE_AARP); 471 472 bcopy(ea->aarp_spnet, ea->aarp_tpnet, sizeof(ea->aarp_tpnet)); 473 bcopy(&ma.s_net, ea->aarp_spnet, sizeof(ea->aarp_spnet)); 474 eh->ether_type = 0; /* if_output will treat as 802 */ 475 } else { 476 eh->ether_type = htons(ETHERTYPE_AARP); 477 } 478 479 ea->aarp_tpnode = ea->aarp_spnode; 480 ea->aarp_spnode = ma.s_node; 481 ea->aarp_op = htons(AARPOP_RESPONSE); 482 483 sa.sa_len = sizeof(struct sockaddr); 484 sa.sa_family = AF_UNSPEC; 485 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 486 return; 487 } 488 489 static void 490 aarptfree(aat) 491 struct aarptab *aat; 492 { 493 494 if (aat->aat_hold) 495 m_freem(aat->aat_hold); 496 aat->aat_hold = 0; 497 aat->aat_timer = aat->aat_flags = 0; 498 aat->aat_ataddr.s_net = 0; 499 aat->aat_ataddr.s_node = 0; 500 } 501 502 static struct aarptab * 503 aarptnew(const struct at_addr *addr) 504 { 505 int n; 506 int oldest = -1; 507 struct aarptab *aat, *aato = NULL; 508 static int first = 1; 509 510 if (first) { 511 first = 0; 512 callout_init(&aarptimer_callout, 0); 513 callout_reset(&aarptimer_callout, hz, aarptimer, NULL); 514 MOWNER_ATTACH(&aarp_mowner); 515 } 516 aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ]; 517 for (n = 0; n < AARPTAB_BSIZ; n++, aat++) { 518 if (aat->aat_flags == 0) 519 goto out; 520 if (aat->aat_flags & ATF_PERM) 521 continue; 522 if ((int) aat->aat_timer > oldest) { 523 oldest = aat->aat_timer; 524 aato = aat; 525 } 526 } 527 if (aato == NULL) 528 return (NULL); 529 aat = aato; 530 aarptfree(aat); 531 out: 532 aat->aat_ataddr = *addr; 533 aat->aat_flags = ATF_INUSE; 534 return (aat); 535 } 536 537 538 void 539 aarpprobe(arp) 540 void *arp; 541 { 542 struct mbuf *m; 543 struct ether_header *eh; 544 struct ether_aarp *ea; 545 struct ifaddr *ia; 546 struct at_ifaddr *aa; 547 struct llc *llc; 548 struct sockaddr sa; 549 struct ifnet *ifp = arp; 550 551 mutex_enter(softnet_lock); 552 553 /* 554 * We need to check whether the output ethernet type should 555 * be phase 1 or 2. We have the interface that we'll be sending 556 * the aarp out. We need to find an AppleTalk network on that 557 * interface with the same address as we're looking for. If the 558 * net is phase 2, generate an 802.2 and SNAP header. 559 */ 560 IFADDR_FOREACH(ia, ifp) { 561 aa = (struct at_ifaddr *)ia; 562 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 563 (aa->aa_flags & AFA_PROBING)) 564 break; 565 } 566 if (ia == NULL) { /* serious error XXX */ 567 printf("aarpprobe why did this happen?!\n"); 568 mutex_exit(softnet_lock); 569 return; 570 } 571 if (aa->aa_probcnt <= 0) { 572 aa->aa_flags &= ~AFA_PROBING; 573 wakeup(aa); 574 mutex_exit(softnet_lock); 575 return; 576 } else { 577 callout_reset(&aa->aa_probe_ch, hz / 5, aarpprobe, arp); 578 } 579 580 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) { 581 mutex_exit(softnet_lock); 582 return; 583 } 584 585 MCLAIM(m, &aarp_mowner); 586 m->m_len = sizeof(*ea); 587 m->m_pkthdr.len = sizeof(*ea); 588 MH_ALIGN(m, sizeof(*ea)); 589 590 ea = mtod(m, struct ether_aarp *); 591 bzero(ea, sizeof(*ea)); 592 593 ea->aarp_hrd = htons(AARPHRD_ETHER); 594 ea->aarp_pro = htons(ETHERTYPE_ATALK); 595 ea->aarp_hln = sizeof(ea->aarp_sha); 596 ea->aarp_pln = sizeof(ea->aarp_spu); 597 ea->aarp_op = htons(AARPOP_PROBE); 598 bcopy(CLLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha)); 599 600 eh = (struct ether_header *) sa.sa_data; 601 602 if (aa->aa_flags & AFA_PHASE2) { 603 bcopy(atmulticastaddr, eh->ether_dhost, 604 sizeof(eh->ether_dhost)); 605 eh->ether_type = 0; /* if_output will treat as 802 */ 606 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 607 if (!m) { 608 mutex_exit(softnet_lock); 609 return; 610 } 611 612 llc = mtod(m, struct llc *); 613 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 614 llc->llc_control = LLC_UI; 615 bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code)); 616 llc->llc_ether_type = htons(ETHERTYPE_AARP); 617 618 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, 619 sizeof(ea->aarp_spnet)); 620 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet, 621 sizeof(ea->aarp_tpnet)); 622 ea->aarp_spnode = ea->aarp_tpnode = 623 AA_SAT(aa)->sat_addr.s_node; 624 } else { 625 bcopy(etherbroadcastaddr, eh->ether_dhost, 626 sizeof(eh->ether_dhost)); 627 eh->ether_type = htons(ETHERTYPE_AARP); 628 ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node; 629 } 630 631 #ifdef NETATALKDEBUG 632 printf("aarp: sending probe for %u.%u\n", 633 ntohs(AA_SAT(aa)->sat_addr.s_net), 634 AA_SAT(aa)->sat_addr.s_node); 635 #endif /* NETATALKDEBUG */ 636 637 sa.sa_len = sizeof(struct sockaddr); 638 sa.sa_family = AF_UNSPEC; 639 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 640 aa->aa_probcnt--; 641 mutex_exit(softnet_lock); 642 } 643 644 void 645 aarp_clean() 646 { 647 struct aarptab *aat; 648 int i; 649 650 callout_stop(&aarptimer_callout); 651 for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) 652 if (aat->aat_hold) 653 m_freem(aat->aat_hold); 654 } 655