source: trunk/minix/servers/inet/generic/arp.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 28.8 KB
Line 
1/*
2arp.c
3
4Copyright 1995 Philip Homburg
5*/
6
7#include "inet.h"
8#include "type.h"
9
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"
17#include "sr.h"
18
19THIS_FILE
20
21#define ARP_CACHE_NR 256
22#define AP_REQ_NR 32
23
24#define ARP_HASH_NR 256
25#define ARP_HASH_MASK 0xff
26#define ARP_HASH_WIDTH 4
27
28#define MAX_ARP_RETRIES 5
29#define ARP_TIMEOUT (HZ/2+1) /* .5 seconds */
30#ifndef ARP_EXP_TIME
31#define ARP_EXP_TIME (20L*60L*HZ) /* 20 minutes */
32#endif
33#define ARP_NOTRCH_EXP_TIME (30*HZ) /* 30 seconds */
34#define ARP_INUSE_OFFSET (60*HZ) /* an entry in the cache can be deleted
35 if its not used for 1 minute */
36
37typedef struct arp46
38{
39 ether_addr_t a46_dstaddr;
40 ether_addr_t a46_srcaddr;
41 ether_type_t a46_ethtype;
42 union
43 {
44 struct
45 {
46 u16_t a_hdr, a_pro;
47 u8_t a_hln, a_pln;
48 u16_t a_op;
49 ether_addr_t a_sha;
50 u8_t a_spa[4];
51 ether_addr_t a_tha;
52 u8_t a_tpa[4];
53 } a46_data;
54 char a46_dummy[ETH_MIN_PACK_SIZE-ETH_HDR_SIZE];
55 } a46_data;
56} arp46_t;
57
58#define a46_hdr a46_data.a46_data.a_hdr
59#define a46_pro a46_data.a46_data.a_pro
60#define a46_hln a46_data.a46_data.a_hln
61#define a46_pln a46_data.a46_data.a_pln
62#define a46_op a46_data.a46_data.a_op
63#define a46_sha a46_data.a46_data.a_sha
64#define a46_spa a46_data.a46_data.a_spa
65#define a46_tha a46_data.a46_data.a_tha
66#define a46_tpa a46_data.a46_data.a_tpa
67
68typedef struct arp_port
69{
70 int ap_flags;
71 int ap_state;
72 int ap_eth_port;
73 int ap_ip_port;
74 int ap_eth_fd;
75
76 ether_addr_t ap_ethaddr; /* Ethernet address of this port */
77 ipaddr_t ap_ipaddr; /* IP address of this port */
78
79 struct arp_req
80 {
81 timer_t ar_timer;
82 int ar_entry;
83 int ar_req_count;
84 } ap_req[AP_REQ_NR];
85
86 arp_func_t ap_arp_func;
87
88 acc_t *ap_sendpkt;
89 acc_t *ap_sendlist;
90 acc_t *ap_reclist;
91 event_t ap_event;
92} arp_port_t;
93
94#define APF_EMPTY 0x00
95#define APF_ARP_RD_IP 0x01
96#define APF_ARP_RD_SP 0x02
97#define APF_ARP_WR_IP 0x04
98#define APF_ARP_WR_SP 0x08
99#define APF_INADDR_SET 0x10
100#define APF_SUSPEND 0x20
101
102#define APS_INITIAL 1
103#define APS_GETADDR 2
104#define APS_ARPSTART 3
105#define APS_ARPPROTO 4
106#define APS_ARPMAIN 5
107#define APS_ERROR 6
108
109typedef struct arp_cache
110{
111 int ac_flags;
112 int ac_state;
113 ether_addr_t ac_ethaddr;
114 ipaddr_t ac_ipaddr;
115 arp_port_t *ac_port;
116 time_t ac_expire;
117 time_t ac_lastuse;
118} arp_cache_t;
119
120#define ACF_EMPTY 0
121#define ACF_PERM 1
122#define ACF_PUB 2
123
124#define ACS_UNUSED 0
125#define ACS_INCOMPLETE 1
126#define ACS_VALID 2
127#define ACS_UNREACHABLE 3
128
129PRIVATE struct arp_hash_ent
130{
131 arp_cache_t *ahe_row[ARP_HASH_WIDTH];
132} arp_hash[ARP_HASH_NR];
133
134PRIVATE arp_port_t *arp_port_table;
135PRIVATE arp_cache_t *arp_cache;
136PRIVATE int arp_cache_nr;
137
138FORWARD acc_t *arp_getdata ARGS(( int fd, size_t offset,
139 size_t count, int for_ioctl ));
140FORWARD int arp_putdata ARGS(( int fd, size_t offset,
141 acc_t *data, int for_ioctl ));
142FORWARD void arp_main ARGS(( arp_port_t *arp_port ));
143FORWARD void arp_timeout ARGS(( int ref, timer_t *timer ));
144FORWARD void setup_write ARGS(( arp_port_t *arp_port ));
145FORWARD void setup_read ARGS(( arp_port_t *arp_port ));
146FORWARD void do_reclist ARGS(( event_t *ev, ev_arg_t ev_arg ));
147FORWARD void process_arp_pkt ARGS(( arp_port_t *arp_port, acc_t *data ));
148FORWARD void client_reply ARGS(( arp_port_t *arp_port,
149 ipaddr_t ipaddr, ether_addr_t *ethaddr ));
150FORWARD arp_cache_t *find_cache_ent ARGS(( arp_port_t *arp_port,
151 ipaddr_t ipaddr ));
152FORWARD arp_cache_t *alloc_cache_ent ARGS(( int flags ));
153FORWARD void arp_buffree ARGS(( int priority ));
154#ifdef BUF_CONSISTENCY_CHECK
155FORWARD void arp_bufcheck ARGS(( void ));
156#endif
157
158PUBLIC void arp_prep()
159{
160 arp_port_table= alloc(eth_conf_nr * sizeof(arp_port_table[0]));
161
162 arp_cache_nr= ARP_CACHE_NR;
163 if (arp_cache_nr < (eth_conf_nr+1)*AP_REQ_NR)
164 {
165 arp_cache_nr= (eth_conf_nr+1)*AP_REQ_NR;
166 printf("arp: using %d cache entries instead of %d\n",
167 arp_cache_nr, ARP_CACHE_NR);
168 }
169 arp_cache= alloc(arp_cache_nr * sizeof(arp_cache[0]));
170}
171
172PUBLIC void arp_init()
173{
174 arp_port_t *arp_port;
175 arp_cache_t *cache;
176 int i;
177
178 assert (BUF_S >= sizeof(struct nwio_ethstat));
179 assert (BUF_S >= sizeof(struct nwio_ethopt));
180 assert (BUF_S >= sizeof(arp46_t));
181
182 for (i=0, arp_port= arp_port_table; i<eth_conf_nr; i++, arp_port++)
183 {
184 arp_port->ap_state= APS_ERROR; /* Mark all ports as
185 * unavailable */
186 }
187
188 cache= arp_cache;
189 for (i=0; i<arp_cache_nr; i++, cache++)
190 {
191 cache->ac_state= ACS_UNUSED;
192 cache->ac_flags= ACF_EMPTY;
193 cache->ac_expire= 0;
194 cache->ac_lastuse= 0;
195 }
196
197#ifndef BUF_CONSISTENCY_CHECK
198 bf_logon(arp_buffree);
199#else
200 bf_logon(arp_buffree, arp_bufcheck);
201#endif
202}
203
204PRIVATE void arp_main(arp_port)
205arp_port_t *arp_port;
206{
207 int result;
208
209 switch (arp_port->ap_state)
210 {
211 case APS_INITIAL:
212 arp_port->ap_eth_fd= eth_open(arp_port->ap_eth_port,
213 arp_port->ap_eth_port, arp_getdata, arp_putdata,
214 0 /* no put_pkt */, 0 /* no select_res */);
215
216 if (arp_port->ap_eth_fd<0)
217 {
218 DBLOCK(1, printf("arp[%d]: unable to open eth[%d]\n",
219 arp_port-arp_port_table,
220 arp_port->ap_eth_port));
221 return;
222 }
223
224 arp_port->ap_state= APS_GETADDR;
225
226 result= eth_ioctl (arp_port->ap_eth_fd, NWIOGETHSTAT);
227
228 if ( result == NW_SUSPEND)
229 {
230 arp_port->ap_flags |= APF_SUSPEND;
231 return;
232 }
233 assert(result == NW_OK);
234
235 /* fall through */
236 case APS_GETADDR:
237 /* Wait for IP address */
238 if (!(arp_port->ap_flags & APF_INADDR_SET))
239 return;
240
241 /* fall through */
242 case APS_ARPSTART:
243 arp_port->ap_state= APS_ARPPROTO;
244
245 result= eth_ioctl (arp_port->ap_eth_fd, NWIOSETHOPT);
246
247 if (result==NW_SUSPEND)
248 {
249 arp_port->ap_flags |= APF_SUSPEND;
250 return;
251 }
252 assert(result == NW_OK);
253
254 /* fall through */
255 case APS_ARPPROTO:
256 arp_port->ap_state= APS_ARPMAIN;
257 setup_write(arp_port);
258 setup_read(arp_port);
259 return;
260
261 default:
262 ip_panic((
263 "arp_main(&arp_port_table[%d]) called but ap_state=0x%x\n",
264 arp_port->ap_eth_port, arp_port->ap_state ));
265 }
266}
267
268PRIVATE acc_t *arp_getdata (fd, offset, count, for_ioctl)
269int fd;
270size_t offset;
271size_t count;
272int for_ioctl;
273{
274 arp_port_t *arp_port;
275 acc_t *data;
276 int result;
277
278 arp_port= &arp_port_table[fd];
279
280 switch (arp_port->ap_state)
281 {
282 case APS_ARPPROTO:
283 if (!count)
284 {
285 result= (int)offset;
286 if (result<0)
287 {
288 arp_port->ap_state= APS_ERROR;
289 break;
290 }
291 if (arp_port->ap_flags & APF_SUSPEND)
292 {
293 arp_port->ap_flags &= ~APF_SUSPEND;
294 arp_main(arp_port);
295 }
296 return NW_OK;
297 }
298 assert ((!offset) && (count == sizeof(struct nwio_ethopt)));
299 {
300 struct nwio_ethopt *ethopt;
301 acc_t *acc;
302
303 acc= bf_memreq(sizeof(*ethopt));
304 ethopt= (struct nwio_ethopt *)ptr2acc_data(acc);
305 ethopt->nweo_flags= NWEO_COPY|NWEO_EN_BROAD|
306 NWEO_TYPESPEC;
307 ethopt->nweo_type= HTONS(ETH_ARP_PROTO);
308 return acc;
309 }
310 case APS_ARPMAIN:
311 assert (arp_port->ap_flags & APF_ARP_WR_IP);
312 if (!count)
313 {
314 data= arp_port->ap_sendpkt;
315 arp_port->ap_sendpkt= NULL;
316 assert(data);
317 bf_afree(data); data= NULL;
318
319 result= (int)offset;
320 if (result<0)
321 {
322 DIFBLOCK(1, (result != NW_SUSPEND),
323 printf(
324 "arp[%d]: write error on port %d: error %d\n",
325 fd, arp_port->ap_eth_fd, result));
326
327 arp_port->ap_state= APS_ERROR;
328 break;
329 }
330 arp_port->ap_flags &= ~APF_ARP_WR_IP;
331 if (arp_port->ap_flags & APF_ARP_WR_SP)
332 setup_write(arp_port);
333 return NW_OK;
334 }
335 assert (offset+count <= sizeof(arp46_t));
336 data= arp_port->ap_sendpkt;
337 assert(data);
338 data= bf_cut(data, offset, count);
339
340 return data;
341 default:
342 printf("arp_getdata(%d, 0x%d, 0x%d) called but ap_state=0x%x\n",
343 fd, offset, count, arp_port->ap_state);
344 break;
345 }
346 return 0;
347}
348
349PRIVATE int arp_putdata (fd, offset, data, for_ioctl)
350int fd;
351size_t offset;
352acc_t *data;
353int for_ioctl;
354{
355 arp_port_t *arp_port;
356 int result;
357 struct nwio_ethstat *ethstat;
358 ev_arg_t ev_arg;
359 acc_t *tmpacc;
360
361 arp_port= &arp_port_table[fd];
362
363 if (arp_port->ap_flags & APF_ARP_RD_IP)
364 {
365 if (!data)
366 {
367 result= (int)offset;
368 if (result<0)
369 {
370 DIFBLOCK(1, (result != NW_SUSPEND), printf(
371 "arp[%d]: read error on port %d: error %d\n",
372 fd, arp_port->ap_eth_fd, result));
373
374 return NW_OK;
375 }
376 if (arp_port->ap_flags & APF_ARP_RD_SP)
377 {
378 arp_port->ap_flags &= ~(APF_ARP_RD_IP|
379 APF_ARP_RD_SP);
380 setup_read(arp_port);
381 }
382 else
383 arp_port->ap_flags &= ~(APF_ARP_RD_IP|
384 APF_ARP_RD_SP);
385 return NW_OK;
386 }
387 assert (!offset);
388 /* Warning: the above assertion is illegal; puts and gets of
389 data can be brokenup in any piece the server likes. However
390 we assume that the server is eth.c and it transfers only
391 whole packets.
392 */
393 data= bf_packIffLess(data, sizeof(arp46_t));
394 if (data->acc_length >= sizeof(arp46_t))
395 {
396 if (!arp_port->ap_reclist)
397 {
398 ev_arg.ev_ptr= arp_port;
399 ev_enqueue(&arp_port->ap_event, do_reclist,
400 ev_arg);
401 }
402 if (data->acc_linkC != 1)
403 {
404 tmpacc= bf_dupacc(data);
405 bf_afree(data);
406 data= tmpacc;
407 tmpacc= NULL;
408 }
409 data->acc_ext_link= arp_port->ap_reclist;
410 arp_port->ap_reclist= data;
411 }
412 else
413 bf_afree(data);
414 return NW_OK;
415 }
416 switch (arp_port->ap_state)
417 {
418 case APS_GETADDR:
419 if (!data)
420 {
421 result= (int)offset;
422 if (result<0)
423 {
424 arp_port->ap_state= APS_ERROR;
425 break;
426 }
427 if (arp_port->ap_flags & APF_SUSPEND)
428 {
429 arp_port->ap_flags &= ~APF_SUSPEND;
430 arp_main(arp_port);
431 }
432 return NW_OK;
433 }
434 compare (bf_bufsize(data), ==, sizeof(*ethstat));
435 data= bf_packIffLess(data, sizeof(*ethstat));
436 compare (data->acc_length, ==, sizeof(*ethstat));
437 ethstat= (struct nwio_ethstat *)ptr2acc_data(data);
438 arp_port->ap_ethaddr= ethstat->nwes_addr;
439 bf_afree(data);
440 return NW_OK;
441 default:
442 printf("arp_putdata(%d, 0x%d, 0x%lx) called but ap_state=0x%x\n",
443 fd, offset, (unsigned long)data, arp_port->ap_state);
444 break;
445 }
446 return EGENERIC;
447}
448
449PRIVATE void setup_read(arp_port)
450arp_port_t *arp_port;
451{
452 int result;
453
454 while (!(arp_port->ap_flags & APF_ARP_RD_IP))
455 {
456 arp_port->ap_flags |= APF_ARP_RD_IP;
457 result= eth_read (arp_port->ap_eth_fd, ETH_MAX_PACK_SIZE);
458 if (result == NW_SUSPEND)
459 {
460 arp_port->ap_flags |= APF_ARP_RD_SP;
461 return;
462 }
463 DIFBLOCK(1, (result != NW_OK),
464 printf("arp[%d]: eth_read(..,%d)=%d\n",
465 arp_port-arp_port_table, ETH_MAX_PACK_SIZE, result));
466 }
467}
468
469PRIVATE void setup_write(arp_port)
470arp_port_t *arp_port;
471{
472 int result;
473 acc_t *data;
474
475 for(;;)
476 {
477 data= arp_port->ap_sendlist;
478 if (!data)
479 break;
480 arp_port->ap_sendlist= data->acc_ext_link;
481
482 if (arp_port->ap_ipaddr == HTONL(0x00000000))
483 {
484 /* Interface is down */
485 printf(
486 "arp[%d]: not sending ARP packet, interface is down\n",
487 arp_port-arp_port_table);
488 bf_afree(data); data= NULL;
489 continue;
490 }
491
492 assert(!arp_port->ap_sendpkt);
493 arp_port->ap_sendpkt= data; data= NULL;
494
495 arp_port->ap_flags= (arp_port->ap_flags & ~APF_ARP_WR_SP) |
496 APF_ARP_WR_IP;
497 result= eth_write(arp_port->ap_eth_fd, sizeof(arp46_t));
498 if (result == NW_SUSPEND)
499 {
500 arp_port->ap_flags |= APF_ARP_WR_SP;
501 break;
502 }
503 if (result<0)
504 {
505 DIFBLOCK(1, (result != NW_SUSPEND),
506 printf("arp[%d]: eth_write(..,%d)=%d\n",
507 arp_port-arp_port_table, sizeof(arp46_t),
508 result));
509 return;
510 }
511 }
512}
513
514PRIVATE void do_reclist(ev, ev_arg)
515event_t *ev;
516ev_arg_t ev_arg;
517{
518 arp_port_t *arp_port;
519 acc_t *data;
520
521 arp_port= ev_arg.ev_ptr;
522 assert(ev == &arp_port->ap_event);
523
524 while (data= arp_port->ap_reclist, data != NULL)
525 {
526 arp_port->ap_reclist= data->acc_ext_link;
527 process_arp_pkt(arp_port, data);
528 bf_afree(data);
529 }
530}
531
532PRIVATE void process_arp_pkt (arp_port, data)
533arp_port_t *arp_port;
534acc_t *data;
535{
536 int i, entry, do_reply;
537 arp46_t *arp;
538 u16_t *p;
539 arp_cache_t *ce, *cache;
540 struct arp_req *reqp;
541 time_t curr_time;
542 ipaddr_t spa, tpa;
543
544 curr_time= get_time();
545
546 arp= (arp46_t *)ptr2acc_data(data);
547 memcpy(&spa, arp->a46_spa, sizeof(ipaddr_t));
548 memcpy(&tpa, arp->a46_tpa, sizeof(ipaddr_t));
549
550 if (arp->a46_hdr != HTONS(ARP_ETHERNET) ||
551 arp->a46_hln != 6 ||
552 arp->a46_pro != HTONS(ETH_IP_PROTO) ||
553 arp->a46_pln != 4)
554 return;
555 if (arp_port->ap_ipaddr == HTONL(0x00000000))
556 {
557 /* Interface is down */
558#if DEBUG
559 printf("arp[%d]: dropping ARP packet, interface is down\n",
560 arp_port-arp_port_table);
561#endif
562 return;
563 }
564
565 ce= find_cache_ent(arp_port, spa);
566 cache= NULL; /* lint */
567
568 do_reply= 0;
569 if (arp->a46_op != HTONS(ARP_REQUEST))
570 ; /* No need to reply */
571 else if (tpa == arp_port->ap_ipaddr)
572 do_reply= 1;
573 else
574 {
575 /* Look for a published entry */
576 cache= find_cache_ent(arp_port, tpa);
577 if (cache)
578 {
579 if (cache->ac_flags & ACF_PUB)
580 {
581 /* Published entry */
582 do_reply= 1;
583 }
584 else
585 {
586 /* Nothing to do */
587 cache= NULL;
588 }
589 }
590 }
591
592 if (ce == NULL)
593 {
594 if (!do_reply)
595 return;
596
597 DBLOCK(0x10, printf("arp[%d]: allocating entry for ",
598 arp_port-arp_port_table);
599 writeIpAddr(spa); printf("\n"));
600
601 ce= alloc_cache_ent(ACF_EMPTY);
602 ce->ac_flags= ACF_EMPTY;
603 ce->ac_state= ACS_VALID;
604 ce->ac_ethaddr= arp->a46_sha;
605 ce->ac_ipaddr= spa;
606 ce->ac_port= arp_port;
607 ce->ac_expire= curr_time+ARP_EXP_TIME;
608 ce->ac_lastuse= curr_time-ARP_INUSE_OFFSET; /* never used */
609 }
610
611 if (ce->ac_state == ACS_INCOMPLETE || ce->ac_state == ACS_UNREACHABLE)
612 {
613 ce->ac_ethaddr= arp->a46_sha;
614 if (ce->ac_state == ACS_INCOMPLETE)
615 {
616 /* Find request entry */
617 entry= ce-arp_cache;
618 for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR;
619 i++, reqp++)
620 {
621 if (reqp->ar_entry == entry)
622 break;
623 }
624 assert(i < AP_REQ_NR);
625 clck_untimer(&reqp->ar_timer);
626 reqp->ar_entry= -1;
627
628 ce->ac_state= ACS_VALID;
629 client_reply(arp_port, spa, &arp->a46_sha);
630 }
631 else
632 ce->ac_state= ACS_VALID;
633 }
634
635 /* Update fields in the arp cache. */
636 if (memcmp(&ce->ac_ethaddr, &arp->a46_sha,
637 sizeof(ce->ac_ethaddr)) != 0)
638 {
639 printf("arp[%d]: ethernet address for IP address ",
640 arp_port-arp_port_table);
641 writeIpAddr(spa);
642 printf(" changed from ");
643 writeEtherAddr(&ce->ac_ethaddr);
644 printf(" to ");
645 writeEtherAddr(&arp->a46_sha);
646 printf("\n");
647 ce->ac_ethaddr= arp->a46_sha;
648 }
649 ce->ac_expire= curr_time+ARP_EXP_TIME;
650
651 if (do_reply)
652 {
653 data= bf_memreq(sizeof(arp46_t));
654 arp= (arp46_t *)ptr2acc_data(data);
655
656 /* Clear padding */
657 assert(sizeof(arp->a46_data.a46_dummy) % sizeof(*p) == 0);
658 for (i= 0, p= (u16_t *)arp->a46_data.a46_dummy;
659 i < sizeof(arp->a46_data.a46_dummy)/sizeof(*p);
660 i++, p++)
661 {
662 *p= 0xdead;
663 }
664
665 arp->a46_dstaddr= ce->ac_ethaddr;
666 arp->a46_hdr= HTONS(ARP_ETHERNET);
667 arp->a46_pro= HTONS(ETH_IP_PROTO);
668 arp->a46_hln= 6;
669 arp->a46_pln= 4;
670
671 arp->a46_op= htons(ARP_REPLY);
672 if (tpa == arp_port->ap_ipaddr)
673 {
674 arp->a46_sha= arp_port->ap_ethaddr;
675 }
676 else
677 {
678 assert(cache);
679 arp->a46_sha= cache->ac_ethaddr;
680 }
681 memcpy (arp->a46_spa, &tpa, sizeof(ipaddr_t));
682 arp->a46_tha= ce->ac_ethaddr;
683 memcpy (arp->a46_tpa, &ce->ac_ipaddr, sizeof(ipaddr_t));
684
685 assert(data->acc_linkC == 1);
686 data->acc_ext_link= arp_port->ap_sendlist;
687 arp_port->ap_sendlist= data; data= NULL;
688
689 if (!(arp_port->ap_flags & APF_ARP_WR_IP))
690 setup_write(arp_port);
691 }
692}
693
694PRIVATE void client_reply (arp_port, ipaddr, ethaddr)
695arp_port_t *arp_port;
696ipaddr_t ipaddr;
697ether_addr_t *ethaddr;
698{
699 (*arp_port->ap_arp_func)(arp_port->ap_ip_port, ipaddr, ethaddr);
700}
701
702PRIVATE arp_cache_t *find_cache_ent (arp_port, ipaddr)
703arp_port_t *arp_port;
704ipaddr_t ipaddr;
705{
706 arp_cache_t *ce;
707 int i;
708 unsigned hash;
709
710 hash= (ipaddr >> 24) ^ (ipaddr >> 16) ^ (ipaddr >> 8) ^ ipaddr;
711 hash &= ARP_HASH_MASK;
712
713 ce= arp_hash[hash].ahe_row[0];
714 if (ce && ce->ac_ipaddr == ipaddr && ce->ac_port == arp_port &&
715 ce->ac_state != ACS_UNUSED)
716 {
717 return ce;
718 }
719 for (i= 1; i<ARP_HASH_WIDTH; i++)
720 {
721 ce= arp_hash[hash].ahe_row[i];
722 if (!ce || ce->ac_ipaddr != ipaddr || ce->ac_port != arp_port
723 || ce->ac_state == ACS_UNUSED)
724 {
725 continue;
726 }
727 arp_hash[hash].ahe_row[i]= arp_hash[hash].ahe_row[0];
728 arp_hash[hash].ahe_row[0]= ce;
729 return ce;
730 }
731
732 for (i=0, ce= arp_cache; i<arp_cache_nr; i++, ce++)
733 {
734 if (ce->ac_state != ACS_UNUSED &&
735 ce->ac_port == arp_port &&
736 ce->ac_ipaddr == ipaddr)
737 {
738 for (i= ARP_HASH_WIDTH-1; i>0; i--)
739 {
740 arp_hash[hash].ahe_row[i]=
741 arp_hash[hash].ahe_row[i-1];
742 }
743 assert(i == 0);
744 arp_hash[hash].ahe_row[0]= ce;
745 return ce;
746 }
747 }
748 return NULL;
749}
750
751PRIVATE arp_cache_t *alloc_cache_ent(flags)
752int flags;
753{
754 arp_cache_t *cache, *old;
755 int i;
756
757 old= NULL;
758 for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++)
759 {
760 if (cache->ac_state == ACS_UNUSED)
761 {
762 old= cache;
763 break;
764 }
765 if (cache->ac_state == ACS_INCOMPLETE)
766 continue;
767 if (cache->ac_flags & ACF_PERM)
768 continue;
769 if (!old || cache->ac_lastuse < old->ac_lastuse)
770 old= cache;
771 }
772 assert(old);
773
774 if (!flags)
775 return old;
776
777 /* Get next permanent entry */
778 for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++)
779 {
780 if (cache->ac_state == ACS_UNUSED)
781 break;
782 if (cache->ac_flags & ACF_PERM)
783 continue;
784 break;
785 }
786 if (i >= arp_cache_nr/2)
787 return NULL; /* Too many entries */
788 if (cache != old)
789 {
790 assert(old > cache);
791 *old= *cache;
792 old= cache;
793 }
794
795 if (!(flags & ACF_PUB))
796 return old;
797
798 /* Get first nonpublished entry */
799 for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++)
800 {
801 if (cache->ac_state == ACS_UNUSED)
802 break;
803 if (cache->ac_flags & ACF_PUB)
804 continue;
805 break;
806 }
807 if (cache != old)
808 {
809 assert(old > cache);
810 *old= *cache;
811 old= cache;
812 }
813 return old;
814}
815
816PUBLIC void arp_set_ipaddr (eth_port, ipaddr)
817int eth_port;
818ipaddr_t ipaddr;
819{
820 arp_port_t *arp_port;
821
822 if (eth_port < 0 || eth_port >= eth_conf_nr)
823 return;
824 arp_port= &arp_port_table[eth_port];
825
826 arp_port->ap_ipaddr= ipaddr;
827 arp_port->ap_flags |= APF_INADDR_SET;
828 arp_port->ap_flags &= ~APF_SUSPEND;
829 if (arp_port->ap_state == APS_GETADDR)
830 arp_main(arp_port);
831}
832
833PUBLIC int arp_set_cb(eth_port, ip_port, arp_func)
834int eth_port;
835int ip_port;
836arp_func_t arp_func;
837{
838 int i;
839 arp_port_t *arp_port;
840
841 assert(eth_port >= 0);
842 if (eth_port >= eth_conf_nr)
843 return ENXIO;
844
845 arp_port= &arp_port_table[eth_port];
846 arp_port->ap_eth_port= eth_port;
847 arp_port->ap_ip_port= ip_port;
848 arp_port->ap_state= APS_INITIAL;
849 arp_port->ap_flags= APF_EMPTY;
850 arp_port->ap_arp_func= arp_func;
851 arp_port->ap_sendpkt= NULL;
852 arp_port->ap_sendlist= NULL;
853 arp_port->ap_reclist= NULL;
854 for (i= 0; i<AP_REQ_NR; i++)
855 arp_port->ap_req[i].ar_entry= -1;
856 ev_init(&arp_port->ap_event);
857
858 arp_main(arp_port);
859
860 return NW_OK;
861}
862
863PUBLIC int arp_ip_eth (eth_port, ipaddr, ethaddr)
864int eth_port;
865ipaddr_t ipaddr;
866ether_addr_t *ethaddr;
867{
868 int i, ref;
869 arp_port_t *arp_port;
870 struct arp_req *reqp;
871 arp_cache_t *ce;
872 time_t curr_time;
873
874 assert(eth_port >= 0 && eth_port < eth_conf_nr);
875 arp_port= &arp_port_table[eth_port];
876 assert(arp_port->ap_state == APS_ARPMAIN ||
877 (printf("arp[%d]: ap_state= %d\n", arp_port-arp_port_table,
878 arp_port->ap_state), 0));
879
880 curr_time= get_time();
881
882 ce= find_cache_ent (arp_port, ipaddr);
883 if (ce && ce->ac_expire < curr_time)
884 {
885 assert(ce->ac_state != ACS_INCOMPLETE);
886
887 /* Check whether there is enough space for an ARP
888 * request or not.
889 */
890 for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR; i++, reqp++)
891 {
892 if (reqp->ar_entry < 0)
893 break;
894 }
895 if (i < AP_REQ_NR)
896 {
897 /* Okay, expire this entry. */
898 ce->ac_state= ACS_UNUSED;
899 ce= NULL;
900 }
901 else
902 {
903 /* Continue using this entry for a while */
904 printf("arp[%d]: Overloaded! Keeping entry for ",
905 arp_port-arp_port_table);
906 writeIpAddr(ipaddr);
907 printf("\n");
908 ce->ac_expire= curr_time+ARP_NOTRCH_EXP_TIME;
909 }
910 }
911 if (ce)
912 {
913 /* Found an entry. This entry should be valid, unreachable
914 * or incomplete.
915 */
916 ce->ac_lastuse= curr_time;
917 if (ce->ac_state == ACS_VALID)
918 {
919 *ethaddr= ce->ac_ethaddr;
920 return NW_OK;
921 }
922 if (ce->ac_state == ACS_UNREACHABLE)
923 return EDSTNOTRCH;
924 assert(ce->ac_state == ACS_INCOMPLETE);
925
926 return NW_SUSPEND;
927 }
928
929 /* Find an empty slot for an ARP request */
930 for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR; i++, reqp++)
931 {
932 if (reqp->ar_entry < 0)
933 break;
934 }
935 if (i >= AP_REQ_NR)
936 {
937 /* We should be able to report that this ARP request
938 * cannot be accepted. At the moment we just return SUSPEND.
939 */
940 return NW_SUSPEND;
941 }
942 ref= (eth_port*AP_REQ_NR + i);
943
944 ce= alloc_cache_ent(ACF_EMPTY);
945 ce->ac_flags= 0;
946 ce->ac_state= ACS_INCOMPLETE;
947 ce->ac_ipaddr= ipaddr;
948 ce->ac_port= arp_port;
949 ce->ac_expire= curr_time+ARP_EXP_TIME;
950 ce->ac_lastuse= curr_time;
951
952 reqp->ar_entry= ce-arp_cache;
953 reqp->ar_req_count= -1;
954
955 /* Send the first packet by expiring the timer */
956 clck_timer(&reqp->ar_timer, 1, arp_timeout, ref);
957
958 return NW_SUSPEND;
959}
960
961PUBLIC int arp_ioctl (eth_port, fd, req, get_userdata, put_userdata)
962int eth_port;
963int fd;
964ioreq_t req;
965get_userdata_t get_userdata;
966put_userdata_t put_userdata;
967{
968 arp_port_t *arp_port;
969 arp_cache_t *ce, *cache;
970 acc_t *data;
971 nwio_arp_t *arp_iop;
972 int entno, result, ac_flags;
973 u32_t flags;
974 ipaddr_t ipaddr;
975 time_t curr_time;
976
977 assert(eth_port >= 0 && eth_port < eth_conf_nr);
978 arp_port= &arp_port_table[eth_port];
979 assert(arp_port->ap_state == APS_ARPMAIN ||
980 (printf("arp[%d]: ap_state= %d\n", arp_port-arp_port_table,
981 arp_port->ap_state), 0));
982
983 switch(req)
984 {
985 case NWIOARPGIP:
986 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
987 if (data == NULL)
988 return EFAULT;
989 data= bf_packIffLess(data, sizeof(*arp_iop));
990 arp_iop= (nwio_arp_t *)ptr2acc_data(data);
991 ipaddr= arp_iop->nwa_ipaddr;
992 ce= NULL; /* lint */
993 for (entno= 0; entno < arp_cache_nr; entno++)
994 {
995 ce= &arp_cache[entno];
996 if (ce->ac_state == ACS_UNUSED ||
997 ce->ac_port != arp_port)
998 {
999 continue;
1000 }
1001 if (ce->ac_ipaddr == ipaddr)
1002 break;
1003 }
1004 if (entno == arp_cache_nr)
1005 {
1006 /* Also report the address of this interface */
1007 if (ipaddr != arp_port->ap_ipaddr)
1008 {
1009 bf_afree(data);
1010 return ENOENT;
1011 }
1012 arp_iop->nwa_entno= arp_cache_nr;
1013 arp_iop->nwa_ipaddr= ipaddr;
1014 arp_iop->nwa_ethaddr= arp_port->ap_ethaddr;
1015 arp_iop->nwa_flags= NWAF_PERM | NWAF_PUB;
1016 }
1017 else
1018 {
1019 arp_iop->nwa_entno= entno+1;
1020 arp_iop->nwa_ipaddr= ce->ac_ipaddr;
1021 arp_iop->nwa_ethaddr= ce->ac_ethaddr;
1022 arp_iop->nwa_flags= 0;
1023 if (ce->ac_state == ACS_INCOMPLETE)
1024 arp_iop->nwa_flags |= NWAF_INCOMPLETE;
1025 if (ce->ac_state == ACS_UNREACHABLE)
1026 arp_iop->nwa_flags |= NWAF_DEAD;
1027 if (ce->ac_flags & ACF_PERM)
1028 arp_iop->nwa_flags |= NWAF_PERM;
1029 if (ce->ac_flags & ACF_PUB)
1030 arp_iop->nwa_flags |= NWAF_PUB;
1031 }
1032
1033 result= (*put_userdata)(fd, 0, data, TRUE);
1034 return result;
1035
1036 case NWIOARPGNEXT:
1037 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
1038 if (data == NULL)
1039 return EFAULT;
1040 data= bf_packIffLess(data, sizeof(*arp_iop));
1041 arp_iop= (nwio_arp_t *)ptr2acc_data(data);
1042 entno= arp_iop->nwa_entno;
1043 if (entno < 0)
1044 entno= 0;
1045 ce= NULL; /* lint */
1046 for (; entno < arp_cache_nr; entno++)
1047 {
1048 ce= &arp_cache[entno];
1049 if (ce->ac_state == ACS_UNUSED ||
1050 ce->ac_port != arp_port)
1051 {
1052 continue;
1053 }
1054 break;
1055 }
1056 if (entno == arp_cache_nr)
1057 {
1058 bf_afree(data);
1059 return ENOENT;
1060 }
1061 arp_iop->nwa_entno= entno+1;
1062 arp_iop->nwa_ipaddr= ce->ac_ipaddr;
1063 arp_iop->nwa_ethaddr= ce->ac_ethaddr;
1064 arp_iop->nwa_flags= 0;
1065 if (ce->ac_state == ACS_INCOMPLETE)
1066 arp_iop->nwa_flags |= NWAF_INCOMPLETE;
1067 if (ce->ac_state == ACS_UNREACHABLE)
1068 arp_iop->nwa_flags |= NWAF_DEAD;
1069 if (ce->ac_flags & ACF_PERM)
1070 arp_iop->nwa_flags |= NWAF_PERM;
1071 if (ce->ac_flags & ACF_PUB)
1072 arp_iop->nwa_flags |= NWAF_PUB;
1073
1074 result= (*put_userdata)(fd, 0, data, TRUE);
1075 return result;
1076
1077 case NWIOARPSIP:
1078 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
1079 if (data == NULL)
1080 return EFAULT;
1081 data= bf_packIffLess(data, sizeof(*arp_iop));
1082 arp_iop= (nwio_arp_t *)ptr2acc_data(data);
1083 ipaddr= arp_iop->nwa_ipaddr;
1084 if (find_cache_ent(arp_port, ipaddr))
1085 {
1086 bf_afree(data);
1087 return EEXIST;
1088 }
1089
1090 flags= arp_iop->nwa_flags;
1091 ac_flags= ACF_EMPTY;
1092 if (flags & NWAF_PERM)
1093 ac_flags |= ACF_PERM;
1094 if (flags & NWAF_PUB)
1095 ac_flags |= ACF_PUB|ACF_PERM;
1096
1097 /* Allocate a cache entry */
1098 ce= alloc_cache_ent(ac_flags);
1099 if (ce == NULL)
1100 {
1101 bf_afree(data);
1102 return ENOMEM;
1103 }
1104
1105 ce->ac_flags= ac_flags;
1106 ce->ac_state= ACS_VALID;
1107 ce->ac_ethaddr= arp_iop->nwa_ethaddr;
1108 ce->ac_ipaddr= arp_iop->nwa_ipaddr;
1109 ce->ac_port= arp_port;
1110
1111 curr_time= get_time();
1112 ce->ac_expire= curr_time+ARP_EXP_TIME;
1113 ce->ac_lastuse= curr_time;
1114
1115 bf_afree(data);
1116 return 0;
1117
1118 case NWIOARPDIP:
1119 data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE);
1120 if (data == NULL)
1121 return EFAULT;
1122 data= bf_packIffLess(data, sizeof(*arp_iop));
1123 arp_iop= (nwio_arp_t *)ptr2acc_data(data);
1124 ipaddr= arp_iop->nwa_ipaddr;
1125 bf_afree(data); data= NULL;
1126 ce= find_cache_ent(arp_port, ipaddr);
1127 if (!ce)
1128 return ENOENT;
1129 if (ce->ac_state == ACS_INCOMPLETE)
1130 return EINVAL;
1131
1132 ac_flags= ce->ac_flags;
1133 if (ac_flags & ACF_PUB)
1134 {
1135 /* Make sure entry is at the end of published
1136 * entries.
1137 */
1138 for (entno= 0, cache= arp_cache;
1139 entno<arp_cache_nr; entno++, cache++)
1140 {
1141 if (cache->ac_state == ACS_UNUSED)
1142 break;
1143 if (cache->ac_flags & ACF_PUB)
1144 continue;
1145 break;
1146 }
1147 assert(cache > arp_cache);
1148 cache--;
1149 if (cache != ce)
1150 {
1151 assert(cache > ce);
1152 *ce= *cache;
1153 ce= cache;
1154 }
1155 }
1156 if (ac_flags & ACF_PERM)
1157 {
1158 /* Make sure entry is at the end of permanent
1159 * entries.
1160 */
1161 for (entno= 0, cache= arp_cache;
1162 entno<arp_cache_nr; entno++, cache++)
1163 {
1164 if (cache->ac_state == ACS_UNUSED)
1165 break;
1166 if (cache->ac_flags & ACF_PERM)
1167 continue;
1168 break;
1169 }
1170 assert(cache > arp_cache);
1171 cache--;
1172 if (cache != ce)
1173 {
1174 assert(cache > ce);
1175 *ce= *cache;
1176 ce= cache;
1177 }
1178 }
1179
1180 /* Clear entry */
1181 ce->ac_state= ACS_UNUSED;
1182
1183 return 0;
1184
1185 default:
1186 ip_panic(("arp_ioctl: unknown request 0x%lx",
1187 (unsigned long)req));
1188 }
1189 return 0;
1190}
1191
1192PRIVATE void arp_timeout (ref, timer)
1193int ref;
1194timer_t *timer;
1195{
1196 int i, port, reqind, acind;
1197 arp_port_t *arp_port;
1198 arp_cache_t *ce;
1199 struct arp_req *reqp;
1200 time_t curr_time;
1201 acc_t *data;
1202 arp46_t *arp;
1203 u16_t *p;
1204
1205 port= ref / AP_REQ_NR;
1206 reqind= ref % AP_REQ_NR;
1207
1208 assert(port >= 0 && port <eth_conf_nr);
1209 arp_port= &arp_port_table[port];
1210
1211 reqp= &arp_port->ap_req[reqind];
1212 assert (timer == &reqp->ar_timer);
1213
1214 acind= reqp->ar_entry;
1215
1216 assert(acind >= 0 && acind < arp_cache_nr);
1217 ce= &arp_cache[acind];
1218
1219 assert(ce->ac_port == arp_port);
1220 assert(ce->ac_state == ACS_INCOMPLETE);
1221
1222 if (++reqp->ar_req_count >= MAX_ARP_RETRIES)
1223 {
1224 curr_time= get_time();
1225 ce->ac_state= ACS_UNREACHABLE;
1226 ce->ac_expire= curr_time+ ARP_NOTRCH_EXP_TIME;
1227 ce->ac_lastuse= curr_time;
1228
1229 clck_untimer(&reqp->ar_timer);
1230 reqp->ar_entry= -1;
1231 client_reply(arp_port, ce->ac_ipaddr, NULL);
1232 return;
1233 }
1234
1235 data= bf_memreq(sizeof(arp46_t));
1236 arp= (arp46_t *)ptr2acc_data(data);
1237
1238 /* Clear padding */
1239 assert(sizeof(arp->a46_data.a46_dummy) % sizeof(*p) == 0);
1240 for (i= 0, p= (u16_t *)arp->a46_data.a46_dummy;
1241 i < sizeof(arp->a46_data.a46_dummy)/sizeof(*p);
1242 i++, p++)
1243 {
1244 *p= 0xdead;
1245 }
1246
1247 arp->a46_dstaddr.ea_addr[0]= 0xff;
1248 arp->a46_dstaddr.ea_addr[1]= 0xff;
1249 arp->a46_dstaddr.ea_addr[2]= 0xff;
1250 arp->a46_dstaddr.ea_addr[3]= 0xff;
1251 arp->a46_dstaddr.ea_addr[4]= 0xff;
1252 arp->a46_dstaddr.ea_addr[5]= 0xff;
1253 arp->a46_hdr= HTONS(ARP_ETHERNET);
1254 arp->a46_pro= HTONS(ETH_IP_PROTO);
1255 arp->a46_hln= 6;
1256 arp->a46_pln= 4;
1257 arp->a46_op= HTONS(ARP_REQUEST);
1258 arp->a46_sha= arp_port->ap_ethaddr;
1259 memcpy (arp->a46_spa, &arp_port->ap_ipaddr, sizeof(ipaddr_t));
1260 memset(&arp->a46_tha, '\0', sizeof(ether_addr_t));
1261 memcpy (arp->a46_tpa, &ce->ac_ipaddr, sizeof(ipaddr_t));
1262
1263 assert(data->acc_linkC == 1);
1264 data->acc_ext_link= arp_port->ap_sendlist;
1265 arp_port->ap_sendlist= data; data= NULL;
1266
1267 if (!(arp_port->ap_flags & APF_ARP_WR_IP))
1268 setup_write(arp_port);
1269
1270 clck_timer(&reqp->ar_timer, get_time() + ARP_TIMEOUT,
1271 arp_timeout, ref);
1272}
1273
1274PRIVATE void arp_buffree(priority)
1275int priority;
1276{
1277 int i;
1278 acc_t *pack, *next_pack;
1279 arp_port_t *arp_port;
1280
1281 for (i= 0, arp_port= arp_port_table; i<eth_conf_nr; i++, arp_port++)
1282 {
1283 if (priority == ARP_PRI_REC)
1284 {
1285 next_pack= arp_port->ap_reclist;
1286 while(next_pack && next_pack->acc_ext_link)
1287 {
1288 pack= next_pack;
1289 next_pack= pack->acc_ext_link;
1290 bf_afree(pack);
1291 }
1292 if (next_pack)
1293 {
1294 if (ev_in_queue(&arp_port->ap_event))
1295 {
1296 DBLOCK(1, printf(
1297 "not freeing ap_reclist, ap_event enqueued\n"));
1298 }
1299 else
1300 {
1301 bf_afree(next_pack);
1302 next_pack= NULL;
1303 }
1304 }
1305 arp_port->ap_reclist= next_pack;
1306 }
1307 if (priority == ARP_PRI_SEND)
1308 {
1309 next_pack= arp_port->ap_sendlist;
1310 while(next_pack && next_pack->acc_ext_link)
1311 {
1312 pack= next_pack;
1313 next_pack= pack->acc_ext_link;
1314 bf_afree(pack);
1315 }
1316 if (next_pack)
1317 {
1318 if (ev_in_queue(&arp_port->ap_event))
1319 {
1320 DBLOCK(1, printf(
1321 "not freeing ap_sendlist, ap_event enqueued\n"));
1322 }
1323 else
1324 {
1325 bf_afree(next_pack);
1326 next_pack= NULL;
1327 }
1328 }
1329 arp_port->ap_sendlist= next_pack;
1330 }
1331 }
1332}
1333
1334#ifdef BUF_CONSISTENCY_CHECK
1335PRIVATE void arp_bufcheck()
1336{
1337 int i;
1338 arp_port_t *arp_port;
1339 acc_t *pack;
1340
1341 for (i= 0, arp_port= arp_port_table; i<eth_conf_nr; i++, arp_port++)
1342 {
1343 for (pack= arp_port->ap_reclist; pack;
1344 pack= pack->acc_ext_link)
1345 {
1346 bf_check_acc(pack);
1347 }
1348 for (pack= arp_port->ap_sendlist; pack;
1349 pack= pack->acc_ext_link)
1350 {
1351 bf_check_acc(pack);
1352 }
1353 }
1354}
1355#endif /* BUF_CONSISTENCY_CHECK */
1356
1357/*
1358 * $PchId: arp.c,v 1.22 2005/06/28 14:15:06 philip Exp $
1359 */
Note: See TracBrowser for help on using the repository browser.