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