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