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