iso9660fs: initialize buffer cache
[minix.git] / servers / inet / generic / arp.c
blob2b68997ed70bd896c0387e26c9641b6a05c10ce3
1 /*
2 arp.c
4 Copyright 1995 Philip Homburg
5 */
7 #include "inet.h"
8 #include "type.h"
10 #include "arp.h"
11 #include "assert.h"
12 #include "buf.h"
13 #include "clock.h"
14 #include "event.h"
15 #include "eth.h"
16 #include "io.h"
18 THIS_FILE
20 #define ARP_CACHE_NR 256
21 #define AP_REQ_NR 32
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 */
29 #ifndef ARP_EXP_TIME
30 #define ARP_EXP_TIME (20L*60L*HZ) /* 20 minutes */
31 #endif
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 */
36 typedef struct arp46
38 ether_addr_t a46_dstaddr;
39 ether_addr_t a46_srcaddr;
40 ether_type_t a46_ethtype;
41 union
43 struct
45 u16_t a_hdr, a_pro;
46 u8_t a_hln, a_pln;
47 u16_t a_op;
48 ether_addr_t a_sha;
49 u8_t a_spa[4];
50 ether_addr_t a_tha;
51 u8_t a_tpa[4];
52 } a46_data;
53 char a46_dummy[ETH_MIN_PACK_SIZE-ETH_HDR_SIZE];
54 } a46_data;
55 } arp46_t;
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
69 int ap_flags;
70 int ap_state;
71 int ap_eth_port;
72 int ap_ip_port;
73 int ap_eth_fd;
75 ether_addr_t ap_ethaddr; /* Ethernet address of this port */
76 ipaddr_t ap_ipaddr; /* IP address of this port */
78 struct arp_req
80 timer_t ar_timer;
81 int ar_entry;
82 int ar_req_count;
83 } ap_req[AP_REQ_NR];
85 arp_func_t ap_arp_func;
87 acc_t *ap_sendpkt;
88 acc_t *ap_sendlist;
89 acc_t *ap_reclist;
90 event_t ap_event;
91 } arp_port_t;
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
106 #define APS_ERROR 6
108 typedef struct arp_cache
110 int ac_flags;
111 int ac_state;
112 ether_addr_t ac_ethaddr;
113 ipaddr_t ac_ipaddr;
114 arp_port_t *ac_port;
115 time_t ac_expire;
116 time_t ac_lastuse;
117 } arp_cache_t;
119 #define ACF_EMPTY 0
120 #define ACF_PERM 1
121 #define ACF_PUB 2
123 #define ACS_UNUSED 0
124 #define ACS_INCOMPLETE 1
125 #define ACS_VALID 2
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,
150 ipaddr_t ipaddr ));
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 ));
155 #endif
157 void arp_prep()
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]));
171 void arp_init()
173 arp_port_t *arp_port;
174 arp_cache_t *cache;
175 int i;
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
184 * unavailable */
187 cache= arp_cache;
188 for (i=0; i<arp_cache_nr; i++, cache++)
190 cache->ac_state= ACS_UNUSED;
191 cache->ac_flags= ACF_EMPTY;
192 cache->ac_expire= 0;
193 cache->ac_lastuse= 0;
196 #ifndef BUF_CONSISTENCY_CHECK
197 bf_logon(arp_buffree);
198 #else
199 bf_logon(arp_buffree, arp_bufcheck);
200 #endif
203 static void arp_main(arp_port)
204 arp_port_t *arp_port;
206 int result;
208 switch (arp_port->ap_state)
210 case APS_INITIAL:
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));
220 return;
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;
230 return;
232 assert(result == NW_OK);
234 /* fall through */
235 case APS_GETADDR:
236 /* Wait for IP address */
237 if (!(arp_port->ap_flags & APF_INADDR_SET))
238 return;
240 /* fall through */
241 case APS_ARPSTART:
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;
249 return;
251 assert(result == NW_OK);
253 /* fall through */
254 case APS_ARPPROTO:
255 arp_port->ap_state= APS_ARPMAIN;
256 setup_write(arp_port);
257 setup_read(arp_port);
258 return;
260 default:
261 ip_panic((
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)
268 int fd;
269 size_t offset;
270 size_t count;
271 int for_ioctl;
273 arp_port_t *arp_port;
274 acc_t *data;
275 int result;
277 arp_port= &arp_port_table[fd];
279 switch (arp_port->ap_state)
281 case APS_ARPPROTO:
282 if (!count)
284 result= (int)offset;
285 if (result<0)
287 arp_port->ap_state= APS_ERROR;
288 break;
290 if (arp_port->ap_flags & APF_SUSPEND)
292 arp_port->ap_flags &= ~APF_SUSPEND;
293 arp_main(arp_port);
295 return NW_OK;
297 assert ((!offset) && (count == sizeof(struct nwio_ethopt)));
299 struct nwio_ethopt *ethopt;
300 acc_t *acc;
302 acc= bf_memreq(sizeof(*ethopt));
303 ethopt= (struct nwio_ethopt *)ptr2acc_data(acc);
304 ethopt->nweo_flags= NWEO_COPY|NWEO_EN_BROAD|
305 NWEO_TYPESPEC;
306 ethopt->nweo_type= HTONS(ETH_ARP_PROTO);
307 return acc;
309 case APS_ARPMAIN:
310 assert (arp_port->ap_flags & APF_ARP_WR_IP);
311 if (!count)
313 data= arp_port->ap_sendpkt;
314 arp_port->ap_sendpkt= NULL;
315 assert(data);
316 bf_afree(data); data= NULL;
318 result= (int)offset;
319 if (result<0)
321 DIFBLOCK(1, (result != NW_SUSPEND),
322 printf(
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;
327 break;
329 arp_port->ap_flags &= ~APF_ARP_WR_IP;
330 if (arp_port->ap_flags & APF_ARP_WR_SP)
331 setup_write(arp_port);
332 return NW_OK;
334 assert (offset+count <= sizeof(arp46_t));
335 data= arp_port->ap_sendpkt;
336 assert(data);
337 data= bf_cut(data, offset, count);
339 return data;
340 default:
341 printf("arp_getdata(%d, 0x%d, 0x%d) called but ap_state=0x%x\n",
342 fd, offset, count, arp_port->ap_state);
343 break;
345 return 0;
348 static int arp_putdata (fd, offset, data, for_ioctl)
349 int fd;
350 size_t offset;
351 acc_t *data;
352 int for_ioctl;
354 arp_port_t *arp_port;
355 int result;
356 struct nwio_ethstat *ethstat;
357 ev_arg_t ev_arg;
358 acc_t *tmpacc;
360 arp_port= &arp_port_table[fd];
362 if (arp_port->ap_flags & APF_ARP_RD_IP)
364 if (!data)
366 result= (int)offset;
367 if (result<0)
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));
373 return NW_OK;
375 if (arp_port->ap_flags & APF_ARP_RD_SP)
377 arp_port->ap_flags &= ~(APF_ARP_RD_IP|
378 APF_ARP_RD_SP);
379 setup_read(arp_port);
381 else
382 arp_port->ap_flags &= ~(APF_ARP_RD_IP|
383 APF_ARP_RD_SP);
384 return NW_OK;
386 assert (!offset);
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
390 whole packets.
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,
399 ev_arg);
401 if (data->acc_linkC != 1)
403 tmpacc= bf_dupacc(data);
404 bf_afree(data);
405 data= tmpacc;
406 tmpacc= NULL;
408 data->acc_ext_link= arp_port->ap_reclist;
409 arp_port->ap_reclist= data;
411 else
412 bf_afree(data);
413 return NW_OK;
415 switch (arp_port->ap_state)
417 case APS_GETADDR:
418 if (!data)
420 result= (int)offset;
421 if (result<0)
423 arp_port->ap_state= APS_ERROR;
424 break;
426 if (arp_port->ap_flags & APF_SUSPEND)
428 arp_port->ap_flags &= ~APF_SUSPEND;
429 arp_main(arp_port);
431 return NW_OK;
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;
438 bf_afree(data);
439 return NW_OK;
440 default:
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);
443 break;
445 return EGENERIC;
448 static void setup_read(arp_port)
449 arp_port_t *arp_port;
451 int result;
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;
460 return;
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;
471 int result;
472 acc_t *data;
474 for(;;)
476 data= arp_port->ap_sendlist;
477 if (!data)
478 break;
479 arp_port->ap_sendlist= data->acc_ext_link;
481 if (arp_port->ap_ipaddr == HTONL(0x00000000))
483 /* Interface is down */
484 printf(
485 "arp[%d]: not sending ARP packet, interface is down\n",
486 arp_port-arp_port_table);
487 bf_afree(data); data= NULL;
488 continue;
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) |
495 APF_ARP_WR_IP;
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;
500 break;
502 if (result<0)
504 DIFBLOCK(1, (result != NW_SUSPEND),
505 printf("arp[%d]: eth_write(..,%d)=%d\n",
506 arp_port-arp_port_table, sizeof(arp46_t),
507 result));
508 return;
513 static void do_reclist(ev, ev_arg)
514 event_t *ev;
515 ev_arg_t ev_arg;
517 arp_port_t *arp_port;
518 acc_t *data;
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);
527 bf_afree(data);
531 static void process_arp_pkt (arp_port, data)
532 arp_port_t *arp_port;
533 acc_t *data;
535 int i, entry, do_reply;
536 arp46_t *arp;
537 u16_t *p;
538 arp_cache_t *ce, *cache;
539 struct arp_req *reqp;
540 time_t curr_time;
541 ipaddr_t spa, tpa;
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) ||
550 arp->a46_hln != 6 ||
551 arp->a46_pro != HTONS(ETH_IP_PROTO) ||
552 arp->a46_pln != 4)
553 return;
554 if (arp_port->ap_ipaddr == HTONL(0x00000000))
556 /* Interface is down */
557 #if DEBUG
558 printf("arp[%d]: dropping ARP packet, interface is down\n",
559 arp_port-arp_port_table);
560 #endif
561 return;
564 ce= find_cache_ent(arp_port, spa);
565 cache= NULL; /* lint */
567 do_reply= 0;
568 if (arp->a46_op != HTONS(ARP_REQUEST))
569 ; /* No need to reply */
570 else if (tpa == arp_port->ap_ipaddr)
571 do_reply= 1;
572 else
574 /* Look for a published entry */
575 cache= find_cache_ent(arp_port, tpa);
576 if (cache)
578 if (cache->ac_flags & ACF_PUB)
580 /* Published entry */
581 do_reply= 1;
583 else
585 /* Nothing to do */
586 cache= NULL;
591 if (ce == NULL)
593 if (!do_reply)
594 return;
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;
604 ce->ac_ipaddr= spa;
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 */
616 entry= ce-arp_cache;
617 for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR;
618 i++, reqp++)
620 if (reqp->ar_entry == entry)
621 break;
623 assert(i < AP_REQ_NR);
624 clck_untimer(&reqp->ar_timer);
625 reqp->ar_entry= -1;
627 ce->ac_state= ACS_VALID;
628 client_reply(arp_port, spa, &arp->a46_sha);
630 else
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);
640 writeIpAddr(spa);
641 printf(" changed from ");
642 writeEtherAddr(&ce->ac_ethaddr);
643 printf(" to ");
644 writeEtherAddr(&arp->a46_sha);
645 printf("\n");
646 ce->ac_ethaddr= arp->a46_sha;
648 ce->ac_expire= curr_time+ARP_EXP_TIME;
650 if (do_reply)
652 data= bf_memreq(sizeof(arp46_t));
653 arp= (arp46_t *)ptr2acc_data(data);
655 /* Clear padding */
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);
659 i++, p++)
661 *p= 0xdead;
664 arp->a46_dstaddr= ce->ac_ethaddr;
665 arp->a46_hdr= HTONS(ARP_ETHERNET);
666 arp->a46_pro= HTONS(ETH_IP_PROTO);
667 arp->a46_hln= 6;
668 arp->a46_pln= 4;
670 arp->a46_op= htons(ARP_REPLY);
671 if (tpa == arp_port->ap_ipaddr)
673 arp->a46_sha= arp_port->ap_ethaddr;
675 else
677 assert(cache);
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;
695 ipaddr_t ipaddr;
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;
703 ipaddr_t ipaddr;
705 arp_cache_t *ce;
706 int i;
707 unsigned hash;
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)
716 return ce;
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)
724 continue;
726 arp_hash[hash].ahe_row[i]= arp_hash[hash].ahe_row[0];
727 arp_hash[hash].ahe_row[0]= ce;
728 return 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];
742 assert(i == 0);
743 arp_hash[hash].ahe_row[0]= ce;
744 return ce;
747 return NULL;
750 static arp_cache_t *alloc_cache_ent(flags)
751 int flags;
753 arp_cache_t *cache, *old;
754 int i;
756 old= NULL;
757 for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++)
759 if (cache->ac_state == ACS_UNUSED)
761 old= cache;
762 break;
764 if (cache->ac_state == ACS_INCOMPLETE)
765 continue;
766 if (cache->ac_flags & ACF_PERM)
767 continue;
768 if (!old || cache->ac_lastuse < old->ac_lastuse)
769 old= cache;
771 assert(old);
773 if (!flags)
774 return old;
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)
780 break;
781 if (cache->ac_flags & ACF_PERM)
782 continue;
783 break;
785 if (i >= arp_cache_nr/2)
786 return NULL; /* Too many entries */
787 if (cache != old)
789 assert(old > cache);
790 *old= *cache;
791 old= cache;
794 if (!(flags & ACF_PUB))
795 return old;
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)
801 break;
802 if (cache->ac_flags & ACF_PUB)
803 continue;
804 break;
806 if (cache != old)
808 assert(old > cache);
809 *old= *cache;
810 old= cache;
812 return old;
815 void arp_set_ipaddr (eth_port, ipaddr)
816 int eth_port;
817 ipaddr_t ipaddr;
819 arp_port_t *arp_port;
821 if (eth_port < 0 || eth_port >= eth_conf_nr)
822 return;
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)
829 arp_main(arp_port);
832 int arp_set_cb(eth_port, ip_port, arp_func)
833 int eth_port;
834 int ip_port;
835 arp_func_t arp_func;
837 int i;
838 arp_port_t *arp_port;
840 assert(eth_port >= 0);
841 if (eth_port >= eth_conf_nr)
842 return ENXIO;
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);
860 arp_main(arp_port);
862 return NW_OK;
865 int arp_ip_eth (eth_port, ipaddr, ethaddr)
866 int eth_port;
867 ipaddr_t ipaddr;
868 ether_addr_t *ethaddr;
870 int i, ref;
871 arp_port_t *arp_port;
872 struct arp_req *reqp;
873 arp_cache_t *ce;
874 time_t curr_time;
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
890 * request or not.
892 for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR; i++, reqp++)
894 if (reqp->ar_entry < 0)
895 break;
897 if (i < AP_REQ_NR)
899 /* Okay, expire this entry. */
900 ce->ac_state= ACS_UNUSED;
901 ce= NULL;
903 else
905 /* Continue using this entry for a while */
906 printf("arp[%d]: Overloaded! Keeping entry for ",
907 arp_port-arp_port_table);
908 writeIpAddr(ipaddr);
909 printf("\n");
910 ce->ac_expire= curr_time+ARP_NOTRCH_EXP_TIME;
913 if (ce)
915 /* Found an entry. This entry should be valid, unreachable
916 * or incomplete.
918 ce->ac_lastuse= curr_time;
919 if (ce->ac_state == ACS_VALID)
921 *ethaddr= ce->ac_ethaddr;
922 return NW_OK;
924 if (ce->ac_state == ACS_UNREACHABLE)
925 return EHOSTUNREACH;
926 assert(ce->ac_state == ACS_INCOMPLETE);
928 return NW_SUSPEND;
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)
935 break;
937 if (i >= AP_REQ_NR)
939 /* We should be able to report that this ARP request
940 * cannot be accepted. At the moment we just return SUSPEND.
942 return NW_SUSPEND;
944 ref= (eth_port*AP_REQ_NR + i);
946 ce= alloc_cache_ent(ACF_EMPTY);
947 ce->ac_flags= 0;
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);
960 return NW_SUSPEND;
963 int arp_ioctl (eth_port, fd, req, get_userdata, put_userdata)
964 int eth_port;
965 int fd;
966 ioreq_t req;
967 get_userdata_t get_userdata;
968 put_userdata_t put_userdata;
970 arp_port_t *arp_port;
971 arp_cache_t *ce, *cache;
972 acc_t *data;
973 nwio_arp_t *arp_iop;
974 int entno, result, ac_flags;
975 u32_t flags;
976 ipaddr_t ipaddr;
977 time_t curr_time;
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));
985 switch(req)
987 case NWIOARPGIP:
988 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
989 if (data == NULL)
990 return EFAULT;
991 data= bf_packIffLess(data, sizeof(*arp_iop));
992 arp_iop= (nwio_arp_t *)ptr2acc_data(data);
993 ipaddr= arp_iop->nwa_ipaddr;
994 ce= NULL; /* lint */
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)
1001 continue;
1003 if (ce->ac_ipaddr == ipaddr)
1004 break;
1006 if (entno == arp_cache_nr)
1008 /* Also report the address of this interface */
1009 if (ipaddr != arp_port->ap_ipaddr)
1011 bf_afree(data);
1012 return ENOENT;
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;
1019 else
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);
1036 return result;
1038 case NWIOARPGNEXT:
1039 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
1040 if (data == NULL)
1041 return EFAULT;
1042 data= bf_packIffLess(data, sizeof(*arp_iop));
1043 arp_iop= (nwio_arp_t *)ptr2acc_data(data);
1044 entno= arp_iop->nwa_entno;
1045 if (entno < 0)
1046 entno= 0;
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)
1054 continue;
1056 break;
1058 if (entno == arp_cache_nr)
1060 bf_afree(data);
1061 return ENOENT;
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);
1077 return result;
1079 case NWIOARPSIP:
1080 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
1081 if (data == NULL)
1082 return EFAULT;
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))
1088 bf_afree(data);
1089 return EEXIST;
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);
1101 if (ce == NULL)
1103 bf_afree(data);
1104 return ENOMEM;
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;
1117 bf_afree(data);
1118 return 0;
1120 case NWIOARPDIP:
1121 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
1122 if (data == NULL)
1123 return EFAULT;
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);
1129 if (!ce)
1130 return ENOENT;
1131 if (ce->ac_state == ACS_INCOMPLETE)
1132 return EINVAL;
1134 ac_flags= ce->ac_flags;
1135 if (ac_flags & ACF_PUB)
1137 /* Make sure entry is at the end of published
1138 * entries.
1140 for (entno= 0, cache= arp_cache;
1141 entno<arp_cache_nr; entno++, cache++)
1143 if (cache->ac_state == ACS_UNUSED)
1144 break;
1145 if (cache->ac_flags & ACF_PUB)
1146 continue;
1147 break;
1149 assert(cache > arp_cache);
1150 cache--;
1151 if (cache != ce)
1153 assert(cache > ce);
1154 *ce= *cache;
1155 ce= cache;
1158 if (ac_flags & ACF_PERM)
1160 /* Make sure entry is at the end of permanent
1161 * entries.
1163 for (entno= 0, cache= arp_cache;
1164 entno<arp_cache_nr; entno++, cache++)
1166 if (cache->ac_state == ACS_UNUSED)
1167 break;
1168 if (cache->ac_flags & ACF_PERM)
1169 continue;
1170 break;
1172 assert(cache > arp_cache);
1173 cache--;
1174 if (cache != ce)
1176 assert(cache > ce);
1177 *ce= *cache;
1178 ce= cache;
1182 /* Clear entry */
1183 ce->ac_state= ACS_UNUSED;
1185 return 0;
1187 default:
1188 ip_panic(("arp_ioctl: unknown request 0x%lx",
1189 (unsigned long)req));
1191 return 0;
1194 static void arp_timeout (ref, timer)
1195 int ref;
1196 timer_t *timer;
1198 int i, port, reqind, acind;
1199 arp_port_t *arp_port;
1200 arp_cache_t *ce;
1201 struct arp_req *reqp;
1202 time_t curr_time;
1203 acc_t *data;
1204 arp46_t *arp;
1205 u16_t *p;
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);
1232 reqp->ar_entry= -1;
1233 client_reply(arp_port, ce->ac_ipaddr, NULL);
1234 return;
1237 data= bf_memreq(sizeof(arp46_t));
1238 arp= (arp46_t *)ptr2acc_data(data);
1240 /* Clear padding */
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);
1244 i++, p++)
1246 *p= 0xdead;
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);
1257 arp->a46_hln= 6;
1258 arp->a46_pln= 4;
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,
1273 arp_timeout, ref);
1276 static void arp_buffree(priority)
1277 int priority;
1279 int i;
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)
1290 pack= next_pack;
1291 next_pack= pack->acc_ext_link;
1292 bf_afree(pack);
1294 if (next_pack)
1296 if (ev_in_queue(&arp_port->ap_event))
1298 DBLOCK(1, printf(
1299 "not freeing ap_reclist, ap_event enqueued\n"));
1301 else
1303 bf_afree(next_pack);
1304 next_pack= NULL;
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)
1314 pack= next_pack;
1315 next_pack= pack->acc_ext_link;
1316 bf_afree(pack);
1318 if (next_pack)
1320 if (ev_in_queue(&arp_port->ap_event))
1322 DBLOCK(1, printf(
1323 "not freeing ap_sendlist, ap_event enqueued\n"));
1325 else
1327 bf_afree(next_pack);
1328 next_pack= NULL;
1331 arp_port->ap_sendlist= next_pack;
1336 #ifdef BUF_CONSISTENCY_CHECK
1337 static void arp_bufcheck()
1339 int i;
1340 arp_port_t *arp_port;
1341 acc_t *pack;
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)
1348 bf_check_acc(pack);
1350 for (pack= arp_port->ap_sendlist; pack;
1351 pack= pack->acc_ext_link)
1353 bf_check_acc(pack);
1357 #endif /* BUF_CONSISTENCY_CHECK */
1360 * $PchId: arp.c,v 1.22 2005/06/28 14:15:06 philip Exp $