Parallelize ifnet.if_addrhead accessing by duplicating the list itself
[dragonfly.git] / sys / netproto / atalk / aarp.c
blob40c1109e92ce6d909eed261635683d83bd890e6a
1 /*
2 * Copyright (c) 1990,1991 Regents of The University of Michigan.
3 * All Rights Reserved.
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 $
7 */
9 #include "opt_atalk.h"
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>
18 #include <sys/thread2.h>
19 #include <sys/msgport2.h>
21 #include <net/if.h>
22 #include <net/netisr.h>
24 #include <netinet/in.h>
25 #undef s_net
26 #include <netinet/if_ether.h>
28 #include "at.h"
29 #include "at_var.h"
30 #include "aarp.h"
31 #include "phase2.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
38 #define AARPTAB_NB 19
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) { \
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; \
56 #define AARPT_AGE (60 * 1)
57 #define AARPT_KILLC 20
58 #define AARPT_KILLI 3
60 static u_char atmulticastaddr[ 6 ] = {
61 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
64 u_char at_org_code[ 3 ] = {
65 0x08, 0x00, 0x07,
67 u_char aarp_org_code[ 3 ] = {
68 0x00, 0x00, 0x00,
71 static struct callout aarptimer_ch;
73 static void
74 aarptimer(void *ignored)
76 struct aarptab *aat;
77 int i;
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();
90 callout_reset(&aarptimer_ch, AARPT_AGE * hz, aarptimer, NULL);
93 /*
94 * search through the network addresses to find one that includes
95 * the given network.. remember to take netranges into
96 * consideration.
98 struct at_ifaddr *
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 ) {
107 break;
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;
115 return( aa );
118 static void
119 aarpwhohas(struct arpcom *ac, struct sockaddr_at *sat)
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;
128 if (( m = m_gethdr( MB_DONTWAIT, MT_DATA )) == NULL ) {
129 return;
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) {
153 m_freem( m );
154 return;
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;
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 );
181 ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
182 ea->aarp_tpa = sat->sat_addr.s_node;
185 #ifdef NETATALKDEBUG
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,
201 u_char *desten )
203 struct at_ifaddr *aa;
204 struct aarptab *aat;
206 if (at_broadcast(destsat)) {
207 m->m_flags |= M_BCAST;
208 if ((aa = at_ifawithnet(destsat)) == NULL) {
209 m_freem(m);
210 return (0);
212 if (aa->aa_flags & AFA_PHASE2)
213 bcopy(atmulticastaddr, desten, sizeof atmulticastaddr);
214 else
215 bcopy(ac->ac_if.if_broadcastaddr, desten, ac->ac_if.if_addrlen);
216 return (1);
219 crit_enter();
220 AARPTAB_LOOK( aat, destsat->sat_addr );
221 if (aat == NULL) { /* No entry */
222 aat = aarptnew( &destsat->sat_addr );
223 if (aat == NULL) {
224 panic("aarpresolve: no free entry");
226 aat->aat_hold = m;
227 aarpwhohas(ac, destsat);
228 crit_exit();
229 return (0);
231 /* found an entry */
232 aat->aat_timer = 0;
233 if (aat->aat_flags & ATF_COM) { /* entry is COMplete */
234 bcopy(aat->aat_enaddr, desten, sizeof aat->aat_enaddr);
235 crit_exit();
236 return (1);
238 /* entry has not completed */
239 if (aat->aat_hold) {
240 m_freem(aat->aat_hold);
242 aat->aat_hold = m;
243 aarpwhohas(ac, destsat);
244 crit_exit();
245 return (0);
248 void
249 aarpintr(struct netmsg *msg)
251 struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
252 struct arphdr *ar;
253 struct arpcom *ac;
255 ac = (struct arpcom *)m->m_pkthdr.rcvif;
256 if ( ac->ac_if.if_flags & IFF_NOARP )
257 goto out;
259 if ( m->m_len < sizeof( struct arphdr )) {
260 goto out;
263 ar = mtod( m, struct arphdr *);
264 if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) {
265 goto out;
268 if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln +
269 2 * ar->ar_pln ) {
270 goto out;
273 switch( ntohs( ar->ar_pro )) {
274 case ETHERTYPE_AT :
275 at_aarpinput( ac, m );
276 goto out2;
278 default:
279 break;
282 out:
283 m_freem(m);
284 out2:
286 /* msg was embedded in the mbuf, do not reply! */
289 static void
290 at_aarpinput( struct arpcom *ac, struct mbuf *m)
292 struct ether_aarp *ea;
293 struct at_ifaddr *aa = NULL;
294 struct aarptab *aat;
295 struct ether_header *eh;
296 struct llc *llc;
297 struct sockaddr_at sat;
298 struct sockaddr sa;
299 struct at_addr spa, tpa, ma;
300 int op;
301 u_short net;
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 ))) {
308 m_freem( m );
309 return;
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) {
320 m_freem( m );
321 return;
323 bcopy(ea->aarp_spnet, &spa.s_net, sizeof spa.s_net);
324 bcopy(ea->aarp_tpnet, &tpa.s_net, sizeof tpa.s_net);
325 } else {
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 ) {
336 break;
339 if ( aa == NULL ) {
340 m_freem( m );
341 return;
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);
362 wakeup( aa );
363 m_freem( m );
364 return;
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...
371 log( LOG_ERR,
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 ]);
375 m_freem( m );
376 return;
380 AARPTAB_LOOK( aat, spa );
381 if ( aat ) {
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
386 * to arp for him.
388 aarptfree( aat );
389 m_freem( m );
390 return;
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;
401 sat.sat_addr = spa;
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
418 * still probing.
420 if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
421 op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) {
422 m_freem( m );
423 return;
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 ));
431 /* XXX */
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 );
440 if ( m == NULL ) {
441 return;
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 ));
451 } else {
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);
464 return;
467 static void
468 aarptfree(struct aarptab *aat)
471 if ( aat->aat_hold )
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;
479 struct aarptab *
480 aarptnew(struct at_addr *addr)
482 int n;
483 int oldest = -1;
484 struct aarptab *aat, *aato = NULL;
485 static int first = 1;
487 if ( first ) {
488 first = 0;
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 )
495 goto out;
496 if ( aat->aat_flags & ATF_PERM )
497 continue;
498 if ((int) aat->aat_timer > oldest ) {
499 oldest = aat->aat_timer;
500 aato = aat;
503 if ( aato == NULL )
504 return( NULL );
505 aat = aato;
506 aarptfree( aat );
507 out:
508 aat->aat_ataddr = *addr;
509 aat->aat_flags = ATF_INUSE;
510 return( aat );
514 void
515 aarpprobe(void *arg)
517 struct arpcom *ac = arg;
518 struct mbuf *m;
519 struct ether_header *eh;
520 struct ether_aarp *ea;
521 struct ifaddr_container *ifac;
522 struct at_ifaddr *aa = NULL;
523 struct llc *llc;
524 struct sockaddr sa;
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 )) {
537 break;
540 if ( aa == NULL ) { /* serious error XXX */
541 kprintf( "aarpprobe why did this happen?!\n" );
542 return;
545 if ( aa->aa_probcnt <= 0 ) {
546 aa->aa_flags &= ~AFA_PROBING;
547 wakeup( aa );
548 return;
549 } else {
550 callout_reset(&aa->aa_ch, hz / 5, aarpprobe, ac);
553 if (( m = m_gethdr( MB_DONTWAIT, MT_DATA )) == NULL ) {
554 return;
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 );
579 /* XXX-MBUF */
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;
591 } else {
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;
598 #ifdef NETATALKDEBUG
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);
609 aa->aa_probcnt--;
612 void
613 aarp_clean(void)
615 struct aarptab *aat;
616 int i;
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;