1 /* $NetBSD: aarp.c,v 1.20 2006/10/12 01:32:37 christos 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.20 2006/10/12 01:32:37 christos 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 <net/if.h> 44 #include <net/route.h> 45 #include <net/if_ether.h> 46 #include <net/if_dl.h> 47 #include <netinet/in.h> 48 #undef s_net 49 50 #include <netatalk/at.h> 51 #include <netatalk/at_var.h> 52 #include <netatalk/aarp.h> 53 #include <netatalk/ddp_var.h> 54 #include <netatalk/phase2.h> 55 #include <netatalk/at_extern.h> 56 57 static struct aarptab *aarptnew __P((struct at_addr *)); 58 static void aarptfree __P((struct aarptab *)); 59 static void at_aarpinput __P((struct ifnet *, struct mbuf *)); 60 static void aarptimer __P((void *)); 61 static void aarpwhohas __P((struct ifnet *, struct sockaddr_at *)); 62 63 #define AARPTAB_BSIZ 9 64 #define AARPTAB_NB 19 65 #define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) 66 struct aarptab aarptab[AARPTAB_SIZE]; 67 68 #define AARPTAB_HASH(a) \ 69 ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB ) 70 71 #define AARPTAB_LOOK(aat,addr) { \ 72 int n; \ 73 aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \ 74 for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \ 75 if ( aat->aat_ataddr.s_net == (addr).s_net && \ 76 aat->aat_ataddr.s_node == (addr).s_node ) \ 77 break; \ 78 if ( n >= AARPTAB_BSIZ ) \ 79 aat = 0; \ 80 } 81 82 #define AARPT_AGE (60 * 1) 83 #define AARPT_KILLC 20 84 #define AARPT_KILLI 3 85 86 const u_char atmulticastaddr[6] = { 87 0x09, 0x00, 0x07, 0xff, 0xff, 0xff 88 }; 89 90 const u_char at_org_code[3] = { 91 0x08, 0x00, 0x07 92 }; 93 const u_char aarp_org_code[3] = { 94 0x00, 0x00, 0x00 95 }; 96 97 struct callout aarptimer_callout; 98 #ifdef MBUFTRACE 99 struct mowner aarp_mowner = MOWNER_INIT("atalk", "arp"); 100 #endif 101 102 /*ARGSUSED*/ 103 static void 104 aarptimer(void *ignored __unused) 105 { 106 struct aarptab *aat; 107 int i, s; 108 109 callout_reset(&aarptimer_callout, AARPT_AGE * hz, aarptimer, NULL); 110 aat = aarptab; 111 for (i = 0; i < AARPTAB_SIZE; i++, aat++) { 112 int killtime = (aat->aat_flags & ATF_COM) ? AARPT_KILLC : 113 AARPT_KILLI; 114 if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM)) 115 continue; 116 if (++aat->aat_timer < killtime) 117 continue; 118 s = splnet(); 119 aarptfree(aat); 120 splx(s); 121 } 122 } 123 124 /* 125 * search through the network addresses to find one that includes the given 126 * network.. remember to take netranges into consideration. 127 */ 128 struct ifaddr * 129 at_ifawithnet(sat, ifp) 130 const struct sockaddr_at *sat; 131 struct ifnet *ifp; 132 { 133 struct ifaddr *ifa; 134 struct sockaddr_at *sat2; 135 struct netrange *nr; 136 137 for (ifa = ifp->if_addrlist.tqh_first; ifa; 138 ifa = ifa->ifa_list.tqe_next) { 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(ifp, sat) 157 struct ifnet *ifp; 158 struct sockaddr_at *sat; 159 { 160 struct mbuf *m; 161 struct ether_header *eh; 162 struct ether_aarp *ea; 163 struct at_ifaddr *aa; 164 struct llc *llc; 165 struct sockaddr sa; 166 167 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 168 return; 169 170 MCLAIM(m, &aarp_mowner); 171 m->m_len = sizeof(*ea); 172 m->m_pkthdr.len = sizeof(*ea); 173 MH_ALIGN(m, sizeof(*ea)); 174 175 ea = mtod(m, struct ether_aarp *); 176 bzero(ea, sizeof(*ea)); 177 178 ea->aarp_hrd = htons(AARPHRD_ETHER); 179 ea->aarp_pro = htons(ETHERTYPE_ATALK); 180 ea->aarp_hln = sizeof(ea->aarp_sha); 181 ea->aarp_pln = sizeof(ea->aarp_spu); 182 ea->aarp_op = htons(AARPOP_REQUEST); 183 bcopy(LLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha)); 184 185 /* 186 * We need to check whether the output ethernet type should 187 * be phase 1 or 2. We have the interface that we'll be sending 188 * the aarp out. We need to find an AppleTalk network on that 189 * interface with the same address as we're looking for. If the 190 * net is phase 2, generate an 802.2 and SNAP header. 191 */ 192 if ((aa = (struct at_ifaddr *) at_ifawithnet(sat, ifp)) == NULL) { 193 m_freem(m); 194 return; 195 } 196 eh = (struct ether_header *) sa.sa_data; 197 198 if (aa->aa_flags & AFA_PHASE2) { 199 bcopy(atmulticastaddr, eh->ether_dhost, 200 sizeof(eh->ether_dhost)); 201 eh->ether_type = 0; /* if_output will treat as 802 */ 202 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 203 if (!m) 204 return; 205 206 llc = mtod(m, struct llc *); 207 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 208 llc->llc_control = LLC_UI; 209 bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code)); 210 llc->llc_ether_type = htons(ETHERTYPE_AARP); 211 212 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, 213 sizeof(ea->aarp_spnet)); 214 bcopy(&sat->sat_addr.s_net, ea->aarp_tpnet, 215 sizeof(ea->aarp_tpnet)); 216 ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node; 217 ea->aarp_tpnode = sat->sat_addr.s_node; 218 } else { 219 bcopy(etherbroadcastaddr, eh->ether_dhost, 220 sizeof(eh->ether_dhost)); 221 eh->ether_type = htons(ETHERTYPE_AARP); 222 223 ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node; 224 ea->aarp_tpa = sat->sat_addr.s_node; 225 } 226 227 #ifdef NETATALKDEBUG 228 printf("aarp: sending request via %u.%u seaking %u.%u\n", 229 ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node, 230 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 231 #endif /* NETATALKDEBUG */ 232 233 sa.sa_len = sizeof(struct sockaddr); 234 sa.sa_family = AF_UNSPEC; 235 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX NULL should be routing */ 236 /* information */ 237 } 238 239 int 240 aarpresolve(ifp, m, destsat, desten) 241 struct ifnet *ifp; 242 struct mbuf *m; 243 struct sockaddr_at *destsat; 244 u_char *desten; 245 { 246 struct at_ifaddr *aa; 247 struct aarptab *aat; 248 int s; 249 250 if (at_broadcast(destsat)) { 251 aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp); 252 if (aa == NULL) { 253 m_freem(m); 254 return (0); 255 } 256 if (aa->aa_flags & AFA_PHASE2) 257 bcopy(atmulticastaddr, desten, 258 sizeof(atmulticastaddr)); 259 else 260 bcopy(etherbroadcastaddr, desten, 261 sizeof(etherbroadcastaddr)); 262 return 1; 263 } 264 s = splnet(); 265 AARPTAB_LOOK(aat, destsat->sat_addr); 266 if (aat == 0) { /* No entry */ 267 aat = aarptnew(&destsat->sat_addr); 268 if (aat == 0) 269 panic("aarpresolve: no free entry"); 270 271 aat->aat_hold = m; 272 aarpwhohas(ifp, destsat); 273 splx(s); 274 return 0; 275 } 276 277 /* found an entry */ 278 aat->aat_timer = 0; 279 if (aat->aat_flags & ATF_COM) { /* entry is COMplete */ 280 bcopy(aat->aat_enaddr, desten, sizeof(aat->aat_enaddr)); 281 splx(s); 282 return 1; 283 } 284 285 /* entry has not completed */ 286 if (aat->aat_hold) 287 m_freem(aat->aat_hold); 288 aat->aat_hold = m; 289 aarpwhohas(ifp, destsat); 290 splx(s); 291 292 return 0; 293 } 294 295 void 296 aarpinput(ifp, m) 297 struct ifnet *ifp; 298 struct mbuf *m; 299 { 300 struct arphdr *ar; 301 302 if (ifp->if_flags & IFF_NOARP) 303 goto out; 304 305 if (m->m_len < sizeof(struct arphdr)) 306 goto out; 307 308 ar = mtod(m, struct arphdr *); 309 if (ntohs(ar->ar_hrd) != AARPHRD_ETHER) 310 goto out; 311 312 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 313 goto out; 314 315 switch (ntohs(ar->ar_pro)) { 316 case ETHERTYPE_ATALK: 317 at_aarpinput(ifp, m); 318 return; 319 320 default: 321 break; 322 } 323 324 out: 325 m_freem(m); 326 } 327 328 static void 329 at_aarpinput(ifp, m) 330 struct ifnet *ifp; 331 struct mbuf *m; 332 { 333 struct ether_aarp *ea; 334 struct at_ifaddr *aa; 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, LLADDR(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 for (aa = (struct at_ifaddr *) ifp->if_addrlist.tqh_first; aa; 371 aa = (struct at_ifaddr *) aa->aa_ifa.ifa_list.tqe_next) { 372 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 373 (aa->aa_flags & AFA_PHASE2) == 0) 374 break; 375 } 376 if (aa == 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(LLADDR(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(addr) 504 struct at_addr *addr; 505 { 506 int n; 507 int oldest = -1; 508 struct aarptab *aat, *aato = NULL; 509 static int first = 1; 510 511 if (first) { 512 first = 0; 513 callout_init(&aarptimer_callout); 514 callout_reset(&aarptimer_callout, hz, aarptimer, NULL); 515 MOWNER_ATTACH(&aarp_mowner); 516 } 517 aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ]; 518 for (n = 0; n < AARPTAB_BSIZ; n++, aat++) { 519 if (aat->aat_flags == 0) 520 goto out; 521 if (aat->aat_flags & ATF_PERM) 522 continue; 523 if ((int) aat->aat_timer > oldest) { 524 oldest = aat->aat_timer; 525 aato = aat; 526 } 527 } 528 if (aato == NULL) 529 return (NULL); 530 aat = aato; 531 aarptfree(aat); 532 out: 533 aat->aat_ataddr = *addr; 534 aat->aat_flags = ATF_INUSE; 535 return (aat); 536 } 537 538 539 void 540 aarpprobe(arp) 541 void *arp; 542 { 543 struct mbuf *m; 544 struct ether_header *eh; 545 struct ether_aarp *ea; 546 struct at_ifaddr *aa; 547 struct llc *llc; 548 struct sockaddr sa; 549 struct ifnet *ifp = arp; 550 551 /* 552 * We need to check whether the output ethernet type should 553 * be phase 1 or 2. We have the interface that we'll be sending 554 * the aarp out. We need to find an AppleTalk network on that 555 * interface with the same address as we're looking for. If the 556 * net is phase 2, generate an 802.2 and SNAP header. 557 */ 558 for (aa = (struct at_ifaddr *) ifp->if_addrlist.tqh_first; aa; 559 aa = (struct at_ifaddr *) aa->aa_ifa.ifa_list.tqe_next) { 560 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 561 (aa->aa_flags & AFA_PROBING)) 562 break; 563 } 564 if (aa == NULL) { /* serious error XXX */ 565 printf("aarpprobe why did this happen?!\n"); 566 return; 567 } 568 if (aa->aa_probcnt <= 0) { 569 aa->aa_flags &= ~AFA_PROBING; 570 wakeup(aa); 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 return; 578 579 MCLAIM(m, &aarp_mowner); 580 m->m_len = sizeof(*ea); 581 m->m_pkthdr.len = sizeof(*ea); 582 MH_ALIGN(m, sizeof(*ea)); 583 584 ea = mtod(m, struct ether_aarp *); 585 bzero(ea, sizeof(*ea)); 586 587 ea->aarp_hrd = htons(AARPHRD_ETHER); 588 ea->aarp_pro = htons(ETHERTYPE_ATALK); 589 ea->aarp_hln = sizeof(ea->aarp_sha); 590 ea->aarp_pln = sizeof(ea->aarp_spu); 591 ea->aarp_op = htons(AARPOP_PROBE); 592 bcopy(LLADDR(ifp->if_sadl), ea->aarp_sha, sizeof(ea->aarp_sha)); 593 594 eh = (struct ether_header *) sa.sa_data; 595 596 if (aa->aa_flags & AFA_PHASE2) { 597 bcopy(atmulticastaddr, eh->ether_dhost, 598 sizeof(eh->ether_dhost)); 599 eh->ether_type = 0; /* if_output will treat as 802 */ 600 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 601 if (!m) 602 return; 603 604 llc = mtod(m, struct llc *); 605 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 606 llc->llc_control = LLC_UI; 607 bcopy(aarp_org_code, llc->llc_org_code, sizeof(aarp_org_code)); 608 llc->llc_ether_type = htons(ETHERTYPE_AARP); 609 610 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, 611 sizeof(ea->aarp_spnet)); 612 bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet, 613 sizeof(ea->aarp_tpnet)); 614 ea->aarp_spnode = ea->aarp_tpnode = 615 AA_SAT(aa)->sat_addr.s_node; 616 } else { 617 bcopy(etherbroadcastaddr, eh->ether_dhost, 618 sizeof(eh->ether_dhost)); 619 eh->ether_type = htons(ETHERTYPE_AARP); 620 ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node; 621 } 622 623 #ifdef NETATALKDEBUG 624 printf("aarp: sending probe for %u.%u\n", 625 ntohs(AA_SAT(aa)->sat_addr.s_net), 626 AA_SAT(aa)->sat_addr.s_node); 627 #endif /* NETATALKDEBUG */ 628 629 sa.sa_len = sizeof(struct sockaddr); 630 sa.sa_family = AF_UNSPEC; 631 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 632 aa->aa_probcnt--; 633 } 634 635 void 636 aarp_clean() 637 { 638 struct aarptab *aat; 639 int i; 640 641 callout_stop(&aarptimer_callout); 642 for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) 643 if (aat->aat_hold) 644 m_freem(aat->aat_hold); 645 } 646