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.22 2008/03/07 11:34:21 sephe 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
;
293 struct at_ifaddr
*aa
= NULL
;
295 struct ether_header
*eh
;
297 struct sockaddr_at sat
;
299 struct at_addr spa
, tpa
, ma
;
303 ea
= mtod( m
, struct ether_aarp
*);
305 /* Check to see if from my hardware address */
306 if ( !bcmp(( caddr_t
)ea
->aarp_sha
, ( caddr_t
)ac
->ac_enaddr
,
307 sizeof( ac
->ac_enaddr
))) {
312 op
= ntohs(ea
->aarp_op
);
313 bcopy(ea
->aarp_tpnet
, &net
, sizeof net
);
315 if ( net
!= 0 ) { /* should be ATADDR_ANYNET? */
316 sat
.sat_len
= sizeof(struct sockaddr_at
);
317 sat
.sat_family
= AF_APPLETALK
;
318 sat
.sat_addr
.s_net
= net
;
319 if ((aa
= at_ifawithnet(&sat
)) == NULL
) {
323 bcopy(ea
->aarp_spnet
, &spa
.s_net
, sizeof spa
.s_net
);
324 bcopy(ea
->aarp_tpnet
, &tpa
.s_net
, sizeof tpa
.s_net
);
326 struct ifaddr_container
*ifac
;
329 * Since we don't know the net, we just look for the first
330 * phase 1 address on the interface.
332 TAILQ_FOREACH(ifac
, &ac
->ac_if
.if_addrheads
[mycpuid
], ifa_link
) {
333 aa
= (struct at_ifaddr
*)(ifac
->ifa
);
334 if ( AA_SAT( aa
)->sat_family
== AF_APPLETALK
&&
335 ( aa
->aa_flags
& AFA_PHASE2
) == 0 ) {
343 tpa
.s_net
= spa
.s_net
= AA_SAT( aa
)->sat_addr
.s_net
;
346 spa
.s_node
= ea
->aarp_spnode
;
347 tpa
.s_node
= ea
->aarp_tpnode
;
348 ma
.s_net
= AA_SAT( aa
)->sat_addr
.s_net
;
349 ma
.s_node
= AA_SAT( aa
)->sat_addr
.s_node
;
352 * This looks like it's from us.
354 if ( spa
.s_net
== ma
.s_net
&& spa
.s_node
== ma
.s_node
) {
355 if ( aa
->aa_flags
& AFA_PROBING
) {
357 * We're probing, someone either responded to our probe, or
358 * probed for the same address we'd like to use. Change the
359 * address we're probing for.
361 callout_stop(&aa
->aa_ch
);
365 } else if ( op
!= AARPOP_PROBE
) {
367 * This is not a probe, and we're not probing. This means
368 * that someone's saying they have the same source address
369 * as the one we're using. Get upset...
372 "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
373 ea
->aarp_sha
[ 0 ], ea
->aarp_sha
[ 1 ], ea
->aarp_sha
[ 2 ],
374 ea
->aarp_sha
[ 3 ], ea
->aarp_sha
[ 4 ], ea
->aarp_sha
[ 5 ]);
380 AARPTAB_LOOK( aat
, spa
);
382 if ( op
== AARPOP_PROBE
) {
384 * Someone's probing for spa, dealocate the one we've got,
385 * so that if the prober keeps the address, we'll be able
393 bcopy(( caddr_t
)ea
->aarp_sha
, ( caddr_t
)aat
->aat_enaddr
,
394 sizeof( ea
->aarp_sha
));
395 aat
->aat_flags
|= ATF_COM
;
396 if ( aat
->aat_hold
) {
397 struct mbuf
*mhold
= aat
->aat_hold
;
398 aat
->aat_hold
= NULL
;
399 sat
.sat_len
= sizeof(struct sockaddr_at
);
400 sat
.sat_family
= AF_APPLETALK
;
402 lwkt_serialize_enter(ac
->ac_if
.if_serializer
);
403 (*ac
->ac_if
.if_output
)( &ac
->ac_if
, mhold
,
404 (struct sockaddr
*)&sat
, NULL
); /* XXX */
405 lwkt_serialize_exit(ac
->ac_if
.if_serializer
);
407 } else if ((tpa
.s_net
== ma
.s_net
)
408 && (tpa
.s_node
== ma
.s_node
)
409 && (op
!= AARPOP_PROBE
)
410 && ((aat
= aarptnew( &spa
)) != NULL
)) {
411 bcopy(( caddr_t
)ea
->aarp_sha
, ( caddr_t
)aat
->aat_enaddr
,
412 sizeof( ea
->aarp_sha
));
413 aat
->aat_flags
|= ATF_COM
;
417 * Don't respond to responses, and never respond if we're
420 if ( tpa
.s_net
!= ma
.s_net
|| tpa
.s_node
!= ma
.s_node
||
421 op
== AARPOP_RESPONSE
|| ( aa
->aa_flags
& AFA_PROBING
)) {
426 bcopy(( caddr_t
)ea
->aarp_sha
, ( caddr_t
)ea
->aarp_tha
,
427 sizeof( ea
->aarp_sha
));
428 bcopy(( caddr_t
)ac
->ac_enaddr
, ( caddr_t
)ea
->aarp_sha
,
429 sizeof( ea
->aarp_sha
));
432 eh
= (struct ether_header
*)sa
.sa_data
;
433 bcopy(( caddr_t
)ea
->aarp_tha
, ( caddr_t
)eh
->ether_dhost
,
434 sizeof( eh
->ether_dhost
));
436 if ( aa
->aa_flags
& AFA_PHASE2
) {
437 eh
->ether_type
= htons( sizeof( struct llc
) +
438 sizeof( struct ether_aarp
));
439 M_PREPEND( m
, sizeof( struct llc
), MB_DONTWAIT
);
443 llc
= mtod( m
, struct llc
*);
444 llc
->llc_dsap
= llc
->llc_ssap
= LLC_SNAP_LSAP
;
445 llc
->llc_control
= LLC_UI
;
446 bcopy( aarp_org_code
, llc
->llc_org_code
, sizeof( aarp_org_code
));
447 llc
->llc_ether_type
= htons( ETHERTYPE_AARP
);
449 bcopy( ea
->aarp_spnet
, ea
->aarp_tpnet
, sizeof( ea
->aarp_tpnet
));
450 bcopy( &ma
.s_net
, ea
->aarp_spnet
, sizeof( ea
->aarp_spnet
));
452 eh
->ether_type
= htons( ETHERTYPE_AARP
);
455 ea
->aarp_tpnode
= ea
->aarp_spnode
;
456 ea
->aarp_spnode
= ma
.s_node
;
457 ea
->aarp_op
= htons( AARPOP_RESPONSE
);
459 sa
.sa_len
= sizeof( struct sockaddr
);
460 sa
.sa_family
= AF_UNSPEC
;
461 lwkt_serialize_enter(ac
->ac_if
.if_serializer
);
462 (*ac
->ac_if
.if_output
)( &ac
->ac_if
, m
, &sa
, NULL
); /* XXX */
463 lwkt_serialize_exit(ac
->ac_if
.if_serializer
);
468 aarptfree(struct aarptab
*aat
)
472 m_freem( aat
->aat_hold
);
473 aat
->aat_hold
= NULL
;
474 aat
->aat_timer
= aat
->aat_flags
= 0;
475 aat
->aat_ataddr
.s_net
= 0;
476 aat
->aat_ataddr
.s_node
= 0;
480 aarptnew(struct at_addr
*addr
)
484 struct aarptab
*aat
, *aato
= NULL
;
485 static int first
= 1;
489 callout_init(&aarptimer_ch
);
490 callout_reset(&aarptimer_ch
, hz
, aarptimer
, NULL
);
492 aat
= &aarptab
[ AARPTAB_HASH( *addr
) * AARPTAB_BSIZ
];
493 for ( n
= 0; n
< AARPTAB_BSIZ
; n
++, aat
++ ) {
494 if ( aat
->aat_flags
== 0 )
496 if ( aat
->aat_flags
& ATF_PERM
)
498 if ((int) aat
->aat_timer
> oldest
) {
499 oldest
= aat
->aat_timer
;
508 aat
->aat_ataddr
= *addr
;
509 aat
->aat_flags
= ATF_INUSE
;
517 struct arpcom
*ac
= arg
;
519 struct ether_header
*eh
;
520 struct ether_aarp
*ea
;
521 struct ifaddr_container
*ifac
;
522 struct at_ifaddr
*aa
= NULL
;
527 * We need to check whether the output ethernet type should
528 * be phase 1 or 2. We have the interface that we'll be sending
529 * the aarp out. We need to find an AppleTalk network on that
530 * interface with the same address as we're looking for. If the
531 * net is phase 2, generate an 802.2 and SNAP header.
533 TAILQ_FOREACH(ifac
, &ac
->ac_if
.if_addrheads
[mycpuid
], ifa_link
) {
534 aa
= (struct at_ifaddr
*)(ifac
->ifa
);
535 if ( AA_SAT( aa
)->sat_family
== AF_APPLETALK
&&
536 ( aa
->aa_flags
& AFA_PROBING
)) {
540 if ( aa
== NULL
) { /* serious error XXX */
541 kprintf( "aarpprobe why did this happen?!\n" );
545 if ( aa
->aa_probcnt
<= 0 ) {
546 aa
->aa_flags
&= ~AFA_PROBING
;
550 callout_reset(&aa
->aa_ch
, hz
/ 5, aarpprobe
, ac
);
553 if (( m
= m_gethdr( MB_DONTWAIT
, MT_DATA
)) == NULL
) {
556 m
->m_len
= sizeof( *ea
);
557 m
->m_pkthdr
.len
= sizeof( *ea
);
558 MH_ALIGN( m
, sizeof( *ea
));
560 ea
= mtod( m
, struct ether_aarp
*);
561 bzero((caddr_t
)ea
, sizeof( *ea
));
563 ea
->aarp_hrd
= htons( AARPHRD_ETHER
);
564 ea
->aarp_pro
= htons( ETHERTYPE_AT
);
565 ea
->aarp_hln
= sizeof( ea
->aarp_sha
);
566 ea
->aarp_pln
= sizeof( ea
->aarp_spu
);
567 ea
->aarp_op
= htons( AARPOP_PROBE
);
568 bcopy((caddr_t
)ac
->ac_enaddr
, (caddr_t
)ea
->aarp_sha
,
569 sizeof( ea
->aarp_sha
));
571 eh
= (struct ether_header
*)sa
.sa_data
;
573 if ( aa
->aa_flags
& AFA_PHASE2
) {
574 bcopy((caddr_t
)atmulticastaddr
, (caddr_t
)eh
->ether_dhost
,
575 sizeof( eh
->ether_dhost
));
576 eh
->ether_type
= htons( sizeof( struct llc
) +
577 sizeof( struct ether_aarp
));
578 M_PREPEND( m
, sizeof( struct llc
), MB_WAIT
);
580 llc
= mtod( m
, struct llc
*);
581 llc
->llc_dsap
= llc
->llc_ssap
= LLC_SNAP_LSAP
;
582 llc
->llc_control
= LLC_UI
;
583 bcopy( aarp_org_code
, llc
->llc_org_code
, sizeof( aarp_org_code
));
584 llc
->llc_ether_type
= htons( ETHERTYPE_AARP
);
586 bcopy( &AA_SAT( aa
)->sat_addr
.s_net
, ea
->aarp_spnet
,
587 sizeof( ea
->aarp_spnet
));
588 bcopy( &AA_SAT( aa
)->sat_addr
.s_net
, ea
->aarp_tpnet
,
589 sizeof( ea
->aarp_tpnet
));
590 ea
->aarp_spnode
= ea
->aarp_tpnode
= AA_SAT( aa
)->sat_addr
.s_node
;
592 bcopy(ac
->ac_if
.if_broadcastaddr
, eh
->ether_dhost
,
593 ac
->ac_if
.if_addrlen
);
594 eh
->ether_type
= htons( ETHERTYPE_AARP
);
595 ea
->aarp_spa
= ea
->aarp_tpa
= AA_SAT( aa
)->sat_addr
.s_node
;
599 kprintf("aarp: sending probe for %u.%u\n",
600 ntohs(AA_SAT( aa
)->sat_addr
.s_net
),
601 AA_SAT( aa
)->sat_addr
.s_node
);
602 #endif /* NETATALKDEBUG */
604 sa
.sa_len
= sizeof( struct sockaddr
);
605 sa
.sa_family
= AF_UNSPEC
;
606 lwkt_serialize_enter(ac
->ac_if
.if_serializer
);
607 (*ac
->ac_if
.if_output
)(&ac
->ac_if
, m
, &sa
, NULL
); /* XXX */
608 lwkt_serialize_exit(ac
->ac_if
.if_serializer
);
618 callout_stop(&aarptimer_ch
);
619 for ( i
= 0, aat
= aarptab
; i
< AARPTAB_SIZE
; i
++, aat
++ ) {
620 if ( aat
->aat_hold
) {
621 m_freem( aat
->aat_hold
);
622 aat
->aat_hold
= NULL
;