2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 * Address Resolution Protocol.
26 * add "inuse/lock" bit (or ref. count) along with valid bit
31 #include <libraries/miami.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
36 #include <sys/socket.h>
38 #include <sys/kernel.h>
39 #include <sys/errno.h>
40 #include <sys/ioctl.h>
41 #include <sys/syslog.h>
42 #include <sys/synch.h>
45 #include <net/if_types.h>
46 #include <net/if_protos.h>
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/in_var.h>
51 #include <netinet/ip.h>
53 #include <net/if_sana.h>
54 #include <net/sana2arp.h>
56 #include <net/if_loop_protos.h>
59 * Internet to hardware address resolution table entry
62 struct arptab
*at_succ
; /* doubly linked list */
63 struct arptab
*at_pred
;
64 struct in_addr at_iaddr
; /* internet address */
65 u_char at_hwaddr
[MAXADDRSANA
]; /* hardware address */
66 u_char at_timer
; /* minutes since last reference */
67 u_char at_flags
; /* flags */
68 struct mbuf
*at_hold
; /* last packet until resolved/timeout */
72 * Global constant for ARP entry allocation
74 unsigned long arpentries
= ARPENTRIES
;
77 * General per interface hash table
80 struct SignalSemaphore atb_lock
;
81 struct arptab
*atb_free
;
82 struct MinList atb_entries
[ARPTAB_HSIZE
];
85 #define ARPTAB_LOCK(atb) (ObtainSemaphore(&atb->atb_lock))
86 #define ARPTAB_UNLOCK(atb) (ReleaseSemaphore(&atb->atb_lock))
87 #define ARPTAB_HASH(a) ((u_long)(a) % ARPTAB_HSIZE)
89 extern struct ifnet loif
;
91 int useloopback
= 0; /* use loopback interface for local traffic */
93 static void arpwhohas(register struct sana_softc
*ssc
, struct in_addr
* addr
);
94 static void in_arpinput(register struct sana_softc
*ssc
, struct mbuf
*m
);
95 static char *sana_sprintf(register u_char
*ap
, int len
);
98 * Initialization routine. Allocate ARP entries.
99 * MUST BE CALLED AT SPLIMP.
102 alloc_arptable(struct sana_softc
* ssc
, int to_allocate
)
105 struct arptable
*atab
;
108 if (ssc
->ss_arp
.table
)
109 return /* (void)ssc->ss_arp.table */;
112 if (to_allocate
< arpentries
)
114 to_allocate
= arpentries
;
116 atab
= bsd_malloc(sizeof(*atab
), M_ARPENT
, M_WAITOK
);
117 at
= bsd_malloc(sizeof(*at
) * to_allocate
, M_ARPENT
, M_WAITOK
);
120 InitSemaphore(&atab
->atb_lock
);
121 for (i
= 0; i
< ARPTAB_HSIZE
; i
++)
122 NewList((struct List
*)(atab
->atb_entries
+ i
));
124 aligned_bzero(at
, sizeof(*at
) * to_allocate
);
126 at
[0].at_succ
= NULL
;
127 for (i
= 1; i
< to_allocate
; i
++) {
128 at
[i
].at_succ
= &at
[i
- 1];
130 atab
->atb_free
= &at
[to_allocate
- 1];
132 if (atab
) bsd_free(atab
, M_ARPENT
);
133 if (at
) bsd_free(at
, M_ARPENT
);
134 __log(LOG_ERR
, "Could not allocate ARP table for %s\n", ssc
->ss_name
);
137 ssc
->ss_arp
.table
= atab
;
141 * Notification function for arp entries
144 arpentries_notify(void *dummy
, LONG value
)
146 return (ULONG
)value
> ARPENTRIES_MIN
;
150 * Free an arptab entry. ARP TABLE MUST BE LOCKED
153 arptfree(register struct arptable
*atb
, register struct arptab
*at
)
156 m_freem(at
->at_hold
);
158 Remove((struct Node
*)at
);
160 if (at
->at_flags
& ATF_PERM
) {
161 bsd_free(at
, M_ARPENT
);
164 at
->at_timer
= at
->at_flags
= 0;
165 at
->at_iaddr
.s_addr
= 0;
166 at
->at_succ
= atb
->atb_free
;
172 * Enter a new address in arptab. ARP TABLE MUST BE LOCKED
174 static struct arptab
*
175 arptnew(u_long addr
, struct arptable
*atb
, int permanent
)
177 struct arptab
*at
= NULL
;
180 at
= bsd_malloc(sizeof(*at
), M_ARPENT
, M_WAITOK
);
181 bzero((caddr_t
)at
, sizeof(*at
));
185 atb
->atb_free
= at
->at_succ
;
188 * The oldest entry is pushed out from the
189 * interface table if there is no free entry.
190 * This should always succeed since all
191 * entries can not be permanent
193 struct arptab
*oldest
= NULL
;
196 for (i
= 0; i
< ARPTAB_HSIZE
; i
++) {
197 for (at
= (struct arptab
*)atb
->atb_entries
[i
].mlh_Head
;
200 if (at
->at_flags
== 0 || (at
->at_flags
& ATF_PERM
))
202 if (!oldest
|| oldest
->at_timer
< at
->at_timer
)
207 Remove((struct Node
*)oldest
);
215 at
->at_iaddr
.s_addr
= addr
;
216 at
->at_flags
= ATF_INUSE
;
217 AddHead((struct List
*)(&atb
->atb_entries
[ARPTAB_HASH(addr
)]),
224 * Locate an IP address in the ARP table
225 * Assume looker have locked the table
227 static struct arptab
*
228 arptab_look(struct arptable
*table
, u_long addr
)
230 register struct arptab
*at
= (struct arptab
*)
231 table
->atb_entries
[ARPTAB_HASH(addr
)].mlh_Head
;
233 for(;at
->at_succ
; at
= at
->at_succ
)
234 if (at
->at_iaddr
.s_addr
== addr
)
241 * Timeout routine. Age arp_tab entries once a minute.
246 struct sana_softc
*ssc
;
247 register struct arptable
*atab
;
248 register struct arptab
*at
;
251 for (ssc
= ssq
; ssc
; ssc
= ssc
->ss_next
) {
252 if (!(atab
= ssc
->ss_arp
.table
))
257 for (i
= 0; i
< ARPTAB_HSIZE
; i
++) {
258 for (at
= (struct arptab
*)atab
->atb_entries
[i
].mlh_Head
;
261 if (at
->at_flags
== 0 || (at
->at_flags
& ATF_PERM
))
263 if (++at
->at_timer
< ((at
->at_flags
& ATF_COM
) ?
264 ARPT_KILLC
: ARPT_KILLI
))
266 /* timer has expired, clear entry */
275 * Broadcast an ARP packet, asking who has addr on interface ssc.
278 arpwhohas(register struct sana_softc
*ssc
, struct in_addr
*addr
)
280 register struct mbuf
*m
;
281 register struct s2_arppkt
*s2a
;
282 struct sockaddr_sana2 ss2
;
284 if ((m
= m_gethdr(M_DONTWAIT
, MT_DATA
)) == NULL
)
286 m
->m_len
= sizeof(*s2a
);
287 m
->m_pkthdr
.len
= sizeof(*s2a
);
288 MH_ALIGN(m
, sizeof(*s2a
));
289 s2a
= mtod(m
, struct s2_arppkt
*);
290 aligned_bzero_const((caddr_t
)s2a
, sizeof (*s2a
));
291 m
->m_flags
|= M_BCAST
;
293 /* fill in header depending of the interface */
294 s2a
->arp_hrd
= htons(ssc
->ss_arp
.hrd
);
295 s2a
->arp_pro
= htons(ssc
->ss_ip
.type
);
296 s2a
->arp_pln
= sizeof(struct in_addr
); /* protocol address length */
297 s2a
->arp_hln
= ssc
->ss_if
.if_addrlen
; /* hardware address length */
298 s2a
->arp_op
= htons(ARPOP_REQUEST
);
300 /* Copy source hardware address */
301 bcopy((caddr_t
)ssc
->ss_hwaddr
,
302 (caddr_t
)&s2a
->arpdata
,
304 /* Copy source protocol address */
305 bcopy((caddr_t
)&ssc
->ss_ipaddr
,
306 (caddr_t
)&s2a
->arpdata
+ s2a
->arp_hln
,
308 /* Zero target hardware address */
309 bzero((caddr_t
)&s2a
->arpdata
+ s2a
->arp_hln
+ s2a
->arp_pln
,
311 /* Copy target protocol address */
313 (caddr_t
)&s2a
->arpdata
+ 2 * s2a
->arp_hln
+ s2a
->arp_pln
,
316 /* Send an ARP packet */
317 ss2
.ss2_len
= sizeof(ss2
);
318 ss2
.ss2_family
= AF_UNSPEC
;
319 ss2
.ss2_type
= ssc
->ss_arp
.type
;
320 (*ssc
->ss_if
.if_output
)(&ssc
->ss_if
, m
, (struct sockaddr
*)&ss2
,
321 (struct rtentry
*)0);
325 * Resolve an IP address into an SANA-II address. If success,
326 * desten is filled in. If there is no entry in arptab,
327 * set one up and broadcast a request for the IP address.
328 * Hold onto this mbuf and resend it once the address
329 * is finally resolved. A return value of 1 indicates
330 * that desten has been filled in and the packet should be sent
331 * normally; a 0 return indicates that the packet has been
332 * taken over here, either now or for later transmission.
334 * We do some (conservative) locking here at splimp, since
335 * arptab is also altered from sana poll routine
338 arpresolve(register struct sana_softc
*ssc
,
340 register struct in_addr
*destip
,
341 register u_char
*desten
,
344 register struct arptab
*at
;
345 register struct arptable
*atb
;
346 struct sockaddr_in sin
;
347 register struct in_ifaddr
*ia
;
349 if (m
->m_flags
& M_BCAST
) { /* broadcast */
353 /* if for us, use software loopback driver if up */
354 for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
355 if ((ia
->ia_ifp
== &ssc
->ss_if
) &&
356 (destip
->s_addr
== ia
->ia_addr
.sin_addr
.s_addr
)) {
358 * This test used to be
359 * if (loif.if_flags & IFF_UP)
360 * It allowed local traffic to be forced
361 * through the hardware by configuring the loopback down.
362 * However, it causes problems during network configuration
363 * for boards that can't receive packets they send.
364 * It is now necessary to clear "useloopback"
365 * to force traffic out to the hardware.
368 sin
.sin_family
= AF_INET
;
369 sin
.sin_addr
= *destip
;
370 (void) looutput(&loif
, m
, (struct sockaddr
*)&sin
, 0);
372 * The packet has already been sent and freed.
376 bcopy((caddr_t
)ssc
->ss_hwaddr
, (caddr_t
)desten
, ssc
->ss_if
.if_addrlen
);
381 if (ssc
->ss_if
.if_flags
& IFF_NOARP
) {
384 "arpresolve: can't resolve address for if %s/%ld\n",
385 ssc
->ss_if
.if_name
, ssc
->ss_if
.if_unit
);
386 *error
= ENETUNREACH
;
391 /* Try to locate ARP table */
392 if (!(atb
= ssc
->ss_arp
.table
)) {
393 alloc_arptable(ssc
, 0);
394 if (!(atb
= ssc
->ss_arp
.table
)) {
395 __log(LOG_ERR
, "arpresolve: memory exhausted");
403 at
= arptab_look(atb
, destip
->s_addr
);
404 if (at
== 0) { /* not found */
405 at
= arptnew(destip
->s_addr
, atb
, FALSE
);
408 arpwhohas(ssc
, destip
);
410 __log(LOG_ERR
, "arpresolve: no free entry");
411 *error
= ENETUNREACH
;
418 at
->at_timer
= 0; /* restart the timer */
419 if (at
->at_flags
& ATF_COM
) { /* entry IS complete */
420 bcopy((caddr_t
)at
->at_hwaddr
, (caddr_t
)desten
, ssc
->ss_if
.if_addrlen
);
425 * There is an arptab entry, but no address response yet.
426 * Replace the held mbuf with this latest one.
429 m_freem(at
->at_hold
);
431 arpwhohas(ssc
, destip
); /* ask again */
437 * Called from the sana poll routine
438 * when ARP type packet is received.
439 * Common length and type checks are done here,
440 * then the protocol-specific routine is called.
441 * In addition, a sanity check is performed on the sender
442 * protocol address, to catch impersonators.
445 arpinput(struct sana_softc
*ssc
,
449 register struct arphdr
*ar
;
452 if (ssc
->ss_if
.if_flags
& IFF_NOARP
)
454 if (m
->m_len
< sizeof(struct arphdr
))
456 ar
= mtod(m
, struct arphdr
*);
457 if (ntohs(ar
->ar_hrd
) != ssc
->ss_arp
.hrd
)
459 if (m
->m_len
< sizeof(struct arphdr
) + 2 * ar
->ar_hln
+ 2 * ar
->ar_pln
)
461 if (ar
->ar_hln
!= ssc
->ss_if
.if_addrlen
)
464 #ifdef paranoid_arp_mode
466 if (bcmp(srcaddr
, (UBYTE
*)ar
+ sizeof(*ar
), ar
->ar_hln
)) {
467 __log(LOG_ERR
, "An ARP packet sent as %s",
468 sana_sprintf(srcaddr
, ar
->ar_hln
));
469 __log(LOG_ERR
, " from address: %s!!\n",
470 sana_sprintf((UBYTE
*)ar
+ sizeof(*ar
), ar
->ar_hln
));
474 pfil_run_hooks(m
, &ssc
->ss_if
, MIAMIPFBPT_ARP
);
475 proto
= ntohs(ar
->ar_pro
);
477 if (proto
== ssc
->ss_ip
.type
) {
487 * ARP for Internet protocols on SANA-II interfaces.
488 * Algorithm is that given in RFC 826.
491 in_arpinput(register struct sana_softc
*ssc
,
494 register struct s2_arppkt
*s2a
;
495 struct sockaddr_in sin
;
496 struct in_addr isaddr
, itaddr
, myaddr
;
501 caddr_t sha
, spa
, tha
, tpa
;
502 size_t len
= ssc
->ss_if
.if_addrlen
;
504 s2a
= mtod(m
, struct s2_arppkt
*);
505 op
= ntohs(s2a
->arp_op
);
507 if (s2a
->arp_pln
!= sizeof(struct in_addr
))
510 sha
= (caddr_t
)&(s2a
->arpdata
); /* other members must be calculated */
511 bcopy(spa
= sha
+ len
, (caddr_t
)&isaddr
, sizeof (isaddr
));
512 tha
= spa
+ sizeof(struct in_addr
);
513 bcopy(tpa
= tha
+ len
, (caddr_t
)&itaddr
, sizeof (itaddr
));
517 register struct in_ifaddr
*ia
;
518 struct in_ifaddr
*maybe_ia
= 0;
520 /* Check for our own ARP packets */
521 for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
522 if (ia
->ia_ifp
== &ssc
->ss_if
) {
524 if ((itaddr
.s_addr
== ia
->ia_addr
.sin_addr
.s_addr
) ||
525 (isaddr
.s_addr
== ia
->ia_addr
.sin_addr
.s_addr
))
530 myaddr
= ia
? ia
->ia_addr
.sin_addr
: maybe_ia
->ia_addr
.sin_addr
;
531 if (!bcmp(sha
, (caddr_t
)ssc
->ss_hwaddr
, len
))
532 goto out
; /* it's from me, ignore it. */
535 if (!bcmp(sha
, (caddr_t
)etherbroadcastaddr
, ac
->ac_if
.if_addrlen
)) {
537 "arp: ether address is broadcast for IP address %lx!\n",
538 ntohl(isaddr
.s_addr
));
543 /* Check for duplicate IP addresses */
544 if (isaddr
.s_addr
== myaddr
.s_addr
) {
546 "duplicate IP address %lx!! sent from hardware address: %s\n",
547 ntohl(isaddr
.s_addr
),
548 sana_sprintf(sha
, len
));
550 if (op
== ARPOP_REQUEST
)
556 struct arptable
*atb
;
557 register struct arptab
*at
= NULL
; /* same as "merge" flag */
559 /* Try to locate ARP table */
560 if (!(atb
= ssc
->ss_arp
.table
)) {
565 at
= arptab_look(atb
, isaddr
.s_addr
);
568 bcopy(sha
, (caddr_t
)at
->at_hwaddr
, len
);
570 if ((at
->at_flags
& ATF_COM
) == 0)
573 at
->at_flags
|= ATF_COM
;
575 sin
.sin_family
= AF_INET
;
576 sin
.sin_addr
= isaddr
;
577 (*ssc
->ss_if
.if_output
)(&ssc
->ss_if
, at
->at_hold
,
578 (struct sockaddr
*)&sin
, (struct rtentry
*)0);
582 if (at
== 0 && itaddr
.s_addr
== myaddr
.s_addr
) {
583 /* ensure we have a table entry */
584 if (at
= arptnew(isaddr
.s_addr
, atb
, FALSE
)) {
585 bcopy(sha
, (caddr_t
)at
->at_hwaddr
, len
);
589 at
->at_flags
|= ATF_COM
;
597 * Reply if this is an IP request
599 if (op
!= ARPOP_REQUEST
)
602 if (itaddr
.s_addr
== myaddr
.s_addr
) {
603 /* I am the target */
604 bcopy(sha
, tha
, len
);
605 bcopy((caddr_t
)ssc
->ss_hwaddr
, sha
, len
);
607 /* Answer if we have a public entry */
608 register struct arptab
*at
;
610 /* Try to locate ARP table */
611 if (!ssc
->ss_arp
.table
)
614 ARPTAB_LOCK(ssc
->ss_arp
.table
);
615 at
= arptab_look(ssc
->ss_arp
.table
, itaddr
.s_addr
);
616 if (at
&& (at
->at_flags
& ATF_PUBL
)) {
617 bcopy(sha
, tha
, len
);
618 bcopy(at
->at_hwaddr
, sha
, len
);
622 ARPTAB_UNLOCK(ssc
->ss_arp
.table
);
627 struct sockaddr_sana2 ss2
;
628 bcopy(spa
, tpa
, sizeof(struct in_addr
));
629 bcopy((caddr_t
)&itaddr
, spa
, sizeof(struct in_addr
));
630 s2a
->arp_op
= htons(ARPOP_REPLY
);
632 ss2
.ss2_len
= sizeof(ss2
);
633 ss2
.ss2_family
= AF_UNSPEC
;
634 ss2
.ss2_type
= ssc
->ss_arp
.type
;
635 bcopy(tha
, ss2
.ss2_host
, len
);
637 m
->m_flags
&= ~(M_BCAST
|M_MCAST
);
639 pfil_run_hooks(m
, &ssc
->ss_if
, MIAMIPFBPT_ARP
);
640 (*ssc
->ss_if
.if_output
)(&ssc
->ss_if
, m
, (struct sockaddr
*)&ss2
,
641 (struct rtentry
*)0);
654 register struct arpreq
*ar
= (struct arpreq
*)data
;
655 register struct arptab
*at
;
656 register struct sockaddr_in
*sin
;
657 struct arptable
*atb
;
659 struct sana_softc
*ssc
;
662 sin
= (struct sockaddr_in
*)&ar
->arp_pa
;
663 sin
->sin_len
= sizeof(ar
->arp_pa
);
665 if (ar
->arp_pa
.sa_family
!= AF_INET
||
666 ar
->arp_ha
.sa_family
!= AF_UNSPEC
)
667 return (EAFNOSUPPORT
);
670 if ((ifa
= ifa_ifwithnet(&ar
->arp_pa
)) == NULL
) {
672 return (ENETUNREACH
);
675 ssc
= (struct sana_softc
*)ifa
->ifa_ifp
;
678 /*if (ssc->ss_if.if_type != IFT_SANA || !(atb = ssc->ss_arp.table)) {*/
679 if (ssc
->ss_if
.if_output
!= sana_output
|| !(atb
= ssc
->ss_arp
.table
)) {
680 return (EAFNOSUPPORT
);
685 if (cmd
!= SIOCGARPT
) {
686 at
= arptab_look(atb
, sin
->sin_addr
.s_addr
);
687 if (at
== NULL
&& cmd
!= SIOCSARP
) {
695 case SIOCSARP
: /* set entry */
696 if (ar
->arp_ha
.sa_len
> sizeof(at
->at_hwaddr
) + 2 ||
697 ar
->arp_ha
.sa_len
!= ssc
->ss_if
.if_addrlen
+ 2) {
702 * Free if new entry should be allocated in a different way
704 if (at
!= NULL
&& (at
->at_flags
^ ar
->arp_flags
) & ATF_PERM
) {
709 at
= arptnew(sin
->sin_addr
.s_addr
, atb
, ar
->arp_flags
& ATF_PERM
);
712 return (EADDRNOTAVAIL
);
716 bcopy((caddr_t
)ar
->arp_ha
.sa_data
, (caddr_t
)at
->at_hwaddr
,
717 ar
->arp_ha
.sa_len
- 2);
718 at
->at_flags
= ATF_COM
| ATF_INUSE
|
719 (ar
->arp_flags
& (ATF_PERM
|ATF_PUBL
));
723 case SIOCDARP
: /* delete entry */
727 case SIOCGARP
: /* get entry */
728 bcopy((caddr_t
)at
->at_hwaddr
, (caddr_t
)ar
->arp_ha
.sa_data
,
729 ar
->arp_ha
.sa_len
= ssc
->ss_if
.if_addrlen
+ 2);
730 ar
->arp_flags
= at
->at_flags
;
733 case SIOCGARPT
: /* get table */
736 register struct arptabreq
*atr
= (struct arptabreq
*)data
;
738 siz
= ar
? atr
->atr_size
: 0;
740 for (n
= i
= 0; i
< ARPTAB_HSIZE
; i
++) {
741 for (at
= (struct arptab
*)atb
->atb_entries
[i
].mlh_Head
;
746 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&ar
->arp_pa
;
747 sin
->sin_len
= sizeof(*sin
);
748 sin
->sin_family
= AF_INET
;
749 sin
->sin_addr
= at
->at_iaddr
;
750 bcopy((caddr_t
)at
->at_hwaddr
, (caddr_t
)ar
->arp_ha
.sa_data
,
751 ar
->arp_ha
.sa_len
= ssc
->ss_if
.if_addrlen
+ 2);
752 ar
->arp_flags
= at
->at_flags
;
758 atr
->atr_size
-= siz
;
767 static const char *digits
= "0123456789ABCDEF";
769 * Print Hardware Address
771 static char *sana_sprintf(register u_char
*ap
, int len
)
774 static char addrbuf
[17*3];
775 register unsigned char *cp
= addrbuf
;
777 for (i
= 0; i
< len
; ) {
778 *cp
++ = digits
[*ap
>> 4];
779 *cp
++ = digits
[*ap
++ & 0xf];