Watt-32 tcp/ip  2.2 dev-rel.10
pcarp.c
Go to the documentation of this file.
1 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "copyrigh.h"
16 #include "wattcp.h"
17 #include "strings.h"
18 #include "language.h"
19 #include "netaddr.h"
20 #include "misc.h"
21 #include "run.h"
22 #include "timer.h"
23 #include "rs232.h"
24 #include "ip4_in.h"
25 #include "ip4_out.h"
26 #include "sock_ini.h"
27 #include "chksum.h"
28 #include "pcdbug.h"
29 #include "pctcp.h"
30 #include "pcsed.h"
31 #include "pcconfig.h"
32 #include "pcqueue.h"
33 #include "pcstat.h"
34 #include "pcicmp.h"
35 #include "pcdhcp.h"
36 #include "pcpkt.h"
37 #include "pcarp.h"
38 
39 #define DO_SORT_GATEWAYS 1
40 
41 #if defined(USE_DEBUG)
42  #define TRACE(args) do { \
43  if (arp_trace_level > 0) { \
44  if (arp_trace_level > 1) \
45  (*_printf) ("%s (%u): ", __FILE__,__LINE__); \
46  (*_printf) (" "); \
47  (*_printf) args; \
48  } \
49  } while (0)
50 
51  static const char *get_ARP_flags (WORD flg);
52  static const char *get_route_flags (WORD flg);
53 #else
54  #define TRACE(args) ((void)0)
55 #endif
56 
57 #define INET_NTOA(ip) _inet_ntoa (NULL, ip)
58 
62 #define ON_SAME_NETWORK(addr1, addr2, mask) ((addr1 & mask) == (addr2 & mask))
63 
64 
65 /* Local parameters.
66  */
67 static int arp_trace_level = 0; /* trace level for this code (>1 include file/line) */
68 static int arp_timeout = 2; /* 2 seconds ARP timeout */
69 static int arp_alive = 300; /* 5 min ARP cache lifespan */
70 static int arp_rexmit_to = 250; /* 250 milliseconds per try */
71 static BOOL dead_gw_detect = FALSE; /* Enable Dead Gateway detection */
72 static BOOL arp_gratiotous = FALSE;
73 
74 static BOOL LAN_lookup (DWORD ip, eth_address *eth);
75 static BOOL is_on_LAN (DWORD ip);
76 static void arp_daemon (void);
77 static BOOL arp_check_common (DWORD ip, eth_address *eth);
78 
82 #define DEAD_GW_TIMEOUT 10000 /* 10 sec */
83 #define GATE_TOP_OF_CACHE 8
84 
85 static int gate_top = 0; /* index into gate_list */
86 
87 static struct gate_entry gate_list [GATE_TOP_OF_CACHE];
88 
94 int W32_CALL _arp_gateways_get (const struct gate_entry **rc)
95 {
96  *rc = gate_list;
97  return (gate_top);
98 }
99 
100 #if defined(USE_DEAD_GWD)
101 
105 static WORD icmp_id = 0;
106 static WORD icmp_seq = 0;
107 
108 static int ping_gateway (DWORD host, void *eth)
109 {
110  struct ping_pkt *pkt;
111  struct ICMP_echo *icmp;
112  struct in_Header *ip;
113  int len;
114 
115  pkt = (struct ping_pkt*) _eth_formatpacket (eth, IP4_TYPE);
116  ip = &pkt->in;
117  icmp = &pkt->icmp;
118  len = sizeof (*icmp);
119  icmp_id = (WORD) set_timeout (0); /* "random" id */
120 
121  TRACE (("ping_gateway (%s)\n", INET_NTOA(host)));
122 
123  icmp->type = ICMP_ECHO;
124  icmp->code = 0;
125  icmp->index = 1;
126  icmp->identifier = icmp_id;
127  icmp->sequence = icmp_seq++;
128  icmp->checksum = 0;
129  icmp->checksum = ~CHECKSUM (icmp, len);
130 
131  return IP4_OUTPUT (ip, 0, intel(host), ICMP_PROTO, 1,
132  (BYTE)_default_tos, 0, len, NULL);
133 }
134 
135 /*
136  * This function is called once each second.
137  */
138 static void check_dead_gw (void)
139 {
140  static int i = 0;
141 
142  if (i >= gate_top)
143  i = 0;
144 
145  for ( ; i < gate_top; i++)
146  {
147  struct gate_entry *gw = gate_list + i;
148  eth_address eth;
149 
150  TRACE (("check_dead_gw (1), i %d\n", i));
151 
152  if (!is_on_LAN(gw->gate_ip))
153  continue;
154 
155  if (!LAN_lookup(gw->gate_ip,&eth))
156  {
157  TRACE (("check_dead_gw (2), IP %s\n", INET_NTOA(gw->gate_ip)));
158  continue;
159  }
160 
161  if (gw->chk_timer == 0UL || !chk_timeout(gw->chk_timer))
162  {
163  gw->chk_timer = set_timeout (DEAD_GW_TIMEOUT);
164  continue;
165  }
166 
167  if (gw->echo_pending &&
168  _chk_ping(gw->gate_ip,NULL) == (DWORD)-1)
169  {
170  TRACE (("check_dead_gw (3), i %d\n", i));
171 
172  gw->is_dead = TRUE;
173  gw->echo_pending = FALSE;
174  TRACE (("Dead default GW %s (%d) detected\n",
175  INET_NTOA(gw->gate_ip), i));
176  }
177 
178  if (ping_gateway(gw->gate_ip, eth))
179  gw->echo_pending = TRUE;
180 
181  gw->chk_timer = set_timeout (DEAD_GW_TIMEOUT);
182  return; /* only one ping per interval */
183  }
184 }
185 #endif /* USE_DEAD_GWD */
186 
187 /*
188  * Check if a mask is legal for specified address.
189  */
190 static BOOL legal_mask (DWORD mask, DWORD addr)
191 {
192 #if 1
193  ARGSUSED (addr);
194  return check_mask (mask);
195 #else
196  if (addr & ~mask) /* E.g. '10.0.0.5' AND '0.0.0.255' */
197  return (FALSE);
198  mask = intel (~mask);
199  if (mask & (mask+1))
200  return (FALSE);
201  return (TRUE);
202 #endif
203 }
204 
205 #if DO_SORT_GATEWAYS
206 
217 static int MS_CDECL compare (const struct gate_entry *a,
218  const struct gate_entry *b)
219 {
220  return (int)(a->mask - b->mask);
221 }
222 #endif
223 
247 BOOL W32_CALL _arp_add_gateway (const char *config_string, DWORD ip)
248 {
249  struct gate_entry *gw;
250  DWORD subnet = 0UL;
251  DWORD mask = 0UL;
252  int i;
253 
254  if (config_string)
255  {
256  const char *subnetp, *maskp;
257 
258  /* Get gateway IP address from string
259  */
260  ip = aton (config_string);
261  if (ip == 0)
262  return (FALSE); /* invalid */
263 
264  /* Check if optional subnet was supplied
265  */
266  subnetp = strchr (config_string, ',');
267  if (subnetp)
268  {
269  /* NB: atoi (used in aton) stops conversion when the first non-number
270  * is hit, so there is no need to manually null-terminate the string.
271  * i.e. aton ("123.123.123.123,blabla") = 123.123.123.123
272  */
273  subnet = aton (++subnetp);
274 
275  /* Check if optional mask was supplied
276  */
277  maskp = strchr (subnetp, ',');
278  if (maskp)
279  {
280  mask = aton (++maskp);
281  }
282  else /* No mask was supplied, we derive it from the supplied subnet */
283  {
284  switch (subnet >> 30)
285  {
286  case 0:
287  case 1:
288  mask = CLASS_A_ADDR;
289  break;
290  case 2:
291  mask = CLASS_B_ADDR;
292  break;
293  case 3:
294  default:
295  mask = CLASS_C_ADDR;
296  break;
297  }
298  }
299  }
300  }
301  else /* (config_string == NULL) */
302  {
303  if (ip == 0UL)
304  {
305  outsnl ("_arp_add_gateway(): Illegal router");
306  return (FALSE); /* args invalid */
307  }
308  }
309 
310  TRACE (("_arp_add_gateway (%s)\n"
311  " ip: %s, mask: %s, subnet: %s\n",
312  config_string ? config_string : "<none>",
313  INET_NTOA(ip), INET_NTOA(mask), INET_NTOA(subnet)));
314 
315  if (!legal_mask(mask,subnet))
316  {
317  outs ("Illegal mask "); outs (INET_NTOA(mask));
318  outs (" for subnet "); outsnl (INET_NTOA(subnet));
319  return (FALSE);
320  }
321 
322  /* Figure out where to put our new gateway
323  */
324  gw = NULL;
325 
326  /* Check if gateway is already is in list
327  */
328  for (i = 0; i < gate_top; i++)
329  if (gate_list[i].gate_ip == ip)
330  {
331  gw = gate_list + i;
332  break;
333  }
334 
335  /* If a 'new' gateway, we check if we have enough room and simply
336  * add it to the end of the list.
337  *
338  * There is not much point in sorting the list, as the 'whole' list is
339  * scanned when a gateway is needed. Usually there will only be 1 anyway.
340  * If we do sort, we would use plain old insert-sort and NOT quicksort,
341  * as quicksort goes O(n^2) on an already sorted list, plus it has a high
342  * overhead that especially hurts on a tiny list like this.
343  */
344  if (gw == NULL)
345  {
346  if (gate_top == DIM(gate_list)-1)
347  {
348  outsnl (_LANG("Gateway table full"));
349  return (FALSE); /* no more room */
350  }
351  gw = gate_list + gate_top;
352  gate_top++;
353  }
354 
355  /* Fill in new (or reused) entry
356  */
357  memset (gw, 0, sizeof(*gw));
358  gw->gate_ip = ip;
359  gw->mask = mask;
360  gw->subnet = subnet;
361 
362 #if DO_SORT_GATEWAYS
363  qsort ((void*)&gate_list, gate_top, sizeof(gate_list[0]),
364  (CmpFunc)compare);
365 #endif
366 
367  return (TRUE);
368 }
369 
373 void W32_CALL _arp_kill_gateways (void)
374 {
375  TRACE (("gate_top=%d, _arp_kill_gateways(), gate_top=0\n", gate_top));
376  gate_top = 0;
377 }
378 
382 BOOL W32_CALL _arp_have_default_gw (void)
383 {
384  int i, num = 0;
385 
386  for (i = 0; i < gate_top; i++)
387  if (gate_list[i].subnet == 0UL)
388  num++;
389  TRACE (("_arp_have_default_gw(), num: %d\n", num));
390  return (num > 0);
391 }
392 
393 
437 #define ARP_TOP_OF_CACHE 64
440 #define ARP_TOP_PENDING ARP_TOP_OF_CACHE
441 #define ARP_TOP_FREE arp_first_pending
442 #define ARP_TOP_DYNAMIC arp_first_free
443 #define ARP_TOP_FIXED arp_first_dynamic
444 #define ARP_FIRST_FIXED 0
445 
446 static int arp_first_pending = ARP_TOP_PENDING;
447 static int arp_first_free = 0;
448 static int arp_first_dynamic = 0;
449 
450 static struct arp_entry arp_list [ARP_TOP_OF_CACHE];
451 
455 static BOOL arp_send (const arp_Header *arp, unsigned line)
456 {
457  TRACE (("_arp_send()\n"));
458  ARGSUSED (arp);
459  return _eth_send (sizeof(*arp), NULL, __FILE__, line);
460 }
461 
462 
466 static BOOL arp_send_request (DWORD ip)
467 {
469 
470  TRACE (("_arp_send_request (%s)\n", INET_NTOA(ip)));
471 
472  arp->hwType = intel16 (_eth_get_hwtype(NULL,NULL));
473  arp->protType = IP4_TYPE;
474  arp->hwAddrLen = sizeof (eth_address);
475  arp->protoAddrLen = sizeof (ip);
476  arp->opcode = ARP_REQUEST;
477  arp->srcIPAddr = intel (my_ip_addr);
478  arp->dstIPAddr = intel (ip);
479  memcpy (arp->srcEthAddr, _eth_addr, sizeof(arp->srcEthAddr));
480  memset (arp->dstEthAddr, 0, sizeof(arp->dstEthAddr));
481  return arp_send (arp, __LINE__);
482 }
483 
484 
489 BOOL W32_CALL _arp_reply (const void *e_dst, DWORD src_ip, DWORD dst_ip)
490 {
491  arp_Header *arp;
492 
493  if (!e_dst)
494  e_dst = &_eth_brdcast;
495 
496  TRACE (("Sending ARP reply (%s [%s] -> %s [%s])\n",
497  INET_NTOA(src_ip), MAC_address(&_eth_addr),
498  INET_NTOA(dst_ip), MAC_address(e_dst)));
499 
500  arp = (arp_Header*) _eth_formatpacket (e_dst, ARP_TYPE);
501  arp->hwType = intel16 (_eth_get_hwtype(NULL,NULL));
502  arp->protType = IP4_TYPE;
503  arp->hwAddrLen = sizeof (mac_address);
504  arp->protoAddrLen = sizeof (dst_ip);
505  arp->opcode = ARP_REPLY;
506  arp->srcIPAddr = intel (src_ip);
507  arp->dstIPAddr = intel (dst_ip);
508 
509  memcpy (arp->srcEthAddr, _eth_addr, sizeof(mac_address));
510  memcpy (arp->dstEthAddr, e_dst, sizeof(mac_address));
511  return arp_send (arp, __LINE__);
512 }
513 
517 static void arp_move_entry (int to_index, int from_index)
518 {
519  memcpy (&arp_list[to_index], &arp_list[from_index], sizeof(struct arp_entry));
520 }
521 
527 int W32_CALL _arp_cache_get (const struct arp_entry **rc)
528 {
529  *rc = arp_list;
530  return DIM(arp_list);
531 }
532 
533 
540 static BOOL LAN_start_lookup (DWORD ip)
541 {
542  struct arp_entry *ae;
543  int i;
544 
545  TRACE (("LAN_start_lookup (%s)\n", INET_NTOA(ip)));
546 
547  /* Ignore if IP is already in any list section (pending, fixed, dynamic)
548  */
549  for (i = arp_first_pending; i < ARP_TOP_PENDING; i++)
550  if (arp_list[i].ip == ip)
551  return (TRUE);
552 
553  for (i = arp_first_dynamic; i < ARP_TOP_DYNAMIC; i++)
554  if (arp_list[i].ip == ip)
555  {
556  STAT (cache_stats.num_arp_hits++);
557  return (TRUE);
558  }
559 
560  for (i = ARP_FIRST_FIXED; i < ARP_TOP_FIXED; i++)
561  if (arp_list[i].ip == ip)
562  {
563  STAT (cache_stats.num_arp_hits++);
564  return (TRUE);
565  }
566 
567  /* Figure out where to put the new guy
568  */
569  if (arp_first_free < ARP_TOP_FREE) /* Do we have any free slots? */
570  {
571  /* yes, ok! */
572  }
573  else if (arp_first_dynamic < ARP_TOP_DYNAMIC) /* any dynamic entries? */
574  {
575  /* This new request is probably more important than an existing
576  * dynamic entry, so we sacrifice the top dynamic entry. It might be
577  * neater to kill the oldest entry, but all this shouldn't happen anyway.
578  * NB: Table size reallocation would go here.
579  */
580  --ARP_TOP_DYNAMIC; /* nuke top entry */
581  STAT (cache_stats.num_arp_overflow++);
582  outsnl (_LANG("ARP table overflow"));
583  }
584  else /* No more room - table is full with pending + fixed entries. */
585  {
586  outsnl (_LANG("ARP table full"));
587  STAT (cache_stats.num_arp_overflow++);
588  return (FALSE); /* failed, nothing we can do right now. */
589  }
590 
591  /* Fill new slot, send out ARP request
592  */
593  --arp_first_pending;
594  ae = arp_list + arp_first_pending;
595  ae->ip = ip;
596  ae->expiry = set_timeout (1000UL * arp_timeout);
597  ae->flags = (ARP_FLG_INUSE | ARP_FLG_PENDING);
598  ae->retransmit_to = set_timeout (arp_rexmit_to);
599 
600  STAT (cache_stats.num_arp_misses++);
601 
602  /* If request fails, we try again a little sooner
603  */
604  if (!arp_send_request(ip))
605  ae->retransmit_to = set_timeout (arp_rexmit_to / 4);
606  else ae->retransmit_to = set_timeout (arp_rexmit_to);
607 
608  return (TRUE); /* ok, new request logged */
609 }
610 
614 static BOOL LAN_lookup (DWORD ip, eth_address *eth)
615 {
616  int i;
617  BOOL rc = FALSE;
618 
619  /* Check in dynamic + fixed list section
620  */
621  for (i = ARP_FIRST_FIXED; i < ARP_TOP_DYNAMIC; i++)
622  {
623  if (arp_list[i].ip != ip)
624  continue;
625  if (eth)
626  memcpy (eth, arp_list[i].hardware, sizeof(*eth));
627  rc = TRUE;
628  break;
629  }
630  TRACE (("LAN_lookup (%s), i: %d, flg: %s, rc: %d\n",
631  INET_NTOA(ip), i, rc ? get_ARP_flags(arp_list[i].flags) : "<n/a>", rc));
632  return (rc);
633 }
634 
638 static BOOL LAN_lookup_pending (DWORD ip)
639 {
640  BOOL rc = FALSE;
641  int i;
642 
643  /* Scan pending list section
644  */
645  for (i = arp_first_pending; i < ARP_TOP_PENDING; i++)
646  if (arp_list[i].ip == ip)
647  {
648  rc = TRUE;
649  break;
650  }
651 
652  TRACE (("LAN_lookup_pending (%s), i: %d, flg: %s, rc: %d\n",
653  INET_NTOA(ip), i, rc ? get_ARP_flags(arp_list[i].flags) : "<n/a>",
654  rc));
655  return (rc);
656 }
657 
665 static void arp_check_timeouts (BOOL check_dynamic_entries)
666 {
667  struct arp_entry *ae;
668  int i, num = 0;
669 
670  /* Check pending entries for retansmit & expiry
671  */
672  for (i = arp_first_pending; i < ARP_TOP_PENDING; i++)
673  {
674  ae = arp_list + i;
675 
676  /* If entry has expired (without being resolved): kill it
677  */
678  if (chk_timeout(ae->expiry))
679  {
680  num++;
681  if (i > arp_first_pending)
682  {
683  ae->flags &= ~ARP_FLG_INUSE;
684  arp_move_entry (i--, arp_first_pending); /* fill hole */
685  arp_first_pending++;
686  continue; /* backed 'i' up a step, now re-check 'new' current entry */
687  }
688  ++arp_first_pending;
689  }
690  /* If time for a retransmission: do it & restart timeout
691  */
692  else if (chk_timeout(ae->retransmit_to))
693  {
694  /* If request fails, we try again a little sooner
695  */
697  arp_rexmit_to : arp_rexmit_to / 4);
698  }
699  }
700 
701  /* Check dynamic entries for expiry
702  */
703  if (!check_dynamic_entries)
704  goto quit;
705 
706  for (i = arp_first_dynamic; i < ARP_TOP_DYNAMIC; i++)
707  {
708  ae = arp_list + i;
709 
710  if (chk_timeout(ae->expiry)) /* entry has expired: kill it */
711  {
712  if (i < --ARP_TOP_DYNAMIC)
713  {
714  ae->flags &= ~ARP_FLG_INUSE;
715  num++;
716  arp_move_entry (i--, ARP_TOP_DYNAMIC); /* fill hole */
717  /* backed 'i' up a step, now re-check 'new' current entry */
718  }
719  }
720  }
721 
722 quit:
723  TRACE (("arp_check_timeouts (%d), num expired/rechecked: %d\n", check_dynamic_entries, num));
724 }
725 
726 
731 /* Routing table internal structure:
732  * \verbatim
733  *
734  * Index pointers Route cache table
735  * -------------- -----------------
736  *
737  * (top_of_cache) ->
738  * (= top_pending) ----------------------
739  * | ...
740  * | PENDING ROUTE ENTRIES (ARPing gateway - no reply yet)
741  * first_pending -> | ... grow downwards (into free slots)
742  * (= top_free) ----------------------
743  * | ...
744  * | ...
745  * | FREE SLOTS
746  * | ...
747  * first_free ----> | ...
748  * (= top_dynamic) ----------------------
749  * | ... grow upwards (into free slots)
750  * | ...
751  * | "DYNAMIC" ROUTE ENTRIES
752  * first_dynamic -> | ...
753  * ----------------------
754  * \endverbatim
755  *
756  * \note
757  * - "Top" means last entry + 1.
758  * - The entries inside each section are not ordered in any way.
759  * - The route cache only holds entries of hosts that are OUTSIDE of our LAN.
760  * - The entries time-out when the gateways ARP cache entry times out.
761  *
762  * \note
763  * Although we don't support multiple physical interfaces, we support
764  * multiple gateways connected to our interface.
765  */
766 
767 #define ROUTE_TOP_OF_CACHE 32
768 #define ROUTE_TOP_PENDING ROUTE_TOP_OF_CACHE
769 #define route_top_free route_first_pending
770 #define route_top_dynamic route_first_free
771 #define ROUTE_FIRST_DYNAMIC 0
772 
773 static int route_first_pending = ROUTE_TOP_PENDING;
774 static int route_first_free = 0;
775 
776 static struct route_entry route_list [ROUTE_TOP_OF_CACHE];
777 
778 static void route_move_entry (int to_index, int from_index)
779 {
780  memcpy (&route_list[to_index], &route_list[from_index], /* never overlapping mem-area */
781  sizeof(route_list[0]));
782 }
783 
784 static BOOL route_make_new_slot (DWORD host_ip, DWORD gate_ip, DWORD mask)
785 {
786  struct route_entry *re;
787 
788  /* We assume IP was already checked for, otherwise we would add it twice.
789  * Check where we have room.
790  */
791  if (route_first_free < route_top_free)
792  {
793  /* Ok, free slots available */
794  }
795  else if (ROUTE_FIRST_DYNAMIC < route_top_dynamic)
796  {
797  /* Slaughter first dynamic entry, as new entry probably is more important
798  */
799  if (ROUTE_FIRST_DYNAMIC < --route_top_dynamic)
800  route_move_entry (ROUTE_FIRST_DYNAMIC, route_top_dynamic);
801  outsnl (_LANG("Route table overflow"));
802  }
803  else
804  {
805  outsnl (_LANG("Route table full"));
806  return (FALSE); /* Nothing we can do - list is full of pending entries */
807  }
808 
809  /* Put the new entry in
810  */
811  --route_first_pending;
812  re = route_list + route_first_pending;
813  re->host_ip = host_ip; /* when connection to this host ... */
814  re->gate_ip = gate_ip; /* ... use this gateway */
815  re->mask = mask; /* remember the mask */
816  re->flags = (ROUTE_FLG_USED | ROUTE_FLG_PENDING);
817 
818  TRACE (("route_make_new_slot(): added host %s, GW %s, mask %s at index %d\n",
819  INET_NTOA(host_ip), INET_NTOA(gate_ip), INET_NTOA(mask), route_first_pending));
820  return (TRUE);
821 }
822 
826 static BOOL is_on_LAN (DWORD ip)
827 {
828 #if 1
829  return (((ip ^ my_ip_addr) & sin_mask) == 0);
830 #else
831  return (ip && sin_mask && ((ip ^ my_ip_addr) & sin_mask) == 0);
832 #endif
833 
834 }
835 
843 BOOL W32_CALL _arp_register (DWORD use_this_gateway_ip, DWORD for_this_host_ip)
844 {
845  int i;
846 
847  TRACE (("_arp_register (%s, %s)\n",
848  INET_NTOA(use_this_gateway_ip),
849  INET_NTOA(for_this_host_ip)));
850 
851  /* Only makes sense if ("old") host is outside of our LAN,
852  * and ("new") gateway is on LAN.
853  */
854  if (!is_on_LAN(use_this_gateway_ip) || is_on_LAN(for_this_host_ip))
855  return (FALSE);
856 
857  /* See if this guy is in our dynamic table
858  */
859  for (i = ROUTE_FIRST_DYNAMIC; i < route_top_dynamic; i++)
860  {
861  struct route_entry *re = route_list + i;
862 
863  if (re->host_ip != for_this_host_ip)
864  continue;
865 
866  if (re->gate_ip == use_this_gateway_ip)
867  return (TRUE); /* Already done */
868 
869  if (LAN_lookup(use_this_gateway_ip, NULL))
870  {
871  re->gate_ip = use_this_gateway_ip;
872  return (TRUE); /* New gateway is already in ARP cache, done */
873  }
874 
875  if (!LAN_start_lookup(use_this_gateway_ip))
876  {
877  outsnl (_LANG ("Unable to add redirect to ARP cache"));
878  return (FALSE); /* ARP table full */
879  }
880 
881  /* Kill 'old' dynamic entry, fill hole
882  */
883  if (i < --route_top_dynamic)
884  route_move_entry (i, route_top_dynamic);
885 
886  /* Add new request, the new dynamic slot will be created when the
887  * gateway ARP reply comes
888  */
889  return route_make_new_slot (use_this_gateway_ip, for_this_host_ip, sin_mask);
890  }
891 
892  /* Note: We do not check the pending section, as the gateway sending
893  * the redirect could not really know the best route to a host that
894  * we have not yet even started to connect to. Redirects referring
895  * to a pending entry could be some sort of redirect attack.
896  */
897  return (FALSE);
898 }
899 
903 static BOOL route_lookup (DWORD ip, eth_address *eth)
904 {
905  BOOL rc = FALSE;
906  int i;
907 
908  TRACE (("route_lookup (%s), ROUTE_FIRST_DYNAMIC: %d, route_top_dynamic: %d\n",
909  INET_NTOA(ip), ROUTE_FIRST_DYNAMIC, route_top_dynamic));
910 
911  /* 1st, we need to find the gateway entry for the specified host
912  * in our route table
913  */
914  for (i = ROUTE_FIRST_DYNAMIC; i < route_top_dynamic; i++)
915  {
916  struct route_entry *re = route_list + i;
917  BOOL same_net = ON_SAME_NETWORK (ip, re->host_ip, re->mask);
918 
919  TRACE ((" route_list[%d]: gate_ip %s, host_ip: %s, ON_SAME_NETWORK: %d\n",
920  i, INET_NTOA(re->gate_ip), INET_NTOA(re->host_ip), same_net));
921 
922  if (re->host_ip != ip && !same_net) // !!
923  continue;
924 
925  /* 2nd, the gateway needs to be in the ARP table
926  */
927  re->flags |= ROUTE_FLG_PENDING;
928  rc = LAN_lookup (re->gate_ip, eth);
929  if (rc)
930  re->flags &= ~ROUTE_FLG_PENDING;
931  break;
932  }
933  TRACE ((" rc: %d\n", rc));
934  return (rc);
935 }
936 
941 static BOOL route_lookup_pending (DWORD ip)
942 {
943  const struct route_entry *re = NULL;
944  BOOL rc = FALSE;
945  int i = 0;
946 
947  /* Scan our pending list for the supplied IP
948  */
949  for (i = route_first_pending; i < ROUTE_TOP_PENDING; i++)
950  {
951  re = route_list + i;
952  if (re->host_ip == ip)
953  {
954  rc = TRUE;
955  break;
956  }
957  }
958  TRACE (("route_lookup_pending (%s), idx: %d, rc: %d, re->flags: %s\n",
959  INET_NTOA(ip), i, rc, rc ? get_route_flags(re->flags) : "<n/a>"));
960  return (rc);
961 }
962 
966 static BOOL route_start_lookup (DWORD ip)
967 {
968  DWORD first_gate_ip;
969  DWORD first_gate_mask;
970  int i;
971 
972  TRACE (("route_start_lookup (%s), gate_top: %d\n", INET_NTOA(ip), gate_top));
973 
974  /* Check if we already have an entry anywhere for this host
975  */
976  for (i = route_first_pending; i < ROUTE_TOP_PENDING; i++)
977  if (route_list[i].host_ip == ip)
978  return (TRUE); /* Already here */
979 
980  for (i = ROUTE_FIRST_DYNAMIC; i < route_top_dynamic; i++)
981  if (route_list[i].host_ip == ip)
982  return (TRUE); /* Already here */
983 
984  /* Abort if we don't have any gateways
985  */
986  if (gate_top <= 0)
987  {
988  outsnl (_LANG ("No gateways defined."));
989  return (FALSE);
990  }
991 
992  /* Find the first 'fitting' gateway
993  */
994  first_gate_ip = 0; /* we remember the first gateway IP that fits */
995  first_gate_mask = 0;
996 
997  for (i = 0; i < gate_top; i++)
998  {
999  const struct gate_entry *gw = gate_list + i;
1000 
1001  TRACE ((" i %d, gw->gate_ip %s, gw->subnet %s, gw->mask %s, gw->is_dead %d\n", i,
1002  INET_NTOA(gw->gate_ip), INET_NTOA(gw->subnet),
1003  INET_NTOA(gw->mask), gw->is_dead));
1004 
1005  if (/* sin_mask != IP_BCAST_ADDR && */ !is_on_LAN(gw->gate_ip))
1006  continue;
1007 
1008  if ((gw->mask & ip) != gw->subnet) /* IP not on same subnet as gw->gate_ip */
1009  continue;
1010 
1011  if (gw->is_dead)
1012  continue;
1013 
1014  if (!LAN_start_lookup(gw->gate_ip))
1015  {
1016  outsnl (_LANG ("Unable to add gateway to ARP cache"));
1017  return (FALSE); /* ARP table full, no point in going on right now */
1018  }
1019  first_gate_ip = gw->gate_ip; /* We start with this guy */
1020  first_gate_mask = gw->mask;
1021  break;
1022  }
1023 
1024  /* Abort if we didn't find anybody at all to ARP, or all ARPs failed
1025  */
1026  if (first_gate_ip == 0)
1027  {
1028  outsnl (_LANG ("No matching gateway"));
1029  return (FALSE);
1030  }
1031 
1032  /* Create a new route cache slot with our guy
1033  */
1034  route_make_new_slot (ip, first_gate_ip, first_gate_mask);
1035  return (TRUE);
1036 }
1037 
1038 
1046 static void route_check_timeouts (BOOL check_dynamic_entries)
1047 {
1048  struct route_entry *re, temp;
1049  int i, j;
1050 
1051  /* Check our pending entries
1052  */
1053  for (i = route_first_pending; i < ROUTE_TOP_PENDING; i++)
1054  {
1055  re = route_list + i;
1056 
1057  /* Was the ARP lookup able to resolve the gateway IP?
1058  */
1059  if (LAN_lookup(re->gate_ip, NULL))
1060  {
1061  /* Success - move route entry from pending to dynamic list
1062  */
1063  temp = *re; /* Make a copy so we can safely delete the pending entry */
1064  if (i > route_first_pending)
1065  route_move_entry (i--, route_first_pending); /* fill hole */
1066  /* (i-- to "re"check new current entry) */
1067 
1068  temp.flags &= ~ROUTE_FLG_PENDING;
1069  ++route_first_pending; /* remove from pending list */
1070  route_list [route_top_dynamic] = temp; /* add to dynamic list */
1071  ++route_top_dynamic;
1072  }
1073  /* Is the ARP lookup still pending? -> Keep waiting
1074  */
1075  else if (LAN_lookup_pending(re->gate_ip))
1076  {
1077  /* Do nothing */
1078  }
1079  /* The ARP lookup failed, we try the next possible gateway
1080  */
1081  else
1082  {
1083  /* Find the gateway that was tried last (the one that just timed out)
1084  */
1085  BOOL found_last_gw = FALSE;
1086  BOOL found_next_gw = FALSE;
1087 
1088  for (j = 0; j < gate_top; j++)
1089  {
1090  if (gate_list[j].gate_ip != re->gate_ip)
1091  continue;
1092  found_last_gw = TRUE;
1093  break;
1094  }
1095 
1096  if (!found_last_gw)
1097  j = -1; /* If search failed, we try the first gateway "again". */
1098 
1099  /* Now we look for the next gateway that could be used
1100  */
1101  while (++j < gate_top)
1102  {
1103  const struct gate_entry *gw = gate_list + j;
1104 
1105  if (/* sin_mask != IP_BCAST_ADDR && */ !is_on_LAN(gw->gate_ip))
1106  continue;
1107 
1108  if ((gw->mask & re->host_ip) != gw->subnet)
1109  continue;
1110 
1111  if (!LAN_start_lookup(gw->gate_ip))
1112  break; /* No room in ARP table, fail */
1113 
1114  re->gate_ip = gw->gate_ip; /* Ok, now we try this gateway */
1115  found_next_gw = TRUE;
1116  break;
1117  }
1118 
1119  /* No more gateways to try, hence lookup failed, kill entry
1120  */
1121  if (!found_next_gw)
1122  {
1123  if (i > route_first_pending)
1124  route_move_entry (i--, route_first_pending); /* fill hole */
1125  ++route_first_pending;
1126  }
1127  }
1128  }
1129 
1130  if (!check_dynamic_entries)
1131  return;
1132 
1133  /* Check our dynamic list for expired entries
1134  */
1135  for (i = ROUTE_FIRST_DYNAMIC; i < route_top_dynamic; i++)
1136  {
1137  re = route_list + i;
1138  if (LAN_lookup(re->gate_ip, NULL))
1139  continue; /* Still in ARP cache - ok */
1140 
1141  /* ARP entry expired. Remove from list.
1142  */
1143  if (i < --route_top_dynamic)
1144  {
1145  route_move_entry (i--, route_top_dynamic); /* fill hole */
1146  /* (i backed up a step so 'new' slot is rechecked) */
1147  re = route_list + i;
1148  re->flags &= ~ROUTE_FLG_USED;
1149  }
1150  }
1151 }
1152 
1153 
1163 #if !defined(USE_UDP_ONLY)
1164 
1169 BOOL W32_CALL _arp_start_lookup (DWORD ip)
1170 {
1171  TRACE (("_arp_start_lookup (%s)\n", INET_NTOA(ip)));
1172 
1173  if (arp_check_common(ip,NULL))
1174  return (TRUE);
1175 
1176  if (is_on_LAN(ip))
1177  return LAN_start_lookup (ip);
1178  return route_start_lookup (ip);
1179 }
1180 
1181 
1186 BOOL W32_CALL _arp_lookup (DWORD ip, eth_address *eth)
1187 {
1188  TRACE (("_arp_lookup (%s), is_on_LAN(): %d\n",
1189  INET_NTOA(ip), is_on_LAN(ip)));
1190 
1191  if (arp_check_common(ip,eth))
1192  return (TRUE);
1193 
1194  if (is_on_LAN(ip))
1195  return LAN_lookup (ip, eth);
1196  return route_lookup (ip, eth);
1197 }
1198 
1199 
1206 BOOL W32_CALL _arp_lookup_pending (DWORD ip)
1207 {
1208  TRACE (("_arp_lookup_pending (%s)\n", INET_NTOA(ip)));
1209 
1210  if (is_on_LAN(ip))
1211  return LAN_lookup_pending (ip);
1212  return route_lookup_pending (ip);
1213 }
1214 
1219 BOOL W32_CALL _arp_lookup_fixed (DWORD ip, eth_address *eth)
1220 {
1221  int i;
1222 
1223  TRACE (("_arp_lookup_fixed (%s)\n", INET_NTOA(ip)));
1224 
1225  if (arp_check_common(ip,eth))
1226  return (TRUE);
1227 
1228  if (!is_on_LAN(ip)) /* We only have/need a LAN version */
1229  return (FALSE);
1230 
1231  /* Scan fixed table section
1232  */
1233  for (i = ARP_FIRST_FIXED; i < ARP_TOP_FIXED; i++)
1234  {
1235  if (arp_list[i].ip != ip)
1236  continue;
1237  if (eth)
1238  memcpy (eth, arp_list[i].hardware, sizeof(*eth));
1239  return (TRUE);
1240  }
1241  return (FALSE);
1242 }
1243 #endif /* USE_UDP_ONLY */
1244 
1248 static BOOL arp_check_common (DWORD ip, eth_address *eth)
1249 {
1250 #if defined(USE_DEBUG)
1251  if (arp_trace_level >= 4)
1252  {
1253  _arp_cache_dump();
1254  _arp_gateways_dump();
1255  _arp_routes_dump();
1256  }
1257 #endif
1258 
1259  STAT (cache_stats.num_arp_search++);
1260 
1261  if (_pktserial) /* A serial driver uses a null MAC */
1262  {
1263  if (eth)
1264  memset (eth, 0, sizeof(*eth));
1265  return (TRUE);
1266  }
1267  if (_ip4_is_local_addr(ip)) /* A local address uses own MAC */
1268  {
1269  if (eth)
1270  memcpy (eth, _eth_addr, sizeof(*eth));
1271  return (TRUE);
1272  }
1273  return (FALSE);
1274 }
1275 
1279 BOOL W32_CALL _arp_resolve (DWORD ip, eth_address *eth)
1280 {
1281  BOOL (*lookup) (DWORD ip, eth_address *eth);
1282  BOOL (*start_lookup) (DWORD ip);
1283  BOOL (*pending_lookup) (DWORD ip);
1284  BOOL rc = FALSE;
1285  WORD brk_mode;
1286 
1287  TRACE (("_arp_resolve (%s)\n", INET_NTOA(ip)));
1288 
1289  if (arp_check_common(ip,eth))
1290  return (TRUE);
1291 
1292  /* Quick check if we have this guy in our cache.
1293  */
1294  if (is_on_LAN(ip))
1295  {
1296  lookup = LAN_lookup;
1297  start_lookup = LAN_start_lookup;
1298  pending_lookup = LAN_lookup_pending;
1299  }
1300  else
1301  {
1302  lookup = route_lookup;
1303  start_lookup = route_start_lookup;
1304  pending_lookup = route_lookup_pending;
1305  }
1306 
1307  if ((*lookup)(ip, eth))
1308  return (TRUE); /* Ok, done */
1309 
1310  /* Put out the request for the MAC
1311  */
1312  if (!(*start_lookup)(ip))
1313  {
1314  TRACE (("%s() failed\n", (start_lookup == LAN_start_lookup) ?
1315  "LAN_start_lookup" : "route_start_lookup"));
1316  return (FALSE); /* Request failed, resolve doomed */
1317  }
1318 
1319  NEW_BREAK_MODE (brk_mode, 1);
1320 
1321  /* Now busy-wait until reply is here or timeout (or Ctrl-C)
1322  */
1323  do
1324  {
1325  tcp_tick (NULL); /* will call our daemon to timeout/retran */
1326  arp_daemon(); /* added for faster lookup */
1327 
1328  if ((*lookup)(ip, eth))
1329  {
1330  rc = TRUE;
1331  break;
1332  }
1333  WATT_YIELD();
1334 
1335  if (_watt_cbroke)
1336  {
1337  _watt_cbroke = 0;
1338  break;
1339  }
1340  }
1341  while ((*pending_lookup)(ip));
1342 
1343  OLD_BREAK_MODE (brk_mode);
1344  return (rc);
1345 }
1346 
1347 
1352 BOOL W32_CALL _arp_cache_add (DWORD ip, const void *eth, BOOL expires)
1353 {
1354  struct arp_entry *ae;
1355 
1356  TRACE (("_arp_cache_add (%s), expires: %d\n", INET_NTOA(ip), expires));
1357 
1358  if (!my_ip_addr && !expires)
1359  {
1360  /* If called from e.g. pcconfig, my_ip_addr may be 0 when using
1361  * DHCP. Allow adding fixed entries.
1362  */
1363  }
1364  else if (!is_on_LAN (ip)) /* Only makes sense if on our LAN. */
1365  return (FALSE);
1366 
1367  _arp_cache_del (ip); /* Kill it if already here somewhere */
1368 
1369  /* Now add to correct list
1370  */
1371  if (expires) /* dynamic list */
1372  {
1373  if (arp_first_free >= ARP_TOP_FREE) /* No free dynamic slots */
1374  return (FALSE);
1375 
1376  /* Fill new slot data
1377  */
1378  ae = arp_list + ARP_TOP_DYNAMIC;
1379  ARP_TOP_DYNAMIC++;
1380  ae->ip = ip;
1381  memcpy (&ae->hardware, eth, sizeof(ae->hardware));
1382  ae->expiry = set_timeout (1000UL * arp_alive);
1383  ae->flags = (ARP_FLG_INUSE | ARP_FLG_DYNAMIC);
1384  }
1385  else /* fixed list */
1386  {
1387  /* Check if we have any free slots; make room if possible
1388  */
1389  if (arp_first_free >= ARP_TOP_FREE) /* No more fixed slots? */
1390  {
1391  if (arp_first_dynamic >= ARP_TOP_DYNAMIC)
1392  return (FALSE); /* No free AND no dynamic slots! */
1393  --ARP_TOP_DYNAMIC; /* Kill the top dynamic slot to make room */
1394  }
1395 
1396  /* Roll dynamic entires up one slot to make room for the new fixed entry
1397  */
1398  if (arp_first_dynamic < ARP_TOP_DYNAMIC)
1399  arp_move_entry (ARP_TOP_DYNAMIC, arp_first_dynamic);
1400  ++ARP_TOP_DYNAMIC;
1401 
1402  /* Fill new slot data
1403  */
1404  ae = arp_list + ARP_TOP_FIXED; /* implies ++arp_first_dynamic! */
1405  ARP_TOP_FIXED++;
1406  ae->ip = ip;
1407  ae->flags = (ARP_FLG_INUSE | ARP_FLG_FIXED);
1408  memcpy (&ae->hardware, eth, sizeof(ae->hardware));
1409 
1410  CONSOLE_MSG (4, ("_arp_cache_add(): ip: %s, eth: %s, ARP_TOP_FIXED: %d, flags: %02X\n",
1411  _inet_ntoa(NULL,ip), MAC_address(eth), ARP_TOP_FIXED-1, ae->flags));
1412  }
1413  return (TRUE);
1414 }
1415 
1416 
1421 BOOL W32_CALL _arp_cache_del (DWORD ip)
1422 {
1423  struct arp_entry *ae;
1424  BOOL rc = FALSE;
1425  int i;
1426 
1427  /* Remove from dynamic list if present
1428  */
1429  for (i = arp_first_dynamic; i < ARP_TOP_DYNAMIC; i++)
1430  {
1431  ae = arp_list + i;
1432  if (ae->ip != ip)
1433  continue;
1434 
1435  if (i < --ARP_TOP_DYNAMIC)
1436  arp_move_entry (i, ARP_TOP_DYNAMIC); /* fill hole */
1437  ae->flags &= ~ARP_FLG_INUSE;
1438  rc = TRUE;
1439  goto quit;
1440  }
1441 
1442  /* Remove from fixed list if present
1443  */
1444  for (i = ARP_FIRST_FIXED; i < ARP_TOP_FIXED; i++)
1445  {
1446  ae = arp_list + i;
1447  if (ae->ip != ip)
1448  continue;
1449 
1450  if (i < --ARP_TOP_FIXED)
1451  arp_move_entry (i, ARP_TOP_FIXED); /* fill hole */
1452 
1453  /* Do we have any dynamic entries we need to roll down one slot?
1454  * arp_first_dynamic same as ARP_TOP_FIXED, already implicity
1455  * decremented above!
1456  */
1457  if (arp_first_dynamic < --ARP_TOP_DYNAMIC)
1458  arp_move_entry (arp_first_dynamic, ARP_TOP_DYNAMIC);
1459  ae->flags &= ~ARP_FLG_INUSE;
1460  rc = TRUE;
1461  goto quit;
1462  }
1463 
1464  /* Remove from pending list if present
1465  */
1466  for (i = arp_first_pending; i < ARP_TOP_PENDING; i++)
1467  {
1468  ae = arp_list + i;
1469  if (ae->ip != ip)
1470  continue;
1471 
1472  if (i > arp_first_pending)
1473  arp_move_entry (i, arp_first_pending); /* fill hole */
1474  ++arp_first_pending;
1475  ae->flags &= ~ARP_FLG_INUSE;
1476  rc = TRUE;
1477  goto quit;
1478  }
1479 
1480  /* Didn't have it in cache */
1481 
1482 quit:
1483  TRACE (("_arp_cache_del (%s). i: %d, rc: %d\n", INET_NTOA(ip), i, rc));
1484  return (rc);
1485 }
1486 
1494 static void arp_daemon (void)
1495 {
1496  static BOOL check_dynamic = TRUE;
1497  static DWORD check_dynamic_timer = 0UL;
1498 
1499  arp_check_timeouts (check_dynamic);
1500  route_check_timeouts (check_dynamic);
1501 
1502  if (check_dynamic)
1503  {
1504 #if defined(USE_DEAD_GWD) /* check dead gateways if we have >1 default GW */
1505  if (dead_gw_detect)
1506  {
1507  if (_arp_check_gateways() <= 1)
1508  dead_gw_detect = FALSE;
1509  else check_dead_gw();
1510  }
1511 #endif
1512 
1513  /* Preset check_dynamic for next call (1 sec)
1514  */
1515  check_dynamic_timer = set_timeout (1000UL);
1516  check_dynamic = FALSE;
1517  }
1518  else if (chk_timeout(check_dynamic_timer))
1519  {
1520  check_dynamic = TRUE;
1521  }
1522 }
1523 
1527 static void (W32_CALL *prev_cfg_hook) (const char*, const char*);
1528 
1529 static void W32_CALL arp_parse (const char *name, const char *value)
1530 {
1531  static const struct config_table arp_cfg[] = {
1532  { "ALIVE", ARG_ATOI, (void*)&arp_alive },
1533  { "DEAD_GW_DETECT",ARG_ATOI, (void*)&dead_gw_detect },
1534  { "GRATIOTOUS", ARG_ATOI, (void*)&arp_gratiotous },
1535  { "RETRANS_TO", ARG_ATOI, (void*)&arp_rexmit_to },
1536  { "TIMEOUT", ARG_ATOI, (void*)&arp_timeout },
1537  { "TRACE", ARG_ATOI, (void*)&arp_trace_level },
1538  { NULL, 0, NULL }
1539  };
1540  if (!parse_config_table(&arp_cfg[0], "ARP.", name, value) && prev_cfg_hook)
1541  (*prev_cfg_hook) (name, value);
1542 }
1543 
1547 void W32_CALL _arp_init (void)
1548 {
1549  DAEMON_ADD (arp_daemon);
1550 
1551  memset (&arp_list, 0, sizeof(arp_list));
1552  prev_cfg_hook = usr_init;
1553  usr_init = arp_parse;
1554 }
1555 
1556 #if defined(WIN32)
1557  #define BROADCAST_MODE() (_pkt_rxmode & RXMODE_BROADCAST)
1558 #else
1559  #define BROADCAST_MODE() (_pkt_rxmode <= RXMODE_BROADCAST)
1560 #endif
1561 
1566 BOOL W32_CALL _arp_handler (const arp_Header *ah, BOOL brdcast)
1567 {
1568  struct arp_entry *ae;
1569  const eth_address *e_src, *e_dst; /* src/dest eth-addresses */
1570  DWORD src, dst; /* src/dest IP-addresses */
1571  WORD hw_needed = intel16 (_eth_get_hwtype(NULL,NULL));
1572  BOOL to_us, do_reply = FALSE;
1573  int i;
1574 
1575  DEBUG_RX (NULL, ah);
1576 
1577  if (ah->hwType != hw_needed || /* wrong hardware type, */
1578  ah->protType != IP4_TYPE) /* or not IPv4-protocol */
1579  {
1580  TRACE (("Bogus ARP-header; hwType: %04X, protoType: %04X.\n",
1581  ah->hwAddrLen, ah->protoAddrLen));
1582  return (FALSE);
1583  }
1584 
1585  if (ah->hwAddrLen != sizeof(mac_address) ||
1586  ah->protoAddrLen != sizeof(src))
1587  {
1588  TRACE (("Bogus ARP-header; hwAddrLen: %d, protoAddrLen: %d.\n",
1589  ah->hwAddrLen, ah->protoAddrLen));
1590  return (FALSE);
1591  }
1592 
1593  src = intel (ah->srcIPAddr);
1594  dst = intel (ah->dstIPAddr);
1595 
1596  e_src = &ah->srcEthAddr;
1597  e_dst = &ah->dstEthAddr;
1598 
1599  to_us = !memcmp(&_eth_addr,MAC_DST(ah),_eth_mac_len) ||
1600  !memcmp(&_eth_addr,e_dst,_eth_mac_len);
1601 
1602  /* Does someone else want our Ethernet address?
1603  */
1604  if (ah->opcode == ARP_REQUEST)
1605  {
1606  if (_ip4_is_local_addr(dst) &&
1607  !_ip4_is_multicast(dst) &&
1608  !_ip4_is_loopback_addr(dst))
1609  do_reply = TRUE;
1610 
1611  if (!to_us && !BROADCAST_MODE())
1612  {
1613  if (src == my_ip_addr)
1614  TRACE (("Address conflict from %s [%s]\n",
1615  INET_NTOA(src), MAC_address(e_src)));
1616 
1617  /* Prevent anti-sniffers detecting us if we're not in normal rx-mode
1618  */
1619  if (memcmp(MAC_DST(ah),_eth_brdcast,sizeof(_eth_brdcast))) /* not bcast */
1620  do_reply = FALSE;
1621  }
1622 
1623  if (do_reply)
1624  _arp_reply (e_src, dst, src);
1625  }
1626 
1627  /* See if the senders IP & MAC is anything we can use
1628  */
1629 
1630  /* Is this the awaited reply to a pending entry?
1631  */
1632  for (i = arp_first_pending; i < ARP_TOP_PENDING; i++)
1633  {
1634  ae = arp_list + i;
1635  if (ah->opcode != ARP_REPLY || ae->ip != src)
1636  continue;
1637 
1638  /* Remove from pending list
1639  */
1640  if (i > arp_first_pending)
1641  arp_move_entry (i, arp_first_pending); /* fill 'hole' */
1642  ++arp_first_pending;
1643 
1644  ae->flags &= ~(ARP_FLG_INUSE | ARP_FLG_PENDING);
1645 
1646  /* fill new dynamic entry
1647  * (at least one slot is free because we just freed a pending slot)
1648  */
1649 #if 1
1650  _arp_cache_add (src, e_src, TRUE);
1651 #else
1652  ae = arp_list + ARP_TOP_DYNAMIC;
1653  ARP_TOP_DYNAMIC++;
1654  ae->ip = src;
1655  ae->flags = (ARP_FLG_INUSE | ARP_FLG_DYNAMIC);
1656  memcpy (&ae->hardware, e_src, sizeof(*e_src));
1657  ae->expiry = set_timeout (1000UL * arp_alive);
1658 #endif
1659 
1660  TRACE (("Got ARP-reply from %s [%s]. No longer pending.\n",
1661  INET_NTOA(src), MAC_address(e_src)));
1662  return (TRUE);
1663  }
1664 
1665  /* Or is this a 'refresher' of a dynamic entry?
1666  * We'll use both ARP_REQUEST and ARP_REPLY to refresh.
1667  */
1668  if (ah->opcode != ARP_REQUEST && ah->opcode != ARP_REPLY)
1669  goto quit;
1670 
1671  for (i = arp_first_dynamic; i < ARP_TOP_DYNAMIC; i++)
1672  {
1673  BOOL equal;
1674  DWORD timeout;
1675 
1676  ae = arp_list + i;
1677  if (ae->ip != src)
1678  continue;
1679 
1680  /* This could also be an 'ARP poisoning attack', where an attacker is
1681  * trying to slip us a fake MAC address.
1682  * Knowing that, we check if the MAC address has changed, and if so
1683  * prematurely expire the entry. We will re-request it when we need it.
1684  * If the MAC address is 'still' the same, we just restart the timeout.
1685  */
1686  equal = (memcmp(&ae->hardware, e_src, sizeof(*e_src)) == 0);
1687 
1688  /* if poisoned, we give the 'real guy' 500 ms grace to reclaim his MAC ;)
1689  */
1690  timeout = (equal ? (1000UL * arp_alive) : 500UL);
1691  ae->expiry = set_timeout (timeout);
1692  TRACE (("Got refreshed (%sequal) entry for %s [%s].\n",
1693  equal ? "" : "not ", INET_NTOA(src), MAC_address(e_src)));
1694  return (TRUE);
1695  }
1696 
1697  /* Add to cache if we replied.
1698  */
1699  if (do_reply)
1700  {
1701  _arp_cache_add (src, e_src, TRUE);
1702  TRACE (("Added entry for %s [%s]\n", INET_NTOA(src), MAC_address(e_src)));
1703  return (TRUE);
1704  }
1705 
1706  /* Most TCP stacks add any 'sniffed' ARP replies to their cache in case
1707  * they're needed later. But what are the odds? :)
1708  * Anyway, this could quickly fill the table with 'junk' entries on
1709  * heavily populated LANs; plus it makes us vulnerable to ARP-flooding
1710  * attacks ... so it's probably wiser to just ignore them.
1711  */
1712 
1713 quit:
1714  if (src != my_ip_addr)
1715  TRACE (("ARP-packet from %s [%s] not handled.\n",
1716  INET_NTOA(src), MAC_address(e_src)));
1717  ARGSUSED (brdcast);
1718  return (FALSE);
1719 }
1720 
1721 
1722 #if defined(USE_DHCP)
1723 
1729 BOOL W32_CALL _arp_check_own_ip (eth_address *other_guy)
1730 {
1731  DWORD save = my_ip_addr;
1732  BOOL rc;
1733 
1734  TRACE (("_arp_check_own_ip()\n"));
1735 
1736  my_ip_addr = 0;
1737  memset (other_guy, 0, sizeof(*other_guy));
1738  rc = _arp_resolve (save, other_guy);
1739  my_ip_addr = save;
1740 
1741  if (rc && memcmp(other_guy,(const void*)"\0\0\0\0\0\0",sizeof(*other_guy)))
1742  return (FALSE);
1743  return (TRUE);
1744 }
1745 #else
1746 /* \todo: Add an empty stub */
1747 #endif
1748 
1752 int W32_CALL _arp_check_gateways (void)
1753 {
1754  int i, num = 0;
1755 
1756  TRACE (("_arp_check_gateways()\n"));
1757 
1758  /* Send a gratiotous ARP. Don't if already done DHCP_arp_check().
1759  */
1760 #if defined(USE_DHCP)
1761  if (DHCP_did_gratuitous_arp)
1762  arp_gratiotous = FALSE;
1763 #endif
1764 
1765  if (arp_gratiotous)
1766  _arp_reply (NULL, my_ip_addr, IP_BCAST_ADDR);
1767 
1768  for (i = 0; i < gate_top; i++)
1769  if (gate_list[i].subnet == 0UL)
1770  num++;
1771  return (num);
1772 }
1773 
1774 #if defined(USE_DEBUG)
1775 void W32_CALL _arp_cache_dump (void)
1776 {
1777  const struct arp_entry *ae;
1778  DWORD now = set_timeout (0);
1779  int i, num = 0, max = _arp_cache_get (&ae);
1780 
1781  (*_printf) ("\nARP-cache:\n");
1782 
1783  for (i = 0; i < max; i++, ae++)
1784  {
1785  const char *remain;
1786 
1787  if (!(ae->flags & ARP_FLG_INUSE))
1788  continue;
1789 
1790  num++;
1791  if (ae->expiry)
1792  {
1793  if (ae->expiry > now)
1794  {
1795  char buf[30];
1796  sprintf (buf, "expires in %ss", time_str(ae->expiry-now));
1797  remain = buf;
1798  }
1799  else
1800  remain = "timed out";
1801  }
1802  else
1803  remain = "no expiry";
1804 
1805  (*_printf) (" IP: %-15s -> %s, %s %s\n",
1806  INET_NTOA(ae->ip), MAC_address(&ae->hardware),
1807  (ae->flags & ARP_FLG_FIXED) ? "Fixed, " :
1808  (ae->flags & ARP_FLG_DYNAMIC) ? "Dynamic," :
1809  (ae->flags & ARP_FLG_PENDING) ? "Pending," : "??, ",
1810  remain);
1811  }
1812  if (num == 0)
1813  (*_printf) (" <Empty>\n");
1814 }
1815 
1816 void W32_CALL _arp_routes_dump (void)
1817 {
1818  const struct route_entry *re = route_list;
1819  int i;
1820 
1821  (*_printf) ("\nRoutes:\n"
1822  " # GATEWAY HOST MASK FLAGS\n");
1823 
1824  for (i = 0; i < DIM(route_list); i++, re++)
1825  {
1826  if (!(re->flags & ROUTE_FLG_USED))
1827  continue;
1828  (*_printf) (" %2d %-15s %-15s %-15s %s\n",
1829  i, INET_NTOA(re->gate_ip), INET_NTOA(re->host_ip),
1830  INET_NTOA(re->mask), get_route_flags(re->flags));
1831  }
1832 }
1833 
1834 void W32_CALL _arp_gateways_dump (void)
1835 {
1836  const struct gate_entry *gw = gate_list;
1837  int i;
1838 
1839  (*_printf) ("\nGateways:\n");
1840  if (gate_top <= 0)
1841  {
1842  (*_printf) ("NONE\n");
1843  return;
1844  }
1845 
1846 #if 0
1847  (*_printf) (" GATEWAY'S IP SUBNET SUBNET MASK\n");
1848 
1849  for (i = 0 ; i < gate_top; i++, gw++)
1850  {
1851  char gate[20], subnet[20], mask[20];
1852 
1853  strcpy (gate, INET_NTOA(gw->gate_ip));
1854 
1855  if (gw->subnet)
1856  strcpy (subnet, INET_NTOA(gw->subnet));
1857  else strcpy (subnet, "0.0.0.0 (def)");
1858 
1859  if (gw->mask)
1860  strcpy (mask, INET_NTOA(gw->mask));
1861  else strcpy (mask, INET_NTOA(sin_mask)), strcat (mask," (def)");
1862 
1863  (*_printf) (" %-15s %-15s %-15s\n", gate, subnet, mask);
1864  }
1865 #else
1866 /*
1867  Print it like "nmap --iflist" does:
1868 
1869  **************************ROUTES**************************
1870  DST/MASK DEV GATEWAY
1871  255.255.255.255/32 eth1 10.0.0.6 my_ip
1872  10.0.0.6/32 lo0 127.0.0.1 loopback network
1873  10.255.255.255/32 eth1 10.0.0.6 all 1 broadcast
1874  255.255.255.255/32 eth1 10.0.0.6 directed broadcast
1875  10.0.0.0/24 eth1 10.0.0.6
1876  127.0.0.0/8 lo0 127.0.0.1
1877  224.0.0.0/4 eth1 10.0.0.6
1878  0.0.0.0/0 eth1 10.0.0.1
1879  */
1880  (*_printf) (" DEST/MASK DEV GATEWAY (MASK)\n");
1881 
1882  for (i = 0 ; i < gate_top; i++, gw++)
1883  {
1884  extern void __get_ifname (char *if_name);
1885  DWORD mask = gw->mask; // ? gw->mask : sin_mask;
1886  char *subnet = INET_NTOA(gw->subnet);
1887  char ifname[10];
1888  int padding, mlen = mask_len(mask);
1889 
1890  __get_ifname (ifname);
1891  padding = 14 - strlen(subnet);
1892  if (mlen > 9)
1893  padding--;
1894 
1895  (*_printf) (" %s/%d%*s %s %-15s (%s)\n",
1896  subnet, mlen, padding, "", ifname,
1897  INET_NTOA(gw->gate_ip), INET_NTOA(mask));
1898  }
1899 #endif
1900 }
1901 
1907 void W32_CALL _arp_debug_dump (void)
1908 {
1909  const struct arp_entry *ae;
1910  const struct gate_entry *gw;
1911  const struct route_entry *re;
1912  DWORD now = set_timeout (0UL);
1913  DWORD mask;
1914  int i;
1915 
1916  /* Gateways
1917  */
1918  if (!dbug_printf ("Gateway list:\n"))
1919  return;
1920 
1921  if (gate_top == 0)
1922  {
1923  dbug_printf (" --none--\n");
1924  }
1925  else for (i = 0; i < gate_top; i++)
1926  {
1927  gw = gate_list + i;
1928  mask = gw->mask ? gw->mask : sin_mask;
1929  dbug_printf (" #%03d: %-15s ", i, INET_NTOA(gw->gate_ip));
1930  dbug_printf ("(network: %-15s ", INET_NTOA(gw->subnet));
1931  dbug_printf ("mask: %s)\n" , INET_NTOA(mask));
1932  }
1933 
1934  /* Route table
1935  */
1936  dbug_printf ("\nRouting cache:\n"
1937  "------- top of cache -----------------------------------------------\n"
1938  " (%03d) top of pending slots ---------------------------------------\n",
1939  ROUTE_TOP_PENDING);
1940 
1941  if (route_first_pending == ROUTE_TOP_PENDING)
1942  {
1943  dbug_printf (" --none--\n");
1944  }
1945  else if (route_first_pending > ROUTE_TOP_PENDING)
1946  {
1947  dbug_printf (" INDEX ERROR!\n");
1948  }
1949  else for (i = ROUTE_TOP_PENDING-1; i >= route_first_pending; i--)
1950  {
1951  re = route_list + i;
1952  dbug_printf (" #%03d: IP: %-15s -> gateway IP %-15s\n",
1953  i, INET_NTOA(re->host_ip), INET_NTOA(re->gate_ip));
1954  }
1955 
1956  dbug_printf ("- (%03d) top of free slots ------------------------------------------\n",
1957  route_top_free);
1958 
1959  if (route_first_free == route_top_free)
1960  {
1961  dbug_printf (" --none--\n");
1962  }
1963  else if (route_first_free > route_top_free)
1964  {
1965  dbug_printf (" INDEX ERROR!\n");
1966  }
1967  else if (route_top_free - route_first_free <= 3)
1968  {
1969  for (i = route_top_free-1; i >= route_first_free; i--)
1970  dbug_printf (" #%03d: (free)\n", i);
1971  }
1972  else
1973  {
1974  dbug_printf (" #%03d: (free)\n", route_top_free-1);
1975  dbug_printf (" ... (free)\n");
1976  dbug_printf (" #%03d: (free)\n", route_first_free);
1977  }
1978 
1979  dbug_printf ("- (%03d) top of dynamic slots ---------------------------------------\n",
1980  route_top_dynamic);
1981  if (ROUTE_FIRST_DYNAMIC == route_top_dynamic)
1982  {
1983  dbug_printf (" --none--\n");
1984  }
1985  else if (ROUTE_FIRST_DYNAMIC > route_top_dynamic)
1986  {
1987  dbug_printf (" INDEX ERROR!\n");
1988  }
1989  else for (i = route_top_dynamic-1; i >= ROUTE_FIRST_DYNAMIC; i--)
1990  {
1991  re = route_list + i;
1992  dbug_printf (" #%03d: IP: %-15s -> gateway IP %-15s\n",
1993  i, INET_NTOA(re->host_ip), INET_NTOA(re->gate_ip));
1994  }
1995  dbug_printf ("------- bottom of cache --------------------------------------------\n");
1996 
1997  /* ARP table
1998  */
1999  dbug_printf ("\nARP cache:\n"
2000  "------- top of cache -----------------------------------------------\n"
2001  " (%03d) top of pending slots ---------------------------------------\n",
2002  ARP_TOP_PENDING);
2003 
2004  if (arp_first_pending == ARP_TOP_PENDING)
2005  {
2006  dbug_printf (" --none--\n");
2007  }
2008  else if (arp_first_pending > ARP_TOP_PENDING)
2009  {
2010  dbug_printf (" INDEX ERROR!\n");
2011  }
2012  else for (i = ARP_TOP_PENDING-1; i >= arp_first_pending; i--)
2013  {
2014  ae = arp_list + i;
2015  dbug_printf (" #%03d: IP: %-15s -> ??:??:??:??:??:?? expires in %ss\n",
2016  i, INET_NTOA(ae->ip), time_str(ae->expiry - now));
2017  }
2018 
2019  dbug_printf ("- (%03d) top of free slots ------------------------------------------\n",
2020  ARP_TOP_FREE);
2021  if (arp_first_free == ARP_TOP_FREE)
2022  {
2023  dbug_printf (" --none--\n");
2024  }
2025  else if (arp_first_free > ARP_TOP_FREE)
2026  {
2027  dbug_printf (" INDEX ERROR!\n");
2028  }
2029  else if (ARP_TOP_FREE - arp_first_free <= 3)
2030  {
2031  for (i = ARP_TOP_FREE-1; i >= arp_first_free; i--)
2032  dbug_printf (" #%03d: (free)\n", i);
2033  }
2034  else
2035  {
2036  dbug_printf (" #%03d: (free)\n", ARP_TOP_FREE-1);
2037  dbug_printf (" ... (free)\n");
2038  dbug_printf (" #%03d: (free)\n", arp_first_free);
2039  }
2040 
2041  dbug_printf ("- (%03d) top of dynamic slots ---------------------------------------\n",
2042  ARP_TOP_DYNAMIC);
2043  if (arp_first_dynamic == ARP_TOP_DYNAMIC)
2044  {
2045  dbug_printf (" --none--\n");
2046  }
2047  else if (arp_first_dynamic > ARP_TOP_DYNAMIC)
2048  {
2049  dbug_printf (" INDEX ERROR!\n");
2050  }
2051  else for (i = ARP_TOP_DYNAMIC-1; i >= arp_first_dynamic; i--)
2052  {
2053  ae = arp_list + i;
2054  dbug_printf (" #%03d: IP: %-15s -> %s expires in %ss\n",
2055  i, INET_NTOA(ae->ip), MAC_address(&ae->hardware),
2056  time_str(ae->expiry - now));
2057  }
2058 
2059  dbug_printf ("- (%03d) top of fixed slots -----------------------------------------\n",
2060  ARP_TOP_FIXED);
2061  if (ARP_FIRST_FIXED == ARP_TOP_FIXED)
2062  {
2063  dbug_printf (" --none--\n");
2064  }
2065  else if (ARP_FIRST_FIXED > ARP_TOP_FIXED)
2066  {
2067  dbug_printf (" INDEX ERROR!\n");
2068  }
2069  else for (i = ARP_TOP_FIXED-1; i >= ARP_FIRST_FIXED; i--)
2070  {
2071  ae = arp_list + i;
2072  dbug_printf (" #%03d: IP: %-15s -> %s\n",
2073  i, INET_NTOA(ae->ip), MAC_address(&ae->hardware));
2074  }
2075  dbug_printf ("------- bottom of cache --------------------------------------------\n");
2076 }
2077 
2078 static const char *get_ARP_flags (WORD flg)
2079 {
2080  static char buf[50];
2081  char *p;
2082 
2083  buf[0] = '\0';
2084  if (flg & ARP_FLG_INUSE)
2085  strcat (buf, "INUSE,");
2086  if (flg & ARP_FLG_PENDING)
2087  strcat (buf, "PEND,");
2088  if (flg & ARP_FLG_DYNAMIC)
2089  strcat (buf, "DYN,");
2090  if (flg & ARP_FLG_FIXED)
2091  strcat (buf, "FIXED,");
2092  p = strrchr (buf,',');
2093  if (p)
2094  *p = '\0';
2095  return (buf);
2096 }
2097 
2098 static const char *get_route_flags (WORD flg)
2099 {
2100  static char buf[50];
2101  char *p;
2102 
2103  buf[0] = '\0';
2104  if (flg & ROUTE_FLG_USED)
2105  strcat (buf, "INUSE, ");
2106  if (flg & ROUTE_FLG_PENDING)
2107  strcat (buf, "PEND, ");
2108  if (flg & ROUTE_FLG_DYNAMIC)
2109  strcat (buf, "DYN, ");
2110  if (flg & ROUTE_FLG_FIXED)
2111  strcat (buf, "FIXED,");
2112  p = strrchr (buf,',');
2113  if (p)
2114  *p = '\0';
2115  return (buf);
2116 }
2117 
2118 #else
2119  W32_CALL void W32_CALL _arp_cache_dump (void) {}
2120  W32_CALL void W32_CALL _arp_gateways_dump (void) {}
2121  W32_CALL void W32_CALL _arp_routes_dump (void) {}
2122  W32_CALL void W32_CALL _arp_debug_dump (void) {}
2123 #endif /* USE_DEBUG */
2124 
2125 
2126 /*
2127  * Find the best 'fitting' gateway for destination IP.
2128  * Return INADDR_ANY if 'ip' is directly reachable.
2129  */
2130 static DWORD route_destin (DWORD ip)
2131 {
2132  DWORD rc = 0;
2133  int i;
2134 
2135  TRACE (("route_destin (%s)\n", INET_NTOA(ip)));
2136 
2137  for (i = 0; i < gate_top; i++)
2138  {
2139  const struct gate_entry *gw = gate_list + i;
2140 
2141  TRACE ((" i %d, gw->gate_ip %s, gw->subnet %s, gw->mask %s\n"
2142  " ON_SAME_NETWORK: %d\n", i,
2143  INET_NTOA(gw->gate_ip), INET_NTOA(gw->subnet),
2144  INET_NTOA(gw->mask), ON_SAME_NETWORK(gw->subnet,ip,gw->mask)));
2145 #if 0
2146  if (sin_mask != IP_BCAST_ADDR && !is_on_LAN(gw->gate_ip))
2147  continue;
2148  if (!ON_SAME_NETWORK(gw->subnet,ip,gw->mask))
2149  continue;
2150 #else
2151  if (((ip ^ gw->subnet) & gw->mask) == 0) /* IP on same subnet as gw->gate_ip */
2152  return (gw->gate_ip);
2153 #endif
2154  }
2155 // if (rc)
2156  return (rc);
2157 // return (is_on_LAN(ip) ? INADDR_ANY : INADDR_NONE);
2158 }
2159 
2160 
2161 #if defined(TEST_PROG)
2162 
2163 #include "pcdns.h"
2164 #include "pcbuf.h"
2165 
2166 static int num_okay = 0;
2167 static int num_fail = 0;
2168 
2169 #define TEST(func, args, expect) do { \
2170  HIGH_TEXT(); \
2171  (*_printf) ("%s() ", #func); \
2172  NORM_TEXT(); \
2173  if (func args == expect) { \
2174  num_okay++; \
2175  YELLOW_TEXT(); \
2176  (*_printf) ("OK\n"); \
2177  } else { \
2178  num_fail++; \
2179  RED_TEXT(); \
2180  (*_printf) ("FAIL\n"); \
2181  } \
2182  NORM_TEXT(); \
2183  } while (0)
2184 
2185 #define TEST_EQUAL(func, args, expect) do { \
2186  int rc; \
2187  HIGH_TEXT(); \
2188  (*_printf) ("%s() ", #func); \
2189  NORM_TEXT(); \
2190  rc = func args; \
2191  if (rc == expect) { \
2192  num_okay++; \
2193  (*_printf) ("OK\n"); \
2194  } else { \
2195  num_fail++; \
2196  (*_printf) ("FAIL. Got %d\n", rc); \
2197  } \
2198  } while (0)
2199 
2200 #define TEST_ROUTE(dest) do { \
2201  DWORD ip = route_destin (aton(dest)); \
2202  HIGH_TEXT(); \
2203  (*_printf) ("Best route for %s is %s\n", \
2204  dest, INET_NTOA(ip)); \
2205  NORM_TEXT(); \
2206  } while (0)
2207 
2208 static int callback (void)
2209 {
2210  static char fan[] = "\\|/-";
2211  static int idx = 0;
2212 
2213  if (_watt_cbroke)
2214  {
2215  RED_TEXT(); (*_printf) ("^C/^Break detected\n");
2216  NORM_TEXT();
2217  exit (-1);
2218  }
2219  (*_outch) (fan[idx++]);
2220  (*_outch) ('\b');
2221  idx &= 3;
2222  return (0);
2223 }
2224 
2225 int main (int argc, char **argv)
2226 {
2227  sock_type sock;
2228  const char *host = "printer"; // "www.google.com";
2229  int status = 0;
2230  DWORD ip;
2231  char buf[1000];
2232  int len;
2233  mac_address eth2, eth1, eth3;
2234 
2235  debug_on = 0;
2236  dbug_init();
2237  sock_init();
2238 
2239 #if 0
2240 //arp_trace_level = 0;
2242 
2243  /* Gateway Subnet Mask */
2244  TEST (_arp_add_gateway, ("127.0.0.1, 127.0.0.0, 255.0.0.0", 0UL), TRUE);
2245  TEST (_arp_add_gateway, ("10.0.0.10, 10.0.0.2, 255.255.255.255", 0UL), TRUE); /* special LAN rule */
2246  TEST (_arp_add_gateway, ("10.0.0.1", 0UL), TRUE); /* default route (Class A-mask) */
2247  TEST (_arp_add_gateway, ("10.0.0.4, 162.100.102.0, 255.255.255.248", 0UL), TRUE); /* special route */
2248 
2249  arp_gateways_dump();
2250 
2251  TEST (legal_mask, (aton("255.255.255.0"), aton("127.0.0.0")), FALSE /*TRUE*/);
2252  TEST (legal_mask, (aton("128.255.255.0"), aton("127.0.0.0")), FALSE);
2253 
2254  TEST (check_mask2, ("255.255.255.128"), 1);
2255  TEST (check_mask2, ("255.255.255.127"), 0);
2256  TEST (check_mask2, ("0.0.0.1"), 0);
2257  TEST (check_mask2, ("255.255.255.2"), 0);
2258  TEST (check_mask2, ("255.255.255.254"), 1);
2259  TEST (check_mask2, ("127.255.255.255"), 0);
2260 
2261  TEST_EQUAL (mask_len, (aton("255.255.255.0")), 8);
2262  TEST_EQUAL (mask_len, (aton("255.255.0.0")), 16);
2263  TEST_EQUAL (mask_len, (aton("255.0.0.0")), 24);
2264  TEST_EQUAL (mask_len, (aton("0.0.0.0")), 32);
2265 
2266  TEST_ROUTE ("10.0.0.1");
2267  TEST_ROUTE ("10.0.0.2");
2268  TEST_ROUTE ("10.0.0.3");
2269  TEST_ROUTE ("11.0.0.1");
2270  TEST_ROUTE ("100.101.102.103");
2271  TEST_ROUTE ("162.100.102.1");
2272  TEST_ROUTE ("127.22.0.5");
2273 
2274 //arp_trace_level = 4;
2275  TEST (_arp_resolve, (aton("10.0.0.1"), &eth1), TRUE);
2276  (*_printf) (" -> %s\n", MAC_address(&eth1));
2277 
2278  TEST (_arp_resolve, (def_nameservers[0], &eth2), TRUE);
2279  (*_printf) (" -> %s\n", MAC_address(&eth2));
2280 
2281  TEST (_arp_resolve, (aton("55.44.33.22"), &eth3), TRUE);
2282  (*_printf) (" -> %s\n", MAC_address(&eth3));
2283 
2284  TEST (memcmp, (&eth1, &eth2, sizeof(eth1)), 0);
2285  TEST (memcmp, (&eth1, &eth3, sizeof(eth1)), 0);
2286 
2287  (*_printf) ("\nTEST RESULT: %d okay, %d fail\n", num_okay, num_fail);
2288 
2289  _arp_cache_dump();
2290 
2291 #else
2292  ip = lookup_host (host, NULL);
2293  if (!ip)
2294  {
2295  printf (dom_strerror(dom_errno));
2296  return (1);
2297  }
2298  if (tcp_open(&sock.tcp, 0, ip, 80, NULL))
2299  {
2300 // sock_yield (&sock.tcp, callback);
2301  sock_wait_established (&sock, sock_delay, NULL, &status);
2302  printf ("Connected. Awaiting response...");
2303  fflush (stdout);
2304  sock_puts (&sock, "GET /index.html HTTP/1.0\r\n"
2305  "User-Agent: pcarp test\r\n\r\n");
2306 
2307  while ((len = sock_read(&sock,buf,sizeof(buf))) > 0)
2308  fwrite (buf, len, 1, stdout);
2309  }
2310 sock_err:
2311  if (status == -1)
2312  printf ("Cannot connect to %s: %s\n", host, sockerr(&sock));
2313 #endif
2314 
2315  return (status);
2316 }
2317 #endif /* TEST_PROG */
static void(W32_CALL *prev_cfg_hook)(const char *
Parser for "\c ARP.xx" keywords in "\c WATTCP.CFG".
static BOOL arp_send(const arp_Header *arp, unsigned line)
Low-level ARP send function.
Definition: pcarp.c:455
int W32_CALL parse_config_table(const struct config_table *tab, const char *section, const char *name, const char *value)
Parse the config-table and if a match is found for ('section'+'.
Definition: pcconfig.c:379
void W32_CALL _arp_init(void)
Setup config-table parse function and add background ARP deamon.
Definition: pcarp.c:1547
int W32_CALL tcp_open(_tcp_Socket *s, WORD lport, DWORD ip, WORD rport, ProtoHandler handler)
Actively open a TCP connection.
Definition: pctcp.c:308
DWORD W32_CALL _chk_ping(DWORD host, DWORD *number)
Check for ICMP echo reply in ping-cache.
Definition: pcping.c:169
BOOL W32_CALL _arp_handler(const arp_Header *ah, BOOL brdcast)
Receive ARP handler.
Definition: pcarp.c:1566
mac_address _eth_brdcast
Link-layer broadcast address.
Definition: pcsed.c:51
int W32_CALL sock_read(sock_type *s, BYTE *buf, size_t maxlen)
Read a socket with maximum 'maxlen' bytes.
Definition: pctcp.c:2875
DWORD W32_CALL aton(const char *str)
Converts [a.b.c.d] or a.b.c.d to 32 bit IPv4 address.
Definition: netaddr.c:86
static BOOL route_start_lookup(DWORD ip)
Start a route lookup.
Definition: pcarp.c:966
int W32_CALL _arp_cache_get(const struct arp_entry **rc)
Return start of arp_list[].
Definition: pcarp.c:527
convert to int
Definition: tcp.h:424
int W32_CALL _arp_check_gateways(void)
Return number of default gateways.
Definition: pcarp.c:1752
WORD flags
ARP flags, see below.
Definition: pcarp.h:28
static BOOL LAN_lookup_pending(DWORD ip)
Lookup host in pending list.
Definition: pcarp.c:638
BOOL W32_CALL _arp_cache_add(DWORD ip, const void *eth, BOOL expires)
Add given IP/Ether address to ARP-cache.
Definition: pcarp.c:1352
static void arp_daemon(void)
ARP background daemon.
Definition: pcarp.c:1494
DWORD retransmit_to
used only for re-requesting MAC while 'pending'
Definition: pcarp.h:27
BYTE W32_CALL _eth_get_hwtype(BYTE *hwtype, BYTE *hwlen)
Fill in hardware address type/length for BOOTP/DHCP packets.
Definition: pcsed.c:751
int W32_CALL sock_puts(sock_type *s, const BYTE *data)
Definition: sock_io.c:39
int W32_CALL _eth_send(WORD len, const void *sock, const char *file, unsigned line)
_eth_send() does the actual transmission once we are complete with filling the buffer.
Definition: pcsed.c:306
void W32_CALL _arp_debug_dump(void)
Debug-dump of configured gateways, route table and ARP cache.
Definition: pcarp.c:1907
BOOL W32_CALL _arp_add_gateway(const char *config_string, DWORD ip)
Add a gateway to the routing table.
Definition: pcarp.c:247
static void arp_check_timeouts(BOOL check_dynamic_entries)
Check ARP entries for timeout.
Definition: pcarp.c:665
static void arp_move_entry(int to_index, int from_index)
Move an ARP entry from from_index to to_index.
Definition: pcarp.c:517
BOOL W32_CALL _arp_check_own_ip(eth_address *other_guy)
Used by DHCP initialisation.
Definition: pcarp.c:1729
static int MS_CDECL compare(const struct gate_entry *a, const struct gate_entry *b)
Compare two entries in gateway-list.
Definition: pcarp.c:217
BOOL W32_CALL _arp_register(DWORD use_this_gateway_ip, DWORD for_this_host_ip)
Register a new host as gateway.
Definition: pcarp.c:843
DWORD expiry
'pending timeout' or 'dynamic expiry'
Definition: pcarp.h:26
static BOOL arp_send_request(DWORD ip)
Send broadcast ARP request.
Definition: pcarp.c:466
void W32_CALL _arp_kill_gateways(void)
Delete all gateways.
Definition: pcarp.c:373
volatile int _watt_cbroke
Definition: pc_cbrk.c:47
int W32_CALL _arp_gateways_get(const struct gate_entry **rc)
Return start of gate_list[].
Definition: pcarp.c:94
Core definitions.
Definition: ip_icmp.h:62
const char * MAC_address(const void *addr)
Return hexa-decimal string for an 6/7 byte MAC-address.
Definition: misc.c:963
mac_address _eth_addr
Local link-layer source address.
Definition: pcsed.c:50
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
static WORD icmp_id
Send a ping (with TTL=1) to a gateway.
Definition: pcarp.c:105
DWORD gate_ip
The IP address of gateway.
Definition: pcarp.h:12
DWORD sin_mask
our net-mask, 255.255.255.0
Definition: pctcp.c:71
static void route_check_timeouts(BOOL check_dynamic_entries)
Periodic route checker.
Definition: pcarp.c:1046
BOOL W32_CALL _arp_lookup_fixed(DWORD ip, eth_address *eth)
Lookup fixed MAC-address of 'ip'.
Definition: pcarp.c:1219
static BOOL route_lookup_pending(DWORD ip)
Returns TRUE if the lookup of the gateway (assigned to the supplied ip) is still pending.
Definition: pcarp.c:941
static BOOL arp_check_common(DWORD ip, eth_address *eth)
Common stuff for _arp_resolve() and _arp_lookup()
Definition: pcarp.c:1248
void *W32_CALL _eth_formatpacket(const void *mac_dest, WORD eth_type)
_eth_format_packet() places the next packet to be transmitted into the above link-layer output packet...
Definition: pcsed.c:135
BOOL W32_CALL _arp_lookup(DWORD ip, eth_address *eth)
Lookup MAC-address of 'ip'.
Definition: pcarp.c:1186
BYTE _eth_mac_len
Size of a MAC address.
Definition: pcsed.c:54
Definition: ip.h:67
BYTE hwAddrLen
MAC addr.
Definition: wattcp.h:511
BOOL W32_CALL _arp_lookup_pending(DWORD ip)
An ARP-lookup timeout check.
Definition: pcarp.c:1206
BOOL W32_CALL _arp_have_default_gw(void)
Check if we have at least one default gateway.
Definition: pcarp.c:382
BOOL W32_CALL _arp_start_lookup(DWORD ip)
"PUBLIC" ARP/ROUTE FUNCTIONS.
Definition: pcarp.c:1169
BOOL _pktserial
using serial driver, SLIP/PPP
Definition: pcpkt.c:54
BOOL W32_CALL _arp_cache_del(DWORD ip)
Delete given 'ip' address from ARP-cache (dynamic, fixed or pending).
Definition: pcarp.c:1421
DWORD ip
IP address of ARP entry.
Definition: pcarp.h:24
DWORD subnet
The subnet mask of gateway.
Definition: pcarp.h:13
const char *W32_CALL dom_strerror(int err)
Return text for error code (dom_errno).
Definition: pcdns.c:746
Definition: pcarp.h:23
BOOL W32_CALL _arp_reply(const void *e_dst, DWORD src_ip, DWORD dst_ip)
Send unicast/broadcast ARP reply.
Definition: pcarp.c:489
static BOOL route_lookup(DWORD ip, eth_address *eth)
Gets MAC of gateway needed to reach the given host.
Definition: pcarp.c:903
DWORD my_ip_addr
our IP address
Definition: pctcp.c:70
static BOOL is_on_LAN(DWORD ip)
This should probably go into route.c.
Definition: pcarp.c:826
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
BOOL W32_CALL _arp_resolve(DWORD ip, eth_address *eth)
The blocking lookup function visible to higher functions.
Definition: pcarp.c:1279
static BOOL LAN_start_lookup(DWORD ip)
Start a host lookup on the LAN.
Definition: pcarp.c:540
Definition: pcarp.h:43
Definition: ah.h:48
Definition: pcarp.h:11
static BOOL LAN_lookup(DWORD ip, eth_address *eth)
Lookup host in fixed/dynamic list.
Definition: pcarp.c:614
eth_address hardware
MAC address of ARP entry.
Definition: pcarp.h:25
char *W32_CALL _inet_ntoa(char *s, DWORD ip)
Convert an IP-address 'ip' into a string.
Definition: netaddr.c:43
BOOL W32_CALL chk_timeout(DWORD value)
Check if milli-sec value has expired:
Definition: timer.c:547
BYTE protoAddrLen
IP addr.
Definition: wattcp.h:512
BYTE _default_tos
Definition: ip4_out.c:53
DWORD mask
The netmask fgor the above entry.
Definition: pcarp.h:14
int main(int argc, char **argv)
Definition: echo.c:223