1/* $NetBSD: aarp.c,v 1.35 2011/05/08 13:51:31 bouyer 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.35 2011/05/08 13:51:31 bouyer 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 58static struct aarptab *aarptnew(const struct at_addr *); 59static void aarptfree(struct aarptab *); 60static void at_aarpinput(struct ifnet *, struct mbuf *); 61static void aarptimer(void *); 62static 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) 67struct 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 87const u_char atmulticastaddr[6] = { 88 0x09, 0x00, 0x07, 0xff, 0xff, 0xff 89}; 90 91const u_char at_org_code[3] = { 92 0x08, 0x00, 0x07 93}; 94const u_char aarp_org_code[3] = { 95 0x00, 0x00, 0x00 96}; 97 98struct callout aarptimer_callout; 99#ifdef MBUFTRACE 100struct mowner aarp_mowner = MOWNER_INIT("atalk", "arp"); 101#endif 102 103/*ARGSUSED*/ 104static void 105aarptimer(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 */ 131struct ifaddr * 132at_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 155static void 156aarpwhohas(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 /* If we are talking to ourselves, use the loopback interface. */ 226 if (AA_SAT(aa)->sat_addr.s_net == sat->sat_addr.s_net && 227 AA_SAT(aa)->sat_addr.s_node == sat->sat_addr.s_node) 228 ifp = lo0ifp; 229 230#ifdef NETATALKDEBUG 231 printf("aarp: sending request via %u.%u through %s seeking %u.%u\n", 232 ntohs(AA_SAT(aa)->sat_addr.s_net), 233 AA_SAT(aa)->sat_addr.s_node, 234 ifp->if_xname, 235 ntohs(sat->sat_addr.s_net), 236 sat->sat_addr.s_node); 237#endif /* NETATALKDEBUG */ 238 239 sa.sa_len = sizeof(struct sockaddr); 240 sa.sa_family = AF_UNSPEC; 241 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX NULL should be routing */ 242 /* information */ 243} 244 245int 246aarpresolve(struct ifnet *ifp, struct mbuf *m, 247 const struct sockaddr_at *destsat, u_char *desten) 248{ 249 struct at_ifaddr *aa; 250 struct aarptab *aat; 251 int s; 252 253 if (at_broadcast(destsat)) { 254 aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp); 255 if (aa == NULL) { 256 m_freem(m); 257 return (0); 258 } 259 if (aa->aa_flags & AFA_PHASE2) 260 memcpy(desten, atmulticastaddr, 261 sizeof(atmulticastaddr)); 262 else 263 memcpy(desten, etherbroadcastaddr, 264 sizeof(etherbroadcastaddr)); 265 return 1; 266 } 267 s = splnet(); 268 AARPTAB_LOOK(aat, destsat->sat_addr); 269 if (aat == 0) { /* No entry */ 270 aat = aarptnew(&destsat->sat_addr); 271 if (aat == 0) 272 panic("aarpresolve: no free entry"); 273 274 aat->aat_hold = m; 275 aarpwhohas(ifp, destsat); 276 splx(s); 277 return 0; 278 } 279 280 /* found an entry */ 281 aat->aat_timer = 0; 282 if (aat->aat_flags & ATF_COM) { /* entry is COMplete */ 283 memcpy(desten, aat->aat_enaddr, sizeof(aat->aat_enaddr)); 284 splx(s); 285 return 1; 286 } 287 288 /* entry has not completed */ 289 if (aat->aat_hold) 290 m_freem(aat->aat_hold); 291 aat->aat_hold = m; 292 aarpwhohas(ifp, destsat); 293 splx(s); 294 295 return 0; 296} 297 298void 299aarpinput(struct ifnet *ifp, struct mbuf *m) 300{ 301 struct arphdr *ar; 302 303 if (ifp->if_flags & IFF_NOARP) 304 goto out; 305 306 if (m->m_len < sizeof(struct arphdr)) 307 goto out; 308 309 ar = mtod(m, struct arphdr *); 310 if (ntohs(ar->ar_hrd) != AARPHRD_ETHER) 311 goto out; 312 313 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 314 goto out; 315 316 switch (ntohs(ar->ar_pro)) { 317 case ETHERTYPE_ATALK: 318 at_aarpinput(ifp, m); 319 return; 320 321 default: 322 break; 323 } 324 325out: 326 m_freem(m); 327} 328 329static void 330at_aarpinput(struct ifnet *ifp, 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 (!memcmp(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 memcpy(&net, ea->aarp_tpnet, 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 memcpy(&spa.s_net, ea->aarp_spnet, sizeof(spa.s_net)); 364 memcpy(&tpa.s_net, ea->aarp_tpnet, 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 memcpy(aat->aat_enaddr, ea->aarp_sha, 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 memcpy(aat->aat_enaddr, ea->aarp_sha, 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 455 /* 456 * Prepare and send AARP-response. 457 */ 458 m->m_len = sizeof(*ea); 459 m->m_pkthdr.len = sizeof(*ea); 460 memcpy(ea->aarp_tha, ea->aarp_sha, sizeof(ea->aarp_sha)); 461 memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha)); 462 463 /* XXX */ 464 eh = (struct ether_header *) sa.sa_data; 465 memcpy(eh->ether_dhost, ea->aarp_tha, sizeof(eh->ether_dhost)); 466 467 if (aa->aa_flags & AFA_PHASE2) { 468 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 469 if (m == NULL) 470 return; 471 472 llc = mtod(m, struct llc *); 473 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 474 llc->llc_control = LLC_UI; 475 memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code)); 476 llc->llc_ether_type = htons(ETHERTYPE_AARP); 477 478 memcpy(ea->aarp_tpnet, ea->aarp_spnet, sizeof(ea->aarp_tpnet)); 479 memcpy(ea->aarp_spnet, &ma.s_net, sizeof(ea->aarp_spnet)); 480 eh->ether_type = 0; /* if_output will treat as 802 */ 481 } else { 482 eh->ether_type = htons(ETHERTYPE_AARP); 483 } 484 485 ea->aarp_tpnode = ea->aarp_spnode; 486 ea->aarp_spnode = ma.s_node; 487 ea->aarp_op = htons(AARPOP_RESPONSE); 488 489 sa.sa_len = sizeof(struct sockaddr); 490 sa.sa_family = AF_UNSPEC; 491 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 492 return; 493} 494 495static void 496aarptfree(struct aarptab *aat) 497{ 498 499 if (aat->aat_hold) 500 m_freem(aat->aat_hold); 501 aat->aat_hold = 0; 502 aat->aat_timer = aat->aat_flags = 0; 503 aat->aat_ataddr.s_net = 0; 504 aat->aat_ataddr.s_node = 0; 505} 506 507static struct aarptab * 508aarptnew(const struct at_addr *addr) 509{ 510 int n; 511 int oldest = -1; 512 struct aarptab *aat, *aato = NULL; 513 static int first = 1; 514 515 if (first) { 516 first = 0; 517 callout_init(&aarptimer_callout, 0); 518 callout_reset(&aarptimer_callout, hz, aarptimer, NULL); 519 } 520 aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ]; 521 for (n = 0; n < AARPTAB_BSIZ; n++, aat++) { 522 if (aat->aat_flags == 0) 523 goto out; 524 if (aat->aat_flags & ATF_PERM) 525 continue; 526 if ((int) aat->aat_timer > oldest) { 527 oldest = aat->aat_timer; 528 aato = aat; 529 } 530 } 531 if (aato == NULL) 532 return (NULL); 533 aat = aato; 534 aarptfree(aat); 535out: 536 aat->aat_ataddr = *addr; 537 aat->aat_flags = ATF_INUSE; 538 return (aat); 539} 540 541 542void 543aarpprobe(void *arp) 544{ 545 struct mbuf *m; 546 struct ether_header *eh; 547 struct ether_aarp *ea; 548 struct ifaddr *ia; 549 struct at_ifaddr *aa; 550 struct llc *llc; 551 struct sockaddr sa; 552 struct ifnet *ifp = arp; 553 554 mutex_enter(softnet_lock); 555 556 /* 557 * We need to check whether the output ethernet type should 558 * be phase 1 or 2. We have the interface that we'll be sending 559 * the aarp out. We need to find an AppleTalk network on that 560 * interface with the same address as we're looking for. If the 561 * net is phase 2, generate an 802.2 and SNAP header. 562 */ 563 IFADDR_FOREACH(ia, ifp) { 564 aa = (struct at_ifaddr *)ia; 565 if (AA_SAT(aa)->sat_family == AF_APPLETALK && 566 (aa->aa_flags & AFA_PROBING)) 567 break; 568 } 569 if (ia == NULL) { /* serious error XXX */ 570 printf("aarpprobe why did this happen?!\n"); 571 mutex_exit(softnet_lock); 572 return; 573 } 574 if (aa->aa_probcnt <= 0) { 575 aa->aa_flags &= ~AFA_PROBING; 576 wakeup(aa); 577 mutex_exit(softnet_lock); 578 return; 579 } else { 580 callout_reset(&aa->aa_probe_ch, hz / 5, aarpprobe, arp); 581 } 582 583 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) { 584 mutex_exit(softnet_lock); 585 return; 586 } 587 588 MCLAIM(m, &aarp_mowner); 589 m->m_len = sizeof(*ea); 590 m->m_pkthdr.len = sizeof(*ea); 591 MH_ALIGN(m, sizeof(*ea)); 592 593 ea = mtod(m, struct ether_aarp *); 594 memset(ea, 0, sizeof(*ea)); 595 596 ea->aarp_hrd = htons(AARPHRD_ETHER); 597 ea->aarp_pro = htons(ETHERTYPE_ATALK); 598 ea->aarp_hln = sizeof(ea->aarp_sha); 599 ea->aarp_pln = sizeof(ea->aarp_spu); 600 ea->aarp_op = htons(AARPOP_PROBE); 601 memcpy(ea->aarp_sha, CLLADDR(ifp->if_sadl), sizeof(ea->aarp_sha)); 602 603 eh = (struct ether_header *) sa.sa_data; 604 605 if (aa->aa_flags & AFA_PHASE2) { 606 memcpy(eh->ether_dhost, atmulticastaddr, 607 sizeof(eh->ether_dhost)); 608 eh->ether_type = 0; /* if_output will treat as 802 */ 609 M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); 610 if (!m) { 611 mutex_exit(softnet_lock); 612 return; 613 } 614 615 llc = mtod(m, struct llc *); 616 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 617 llc->llc_control = LLC_UI; 618 memcpy(llc->llc_org_code, aarp_org_code, sizeof(aarp_org_code)); 619 llc->llc_ether_type = htons(ETHERTYPE_AARP); 620 621 memcpy(ea->aarp_spnet, &AA_SAT(aa)->sat_addr.s_net, 622 sizeof(ea->aarp_spnet)); 623 memcpy(ea->aarp_tpnet, &AA_SAT(aa)->sat_addr.s_net, 624 sizeof(ea->aarp_tpnet)); 625 ea->aarp_spnode = ea->aarp_tpnode = 626 AA_SAT(aa)->sat_addr.s_node; 627 } else { 628 memcpy(eh->ether_dhost, etherbroadcastaddr, 629 sizeof(eh->ether_dhost)); 630 eh->ether_type = htons(ETHERTYPE_AARP); 631 ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node; 632 } 633 634#ifdef NETATALKDEBUG 635 printf("aarp: sending probe for %u.%u\n", 636 ntohs(AA_SAT(aa)->sat_addr.s_net), 637 AA_SAT(aa)->sat_addr.s_node); 638#endif /* NETATALKDEBUG */ 639 640 sa.sa_len = sizeof(struct sockaddr); 641 sa.sa_family = AF_UNSPEC; 642 (*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */ 643 aa->aa_probcnt--; 644 mutex_exit(softnet_lock); 645} 646 647void 648aarp_clean(void) 649{ 650 struct aarptab *aat; 651 int i; 652 653 callout_stop(&aarptimer_callout); 654 for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) 655 if (aat->aat_hold) 656 m_freem(aat->aat_hold); 657} 658