Contiki 3.x
ip64-arp.c
1 /*
2  * Copyright (c) 2001-2003, Adam Dunkels.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote
14  * products derived from this software without specific prior
15  * written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * This file is part of the uIP TCP/IP stack.
30  *
31  * $Id: uip_arp.c,v 1.8 2010/12/14 22:45:22 dak664 Exp $
32  *
33  */
34 
35 #include "ip64.h"
36 #include "ip64-eth.h"
37 #include "ip64-arp.h"
38 
39 #include <string.h>
40 #include <stdio.h>
41 
42 #define printf(...)
43 
44 struct arp_hdr {
45  struct ip64_eth_hdr ethhdr;
46  uint16_t hwtype;
47  uint16_t protocol;
48  uint8_t hwlen;
49  uint8_t protolen;
50  uint16_t opcode;
51  struct uip_eth_addr shwaddr;
52  uip_ip4addr_t sipaddr;
53  struct uip_eth_addr dhwaddr;
54  uip_ip4addr_t dipaddr;
55 };
56 
57 struct ethip_hdr {
58  struct ip64_eth_hdr ethhdr;
59  /* IP header. */
60  uint8_t vhl,
61  tos,
62  len[2],
63  ipid[2],
64  ipoffset[2],
65  ttl,
66  proto;
67  uint16_t ipchksum;
68  uip_ip4addr_t srcipaddr, destipaddr;
69 };
70 
71 struct ipv4_hdr {
72  /* IP header. */
73  uint8_t vhl,
74  tos,
75  len[2],
76  ipid[2],
77  ipoffset[2],
78  ttl,
79  proto;
80  uint16_t ipchksum;
81  uip_ip4addr_t srcipaddr, destipaddr;
82 };
83 
84 #define ARP_REQUEST 1
85 #define ARP_REPLY 2
86 
87 #define ARP_HWTYPE_ETH 1
88 
89 struct arp_entry {
90  uip_ip4addr_t ipaddr;
91  struct uip_eth_addr ethaddr;
92  uint8_t time;
93 };
94 
95 static const struct ip64_eth_addr broadcast_ethaddr =
96  {{0xff,0xff,0xff,0xff,0xff,0xff}};
97 static const uint16_t broadcast_ipaddr[2] = {0xffff,0xffff};
98 
99 static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
100 
101 static uint8_t arptime;
102 static uint8_t tmpage;
103 
104 #define DEBUG 0
105 #if DEBUG
106 #include <stdio.h>
107 #define PRINTF(...) printf(__VA_ARGS__)
108 #else
109 #define PRINTF(...)
110 #endif
111 
112 const uip_ipaddr_t uip_all_zeroes_addr;
113 
114 /*---------------------------------------------------------------------------*/
115 /**
116  * Initialize the ARP module.
117  *
118  */
119 /*---------------------------------------------------------------------------*/
120 void
121 ip64_arp_init(void)
122 {
123  int i;
124  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
125  memset(&arp_table[i].ipaddr, 0, 4);
126  }
127 }
128 /*---------------------------------------------------------------------------*/
129 /**
130  * Periodic ARP processing function.
131  *
132  * This function performs periodic timer processing in the ARP module
133  * and should be called at regular intervals. The recommended interval
134  * is 10 seconds between the calls.
135  *
136  */
137 /*---------------------------------------------------------------------------*/
138 void
139 ip64_arp_timer(void)
140 {
141  struct arp_entry *tabptr;
142  int i;
143 
144  ++arptime;
145  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
146  tabptr = &arp_table[i];
147  if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr) &&
148  arptime - tabptr->time >= UIP_ARP_MAXAGE) {
149  memset(&tabptr->ipaddr, 0, 4);
150  }
151  }
152 
153 }
154 
155 /*---------------------------------------------------------------------------*/
156 static void
157 arp_update(uip_ip4addr_t *ipaddr, struct uip_eth_addr *ethaddr)
158 {
159  register struct arp_entry *tabptr = arp_table;
160  int i, c;
161 
162  /* Walk through the ARP mapping table and try to find an entry to
163  update. If none is found, the IP -> MAC address mapping is
164  inserted in the ARP table. */
165  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
166  tabptr = &arp_table[i];
167 
168  /* Only check those entries that are actually in use. */
169  if(!uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
170 
171  /* Check if the source IP address of the incoming packet matches
172  the IP address in this ARP table entry. */
173  if(uip_ip4addr_cmp(ipaddr, &tabptr->ipaddr)) {
174 
175  /* An old entry found, update this and return. */
176  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
177  tabptr->time = arptime;
178 
179  return;
180  }
181  }
182  tabptr++;
183  }
184 
185  /* If we get here, no existing ARP table entry was found, so we
186  create one. */
187 
188  /* First, we try to find an unused entry in the ARP table. */
189  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
190  tabptr = &arp_table[i];
191  if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
192  break;
193  }
194  }
195 
196  /* If no unused entry is found, we try to find the oldest entry and
197  throw it away. */
198  if(i == UIP_ARPTAB_SIZE) {
199  tmpage = 0;
200  c = 0;
201  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
202  tabptr = &arp_table[i];
203  if(arptime - tabptr->time > tmpage) {
204  tmpage = arptime - tabptr->time;
205  c = i;
206  }
207  }
208  i = c;
209  tabptr = &arp_table[i];
210  }
211 
212  /* Now, i is the ARP table entry which we will fill with the new
213  information. */
214  uip_ip4addr_copy(&tabptr->ipaddr, ipaddr);
215  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
216  tabptr->time = arptime;
217 }
218 /*---------------------------------------------------------------------------*/
219 uint16_t
220 ip64_arp_arp_input(const uint8_t *packet, uint16_t packet_len)
221 {
222  struct arp_hdr *arphdr = (struct arp_hdr *)packet;
223 
224  if(packet_len < sizeof(struct arp_hdr)) {
225  printf("ip64_arp_arp_input: len too small %d\n", packet_len);
226  return 0;
227  }
228 
229  switch(arphdr->opcode) {
230  case UIP_HTONS(ARP_REQUEST):
231  /* ARP request. If it asked for our address, we send out a
232  reply. */
233  printf("ip64_arp_arp_input: request for %d.%d.%d.%d (we are %d.%d.%d.%d)\n",
234  arphdr->dipaddr.u8[0], arphdr->dipaddr.u8[1],
235  arphdr->dipaddr.u8[2], arphdr->dipaddr.u8[3],
236  ip64_get_hostaddr()->u8[0], ip64_get_hostaddr()->u8[1],
237  ip64_get_hostaddr()->u8[2], ip64_get_hostaddr()->u8[3]);
238  if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) {
239  /* First, we register the one who made the request in our ARP
240  table, since it is likely that we will do more communication
241  with this host in the future. */
242  arp_update(&arphdr->sipaddr, &arphdr->shwaddr);
243 
244  arphdr->opcode = UIP_HTONS(ARP_REPLY);
245 
246  memcpy(arphdr->dhwaddr.addr, arphdr->shwaddr.addr, 6);
247  memcpy(arphdr->shwaddr.addr, ip64_eth_addr.addr, 6);
248  memcpy(arphdr->ethhdr.src.addr, ip64_eth_addr.addr, 6);
249  memcpy(arphdr->ethhdr.dest.addr, arphdr->dhwaddr.addr, 6);
250 
251  uip_ip4addr_copy(&arphdr->dipaddr, &arphdr->sipaddr);
252  uip_ip4addr_copy(&arphdr->sipaddr, ip64_get_hostaddr());
253 
254  arphdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP);
255  return sizeof(struct arp_hdr);
256  }
257  break;
258  case UIP_HTONS(ARP_REPLY):
259  /* ARP reply. We insert or update the ARP table if it was meant
260  for us. */
261  if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) {
262  arp_update(&arphdr->sipaddr, &arphdr->shwaddr);
263  }
264  break;
265  }
266 
267  return 0;
268 }
269 /*---------------------------------------------------------------------------*/
270 int
271 ip64_arp_check_cache(const uint8_t *nlhdr)
272 {
273  struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
274  uip_ip4addr_t broadcast_addr;
275  struct arp_entry *tabptr = arp_table;
276 
277  printf("check cache %d.%d.%d.%d\n",
278  uip_ipaddr_to_quad(&ipv4_hdr->destipaddr));
279 
280  /* First check if destination is a local broadcast. */
281  uip_ipaddr(&broadcast_addr, 255,255,255,255);
282  if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) {
283  printf("Return 1\n");
284  return 1;
285  } else if(ipv4_hdr->destipaddr.u8[0] == 224) {
286  /* Multicast. */
287  return 1;
288  } else {
289  uip_ip4addr_t ipaddr;
290  int i;
291  /* Check if the destination address is on the local network. */
292  if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
293  ip64_get_hostaddr(),
294  ip64_get_netmask())) {
295  /* Destination address was not on the local network, so we need to
296  use the default router's IP address instead of the destination
297  address when determining the MAC address. */
298  uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
299  } else {
300  /* Else, we use the destination IP address. */
301  uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
302  }
303  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
304  if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) {
305  break;
306  }
307  tabptr++;
308  }
309 
310  if(i == UIP_ARPTAB_SIZE) {
311  return 0;
312  }
313  return 1;
314  }
315  return 0;
316 }
317 /*---------------------------------------------------------------------------*/
318 int
319 ip64_arp_create_ethhdr(uint8_t *llhdr, const uint8_t *nlhdr)
320 {
321  struct arp_entry *tabptr = arp_table;
322  struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
323  struct ip64_eth_hdr *ethhdr = (struct ip64_eth_hdr *)llhdr;
324  uip_ip4addr_t broadcast_addr;
325 
326  /* Find the destination IP address in the ARP table and construct
327  the Ethernet header. If the destination IP addres isn't on the
328  local network, we use the default router's IP address instead.
329 
330  If not ARP table entry is found, we overwrite the original IP
331  packet with an ARP request for the IP address. */
332 
333  /* First check if destination is a local broadcast. */
334  uip_ipaddr(&broadcast_addr, 255,255,255,255);
335  if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) {
336  memcpy(&ethhdr->dest.addr, &broadcast_ethaddr.addr, 6);
337  } else if(ipv4_hdr->destipaddr.u8[0] == 224) {
338  /* Multicast. */
339  ethhdr->dest.addr[0] = 0x01;
340  ethhdr->dest.addr[1] = 0x00;
341  ethhdr->dest.addr[2] = 0x5e;
342  ethhdr->dest.addr[3] = ipv4_hdr->destipaddr.u8[1];
343  ethhdr->dest.addr[4] = ipv4_hdr->destipaddr.u8[2];
344  ethhdr->dest.addr[5] = ipv4_hdr->destipaddr.u8[3];
345  } else {
346  uip_ip4addr_t ipaddr;
347  int i;
348  /* Check if the destination address is on the local network. */
349  if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
350  ip64_get_hostaddr(),
351  ip64_get_netmask())) {
352  /* Destination address was not on the local network, so we need to
353  use the default router's IP address instead of the destination
354  address when determining the MAC address. */
355  uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
356  } else {
357  /* Else, we use the destination IP address. */
358  uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
359  }
360  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
361  if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) {
362  break;
363  }
364  tabptr++;
365  }
366 
367  if(i == UIP_ARPTAB_SIZE) {
368  return 0;
369  }
370 
371  memcpy(ethhdr->dest.addr, tabptr->ethaddr.addr, 6);
372 
373  }
374  memcpy(ethhdr->src.addr, ip64_eth_addr.addr, 6);
375 
376  ethhdr->type = UIP_HTONS(IP64_ETH_TYPE_IP);
377  return sizeof(struct ip64_eth_hdr);
378 }
379 /*---------------------------------------------------------------------------*/
380 int
381 ip64_arp_create_arp_request(uint8_t *llhdr, const uint8_t *nlhdr)
382 {
383  struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
384  struct arp_hdr *arp_hdr = (struct arp_hdr *)llhdr;
385  uip_ip4addr_t ipaddr;
386 
387  if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
388  ip64_get_hostaddr(),
389  ip64_get_netmask())) {
390  /* Destination address was not on the local network, so we need to
391  use the default router's IP address instead of the destination
392  address when determining the MAC address. */
393  uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
394  } else {
395  /* Else, we use the destination IP address. */
396  uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
397  }
398 
399  memset(arp_hdr->ethhdr.dest.addr, 0xff, 6);
400  memset(arp_hdr->dhwaddr.addr, 0x00, 6);
401  memcpy(arp_hdr->ethhdr.src.addr, ip64_eth_addr.addr, 6);
402  memcpy(arp_hdr->shwaddr.addr, ip64_eth_addr.addr, 6);
403 
404  uip_ip4addr_copy(&arp_hdr->dipaddr, &ipaddr);
405  uip_ip4addr_copy(&arp_hdr->sipaddr, ip64_get_hostaddr());
406  arp_hdr->opcode = UIP_HTONS(ARP_REQUEST);
407  arp_hdr->hwtype = UIP_HTONS(ARP_HWTYPE_ETH);
408  arp_hdr->protocol = UIP_HTONS(IP64_ETH_TYPE_IP);
409  arp_hdr->hwlen = 6;
410  arp_hdr->protolen = 4;
411  arp_hdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP);
412 
413  uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
414 
415  return sizeof(struct arp_hdr);
416 }
417 /*---------------------------------------------------------------------------*/
The Ethernet address.
Definition: ip64-eth.h:39
#define uip_ipaddr_maskcmp(addr1, addr2, mask)
Compare two IP addresses with netmasks.
Definition: uip.h:1090
#define UIP_ARPTAB_SIZE
The size of the ARP table.
Definition: uipopt.h:532
The Ethernet header.
Definition: ip64-eth.h:50
#define uip_ip4addr_cmp(addr1, addr2)
Compare two IP addresses.
Definition: uip.h:1055
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1238
#define UIP_ARP_MAXAGE
The maximum age of ARP table entries measured in 10ths of seconds.
Definition: uipopt.h:541
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:160
Representation of an IP address.
Definition: uip.h:101
#define uip_ipaddr_to_quad(a)
Convert an IP address to four bytes separated by commas.
Definition: uip.h:927
802.3 address
Definition: uip.h:135
#define uip_ipaddr(addr, addr0, addr1, addr2, addr3)
Construct an IP address from four bytes.
Definition: uip.h:955
uip_appdata
Pointer to the application data in the packet buffer.
Definition: tcp_loader.c:74