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