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
41struct arp_hdr {
42 struct ip64_eth_hdr ethhdr;
43 uint16_t hwtype;
44 uint16_t protocol;
45 uint8_t hwlen;
46 uint8_t protolen;
47 uint16_t opcode;
48 struct uip_eth_addr shwaddr;
49 uip_ip4addr_t sipaddr;
50 struct uip_eth_addr dhwaddr;
51 uip_ip4addr_t dipaddr;
52};
53
54struct ethip_hdr {
55 struct ip64_eth_hdr ethhdr;
56 /* IP header. */
57 uint8_t vhl,
58 tos,
59 len[2],
60 ipid[2],
61 ipoffset[2],
62 ttl,
63 proto;
64 uint16_t ipchksum;
65 uip_ip4addr_t srcipaddr, destipaddr;
66};
67
68struct ipv4_hdr {
69 /* IP header. */
70 uint8_t vhl,
71 tos,
72 len[2],
73 ipid[2],
74 ipoffset[2],
75 ttl,
76 proto;
77 uint16_t ipchksum;
78 uip_ip4addr_t srcipaddr, destipaddr;
79};
80
81#define ARP_REQUEST 1
82#define ARP_REPLY 2
83
84#define ARP_HWTYPE_ETH 1
85
86struct arp_entry {
88 struct uip_eth_addr ethaddr;
89 uint8_t time;
90};
91
92static const struct ip64_eth_addr broadcast_ethaddr =
93 {{0xff,0xff,0xff,0xff,0xff,0xff}};
94
95static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
96
97static uint8_t arptime;
98static uint8_t tmpage;
99
100/*---------------------------------------------------------------------------*/
101
102#include "sys/log.h"
103#define LOG_MODULE "IP64"
104#define LOG_LEVEL LOG_LEVEL_IP64
105
106/*---------------------------------------------------------------------------*/
107
108const uip_ipaddr_t uip_all_zeroes_addr;
109
110/*---------------------------------------------------------------------------*/
111/**
112 * Initialize the ARP module.
113 *
114 */
115/*---------------------------------------------------------------------------*/
116void
117ip64_arp_init(void)
118{
119 int i;
120 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
121 memset(&arp_table[i].ipaddr, 0, 4);
122 }
123}
124/*---------------------------------------------------------------------------*/
125/**
126 * Periodic ARP processing function.
127 *
128 * This function performs periodic timer processing in the ARP module
129 * and should be called at regular intervals. The recommended interval
130 * is 10 seconds between the calls.
131 *
132 */
133/*---------------------------------------------------------------------------*/
134void
135ip64_arp_timer(void)
136{
137 struct arp_entry *tabptr;
138 int i;
139
140 ++arptime;
141 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
142 tabptr = &arp_table[i];
143 if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr) &&
144 arptime - tabptr->time >= UIP_ARP_MAXAGE) {
145 memset(&tabptr->ipaddr, 0, 4);
146 }
147 }
148
149}
150
151/*---------------------------------------------------------------------------*/
152static void
153arp_update(uip_ip4addr_t *ipaddr, struct uip_eth_addr *ethaddr)
154{
155 register struct arp_entry *tabptr = arp_table;
156 int i, c;
157
158 /* Walk through the ARP mapping table and try to find an entry to
159 update. If none is found, the IP -> MAC address mapping is
160 inserted in the ARP table. */
161 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
162 tabptr = &arp_table[i];
163
164 /* Only check those entries that are actually in use. */
165 if(!uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
166
167 /* Check if the source IP address of the incoming packet matches
168 the IP address in this ARP table entry. */
169 if(uip_ip4addr_cmp(ipaddr, &tabptr->ipaddr)) {
170
171 /* An old entry found, update this and return. */
172 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
173 tabptr->time = arptime;
174
175 return;
176 }
177 }
178 tabptr++;
179 }
180
181 /* If we get here, no existing ARP table entry was found, so we
182 create one. */
183
184 /* First, we try to find an unused entry in the ARP table. */
185 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
186 tabptr = &arp_table[i];
187 if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
188 break;
189 }
190 }
191
192 /* If no unused entry is found, we try to find the oldest entry and
193 throw it away. */
194 if(i == UIP_ARPTAB_SIZE) {
195 tmpage = 0;
196 c = 0;
197 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
198 tabptr = &arp_table[i];
199 if(arptime - tabptr->time > tmpage) {
200 tmpage = arptime - tabptr->time;
201 c = i;
202 }
203 }
204 i = c;
205 tabptr = &arp_table[i];
206 }
207
208 /* Now, i is the ARP table entry which we will fill with the new
209 information. */
210 uip_ip4addr_copy(&tabptr->ipaddr, ipaddr);
211 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
212 tabptr->time = arptime;
213}
214/*---------------------------------------------------------------------------*/
215uint16_t
216ip64_arp_arp_input(const uint8_t *packet, uint16_t packet_len)
217{
218 struct arp_hdr *arphdr = (struct arp_hdr *)packet;
219
220 if(packet_len < sizeof(struct arp_hdr)) {
221 LOG_WARN("ARP input: len too small %d\n", packet_len);
222 return 0;
223 }
224
225 switch(arphdr->opcode) {
226 case UIP_HTONS(ARP_REQUEST):
227 /* ARP request. If it asked for our address, we send out a
228 reply. */
229 LOG_DBG("ARP input: request for %d.%d.%d.%d (we are %d.%d.%d.%d)\n",
230 arphdr->dipaddr.u8[0], arphdr->dipaddr.u8[1],
231 arphdr->dipaddr.u8[2], arphdr->dipaddr.u8[3],
232 ip64_get_hostaddr()->u8[0], ip64_get_hostaddr()->u8[1],
233 ip64_get_hostaddr()->u8[2], ip64_get_hostaddr()->u8[3]);
234 if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) {
235 /* First, we register the one who made the request in our ARP
236 table, since it is likely that we will do more communication
237 with this host in the future. */
238 arp_update(&arphdr->sipaddr, &arphdr->shwaddr);
239
240 arphdr->opcode = UIP_HTONS(ARP_REPLY);
241
242 memcpy(arphdr->dhwaddr.addr, arphdr->shwaddr.addr, 6);
243 memcpy(arphdr->shwaddr.addr, ip64_eth_addr.addr, 6);
244 memcpy(arphdr->ethhdr.src.addr, ip64_eth_addr.addr, 6);
245 memcpy(arphdr->ethhdr.dest.addr, arphdr->dhwaddr.addr, 6);
246
247 uip_ip4addr_copy(&arphdr->dipaddr, &arphdr->sipaddr);
248 uip_ip4addr_copy(&arphdr->sipaddr, ip64_get_hostaddr());
249
250 arphdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP);
251 return sizeof(struct arp_hdr);
252 }
253 break;
254 case UIP_HTONS(ARP_REPLY):
255 /* ARP reply. We insert or update the ARP table if it was meant
256 for us. */
257 if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) {
258 arp_update(&arphdr->sipaddr, &arphdr->shwaddr);
259 }
260 break;
261 }
262
263 return 0;
264}
265/*---------------------------------------------------------------------------*/
266int
267ip64_arp_check_cache(const uint8_t *nlhdr)
268{
269 struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
270 uip_ip4addr_t broadcast_addr;
271 struct arp_entry *tabptr = arp_table;
272
273 LOG_DBG("ARP check cache %d.%d.%d.%d\n",
274 uip_ipaddr_to_quad(&ipv4_hdr->destipaddr));
275
276 /* First check if destination is a local broadcast. */
277 uip_ipaddr(&broadcast_addr, 255,255,255,255);
278 if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) {
279 LOG_DBG("ARP check return 1\n");
280 return 1;
281 } else if(ipv4_hdr->destipaddr.u8[0] == 224) {
282 /* Multicast. */
283 return 1;
284 } else {
286 int i;
287 /* Check if the destination address is on the local network. */
288 if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
289 ip64_get_hostaddr(),
290 ip64_get_netmask())) {
291 /* Destination address was not on the local network, so we need to
292 use the default router's IP address instead of the destination
293 address when determining the MAC address. */
294 uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
295 } else {
296 /* Else, we use the destination IP address. */
297 uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
298 }
299 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
300 if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) {
301 break;
302 }
303 tabptr++;
304 }
305
306 if(i == UIP_ARPTAB_SIZE) {
307 return 0;
308 }
309 return 1;
310 }
311 return 0;
312}
313/*---------------------------------------------------------------------------*/
314int
315ip64_arp_create_ethhdr(uint8_t *llhdr, const uint8_t *nlhdr)
316{
317 struct arp_entry *tabptr = arp_table;
318 struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
319 struct ip64_eth_hdr *ethhdr = (struct ip64_eth_hdr *)llhdr;
320 uip_ip4addr_t broadcast_addr;
321
322 /* Find the destination IP address in the ARP table and construct
323 the Ethernet header. If the destination IP addres isn't on the
324 local network, we use the default router's IP address instead.
325
326 If not ARP table entry is found, we overwrite the original IP
327 packet with an ARP request for the IP address. */
328
329 /* First check if destination is a local broadcast. */
330 uip_ipaddr(&broadcast_addr, 255,255,255,255);
331 if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) {
332 memcpy(&ethhdr->dest.addr, &broadcast_ethaddr.addr, 6);
333 } else if(ipv4_hdr->destipaddr.u8[0] == 224) {
334 /* Multicast. */
335 ethhdr->dest.addr[0] = 0x01;
336 ethhdr->dest.addr[1] = 0x00;
337 ethhdr->dest.addr[2] = 0x5e;
338 ethhdr->dest.addr[3] = ipv4_hdr->destipaddr.u8[1];
339 ethhdr->dest.addr[4] = ipv4_hdr->destipaddr.u8[2];
340 ethhdr->dest.addr[5] = ipv4_hdr->destipaddr.u8[3];
341 } else {
343 int i;
344 /* Check if the destination address is on the local network. */
345 if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
346 ip64_get_hostaddr(),
347 ip64_get_netmask())) {
348 /* Destination address was not on the local network, so we need to
349 use the default router's IP address instead of the destination
350 address when determining the MAC address. */
351 uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
352 } else {
353 /* Else, we use the destination IP address. */
354 uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
355 }
356 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
357 if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) {
358 break;
359 }
360 tabptr++;
361 }
362
363 if(i == UIP_ARPTAB_SIZE) {
364 return 0;
365 }
366
367 memcpy(ethhdr->dest.addr, tabptr->ethaddr.addr, 6);
368
369 }
370 memcpy(ethhdr->src.addr, ip64_eth_addr.addr, 6);
371
372 ethhdr->type = UIP_HTONS(IP64_ETH_TYPE_IP);
373 return sizeof(struct ip64_eth_hdr);
374}
375/*---------------------------------------------------------------------------*/
376int
377ip64_arp_create_arp_request(uint8_t *llhdr, const uint8_t *nlhdr)
378{
379 struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr;
380 struct arp_hdr *arp_hdr = (struct arp_hdr *)llhdr;
382
383 if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr,
384 ip64_get_hostaddr(),
385 ip64_get_netmask())) {
386 /* Destination address was not on the local network, so we need to
387 use the default router's IP address instead of the destination
388 address when determining the MAC address. */
389 uip_ip4addr_copy(&ipaddr, ip64_get_draddr());
390 } else {
391 /* Else, we use the destination IP address. */
392 uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr);
393 }
394
395 memset(arp_hdr->ethhdr.dest.addr, 0xff, 6);
396 memset(arp_hdr->dhwaddr.addr, 0x00, 6);
397 memcpy(arp_hdr->ethhdr.src.addr, ip64_eth_addr.addr, 6);
398 memcpy(arp_hdr->shwaddr.addr, ip64_eth_addr.addr, 6);
399
400 uip_ip4addr_copy(&arp_hdr->dipaddr, &ipaddr);
401 uip_ip4addr_copy(&arp_hdr->sipaddr, ip64_get_hostaddr());
402 arp_hdr->opcode = UIP_HTONS(ARP_REQUEST);
403 arp_hdr->hwtype = UIP_HTONS(ARP_HWTYPE_ETH);
404 arp_hdr->protocol = UIP_HTONS(IP64_ETH_TYPE_IP);
405 arp_hdr->hwlen = 6;
406 arp_hdr->protolen = 4;
407 arp_hdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP);
408
409 uip_appdata = &uip_buf[UIP_IPTCPH_LEN];
410
411 return sizeof(struct arp_hdr);
412}
413/*---------------------------------------------------------------------------*/
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:407
#define UIP_ARPTAB_SIZE
The size of the ARP table.
Definition: uipopt.h:398
Header file for the logging system.
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