Contiki-NG
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/ip64.h"
36 #include "ip64/ip64-eth.h"
37 #include "ip64/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 {
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 
98 static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
99 
100 static uint8_t arptime;
101 static uint8_t tmpage;
102 
103 #define DEBUG 0
104 #if DEBUG
105 #include <stdio.h>
106 #define PRINTF(...) printf(__VA_ARGS__)
107 #else
108 #define PRINTF(...)
109 #endif
110 
111 const uip_ipaddr_t uip_all_zeroes_addr;
112 
113 /*---------------------------------------------------------------------------*/
114 /**
115  * Initialize the ARP module.
116  *
117  */
118 /*---------------------------------------------------------------------------*/
119 void
120 ip64_arp_init(void)
121 {
122  int i;
123  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
124  memset(&arp_table[i].ipaddr, 0, 4);
125  }
126 }
127 /*---------------------------------------------------------------------------*/
128 /**
129  * Periodic ARP processing function.
130  *
131  * This function performs periodic timer processing in the ARP module
132  * and should be called at regular intervals. The recommended interval
133  * is 10 seconds between the calls.
134  *
135  */
136 /*---------------------------------------------------------------------------*/
137 void
138 ip64_arp_timer(void)
139 {
140  struct arp_entry *tabptr;
141  int i;
142 
143  ++arptime;
144  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
145  tabptr = &arp_table[i];
146  if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr) &&
147  arptime - tabptr->time >= UIP_ARP_MAXAGE) {
148  memset(&tabptr->ipaddr, 0, 4);
149  }
150  }
151 
152 }
153 
154 /*---------------------------------------------------------------------------*/
155 static void
156 arp_update(uip_ip4addr_t *ipaddr, struct uip_eth_addr *ethaddr)
157 {
158  register struct arp_entry *tabptr = arp_table;
159  int i, c;
160 
161  /* Walk through the ARP mapping table and try to find an entry to
162  update. If none is found, the IP -> MAC address mapping is
163  inserted in the ARP table. */
164  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
165  tabptr = &arp_table[i];
166 
167  /* Only check those entries that are actually in use. */
168  if(!uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
169 
170  /* Check if the source IP address of the incoming packet matches
171  the IP address in this ARP table entry. */
172  if(uip_ip4addr_cmp(ipaddr, &tabptr->ipaddr)) {
173 
174  /* An old entry found, update this and return. */
175  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
176  tabptr->time = arptime;
177 
178  return;
179  }
180  }
181  tabptr++;
182  }
183 
184  /* If we get here, no existing ARP table entry was found, so we
185  create one. */
186 
187  /* First, we try to find an unused entry in the ARP table. */
188  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
189  tabptr = &arp_table[i];
190  if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
191  break;
192  }
193  }
194 
195  /* If no unused entry is found, we try to find the oldest entry and
196  throw it away. */
197  if(i == UIP_ARPTAB_SIZE) {
198  tmpage = 0;
199  c = 0;
200  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
201  tabptr = &arp_table[i];
202  if(arptime - tabptr->time > tmpage) {
203  tmpage = arptime - tabptr->time;
204  c = i;
205  }
206  }
207  i = c;
208  tabptr = &arp_table[i];
209  }
210 
211  /* Now, i is the ARP table entry which we will fill with the new
212  information. */
213  uip_ip4addr_copy(&tabptr->ipaddr, ipaddr);
214  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
215  tabptr->time = arptime;
216 }
217 /*---------------------------------------------------------------------------*/
218 uint16_t
219 ip64_arp_arp_input(const uint8_t *packet, uint16_t packet_len)
220 {
221  struct arp_hdr *arphdr = (struct arp_hdr *)packet;
222 
223  if(packet_len < sizeof(struct arp_hdr)) {
224  printf("ip64_arp_arp_input: len too small %d\n", packet_len);
225  return 0;
226  }
227 
228  switch(arphdr->opcode) {
229  case UIP_HTONS(ARP_REQUEST):
230  /* ARP request. If it asked for our address, we send out a
231  reply. */
232  printf("ip64_arp_arp_input: request for %d.%d.%d.%d (we are %d.%d.%d.%d)\n",
233  arphdr->dipaddr.u8[0], arphdr->dipaddr.u8[1],
234  arphdr->dipaddr.u8[2], arphdr->dipaddr.u8[3],
235  ip64_get_hostaddr()->u8[0], ip64_get_hostaddr()->u8[1],
236  ip64_get_hostaddr()->u8[2], ip64_get_hostaddr()->u8[3]);
237  if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) {
238  /* First, we register the one who made the request in our ARP
239  table, since it is likely that we will do more communication
240  with this host in the future. */
241  arp_update(&arphdr->sipaddr, &arphdr->shwaddr);
242 
243  arphdr->opcode = UIP_HTONS(ARP_REPLY);
244 
245  memcpy(arphdr->dhwaddr.addr, arphdr->shwaddr.addr, 6);
246  memcpy(arphdr->shwaddr.addr, ip64_eth_addr.addr, 6);
247  memcpy(arphdr->ethhdr.src.addr, ip64_eth_addr.addr, 6);
248  memcpy(arphdr->ethhdr.dest.addr, arphdr->dhwaddr.addr, 6);
249 
250  uip_ip4addr_copy(&arphdr->dipaddr, &arphdr->sipaddr);
251  uip_ip4addr_copy(&arphdr->sipaddr, ip64_get_hostaddr());
252 
253  arphdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP);
254  return sizeof(struct arp_hdr);
255  }
256  break;
257  case UIP_HTONS(ARP_REPLY):
258  /* ARP reply. We insert or update the ARP table if it was meant
259  for us. */
260  if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) {
261  arp_update(&arphdr->sipaddr, &arphdr->shwaddr);
262  }
263  break;
264  }
265 
266  return 0;
267 }
268 /*---------------------------------------------------------------------------*/
269 int
270 ip64_arp_check_cache(const uint8_t *nlhdr)
271 {
272  struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
273  uip_ip4addr_t broadcast_addr;
274  struct arp_entry *tabptr = arp_table;
275 
276  printf("check cache %d.%d.%d.%d\n",
277  uip_ipaddr_to_quad(&ipv4_hdr->destipaddr));
278 
279  /* First check if destination is a local broadcast. */
280  uip_ipaddr(&broadcast_addr, 255,255,255,255);
281  if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) {
282  printf("Return 1\n");
283  return 1;
284  } else if(ipv4_hdr->destipaddr.u8[0] == 224) {
285  /* Multicast. */
286  return 1;
287  } else {
289  int i;
290  /* Check if the destination address is on the local network. */
291  if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
292  ip64_get_hostaddr(),
293  ip64_get_netmask())) {
294  /* Destination address was not on the local network, so we need to
295  use the default router's IP address instead of the destination
296  address when determining the MAC address. */
297  uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
298  } else {
299  /* Else, we use the destination IP address. */
300  uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
301  }
302  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
303  if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) {
304  break;
305  }
306  tabptr++;
307  }
308 
309  if(i == UIP_ARPTAB_SIZE) {
310  return 0;
311  }
312  return 1;
313  }
314  return 0;
315 }
316 /*---------------------------------------------------------------------------*/
317 int
318 ip64_arp_create_ethhdr(uint8_t *llhdr, const uint8_t *nlhdr)
319 {
320  struct arp_entry *tabptr = arp_table;
321  struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
322  struct ip64_eth_hdr *ethhdr = (struct ip64_eth_hdr *)llhdr;
323  uip_ip4addr_t broadcast_addr;
324 
325  /* Find the destination IP address in the ARP table and construct
326  the Ethernet header. If the destination IP addres isn't on the
327  local network, we use the default router's IP address instead.
328 
329  If not ARP table entry is found, we overwrite the original IP
330  packet with an ARP request for the IP address. */
331 
332  /* First check if destination is a local broadcast. */
333  uip_ipaddr(&broadcast_addr, 255,255,255,255);
334  if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) {
335  memcpy(&ethhdr->dest.addr, &broadcast_ethaddr.addr, 6);
336  } else if(ipv4_hdr->destipaddr.u8[0] == 224) {
337  /* Multicast. */
338  ethhdr->dest.addr[0] = 0x01;
339  ethhdr->dest.addr[1] = 0x00;
340  ethhdr->dest.addr[2] = 0x5e;
341  ethhdr->dest.addr[3] = ipv4_hdr->destipaddr.u8[1];
342  ethhdr->dest.addr[4] = ipv4_hdr->destipaddr.u8[2];
343  ethhdr->dest.addr[5] = ipv4_hdr->destipaddr.u8[3];
344  } else {
346  int i;
347  /* Check if the destination address is on the local network. */
348  if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
349  ip64_get_hostaddr(),
350  ip64_get_netmask())) {
351  /* Destination address was not on the local network, so we need to
352  use the default router's IP address instead of the destination
353  address when determining the MAC address. */
354  uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
355  } else {
356  /* Else, we use the destination IP address. */
357  uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
358  }
359  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
360  if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) {
361  break;
362  }
363  tabptr++;
364  }
365 
366  if(i == UIP_ARPTAB_SIZE) {
367  return 0;
368  }
369 
370  memcpy(ethhdr->dest.addr, tabptr->ethaddr.addr, 6);
371 
372  }
373  memcpy(ethhdr->src.addr, ip64_eth_addr.addr, 6);
374 
375  ethhdr->type = UIP_HTONS(IP64_ETH_TYPE_IP);
376  return sizeof(struct ip64_eth_hdr);
377 }
378 /*---------------------------------------------------------------------------*/
379 int
380 ip64_arp_create_arp_request(uint8_t *llhdr, const uint8_t *nlhdr)
381 {
382  struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
383  struct arp_hdr *arp_hdr = (struct arp_hdr *)llhdr;
385 
386  if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
387  ip64_get_hostaddr(),
388  ip64_get_netmask())) {
389  /* Destination address was not on the local network, so we need to
390  use the default router's IP address instead of the destination
391  address when determining the MAC address. */
392  uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
393  } else {
394  /* Else, we use the destination IP address. */
395  uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
396  }
397 
398  memset(arp_hdr->ethhdr.dest.addr, 0xff, 6);
399  memset(arp_hdr->dhwaddr.addr, 0x00, 6);
400  memcpy(arp_hdr->ethhdr.src.addr, ip64_eth_addr.addr, 6);
401  memcpy(arp_hdr->shwaddr.addr, ip64_eth_addr.addr, 6);
402 
403  uip_ip4addr_copy(&arp_hdr->dipaddr, &ipaddr);
404  uip_ip4addr_copy(&arp_hdr->sipaddr, ip64_get_hostaddr());
405  arp_hdr->opcode = UIP_HTONS(ARP_REQUEST);
406  arp_hdr->hwtype = UIP_HTONS(ARP_HWTYPE_ETH);
407  arp_hdr->protocol = UIP_HTONS(IP64_ETH_TYPE_IP);
408  arp_hdr->hwlen = 6;
409  arp_hdr->protolen = 4;
410  arp_hdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP);
411 
412  uip_appdata = &uip_buf[UIP_IPTCPH_LEN];
413 
414  return sizeof(struct arp_hdr);
415 }
416 /*---------------------------------------------------------------------------*/
#define uip_ip4addr_cmp(addr1, addr2)
Compare two IP addresses.
Definition: uip.h:1044
#define UIP_ARP_MAXAGE
The maximum age of ARP table entries measured in 10ths of seconds.
Definition: uipopt.h:481
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:116
#define uip_ipaddr_maskcmp(addr1, addr2, mask)
Compare two IP addresses with netmasks.
Definition: uip.h:1075
The Ethernet address.
Definition: ip64-eth.h:40
#define uip_ipaddr_to_quad(a)
Convert an IP address to four bytes separated by commas.
Definition: uip.h:916
802.3 address
Definition: uip.h:126
Representation of an IP address.
Definition: uip.h:95
#define uip_ipaddr(addr, addr0, addr1, addr2, addr3)
Construct an IP address from four bytes.
Definition: uip.h:944
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:510
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1223
#define UIP_ARPTAB_SIZE
The size of the ARP table.
Definition: uipopt.h:472
The Ethernet header.
Definition: ip64-eth.h:51
void * uip_appdata
Pointer to the application data in the packet buffer.
Definition: uip6.c:148