2 * Copyright (c) 1990,1991 Regents of The University of Michigan.
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.21 2007/05/23 08:57:06 dillon Exp $
11 #include <sys/param.h>
12 #include <sys/systm.h>
14 #include <sys/kernel.h>
15 #include <sys/socket.h>
16 #include <sys/syslog.h>
18 #include <sys/thread2.h>
19 #include <sys/msgport2.h>
22 #include <net/netisr.h>
24 #include <netinet/in.h>
26 #include <netinet/if_ether.h>
32 #include "at_extern.h"
34 static void aarptfree( struct aarptab
*aat
);
35 static void at_aarpinput( struct arpcom
*ac
, struct mbuf
*m
);
37 #define AARPTAB_BSIZ 9
39 #define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB)
40 static struct aarptab aarptab
[AARPTAB_SIZE
];
42 #define AARPTAB_HASH(a) \
43 ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
45 #define AARPTAB_LOOK(aat,addr) { \
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 ) \
52 if ( n >= AARPTAB_BSIZ ) \
56 #define AARPT_AGE (60 * 1)
57 #define AARPT_KILLC 20
60 static u_char atmulticastaddr
[ 6 ] = {
61 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
64 u_char at_org_code
[ 3 ] = {
67 u_char aarp_org_code
[ 3 ] = {
71 static struct callout aarptimer_ch
;
74 aarptimer(void *ignored
)
80 for ( i
= 0; i
< AARPTAB_SIZE
; i
++, aat
++ ) {
81 if ( aat
->aat_flags
== 0 || ( aat
->aat_flags
& ATF_PERM
))
83 if ( ++aat
->aat_timer
< (( aat
->aat_flags
& ATF_COM
) ?
84 AARPT_KILLC
: AARPT_KILLI
))
90 callout_reset(&aarptimer_ch
, AARPT_AGE
* hz
, aarptimer
, NULL
);
94 * search through the network addresses to find one that includes
95 * the given network.. remember to take netranges into
99 at_ifawithnet(struct sockaddr_at
*sat
)
101 struct at_ifaddr
*aa
;
102 struct sockaddr_at
*sat2
;
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
) {
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
))) {
119 aarpwhohas(struct arpcom
*ac
, struct sockaddr_at
*sat
)
122 struct ether_header
*eh
;
123 struct ether_aarp
*ea
;
124 struct at_ifaddr
*aa
;
128 if (( m
= m_gethdr( MB_DONTWAIT
, MT_DATA
)) == NULL
) {
131 m
->m_len
= sizeof( *ea
);
132 m
->m_pkthdr
.len
= sizeof( *ea
);
133 MH_ALIGN( m
, sizeof( *ea
));
135 ea
= mtod( m
, struct ether_aarp
*);
136 bzero((caddr_t
)ea
, sizeof( *ea
));
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
);
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.
152 if ((aa
= at_ifawithnet( sat
)) == NULL
) {
157 eh
= (struct ether_header
*)sa
.sa_data
;
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
);
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
;
177 bcopy(ac
->ac_if
.if_broadcastaddr
, eh
->ether_dhost
,
178 ac
->ac_if
.if_addrlen
);
179 eh
->ether_type
= htons( ETHERTYPE_AARP
);
181 ea
->aarp_spa
= AA_SAT( aa
)->sat_addr
.s_node
;
182 ea
->aarp_tpa
= sat
->sat_addr
.s_node
;
186 kprintf("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 */
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
);
200 aarpresolve(struct arpcom
*ac
, struct mbuf
*m
, struct sockaddr_at
*destsat
,
203 struct at_ifaddr
*aa
;
206 if (at_broadcast(destsat
)) {
207 m
->m_flags
|= M_BCAST
;
208 if ((aa
= at_ifawithnet(destsat
)) == NULL
) {
212 if (aa
->aa_flags
& AFA_PHASE2
)
213 bcopy(atmulticastaddr
, desten
, sizeof atmulticastaddr
);
215 bcopy(ac
->ac_if
.if_broadcastaddr
, desten
, ac
->ac_if
.if_addrlen
);
220 AARPTAB_LOOK( aat
, destsat
->sat_addr
);
221 if (aat
== NULL
) { /* No entry */
222 aat
= aarptnew( &destsat
->sat_addr
);
224 panic("aarpresolve: no free entry");
227 aarpwhohas(ac
, destsat
);
233 if (aat
->aat_flags
& ATF_COM
) { /* entry is COMplete */
234 bcopy(aat
->aat_enaddr
, desten
, sizeof aat
->aat_enaddr
);
238 /* entry has not completed */
240 m_freem(aat
->aat_hold
);
243 aarpwhohas(ac
, destsat
);
249 aarpintr(struct netmsg
*msg
)
251 struct mbuf
*m
= ((struct netmsg_packet
*)msg
)->nm_packet
;
255 ac
= (struct arpcom
*)m
->m_pkthdr
.rcvif
;
256 if ( ac
->ac_if
.if_flags
& IFF_NOARP
)
259 if ( m
->m_len
< sizeof( struct arphdr
)) {
263 ar
= mtod( m
, struct arphdr
*);
264 if ( ntohs( ar
->ar_hrd
) != AARPHRD_ETHER
) {
268 if ( m
->m_len
< sizeof( struct arphdr
) + 2 * ar
->ar_hln
+
273 switch( ntohs( ar
->ar_pro
)) {
275 at_aarpinput( ac
, m
);
286 /* msg was embedded in the mbuf, do not reply! */
290 at_aarpinput( struct arpcom
*ac
, struct mbuf
*m
)
292 struct ether_aarp
*ea
;
294 struct at_ifaddr
*aa
= NULL
;
296 struct ether_header
*eh
;
298 struct sockaddr_at sat
;
300 struct at_addr spa
, tpa
, ma
;
304 ea
= mtod( m
, struct ether_aarp
*);
306 /* Check to see if from my hardware address */
307 if ( !bcmp(( caddr_t
)ea
->aarp_sha
, ( caddr_t
)ac
->ac_enaddr
,
308 sizeof( ac
->ac_enaddr
))) {
313 op
= ntohs(ea
->aarp_op
);
314 bcopy(ea
->aarp_tpnet
, &net
, sizeof net
);
316 if ( net
!= 0 ) { /* should be ATADDR_ANYNET? */
317 sat
.sat_len
= sizeof(struct sockaddr_at
);
318 sat
.sat_family
= AF_APPLETALK
;
319 sat
.sat_addr
.s_net
= net
;
320 if ((aa
= at_ifawithnet(&sat
)) == NULL
) {
324 bcopy(ea
->aarp_spnet
, &spa
.s_net
, sizeof spa
.s_net
);
325 bcopy(ea
->aarp_tpnet
, &tpa
.s_net
, sizeof tpa
.s_net
);
328 * Since we don't know the net, we just look for the first
329 * phase 1 address on the interface.
331 TAILQ_FOREACH(ifa
, &ac
->ac_if
.if_addrhead
, ifa_link
) {
332 aa
= (struct at_ifaddr
*)ifa
;
333 if ( AA_SAT( aa
)->sat_family
== AF_APPLETALK
&&
334 ( aa
->aa_flags
& AFA_PHASE2
) == 0 ) {
342 tpa
.s_net
= spa
.s_net
= AA_SAT( aa
)->sat_addr
.s_net
;
345 spa
.s_node
= ea
->aarp_spnode
;
346 tpa
.s_node
= ea
->aarp_tpnode
;
347 ma
.s_net
= AA_SAT( aa
)->sat_addr
.s_net
;
348 ma
.s_node
= AA_SAT( aa
)->sat_addr
.s_node
;
351 * This looks like it's from us.
353 if ( spa
.s_net
== ma
.s_net
&& spa
.s_node
== ma
.s_node
) {
354 if ( aa
->aa_flags
& AFA_PROBING
) {
356 * We're probing, someone either responded to our probe, or
357 * probed for the same address we'd like to use. Change the
358 * address we're probing for.
360 callout_stop(&aa
->aa_ch
);
364 } else if ( op
!= AARPOP_PROBE
) {
366 * This is not a probe, and we're not probing. This means
367 * that someone's saying they have the same source address
368 * as the one we're using. Get upset...
371 "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
372 ea
->aarp_sha
[ 0 ], ea
->aarp_sha
[ 1 ], ea
->aarp_sha
[ 2 ],
373 ea
->aarp_sha
[ 3 ], ea
->aarp_sha
[ 4 ], ea
->aarp_sha
[ 5 ]);
379 AARPTAB_LOOK( aat
, spa
);
381 if ( op
== AARPOP_PROBE
) {
383 * Someone's probing for spa, dealocate the one we've got,
384 * so that if the prober keeps the address, we'll be able
392 bcopy(( caddr_t
)ea
->aarp_sha
, ( caddr_t
)aat
->aat_enaddr
,
393 sizeof( ea
->aarp_sha
));
394 aat
->aat_flags
|= ATF_COM
;
395 if ( aat
->aat_hold
) {
396 struct mbuf
*mhold
= aat
->aat_hold
;
397 aat
->aat_hold
= NULL
;
398 sat
.sat_len
= sizeof(struct sockaddr_at
);
399 sat
.sat_family
= AF_APPLETALK
;
401 lwkt_serialize_enter(ac
->ac_if
.if_serializer
);
402 (*ac
->ac_if
.if_output
)( &ac
->ac_if
, mhold
,
403 (struct sockaddr
*)&sat
, NULL
); /* XXX */
404 lwkt_serialize_exit(ac
->ac_if
.if_serializer
);
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
;
416 * Don't respond to responses, and never respond if we're
419 if ( tpa
.s_net
!= ma
.s_net
|| tpa
.s_node
!= ma
.s_node
||
420 op
== AARPOP_RESPONSE
|| ( aa
->aa_flags
& AFA_PROBING
)) {
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
));
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
));
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
), MB_DONTWAIT
);
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
);
448 bcopy( ea
->aarp_spnet
, ea
->aarp_tpnet
, sizeof( ea
->aarp_tpnet
));
449 bcopy( &ma
.s_net
, ea
->aarp_spnet
, sizeof( ea
->aarp_spnet
));
451 eh
->ether_type
= htons( ETHERTYPE_AARP
);
454 ea
->aarp_tpnode
= ea
->aarp_spnode
;
455 ea
->aarp_spnode
= ma
.s_node
;
456 ea
->aarp_op
= htons( AARPOP_RESPONSE
);
458 sa
.sa_len
= sizeof( struct sockaddr
);
459 sa
.sa_family
= AF_UNSPEC
;
460 lwkt_serialize_enter(ac
->ac_if
.if_serializer
);
461 (*ac
->ac_if
.if_output
)( &ac
->ac_if
, m
, &sa
, NULL
); /* XXX */
462 lwkt_serialize_exit(ac
->ac_if
.if_serializer
);
467 aarptfree(struct aarptab
*aat
)
471 m_freem( aat
->aat_hold
);
472 aat
->aat_hold
= NULL
;
473 aat
->aat_timer
= aat
->aat_flags
= 0;
474 aat
->aat_ataddr
.s_net
= 0;
475 aat
->aat_ataddr
.s_node
= 0;
479 aarptnew(struct at_addr
*addr
)
483 struct aarptab
*aat
, *aato
= NULL
;
484 static int first
= 1;
488 callout_init(&aarptimer_ch
);
489 callout_reset(&aarptimer_ch
, hz
, aarptimer
, NULL
);
491 aat
= &aarptab
[ AARPTAB_HASH( *addr
) * AARPTAB_BSIZ
];
492 for ( n
= 0; n
< AARPTAB_BSIZ
; n
++, aat
++ ) {
493 if ( aat
->aat_flags
== 0 )
495 if ( aat
->aat_flags
& ATF_PERM
)
497 if ((int) aat
->aat_timer
> oldest
) {
498 oldest
= aat
->aat_timer
;
507 aat
->aat_ataddr
= *addr
;
508 aat
->aat_flags
= ATF_INUSE
;
516 struct arpcom
*ac
= arg
;
518 struct ether_header
*eh
;
519 struct ether_aarp
*ea
;
521 struct at_ifaddr
*aa
= NULL
;
526 * We need to check whether the output ethernet type should
527 * be phase 1 or 2. We have the interface that we'll be sending
528 * the aarp out. We need to find an AppleTalk network on that
529 * interface with the same address as we're looking for. If the
530 * net is phase 2, generate an 802.2 and SNAP header.
532 TAILQ_FOREACH(ifa
, &ac
->ac_if
.if_addrhead
, ifa_link
) {
533 aa
= (struct at_ifaddr
*)ifa
;
534 if ( AA_SAT( aa
)->sat_family
== AF_APPLETALK
&&
535 ( aa
->aa_flags
& AFA_PROBING
)) {
539 if ( aa
== NULL
) { /* serious error XXX */
540 kprintf( "aarpprobe why did this happen?!\n" );
544 if ( aa
->aa_probcnt
<= 0 ) {
545 aa
->aa_flags
&= ~AFA_PROBING
;
549 callout_reset(&aa
->aa_ch
, hz
/ 5, aarpprobe
, ac
);
552 if (( m
= m_gethdr( MB_DONTWAIT
, MT_DATA
)) == NULL
) {
555 m
->m_len
= sizeof( *ea
);
556 m
->m_pkthdr
.len
= sizeof( *ea
);
557 MH_ALIGN( m
, sizeof( *ea
));
559 ea
= mtod( m
, struct ether_aarp
*);
560 bzero((caddr_t
)ea
, sizeof( *ea
));
562 ea
->aarp_hrd
= htons( AARPHRD_ETHER
);
563 ea
->aarp_pro
= htons( ETHERTYPE_AT
);
564 ea
->aarp_hln
= sizeof( ea
->aarp_sha
);
565 ea
->aarp_pln
= sizeof( ea
->aarp_spu
);
566 ea
->aarp_op
= htons( AARPOP_PROBE
);
567 bcopy((caddr_t
)ac
->ac_enaddr
, (caddr_t
)ea
->aarp_sha
,
568 sizeof( ea
->aarp_sha
));
570 eh
= (struct ether_header
*)sa
.sa_data
;
572 if ( aa
->aa_flags
& AFA_PHASE2
) {
573 bcopy((caddr_t
)atmulticastaddr
, (caddr_t
)eh
->ether_dhost
,
574 sizeof( eh
->ether_dhost
));
575 eh
->ether_type
= htons( sizeof( struct llc
) +
576 sizeof( struct ether_aarp
));
577 M_PREPEND( m
, sizeof( struct llc
), MB_WAIT
);
579 llc
= mtod( m
, struct llc
*);
580 llc
->llc_dsap
= llc
->llc_ssap
= LLC_SNAP_LSAP
;
581 llc
->llc_control
= LLC_UI
;
582 bcopy( aarp_org_code
, llc
->llc_org_code
, sizeof( aarp_org_code
));
583 llc
->llc_ether_type
= htons( ETHERTYPE_AARP
);
585 bcopy( &AA_SAT( aa
)->sat_addr
.s_net
, ea
->aarp_spnet
,
586 sizeof( ea
->aarp_spnet
));
587 bcopy( &AA_SAT( aa
)->sat_addr
.s_net
, ea
->aarp_tpnet
,
588 sizeof( ea
->aarp_tpnet
));
589 ea
->aarp_spnode
= ea
->aarp_tpnode
= AA_SAT( aa
)->sat_addr
.s_node
;
591 bcopy(ac
->ac_if
.if_broadcastaddr
, eh
->ether_dhost
,
592 ac
->ac_if
.if_addrlen
);
593 eh
->ether_type
= htons( ETHERTYPE_AARP
);
594 ea
->aarp_spa
= ea
->aarp_tpa
= AA_SAT( aa
)->sat_addr
.s_node
;
598 kprintf("aarp: sending probe for %u.%u\n",
599 ntohs(AA_SAT( aa
)->sat_addr
.s_net
),
600 AA_SAT( aa
)->sat_addr
.s_node
);
601 #endif /* NETATALKDEBUG */
603 sa
.sa_len
= sizeof( struct sockaddr
);
604 sa
.sa_family
= AF_UNSPEC
;
605 lwkt_serialize_enter(ac
->ac_if
.if_serializer
);
606 (*ac
->ac_if
.if_output
)(&ac
->ac_if
, m
, &sa
, NULL
); /* XXX */
607 lwkt_serialize_exit(ac
->ac_if
.if_serializer
);
617 callout_stop(&aarptimer_ch
);
618 for ( i
= 0, aat
= aarptab
; i
< AARPTAB_SIZE
; i
++, aat
++ ) {
619 if ( aat
->aat_hold
) {
620 m_freem( aat
->aat_hold
);
621 aat
->aat_hold
= NULL
;