Use a normal malloc() for PCB allocations instead of the really aweful mbuf
[dragonfly.git] / sys / netproto / atalk / aarp.c
1 /*
2  * Copyright (c) 1990,1991 Regents of The University of Michigan.
3  * All Rights Reserved.
4  *
5  * $FreeBSD: src/sys/netatalk/aarp.c,v 1.12.2.2 2001/06/23 20:43:09 iedowse Exp $
6  * $DragonFly: src/sys/netproto/atalk/aarp.c,v 1.11 2004/06/02 14:43:02 eirikn Exp $
7  */
8
9 #include "opt_atalk.h"
10
11 #include <sys/param.h>
12 #include <sys/systm.h>
13 #include <sys/mbuf.h>
14 #include <sys/kernel.h>
15 #include <sys/socket.h>
16 #include <sys/syslog.h>
17
18 #include <sys/thread2.h>
19 #include <sys/msgport2.h>
20
21 #include <net/if.h>
22 #include <net/netisr.h>
23
24 #include <netinet/in.h>
25 #undef s_net
26 #include <netinet/if_ether.h>
27
28 #include "at.h"
29 #include "at_var.h"
30 #include "aarp.h"
31 #include "phase2.h"
32 #include "at_extern.h"
33
34 static void aarptfree( struct aarptab *aat);
35 static void at_aarpinput( struct arpcom *ac, struct mbuf *m);
36
37 #define AARPTAB_BSIZ    9
38 #define AARPTAB_NB      19
39 #define AARPTAB_SIZE    (AARPTAB_BSIZ * AARPTAB_NB)
40 static struct aarptab   aarptab[AARPTAB_SIZE];
41
42 #define AARPTAB_HASH(a) \
43     ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
44
45 #define AARPTAB_LOOK(aat,addr) { \
46     int         n; \
47     aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \
48     for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \
49         if ( aat->aat_ataddr.s_net == (addr).s_net && \
50              aat->aat_ataddr.s_node == (addr).s_node ) \
51             break; \
52         if ( n >= AARPTAB_BSIZ ) \
53             aat = 0; \
54 }
55
56 #define AARPT_AGE       (60 * 1)
57 #define AARPT_KILLC     20
58 #define AARPT_KILLI     3
59
60 # if !defined( __DragonFly__ )
61 extern u_char                   etherbroadcastaddr[6];
62 # endif __DragonFly__
63
64 static u_char atmulticastaddr[ 6 ] = {
65     0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
66 };
67
68 u_char  at_org_code[ 3 ] = {
69     0x08, 0x00, 0x07,
70 };
71 u_char  aarp_org_code[ 3 ] = {
72     0x00, 0x00, 0x00,
73 };
74
75 static struct callout_handle aarptimer_ch =
76     CALLOUT_HANDLE_INITIALIZER(&aarptimer_ch);
77
78 static void
79 aarptimer(void *ignored)
80 {
81     struct aarptab      *aat;
82     int                 i, s;
83
84     aarptimer_ch = timeout( aarptimer, (caddr_t)0, AARPT_AGE * hz );
85     aat = aarptab;
86     for ( i = 0; i < AARPTAB_SIZE; i++, aat++ ) {
87         if ( aat->aat_flags == 0 || ( aat->aat_flags & ATF_PERM ))
88             continue;
89         if ( ++aat->aat_timer < (( aat->aat_flags & ATF_COM ) ?
90                 AARPT_KILLC : AARPT_KILLI ))
91             continue;
92         s = splimp();
93         aarptfree( aat );
94         splx( s );
95     }
96 }
97
98 /* 
99  * search through the network addresses to find one that includes
100  * the given network.. remember to take netranges into
101  * consideration.
102  */
103 struct at_ifaddr *
104 at_ifawithnet(struct sockaddr_at  *sat )
105 {
106     struct at_ifaddr    *aa;
107     struct sockaddr_at  *sat2;
108
109         for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
110                 sat2 = &(aa->aa_addr);
111                 if ( sat2->sat_addr.s_net == sat->sat_addr.s_net ) {
112                         break;
113                 }
114                 if( (aa->aa_flags & AFA_PHASE2 )
115                 && (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net))
116                 && (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net))) {
117                         break;
118                 }
119         }
120         return( aa );
121 }
122
123 static void
124 aarpwhohas( struct arpcom *ac, struct sockaddr_at *sat )
125 {
126     struct mbuf         *m;
127     struct ether_header *eh;
128     struct ether_aarp   *ea;
129     struct at_ifaddr    *aa;
130     struct llc          *llc;
131     struct sockaddr     sa;
132
133     if (( m = m_gethdr( MB_DONTWAIT, MT_DATA )) == NULL ) {
134         return;
135     }
136     m->m_len = sizeof( *ea );
137     m->m_pkthdr.len = sizeof( *ea );
138     MH_ALIGN( m, sizeof( *ea ));
139
140     ea = mtod( m, struct ether_aarp *);
141     bzero((caddr_t)ea, sizeof( *ea ));
142
143     ea->aarp_hrd = htons( AARPHRD_ETHER );
144     ea->aarp_pro = htons( ETHERTYPE_AT );
145     ea->aarp_hln = sizeof( ea->aarp_sha );
146     ea->aarp_pln = sizeof( ea->aarp_spu );
147     ea->aarp_op = htons( AARPOP_REQUEST );
148     bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
149             sizeof( ea->aarp_sha ));
150
151     /*
152      * We need to check whether the output ethernet type should
153      * be phase 1 or 2. We have the interface that we'll be sending
154      * the aarp out. We need to find an AppleTalk network on that
155      * interface with the same address as we're looking for. If the
156      * net is phase 2, generate an 802.2 and SNAP header.
157      */
158     if ((aa = at_ifawithnet( sat )) == NULL) {
159         m_freem( m );
160         return;
161     }
162
163     eh = (struct ether_header *)sa.sa_data;
164
165     if ( aa->aa_flags & AFA_PHASE2 ) {
166         bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
167                 sizeof( eh->ether_dhost ));
168         eh->ether_type = htons(sizeof(struct llc) + sizeof(struct ether_aarp));
169         M_PREPEND( m, sizeof( struct llc ), MB_WAIT );
170         llc = mtod( m, struct llc *);
171         llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
172         llc->llc_control = LLC_UI;
173         bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
174         llc->llc_ether_type = htons( ETHERTYPE_AARP );
175
176         bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
177                sizeof( ea->aarp_spnet ));
178         bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet,
179                sizeof( ea->aarp_tpnet ));
180         ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node;
181         ea->aarp_tpnode = sat->sat_addr.s_node;
182     } else {
183         bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
184                 sizeof( eh->ether_dhost ));
185         eh->ether_type = htons( ETHERTYPE_AARP );
186
187         ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
188         ea->aarp_tpa = sat->sat_addr.s_node;
189     }
190
191 #ifdef NETATALKDEBUG
192     printf("aarp: sending request for %u.%u\n",
193            ntohs(AA_SAT( aa )->sat_addr.s_net),
194            AA_SAT( aa )->sat_addr.s_node);
195 #endif /* NETATALKDEBUG */
196
197     sa.sa_len = sizeof( struct sockaddr );
198     sa.sa_family = AF_UNSPEC;
199     (*ac->ac_if.if_output)(&ac->ac_if,
200         m, &sa, NULL);  /* XXX NULL should be routing information */
201 }
202
203 int
204 aarpresolve( ac, m, destsat, desten )
205     struct arpcom       *ac;
206     struct mbuf         *m;
207     struct sockaddr_at  *destsat;
208     u_char              *desten;
209 {
210     struct at_ifaddr    *aa;
211     struct aarptab      *aat;
212     int                 s;
213
214     if ( at_broadcast( destsat )) {
215         m->m_flags |= M_BCAST;
216         if ((aa = at_ifawithnet( destsat )) == NULL)  {
217             m_freem( m );
218             return( 0 );
219         }
220         if ( aa->aa_flags & AFA_PHASE2 ) {
221             bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten,
222                     sizeof( atmulticastaddr ));
223         } else {
224             bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten,
225                     sizeof( etherbroadcastaddr ));
226         }
227         return( 1 );
228     }
229
230     s = splimp();
231     AARPTAB_LOOK( aat, destsat->sat_addr );
232     if ( aat == 0 ) {                   /* No entry */
233         aat = aarptnew( &destsat->sat_addr );
234         if ( aat == 0 ) {
235             panic( "aarpresolve: no free entry" );
236         }
237         aat->aat_hold = m;
238         aarpwhohas( ac, destsat );
239         splx( s );
240         return( 0 );
241     }
242     /* found an entry */
243     aat->aat_timer = 0;
244     if ( aat->aat_flags & ATF_COM ) {   /* entry is COMplete */
245         bcopy( (caddr_t)aat->aat_enaddr, (caddr_t)desten,
246                 sizeof( aat->aat_enaddr ));
247         splx( s );
248         return( 1 );
249     }
250     /* entry has not completed */
251     if ( aat->aat_hold ) {
252         m_freem( aat->aat_hold );
253     }
254     aat->aat_hold = m;
255     aarpwhohas( ac, destsat );
256     splx( s );
257     return( 0 );
258 }
259
260 int
261 aarpintr(struct netmsg *msg)
262 {
263     struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;   
264     struct arphdr       *ar;
265     struct arpcom       *ac;
266
267     ac = (struct arpcom *)m->m_pkthdr.rcvif;
268     if ( ac->ac_if.if_flags & IFF_NOARP )
269         goto out;
270
271     if ( m->m_len < sizeof( struct arphdr )) {
272         goto out;
273     }
274
275     ar = mtod( m, struct arphdr *);
276     if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) {
277         goto out;
278     }
279     
280     if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln +
281             2 * ar->ar_pln ) {
282         goto out;
283     }
284     
285     switch( ntohs( ar->ar_pro )) {
286     case ETHERTYPE_AT :
287         at_aarpinput( ac, m );
288         goto out2;
289
290     default:
291         break;
292     }
293
294 out:
295     m_freem(m);
296 out2:
297     lwkt_replymsg(&msg->nm_lmsg, 0);
298     return(EASYNC);
299 }
300
301 static void
302 at_aarpinput( struct arpcom *ac, struct mbuf *m)
303 {
304     struct ether_aarp   *ea;
305     struct at_ifaddr    *aa;
306     struct aarptab      *aat;
307     struct ether_header *eh;
308     struct llc          *llc;
309     struct sockaddr_at  sat;
310     struct sockaddr     sa;
311     struct at_addr      spa, tpa, ma;
312     int                 op;
313     u_short             net;
314
315     ea = mtod( m, struct ether_aarp *);
316
317     /* Check to see if from my hardware address */
318     if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr,
319             sizeof( ac->ac_enaddr ))) {
320         m_freem( m );
321         return;
322     }
323
324     op = ntohs( ea->aarp_op );
325     bcopy( ea->aarp_tpnet, &net, sizeof( net ));
326
327     if ( net != 0 ) { /* should be ATADDR_ANYNET? */
328         sat.sat_len = sizeof(struct sockaddr_at);
329         sat.sat_family = AF_APPLETALK;
330         sat.sat_addr.s_net = net;
331         if ((aa = at_ifawithnet( &sat )) == NULL) {
332             m_freem( m );
333             return;
334         }
335         bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net ));
336         bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net ));
337     } else {
338         /*
339          * Since we don't know the net, we just look for the first
340          * phase 1 address on the interface.
341          */
342         for (aa = (struct at_ifaddr *)ac->ac_if.if_addrhead.tqh_first; aa;
343                 aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) {
344             if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
345                     ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
346                 break;
347             }
348         }
349         if ( aa == NULL ) {
350             m_freem( m );
351             return;
352         }
353         tpa.s_net = spa.s_net = AA_SAT( aa )->sat_addr.s_net;
354     }
355
356     spa.s_node = ea->aarp_spnode;
357     tpa.s_node = ea->aarp_tpnode;
358     ma.s_net = AA_SAT( aa )->sat_addr.s_net;
359     ma.s_node = AA_SAT( aa )->sat_addr.s_node;
360
361     /*
362      * This looks like it's from us.
363      */
364     if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) {
365         if ( aa->aa_flags & AFA_PROBING ) {
366             /*
367              * We're probing, someone either responded to our probe, or
368              * probed for the same address we'd like to use. Change the
369              * address we're probing for.
370              */
371             untimeout( aarpprobe, ac, aa->aa_ch );
372             wakeup( aa );
373             m_freem( m );
374             return;
375         } else if ( op != AARPOP_PROBE ) {
376             /*
377              * This is not a probe, and we're not probing. This means
378              * that someone's saying they have the same source address
379              * as the one we're using. Get upset...
380              */
381             log( LOG_ERR,
382                     "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
383                     ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ],
384                     ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]);
385             m_freem( m );
386             return;
387         }
388     }
389
390     AARPTAB_LOOK( aat, spa );
391     if ( aat ) {
392         if ( op == AARPOP_PROBE ) {
393             /*
394              * Someone's probing for spa, dealocate the one we've got,
395              * so that if the prober keeps the address, we'll be able
396              * to arp for him.
397              */
398             aarptfree( aat );
399             m_freem( m );
400             return;
401         }
402
403         bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
404                 sizeof( ea->aarp_sha ));
405         aat->aat_flags |= ATF_COM;
406         if ( aat->aat_hold ) {
407             struct mbuf *mhold = aat->aat_hold;
408             aat->aat_hold = NULL;
409             sat.sat_len = sizeof(struct sockaddr_at);
410             sat.sat_family = AF_APPLETALK;
411             sat.sat_addr = spa;
412             (*ac->ac_if.if_output)( &ac->ac_if, mhold,
413                     (struct sockaddr *)&sat, NULL); /* XXX */
414         }
415     } else if ((tpa.s_net == ma.s_net)
416            && (tpa.s_node == ma.s_node)
417            && (op != AARPOP_PROBE)
418            && ((aat = aarptnew( &spa )) != NULL)) {
419                 bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
420                     sizeof( ea->aarp_sha ));
421                 aat->aat_flags |= ATF_COM;
422     }
423
424     /*
425      * Don't respond to responses, and never respond if we're
426      * still probing.
427      */
428     if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
429             op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) {
430         m_freem( m );
431         return;
432     }
433
434     bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha,
435             sizeof( ea->aarp_sha ));
436     bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
437             sizeof( ea->aarp_sha ));
438
439     /* XXX */
440     eh = (struct ether_header *)sa.sa_data;
441     bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost,
442             sizeof( eh->ether_dhost ));
443
444     if ( aa->aa_flags & AFA_PHASE2 ) {
445         eh->ether_type = htons( sizeof( struct llc ) +
446                 sizeof( struct ether_aarp ));
447         M_PREPEND( m, sizeof( struct llc ), MB_DONTWAIT );
448         if ( m == NULL ) {
449             return;
450         }
451         llc = mtod( m, struct llc *);
452         llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
453         llc->llc_control = LLC_UI;
454         bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
455         llc->llc_ether_type = htons( ETHERTYPE_AARP );
456
457         bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet ));
458         bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet ));
459     } else {
460         eh->ether_type = htons( ETHERTYPE_AARP );
461     }
462
463     ea->aarp_tpnode = ea->aarp_spnode;
464     ea->aarp_spnode = ma.s_node;
465     ea->aarp_op = htons( AARPOP_RESPONSE );
466
467     sa.sa_len = sizeof( struct sockaddr );
468     sa.sa_family = AF_UNSPEC;
469     (*ac->ac_if.if_output)( &ac->ac_if, m, &sa, NULL); /* XXX */
470     return;
471 }
472
473 static void
474 aarptfree( struct aarptab *aat)
475 {
476
477     if ( aat->aat_hold )
478         m_freem( aat->aat_hold );
479     aat->aat_hold = NULL;
480     aat->aat_timer = aat->aat_flags = 0;
481     aat->aat_ataddr.s_net = 0;
482     aat->aat_ataddr.s_node = 0;
483 }
484
485     struct aarptab *
486 aarptnew( addr )
487     struct at_addr      *addr;
488 {
489     int                 n;
490     int                 oldest = -1;
491     struct aarptab      *aat, *aato = NULL;
492     static int          first = 1;
493
494     if ( first ) {
495         first = 0;
496         aarptimer_ch = timeout( aarptimer, (caddr_t)0, hz );
497     }
498     aat = &aarptab[ AARPTAB_HASH( *addr ) * AARPTAB_BSIZ ];
499     for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) {
500         if ( aat->aat_flags == 0 )
501             goto out;
502         if ( aat->aat_flags & ATF_PERM )
503             continue;
504         if ((int) aat->aat_timer > oldest ) {
505             oldest = aat->aat_timer;
506             aato = aat;
507         }
508     }
509     if ( aato == NULL )
510         return( NULL );
511     aat = aato;
512     aarptfree( aat );
513 out:
514     aat->aat_ataddr = *addr;
515     aat->aat_flags = ATF_INUSE;
516     return( aat );
517 }
518
519
520 void
521 aarpprobe( void *arg )
522 {
523     struct arpcom       *ac = arg;
524     struct mbuf         *m;
525     struct ether_header *eh;
526     struct ether_aarp   *ea;
527     struct at_ifaddr    *aa;
528     struct llc          *llc;
529     struct sockaddr     sa;
530
531     /*
532      * We need to check whether the output ethernet type should
533      * be phase 1 or 2. We have the interface that we'll be sending
534      * the aarp out. We need to find an AppleTalk network on that
535      * interface with the same address as we're looking for. If the
536      * net is phase 2, generate an 802.2 and SNAP header.
537      */
538     for (aa = (struct at_ifaddr *)ac->ac_if.if_addrhead.tqh_first; aa;
539             aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) {
540         if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
541                 ( aa->aa_flags & AFA_PROBING )) {
542             break;
543         }
544     }
545     if ( aa == NULL ) {         /* serious error XXX */
546         printf( "aarpprobe why did this happen?!\n" );
547         return;
548     }
549
550     if ( aa->aa_probcnt <= 0 ) {
551         aa->aa_flags &= ~AFA_PROBING;
552         wakeup( aa );
553         return;
554     } else {
555         aa->aa_ch = timeout( aarpprobe, (caddr_t)ac, hz / 5 );
556     }
557
558     if (( m = m_gethdr( MB_DONTWAIT, MT_DATA )) == NULL ) {
559         return;
560     }
561     m->m_len = sizeof( *ea );
562     m->m_pkthdr.len = sizeof( *ea );
563     MH_ALIGN( m, sizeof( *ea ));
564
565     ea = mtod( m, struct ether_aarp *);
566     bzero((caddr_t)ea, sizeof( *ea ));
567
568     ea->aarp_hrd = htons( AARPHRD_ETHER );
569     ea->aarp_pro = htons( ETHERTYPE_AT );
570     ea->aarp_hln = sizeof( ea->aarp_sha );
571     ea->aarp_pln = sizeof( ea->aarp_spu );
572     ea->aarp_op = htons( AARPOP_PROBE );
573     bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
574             sizeof( ea->aarp_sha ));
575
576     eh = (struct ether_header *)sa.sa_data;
577
578     if ( aa->aa_flags & AFA_PHASE2 ) {
579         bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
580                 sizeof( eh->ether_dhost ));
581         eh->ether_type = htons( sizeof( struct llc ) +
582                 sizeof( struct ether_aarp ));
583         M_PREPEND( m, sizeof( struct llc ), MB_WAIT );
584         /* XXX-MBUF */
585         llc = mtod( m, struct llc *);
586         llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
587         llc->llc_control = LLC_UI;
588         bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
589         llc->llc_ether_type = htons( ETHERTYPE_AARP );
590
591         bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
592                 sizeof( ea->aarp_spnet ));
593         bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet,
594                 sizeof( ea->aarp_tpnet ));
595         ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node;
596     } else {
597         bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
598                 sizeof( eh->ether_dhost ));
599         eh->ether_type = htons( ETHERTYPE_AARP );
600         ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node;
601     }
602
603 #ifdef NETATALKDEBUG
604     printf("aarp: sending probe for %u.%u\n",
605            ntohs(AA_SAT( aa )->sat_addr.s_net),
606            AA_SAT( aa )->sat_addr.s_node);
607 #endif /* NETATALKDEBUG */
608
609     sa.sa_len = sizeof( struct sockaddr );
610     sa.sa_family = AF_UNSPEC;
611     (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, NULL); /* XXX */
612     aa->aa_probcnt--;
613 }
614
615 void
616 aarp_clean(void)
617 {
618     struct aarptab      *aat;
619     int                 i;
620
621     untimeout( aarptimer, 0, aarptimer_ch );
622     for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) {
623         if ( aat->aat_hold ) {
624             m_freem( aat->aat_hold );
625             aat->aat_hold = NULL;
626         }
627     }
628 }