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