4 Copyright 1995 Philip Homburg
20 #define ARP_CACHE_NR 256
23 #define ARP_HASH_NR 256
24 #define ARP_HASH_MASK 0xff
25 #define ARP_HASH_WIDTH 4
27 #define MAX_ARP_RETRIES 5
28 #define ARP_TIMEOUT (HZ/2+1) /* .5 seconds */
30 #define ARP_EXP_TIME (20L*60L*HZ) /* 20 minutes */
32 #define ARP_NOTRCH_EXP_TIME (30*HZ) /* 30 seconds */
33 #define ARP_INUSE_OFFSET (60*HZ) /* an entry in the cache can be deleted
34 if its not used for 1 minute */
38 ether_addr_t a46_dstaddr
;
39 ether_addr_t a46_srcaddr
;
40 ether_type_t a46_ethtype
;
53 char a46_dummy
[ETH_MIN_PACK_SIZE
-ETH_HDR_SIZE
];
57 #define a46_hdr a46_data.a46_data.a_hdr
58 #define a46_pro a46_data.a46_data.a_pro
59 #define a46_hln a46_data.a46_data.a_hln
60 #define a46_pln a46_data.a46_data.a_pln
61 #define a46_op a46_data.a46_data.a_op
62 #define a46_sha a46_data.a46_data.a_sha
63 #define a46_spa a46_data.a46_data.a_spa
64 #define a46_tha a46_data.a46_data.a_tha
65 #define a46_tpa a46_data.a46_data.a_tpa
67 typedef struct arp_port
75 ether_addr_t ap_ethaddr
; /* Ethernet address of this port */
76 ipaddr_t ap_ipaddr
; /* IP address of this port */
85 arp_func_t ap_arp_func
;
93 #define APF_EMPTY 0x00
94 #define APF_ARP_RD_IP 0x01
95 #define APF_ARP_RD_SP 0x02
96 #define APF_ARP_WR_IP 0x04
97 #define APF_ARP_WR_SP 0x08
98 #define APF_INADDR_SET 0x10
99 #define APF_SUSPEND 0x20
101 #define APS_INITIAL 1
102 #define APS_GETADDR 2
103 #define APS_ARPSTART 3
104 #define APS_ARPPROTO 4
105 #define APS_ARPMAIN 5
108 typedef struct arp_cache
112 ether_addr_t ac_ethaddr
;
124 #define ACS_INCOMPLETE 1
126 #define ACS_UNREACHABLE 3
128 static struct arp_hash_ent
130 arp_cache_t
*ahe_row
[ARP_HASH_WIDTH
];
131 } arp_hash
[ARP_HASH_NR
];
133 static arp_port_t
*arp_port_table
;
134 static arp_cache_t
*arp_cache
;
135 static int arp_cache_nr
;
137 static acc_t
*arp_getdata
ARGS(( int fd
, size_t offset
,
138 size_t count
, int for_ioctl
));
139 static int arp_putdata
ARGS(( int fd
, size_t offset
,
140 acc_t
*data
, int for_ioctl
));
141 static void arp_main
ARGS(( arp_port_t
*arp_port
));
142 static void arp_timeout
ARGS(( int ref
, timer_t
*timer
));
143 static void setup_write
ARGS(( arp_port_t
*arp_port
));
144 static void setup_read
ARGS(( arp_port_t
*arp_port
));
145 static void do_reclist
ARGS(( event_t
*ev
, ev_arg_t ev_arg
));
146 static void process_arp_pkt
ARGS(( arp_port_t
*arp_port
, acc_t
*data
));
147 static void client_reply
ARGS(( arp_port_t
*arp_port
,
148 ipaddr_t ipaddr
, ether_addr_t
*ethaddr
));
149 static arp_cache_t
*find_cache_ent
ARGS(( arp_port_t
*arp_port
,
151 static arp_cache_t
*alloc_cache_ent
ARGS(( int flags
));
152 static void arp_buffree
ARGS(( int priority
));
153 #ifdef BUF_CONSISTENCY_CHECK
154 static void arp_bufcheck
ARGS(( void ));
159 arp_port_table
= alloc(eth_conf_nr
* sizeof(arp_port_table
[0]));
161 arp_cache_nr
= ARP_CACHE_NR
;
162 if (arp_cache_nr
< (eth_conf_nr
+1)*AP_REQ_NR
)
164 arp_cache_nr
= (eth_conf_nr
+1)*AP_REQ_NR
;
165 printf("arp: using %d cache entries instead of %d\n",
166 arp_cache_nr
, ARP_CACHE_NR
);
168 arp_cache
= alloc(arp_cache_nr
* sizeof(arp_cache
[0]));
173 arp_port_t
*arp_port
;
177 assert (BUF_S
>= sizeof(struct nwio_ethstat
));
178 assert (BUF_S
>= sizeof(struct nwio_ethopt
));
179 assert (BUF_S
>= sizeof(arp46_t
));
181 for (i
=0, arp_port
= arp_port_table
; i
<eth_conf_nr
; i
++, arp_port
++)
183 arp_port
->ap_state
= APS_ERROR
; /* Mark all ports as
188 for (i
=0; i
<arp_cache_nr
; i
++, cache
++)
190 cache
->ac_state
= ACS_UNUSED
;
191 cache
->ac_flags
= ACF_EMPTY
;
193 cache
->ac_lastuse
= 0;
196 #ifndef BUF_CONSISTENCY_CHECK
197 bf_logon(arp_buffree
);
199 bf_logon(arp_buffree
, arp_bufcheck
);
203 static void arp_main(arp_port
)
204 arp_port_t
*arp_port
;
208 switch (arp_port
->ap_state
)
211 arp_port
->ap_eth_fd
= eth_open(arp_port
->ap_eth_port
,
212 arp_port
->ap_eth_port
, arp_getdata
, arp_putdata
,
213 0 /* no put_pkt */, 0 /* no select_res */);
215 if (arp_port
->ap_eth_fd
<0)
217 DBLOCK(1, printf("arp[%d]: unable to open eth[%d]\n",
218 arp_port
-arp_port_table
,
219 arp_port
->ap_eth_port
));
223 arp_port
->ap_state
= APS_GETADDR
;
225 result
= eth_ioctl (arp_port
->ap_eth_fd
, NWIOGETHSTAT
);
227 if ( result
== NW_SUSPEND
)
229 arp_port
->ap_flags
|= APF_SUSPEND
;
232 assert(result
== NW_OK
);
236 /* Wait for IP address */
237 if (!(arp_port
->ap_flags
& APF_INADDR_SET
))
242 arp_port
->ap_state
= APS_ARPPROTO
;
244 result
= eth_ioctl (arp_port
->ap_eth_fd
, NWIOSETHOPT
);
246 if (result
==NW_SUSPEND
)
248 arp_port
->ap_flags
|= APF_SUSPEND
;
251 assert(result
== NW_OK
);
255 arp_port
->ap_state
= APS_ARPMAIN
;
256 setup_write(arp_port
);
257 setup_read(arp_port
);
262 "arp_main(&arp_port_table[%d]) called but ap_state=0x%x\n",
263 arp_port
->ap_eth_port
, arp_port
->ap_state
));
267 static acc_t
*arp_getdata (fd
, offset
, count
, for_ioctl
)
273 arp_port_t
*arp_port
;
277 arp_port
= &arp_port_table
[fd
];
279 switch (arp_port
->ap_state
)
287 arp_port
->ap_state
= APS_ERROR
;
290 if (arp_port
->ap_flags
& APF_SUSPEND
)
292 arp_port
->ap_flags
&= ~APF_SUSPEND
;
297 assert ((!offset
) && (count
== sizeof(struct nwio_ethopt
)));
299 struct nwio_ethopt
*ethopt
;
302 acc
= bf_memreq(sizeof(*ethopt
));
303 ethopt
= (struct nwio_ethopt
*)ptr2acc_data(acc
);
304 ethopt
->nweo_flags
= NWEO_COPY
|NWEO_EN_BROAD
|
306 ethopt
->nweo_type
= HTONS(ETH_ARP_PROTO
);
310 assert (arp_port
->ap_flags
& APF_ARP_WR_IP
);
313 data
= arp_port
->ap_sendpkt
;
314 arp_port
->ap_sendpkt
= NULL
;
316 bf_afree(data
); data
= NULL
;
321 DIFBLOCK(1, (result
!= NW_SUSPEND
),
323 "arp[%d]: write error on port %d: error %d\n",
324 fd
, arp_port
->ap_eth_fd
, result
));
326 arp_port
->ap_state
= APS_ERROR
;
329 arp_port
->ap_flags
&= ~APF_ARP_WR_IP
;
330 if (arp_port
->ap_flags
& APF_ARP_WR_SP
)
331 setup_write(arp_port
);
334 assert (offset
+count
<= sizeof(arp46_t
));
335 data
= arp_port
->ap_sendpkt
;
337 data
= bf_cut(data
, offset
, count
);
341 printf("arp_getdata(%d, 0x%d, 0x%d) called but ap_state=0x%x\n",
342 fd
, offset
, count
, arp_port
->ap_state
);
348 static int arp_putdata (fd
, offset
, data
, for_ioctl
)
354 arp_port_t
*arp_port
;
356 struct nwio_ethstat
*ethstat
;
360 arp_port
= &arp_port_table
[fd
];
362 if (arp_port
->ap_flags
& APF_ARP_RD_IP
)
369 DIFBLOCK(1, (result
!= NW_SUSPEND
), printf(
370 "arp[%d]: read error on port %d: error %d\n",
371 fd
, arp_port
->ap_eth_fd
, result
));
375 if (arp_port
->ap_flags
& APF_ARP_RD_SP
)
377 arp_port
->ap_flags
&= ~(APF_ARP_RD_IP
|
379 setup_read(arp_port
);
382 arp_port
->ap_flags
&= ~(APF_ARP_RD_IP
|
387 /* Warning: the above assertion is illegal; puts and gets of
388 data can be brokenup in any piece the server likes. However
389 we assume that the server is eth.c and it transfers only
392 data
= bf_packIffLess(data
, sizeof(arp46_t
));
393 if (data
->acc_length
>= sizeof(arp46_t
))
395 if (!arp_port
->ap_reclist
)
397 ev_arg
.ev_ptr
= arp_port
;
398 ev_enqueue(&arp_port
->ap_event
, do_reclist
,
401 if (data
->acc_linkC
!= 1)
403 tmpacc
= bf_dupacc(data
);
408 data
->acc_ext_link
= arp_port
->ap_reclist
;
409 arp_port
->ap_reclist
= data
;
415 switch (arp_port
->ap_state
)
423 arp_port
->ap_state
= APS_ERROR
;
426 if (arp_port
->ap_flags
& APF_SUSPEND
)
428 arp_port
->ap_flags
&= ~APF_SUSPEND
;
433 compare (bf_bufsize(data
), ==, sizeof(*ethstat
));
434 data
= bf_packIffLess(data
, sizeof(*ethstat
));
435 compare (data
->acc_length
, ==, sizeof(*ethstat
));
436 ethstat
= (struct nwio_ethstat
*)ptr2acc_data(data
);
437 arp_port
->ap_ethaddr
= ethstat
->nwes_addr
;
441 printf("arp_putdata(%d, 0x%d, 0x%lx) called but ap_state=0x%x\n",
442 fd
, offset
, (unsigned long)data
, arp_port
->ap_state
);
448 static void setup_read(arp_port
)
449 arp_port_t
*arp_port
;
453 while (!(arp_port
->ap_flags
& APF_ARP_RD_IP
))
455 arp_port
->ap_flags
|= APF_ARP_RD_IP
;
456 result
= eth_read (arp_port
->ap_eth_fd
, ETH_MAX_PACK_SIZE
);
457 if (result
== NW_SUSPEND
)
459 arp_port
->ap_flags
|= APF_ARP_RD_SP
;
462 DIFBLOCK(1, (result
!= NW_OK
),
463 printf("arp[%d]: eth_read(..,%d)=%d\n",
464 arp_port
-arp_port_table
, ETH_MAX_PACK_SIZE
, result
));
468 static void setup_write(arp_port
)
469 arp_port_t
*arp_port
;
476 data
= arp_port
->ap_sendlist
;
479 arp_port
->ap_sendlist
= data
->acc_ext_link
;
481 if (arp_port
->ap_ipaddr
== HTONL(0x00000000))
483 /* Interface is down */
485 "arp[%d]: not sending ARP packet, interface is down\n",
486 arp_port
-arp_port_table
);
487 bf_afree(data
); data
= NULL
;
491 assert(!arp_port
->ap_sendpkt
);
492 arp_port
->ap_sendpkt
= data
; data
= NULL
;
494 arp_port
->ap_flags
= (arp_port
->ap_flags
& ~APF_ARP_WR_SP
) |
496 result
= eth_write(arp_port
->ap_eth_fd
, sizeof(arp46_t
));
497 if (result
== NW_SUSPEND
)
499 arp_port
->ap_flags
|= APF_ARP_WR_SP
;
504 DIFBLOCK(1, (result
!= NW_SUSPEND
),
505 printf("arp[%d]: eth_write(..,%d)=%d\n",
506 arp_port
-arp_port_table
, sizeof(arp46_t
),
513 static void do_reclist(ev
, ev_arg
)
517 arp_port_t
*arp_port
;
520 arp_port
= ev_arg
.ev_ptr
;
521 assert(ev
== &arp_port
->ap_event
);
523 while (data
= arp_port
->ap_reclist
, data
!= NULL
)
525 arp_port
->ap_reclist
= data
->acc_ext_link
;
526 process_arp_pkt(arp_port
, data
);
531 static void process_arp_pkt (arp_port
, data
)
532 arp_port_t
*arp_port
;
535 int i
, entry
, do_reply
;
538 arp_cache_t
*ce
, *cache
;
539 struct arp_req
*reqp
;
543 curr_time
= get_time();
545 arp
= (arp46_t
*)ptr2acc_data(data
);
546 memcpy(&spa
, arp
->a46_spa
, sizeof(ipaddr_t
));
547 memcpy(&tpa
, arp
->a46_tpa
, sizeof(ipaddr_t
));
549 if (arp
->a46_hdr
!= HTONS(ARP_ETHERNET
) ||
551 arp
->a46_pro
!= HTONS(ETH_IP_PROTO
) ||
554 if (arp_port
->ap_ipaddr
== HTONL(0x00000000))
556 /* Interface is down */
558 printf("arp[%d]: dropping ARP packet, interface is down\n",
559 arp_port
-arp_port_table
);
564 ce
= find_cache_ent(arp_port
, spa
);
565 cache
= NULL
; /* lint */
568 if (arp
->a46_op
!= HTONS(ARP_REQUEST
))
569 ; /* No need to reply */
570 else if (tpa
== arp_port
->ap_ipaddr
)
574 /* Look for a published entry */
575 cache
= find_cache_ent(arp_port
, tpa
);
578 if (cache
->ac_flags
& ACF_PUB
)
580 /* Published entry */
596 DBLOCK(0x10, printf("arp[%d]: allocating entry for ",
597 arp_port
-arp_port_table
);
598 writeIpAddr(spa
); printf("\n"));
600 ce
= alloc_cache_ent(ACF_EMPTY
);
601 ce
->ac_flags
= ACF_EMPTY
;
602 ce
->ac_state
= ACS_VALID
;
603 ce
->ac_ethaddr
= arp
->a46_sha
;
605 ce
->ac_port
= arp_port
;
606 ce
->ac_expire
= curr_time
+ARP_EXP_TIME
;
607 ce
->ac_lastuse
= curr_time
-ARP_INUSE_OFFSET
; /* never used */
610 if (ce
->ac_state
== ACS_INCOMPLETE
|| ce
->ac_state
== ACS_UNREACHABLE
)
612 ce
->ac_ethaddr
= arp
->a46_sha
;
613 if (ce
->ac_state
== ACS_INCOMPLETE
)
615 /* Find request entry */
617 for (i
= 0, reqp
= arp_port
->ap_req
; i
<AP_REQ_NR
;
620 if (reqp
->ar_entry
== entry
)
623 assert(i
< AP_REQ_NR
);
624 clck_untimer(&reqp
->ar_timer
);
627 ce
->ac_state
= ACS_VALID
;
628 client_reply(arp_port
, spa
, &arp
->a46_sha
);
631 ce
->ac_state
= ACS_VALID
;
634 /* Update fields in the arp cache. */
635 if (memcmp(&ce
->ac_ethaddr
, &arp
->a46_sha
,
636 sizeof(ce
->ac_ethaddr
)) != 0)
638 printf("arp[%d]: ethernet address for IP address ",
639 arp_port
-arp_port_table
);
641 printf(" changed from ");
642 writeEtherAddr(&ce
->ac_ethaddr
);
644 writeEtherAddr(&arp
->a46_sha
);
646 ce
->ac_ethaddr
= arp
->a46_sha
;
648 ce
->ac_expire
= curr_time
+ARP_EXP_TIME
;
652 data
= bf_memreq(sizeof(arp46_t
));
653 arp
= (arp46_t
*)ptr2acc_data(data
);
656 assert(sizeof(arp
->a46_data
.a46_dummy
) % sizeof(*p
) == 0);
657 for (i
= 0, p
= (u16_t
*)arp
->a46_data
.a46_dummy
;
658 i
< sizeof(arp
->a46_data
.a46_dummy
)/sizeof(*p
);
664 arp
->a46_dstaddr
= ce
->ac_ethaddr
;
665 arp
->a46_hdr
= HTONS(ARP_ETHERNET
);
666 arp
->a46_pro
= HTONS(ETH_IP_PROTO
);
670 arp
->a46_op
= htons(ARP_REPLY
);
671 if (tpa
== arp_port
->ap_ipaddr
)
673 arp
->a46_sha
= arp_port
->ap_ethaddr
;
678 arp
->a46_sha
= cache
->ac_ethaddr
;
680 memcpy (arp
->a46_spa
, &tpa
, sizeof(ipaddr_t
));
681 arp
->a46_tha
= ce
->ac_ethaddr
;
682 memcpy (arp
->a46_tpa
, &ce
->ac_ipaddr
, sizeof(ipaddr_t
));
684 assert(data
->acc_linkC
== 1);
685 data
->acc_ext_link
= arp_port
->ap_sendlist
;
686 arp_port
->ap_sendlist
= data
; data
= NULL
;
688 if (!(arp_port
->ap_flags
& APF_ARP_WR_IP
))
689 setup_write(arp_port
);
693 static void client_reply (arp_port
, ipaddr
, ethaddr
)
694 arp_port_t
*arp_port
;
696 ether_addr_t
*ethaddr
;
698 (*arp_port
->ap_arp_func
)(arp_port
->ap_ip_port
, ipaddr
, ethaddr
);
701 static arp_cache_t
*find_cache_ent (arp_port
, ipaddr
)
702 arp_port_t
*arp_port
;
709 hash
= (ipaddr
>> 24) ^ (ipaddr
>> 16) ^ (ipaddr
>> 8) ^ ipaddr
;
710 hash
&= ARP_HASH_MASK
;
712 ce
= arp_hash
[hash
].ahe_row
[0];
713 if (ce
&& ce
->ac_ipaddr
== ipaddr
&& ce
->ac_port
== arp_port
&&
714 ce
->ac_state
!= ACS_UNUSED
)
718 for (i
= 1; i
<ARP_HASH_WIDTH
; i
++)
720 ce
= arp_hash
[hash
].ahe_row
[i
];
721 if (!ce
|| ce
->ac_ipaddr
!= ipaddr
|| ce
->ac_port
!= arp_port
722 || ce
->ac_state
== ACS_UNUSED
)
726 arp_hash
[hash
].ahe_row
[i
]= arp_hash
[hash
].ahe_row
[0];
727 arp_hash
[hash
].ahe_row
[0]= ce
;
731 for (i
=0, ce
= arp_cache
; i
<arp_cache_nr
; i
++, ce
++)
733 if (ce
->ac_state
!= ACS_UNUSED
&&
734 ce
->ac_port
== arp_port
&&
735 ce
->ac_ipaddr
== ipaddr
)
737 for (i
= ARP_HASH_WIDTH
-1; i
>0; i
--)
739 arp_hash
[hash
].ahe_row
[i
]=
740 arp_hash
[hash
].ahe_row
[i
-1];
743 arp_hash
[hash
].ahe_row
[0]= ce
;
750 static arp_cache_t
*alloc_cache_ent(flags
)
753 arp_cache_t
*cache
, *old
;
757 for (i
=0, cache
= arp_cache
; i
<arp_cache_nr
; i
++, cache
++)
759 if (cache
->ac_state
== ACS_UNUSED
)
764 if (cache
->ac_state
== ACS_INCOMPLETE
)
766 if (cache
->ac_flags
& ACF_PERM
)
768 if (!old
|| cache
->ac_lastuse
< old
->ac_lastuse
)
776 /* Get next permanent entry */
777 for (i
=0, cache
= arp_cache
; i
<arp_cache_nr
; i
++, cache
++)
779 if (cache
->ac_state
== ACS_UNUSED
)
781 if (cache
->ac_flags
& ACF_PERM
)
785 if (i
>= arp_cache_nr
/2)
786 return NULL
; /* Too many entries */
794 if (!(flags
& ACF_PUB
))
797 /* Get first nonpublished entry */
798 for (i
=0, cache
= arp_cache
; i
<arp_cache_nr
; i
++, cache
++)
800 if (cache
->ac_state
== ACS_UNUSED
)
802 if (cache
->ac_flags
& ACF_PUB
)
815 void arp_set_ipaddr (eth_port
, ipaddr
)
819 arp_port_t
*arp_port
;
821 if (eth_port
< 0 || eth_port
>= eth_conf_nr
)
823 arp_port
= &arp_port_table
[eth_port
];
825 arp_port
->ap_ipaddr
= ipaddr
;
826 arp_port
->ap_flags
|= APF_INADDR_SET
;
827 arp_port
->ap_flags
&= ~APF_SUSPEND
;
828 if (arp_port
->ap_state
== APS_GETADDR
)
832 int arp_set_cb(eth_port
, ip_port
, arp_func
)
838 arp_port_t
*arp_port
;
840 assert(eth_port
>= 0);
841 if (eth_port
>= eth_conf_nr
)
844 arp_port
= &arp_port_table
[eth_port
];
845 arp_port
->ap_eth_port
= eth_port
;
846 arp_port
->ap_ip_port
= ip_port
;
847 arp_port
->ap_state
= APS_INITIAL
;
848 arp_port
->ap_flags
= APF_EMPTY
;
849 arp_port
->ap_arp_func
= arp_func
;
850 arp_port
->ap_sendpkt
= NULL
;
851 arp_port
->ap_sendlist
= NULL
;
852 arp_port
->ap_reclist
= NULL
;
853 for (i
= 0; i
<AP_REQ_NR
; i
++) {
854 arp_port
->ap_req
[i
].ar_entry
= -1;
855 arp_port
->ap_req
[i
].ar_timer
.tim_active
= 0;
858 ev_init(&arp_port
->ap_event
);
865 int arp_ip_eth (eth_port
, ipaddr
, ethaddr
)
868 ether_addr_t
*ethaddr
;
871 arp_port_t
*arp_port
;
872 struct arp_req
*reqp
;
876 assert(eth_port
>= 0 && eth_port
< eth_conf_nr
);
877 arp_port
= &arp_port_table
[eth_port
];
878 assert(arp_port
->ap_state
== APS_ARPMAIN
||
879 (printf("arp[%d]: ap_state= %d\n", arp_port
-arp_port_table
,
880 arp_port
->ap_state
), 0));
882 curr_time
= get_time();
884 ce
= find_cache_ent (arp_port
, ipaddr
);
885 if (ce
&& ce
->ac_expire
< curr_time
)
887 assert(ce
->ac_state
!= ACS_INCOMPLETE
);
889 /* Check whether there is enough space for an ARP
892 for (i
= 0, reqp
= arp_port
->ap_req
; i
<AP_REQ_NR
; i
++, reqp
++)
894 if (reqp
->ar_entry
< 0)
899 /* Okay, expire this entry. */
900 ce
->ac_state
= ACS_UNUSED
;
905 /* Continue using this entry for a while */
906 printf("arp[%d]: Overloaded! Keeping entry for ",
907 arp_port
-arp_port_table
);
910 ce
->ac_expire
= curr_time
+ARP_NOTRCH_EXP_TIME
;
915 /* Found an entry. This entry should be valid, unreachable
918 ce
->ac_lastuse
= curr_time
;
919 if (ce
->ac_state
== ACS_VALID
)
921 *ethaddr
= ce
->ac_ethaddr
;
924 if (ce
->ac_state
== ACS_UNREACHABLE
)
926 assert(ce
->ac_state
== ACS_INCOMPLETE
);
931 /* Find an empty slot for an ARP request */
932 for (i
= 0, reqp
= arp_port
->ap_req
; i
<AP_REQ_NR
; i
++, reqp
++)
934 if (reqp
->ar_entry
< 0)
939 /* We should be able to report that this ARP request
940 * cannot be accepted. At the moment we just return SUSPEND.
944 ref
= (eth_port
*AP_REQ_NR
+ i
);
946 ce
= alloc_cache_ent(ACF_EMPTY
);
948 ce
->ac_state
= ACS_INCOMPLETE
;
949 ce
->ac_ipaddr
= ipaddr
;
950 ce
->ac_port
= arp_port
;
951 ce
->ac_expire
= curr_time
+ARP_EXP_TIME
;
952 ce
->ac_lastuse
= curr_time
;
954 reqp
->ar_entry
= ce
-arp_cache
;
955 reqp
->ar_req_count
= -1;
957 /* Send the first packet by expiring the timer */
958 clck_timer(&reqp
->ar_timer
, 1, arp_timeout
, ref
);
963 int arp_ioctl (eth_port
, fd
, req
, get_userdata
, put_userdata
)
967 get_userdata_t get_userdata
;
968 put_userdata_t put_userdata
;
970 arp_port_t
*arp_port
;
971 arp_cache_t
*ce
, *cache
;
974 int entno
, result
, ac_flags
;
979 assert(eth_port
>= 0 && eth_port
< eth_conf_nr
);
980 arp_port
= &arp_port_table
[eth_port
];
981 assert(arp_port
->ap_state
== APS_ARPMAIN
||
982 (printf("arp[%d]: ap_state= %d\n", arp_port
-arp_port_table
,
983 arp_port
->ap_state
), 0));
988 data
= (*get_userdata
)(fd
, 0, sizeof(*arp_iop
), TRUE
);
991 data
= bf_packIffLess(data
, sizeof(*arp_iop
));
992 arp_iop
= (nwio_arp_t
*)ptr2acc_data(data
);
993 ipaddr
= arp_iop
->nwa_ipaddr
;
995 for (entno
= 0; entno
< arp_cache_nr
; entno
++)
997 ce
= &arp_cache
[entno
];
998 if (ce
->ac_state
== ACS_UNUSED
||
999 ce
->ac_port
!= arp_port
)
1003 if (ce
->ac_ipaddr
== ipaddr
)
1006 if (entno
== arp_cache_nr
)
1008 /* Also report the address of this interface */
1009 if (ipaddr
!= arp_port
->ap_ipaddr
)
1014 arp_iop
->nwa_entno
= arp_cache_nr
;
1015 arp_iop
->nwa_ipaddr
= ipaddr
;
1016 arp_iop
->nwa_ethaddr
= arp_port
->ap_ethaddr
;
1017 arp_iop
->nwa_flags
= NWAF_PERM
| NWAF_PUB
;
1021 arp_iop
->nwa_entno
= entno
+1;
1022 arp_iop
->nwa_ipaddr
= ce
->ac_ipaddr
;
1023 arp_iop
->nwa_ethaddr
= ce
->ac_ethaddr
;
1024 arp_iop
->nwa_flags
= 0;
1025 if (ce
->ac_state
== ACS_INCOMPLETE
)
1026 arp_iop
->nwa_flags
|= NWAF_INCOMPLETE
;
1027 if (ce
->ac_state
== ACS_UNREACHABLE
)
1028 arp_iop
->nwa_flags
|= NWAF_DEAD
;
1029 if (ce
->ac_flags
& ACF_PERM
)
1030 arp_iop
->nwa_flags
|= NWAF_PERM
;
1031 if (ce
->ac_flags
& ACF_PUB
)
1032 arp_iop
->nwa_flags
|= NWAF_PUB
;
1035 result
= (*put_userdata
)(fd
, 0, data
, TRUE
);
1039 data
= (*get_userdata
)(fd
, 0, sizeof(*arp_iop
), TRUE
);
1042 data
= bf_packIffLess(data
, sizeof(*arp_iop
));
1043 arp_iop
= (nwio_arp_t
*)ptr2acc_data(data
);
1044 entno
= arp_iop
->nwa_entno
;
1047 ce
= NULL
; /* lint */
1048 for (; entno
< arp_cache_nr
; entno
++)
1050 ce
= &arp_cache
[entno
];
1051 if (ce
->ac_state
== ACS_UNUSED
||
1052 ce
->ac_port
!= arp_port
)
1058 if (entno
== arp_cache_nr
)
1063 arp_iop
->nwa_entno
= entno
+1;
1064 arp_iop
->nwa_ipaddr
= ce
->ac_ipaddr
;
1065 arp_iop
->nwa_ethaddr
= ce
->ac_ethaddr
;
1066 arp_iop
->nwa_flags
= 0;
1067 if (ce
->ac_state
== ACS_INCOMPLETE
)
1068 arp_iop
->nwa_flags
|= NWAF_INCOMPLETE
;
1069 if (ce
->ac_state
== ACS_UNREACHABLE
)
1070 arp_iop
->nwa_flags
|= NWAF_DEAD
;
1071 if (ce
->ac_flags
& ACF_PERM
)
1072 arp_iop
->nwa_flags
|= NWAF_PERM
;
1073 if (ce
->ac_flags
& ACF_PUB
)
1074 arp_iop
->nwa_flags
|= NWAF_PUB
;
1076 result
= (*put_userdata
)(fd
, 0, data
, TRUE
);
1080 data
= (*get_userdata
)(fd
, 0, sizeof(*arp_iop
), TRUE
);
1083 data
= bf_packIffLess(data
, sizeof(*arp_iop
));
1084 arp_iop
= (nwio_arp_t
*)ptr2acc_data(data
);
1085 ipaddr
= arp_iop
->nwa_ipaddr
;
1086 if (find_cache_ent(arp_port
, ipaddr
))
1092 flags
= arp_iop
->nwa_flags
;
1093 ac_flags
= ACF_EMPTY
;
1094 if (flags
& NWAF_PERM
)
1095 ac_flags
|= ACF_PERM
;
1096 if (flags
& NWAF_PUB
)
1097 ac_flags
|= ACF_PUB
|ACF_PERM
;
1099 /* Allocate a cache entry */
1100 ce
= alloc_cache_ent(ac_flags
);
1107 ce
->ac_flags
= ac_flags
;
1108 ce
->ac_state
= ACS_VALID
;
1109 ce
->ac_ethaddr
= arp_iop
->nwa_ethaddr
;
1110 ce
->ac_ipaddr
= arp_iop
->nwa_ipaddr
;
1111 ce
->ac_port
= arp_port
;
1113 curr_time
= get_time();
1114 ce
->ac_expire
= curr_time
+ARP_EXP_TIME
;
1115 ce
->ac_lastuse
= curr_time
;
1121 data
= (*get_userdata
)(fd
, 0, sizeof(*arp_iop
), TRUE
);
1124 data
= bf_packIffLess(data
, sizeof(*arp_iop
));
1125 arp_iop
= (nwio_arp_t
*)ptr2acc_data(data
);
1126 ipaddr
= arp_iop
->nwa_ipaddr
;
1127 bf_afree(data
); data
= NULL
;
1128 ce
= find_cache_ent(arp_port
, ipaddr
);
1131 if (ce
->ac_state
== ACS_INCOMPLETE
)
1134 ac_flags
= ce
->ac_flags
;
1135 if (ac_flags
& ACF_PUB
)
1137 /* Make sure entry is at the end of published
1140 for (entno
= 0, cache
= arp_cache
;
1141 entno
<arp_cache_nr
; entno
++, cache
++)
1143 if (cache
->ac_state
== ACS_UNUSED
)
1145 if (cache
->ac_flags
& ACF_PUB
)
1149 assert(cache
> arp_cache
);
1158 if (ac_flags
& ACF_PERM
)
1160 /* Make sure entry is at the end of permanent
1163 for (entno
= 0, cache
= arp_cache
;
1164 entno
<arp_cache_nr
; entno
++, cache
++)
1166 if (cache
->ac_state
== ACS_UNUSED
)
1168 if (cache
->ac_flags
& ACF_PERM
)
1172 assert(cache
> arp_cache
);
1183 ce
->ac_state
= ACS_UNUSED
;
1188 ip_panic(("arp_ioctl: unknown request 0x%lx",
1189 (unsigned long)req
));
1194 static void arp_timeout (ref
, timer
)
1198 int i
, port
, reqind
, acind
;
1199 arp_port_t
*arp_port
;
1201 struct arp_req
*reqp
;
1207 port
= ref
/ AP_REQ_NR
;
1208 reqind
= ref
% AP_REQ_NR
;
1210 assert(port
>= 0 && port
<eth_conf_nr
);
1211 arp_port
= &arp_port_table
[port
];
1213 reqp
= &arp_port
->ap_req
[reqind
];
1214 assert (timer
== &reqp
->ar_timer
);
1216 acind
= reqp
->ar_entry
;
1218 assert(acind
>= 0 && acind
< arp_cache_nr
);
1219 ce
= &arp_cache
[acind
];
1221 assert(ce
->ac_port
== arp_port
);
1222 assert(ce
->ac_state
== ACS_INCOMPLETE
);
1224 if (++reqp
->ar_req_count
>= MAX_ARP_RETRIES
)
1226 curr_time
= get_time();
1227 ce
->ac_state
= ACS_UNREACHABLE
;
1228 ce
->ac_expire
= curr_time
+ ARP_NOTRCH_EXP_TIME
;
1229 ce
->ac_lastuse
= curr_time
;
1231 clck_untimer(&reqp
->ar_timer
);
1233 client_reply(arp_port
, ce
->ac_ipaddr
, NULL
);
1237 data
= bf_memreq(sizeof(arp46_t
));
1238 arp
= (arp46_t
*)ptr2acc_data(data
);
1241 assert(sizeof(arp
->a46_data
.a46_dummy
) % sizeof(*p
) == 0);
1242 for (i
= 0, p
= (u16_t
*)arp
->a46_data
.a46_dummy
;
1243 i
< sizeof(arp
->a46_data
.a46_dummy
)/sizeof(*p
);
1249 arp
->a46_dstaddr
.ea_addr
[0]= 0xff;
1250 arp
->a46_dstaddr
.ea_addr
[1]= 0xff;
1251 arp
->a46_dstaddr
.ea_addr
[2]= 0xff;
1252 arp
->a46_dstaddr
.ea_addr
[3]= 0xff;
1253 arp
->a46_dstaddr
.ea_addr
[4]= 0xff;
1254 arp
->a46_dstaddr
.ea_addr
[5]= 0xff;
1255 arp
->a46_hdr
= HTONS(ARP_ETHERNET
);
1256 arp
->a46_pro
= HTONS(ETH_IP_PROTO
);
1259 arp
->a46_op
= HTONS(ARP_REQUEST
);
1260 arp
->a46_sha
= arp_port
->ap_ethaddr
;
1261 memcpy (arp
->a46_spa
, &arp_port
->ap_ipaddr
, sizeof(ipaddr_t
));
1262 memset(&arp
->a46_tha
, '\0', sizeof(ether_addr_t
));
1263 memcpy (arp
->a46_tpa
, &ce
->ac_ipaddr
, sizeof(ipaddr_t
));
1265 assert(data
->acc_linkC
== 1);
1266 data
->acc_ext_link
= arp_port
->ap_sendlist
;
1267 arp_port
->ap_sendlist
= data
; data
= NULL
;
1269 if (!(arp_port
->ap_flags
& APF_ARP_WR_IP
))
1270 setup_write(arp_port
);
1272 clck_timer(&reqp
->ar_timer
, get_time() + ARP_TIMEOUT
,
1276 static void arp_buffree(priority
)
1280 acc_t
*pack
, *next_pack
;
1281 arp_port_t
*arp_port
;
1283 for (i
= 0, arp_port
= arp_port_table
; i
<eth_conf_nr
; i
++, arp_port
++)
1285 if (priority
== ARP_PRI_REC
)
1287 next_pack
= arp_port
->ap_reclist
;
1288 while(next_pack
&& next_pack
->acc_ext_link
)
1291 next_pack
= pack
->acc_ext_link
;
1296 if (ev_in_queue(&arp_port
->ap_event
))
1299 "not freeing ap_reclist, ap_event enqueued\n"));
1303 bf_afree(next_pack
);
1307 arp_port
->ap_reclist
= next_pack
;
1309 if (priority
== ARP_PRI_SEND
)
1311 next_pack
= arp_port
->ap_sendlist
;
1312 while(next_pack
&& next_pack
->acc_ext_link
)
1315 next_pack
= pack
->acc_ext_link
;
1320 if (ev_in_queue(&arp_port
->ap_event
))
1323 "not freeing ap_sendlist, ap_event enqueued\n"));
1327 bf_afree(next_pack
);
1331 arp_port
->ap_sendlist
= next_pack
;
1336 #ifdef BUF_CONSISTENCY_CHECK
1337 static void arp_bufcheck()
1340 arp_port_t
*arp_port
;
1343 for (i
= 0, arp_port
= arp_port_table
; i
<eth_conf_nr
; i
++, arp_port
++)
1345 for (pack
= arp_port
->ap_reclist
; pack
;
1346 pack
= pack
->acc_ext_link
)
1350 for (pack
= arp_port
->ap_sendlist
; pack
;
1351 pack
= pack
->acc_ext_link
)
1357 #endif /* BUF_CONSISTENCY_CHECK */
1360 * $PchId: arp.c,v 1.22 2005/06/28 14:15:06 philip Exp $