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
44struct 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
57struct 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
71struct 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
89struct arp_entry {
91 struct uip_eth_addr ethaddr;
92 uint8_t time;
93};
94
95static const struct ip64_eth_addr broadcast_ethaddr =
96 {{0xff,0xff,0xff,0xff,0xff,0xff}};
97
98static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
99
100static uint8_t arptime;
101static 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
111const uip_ipaddr_t uip_all_zeroes_addr;
112
113/*---------------------------------------------------------------------------*/
114/**
115 * Initialize the ARP module.
116 *
117 */
118/*---------------------------------------------------------------------------*/
119void
120ip64_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/*---------------------------------------------------------------------------*/
137void
138ip64_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/*---------------------------------------------------------------------------*/
155static void
156arp_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/*---------------------------------------------------------------------------*/
218uint16_t
219ip64_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/*---------------------------------------------------------------------------*/
269int
270ip64_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/*---------------------------------------------------------------------------*/
317int
318ip64_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/*---------------------------------------------------------------------------*/
379int
380ip64_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/*---------------------------------------------------------------------------*/
void * uip_appdata
Pointer to the application data in the packet buffer.
Definition: uip6.c:148
#define uip_ip4addr_cmp(addr1, addr2)
Compare two IP addresses.
Definition: uip.h:998
#define uip_ipaddr_maskcmp(addr1, addr2, mask)
Compare two IP addresses with netmasks.
Definition: uip.h:1029
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1157
#define uip_ipaddr(addr, addr0, addr1, addr2, addr3)
Construct an IP address from four bytes.
Definition: uip.h:898
#define uip_ipaddr_to_quad(a)
Convert an IP address to four bytes separated by commas.
Definition: uip.h:870
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:465
#define UIP_ARP_MAXAGE
The maximum age of ARP table entries measured in 10ths of seconds.
Definition: uipopt.h:425
#define UIP_ARPTAB_SIZE
The size of the ARP table.
Definition: uipopt.h:416
The Ethernet address.
Definition: ip64-eth.h:40
The Ethernet header.
Definition: ip64-eth.h:51
802.3 address
Definition: uip.h:126
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:116
Representation of an IP address.
Definition: uip.h:95