source: uKadecot/trunk/uip/net/ipv4/uip_arp.c@ 262

Last change on this file since 262 was 262, checked in by coas-nagasima, 7 years ago

uIPを更新
プロジェクトファイルを更新

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-chdr; charset=SHIFT_JIS
File size: 13.8 KB
Line 
1/**
2 * \addtogroup uip
3 * @{
4 */
5
6/**
7 * \defgroup uiparp uIP Address Resolution Protocol
8 * @{
9 *
10 * The Address Resolution Protocol ARP is used for mapping between IP
11 * addresses and link level addresses such as the Ethernet MAC
12 * addresses. ARP uses broadcast queries to ask for the link level
13 * address of a known IP address and the host which is configured with
14 * the IP address for which the query was meant, will respond with its
15 * link level address.
16 *
17 * \note This ARP implementation only supports Ethernet.
18 */
19
20/**
21 * \file
22 * Implementation of the ARP Address Resolution Protocol.
23 * \author Adam Dunkels <adam@dunkels.com>
24 *
25 */
26
27/*
28 * Copyright (c) 2001-2003, Adam Dunkels.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior
41 * written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * This file is part of the uIP TCP/IP stack.
56 *
57 * $Id: uip_arp.c 262 2016-11-18 05:58:30Z coas-nagasima $
58 *
59 */
60
61
62#include "net/ipv4/uip_arp.h"
63
64#include <string.h>
65
66#ifdef __RX
67#pragma pack
68#elif _MSC_VER
69#pragma pack(push, 1)
70#endif
71
72struct arp_hdr {
73 struct uip_eth_hdr ethhdr;
74 uint16_t hwtype;
75 uint16_t protocol;
76 uint8_t hwlen;
77 uint8_t protolen;
78 uint16_t opcode;
79 struct uip_eth_addr shwaddr;
80 uip_ipaddr_t sipaddr;
81 struct uip_eth_addr dhwaddr;
82 uip_ipaddr_t dipaddr;
83};
84
85struct ethip_hdr {
86 struct uip_eth_hdr ethhdr;
87 /* IP header. */
88 uint8_t vhl,
89 tos,
90 len[2],
91 ipid[2],
92 ipoffset[2],
93 ttl,
94 proto;
95 uint16_t ipchksum;
96 uip_ipaddr_t srcipaddr, destipaddr;
97};
98
99#ifdef __RX
100#pragma unpack
101#elif _MSC_VER
102#pragma pack(pop)
103#endif
104
105#define ARP_REQUEST 1
106#define ARP_REPLY 2
107
108#define ARP_HWTYPE_ETH 1
109
110struct arp_entry {
111 uip_ipaddr_t ipaddr;
112 struct uip_eth_addr ethaddr;
113 uint8_t time;
114};
115
116static const struct uip_eth_addr broadcast_ethaddr =
117 {{0xff,0xff,0xff,0xff,0xff,0xff}};
118static const uint16_t broadcast_ipaddr[2] = {0xffff,0xffff};
119
120static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
121static uip_ipaddr_t ipaddr;
122static uint8_t i, c;
123
124static uint8_t arptime;
125static uint8_t tmpage;
126
127#define BUF ((struct arp_hdr *)&uip_buf[0])
128#define IPBUF ((struct ethip_hdr *)&uip_buf[0])
129/*-----------------------------------------------------------------------------------*/
130/**
131 * Initialize the ARP module.
132 *
133 */
134/*-----------------------------------------------------------------------------------*/
135void
136uip_arp_init(void)
137{
138 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
139 memset(&arp_table[i].ipaddr, 0, 4);
140 }
141}
142/*-----------------------------------------------------------------------------------*/
143/**
144 * Periodic ARP processing function.
145 *
146 * This function performs periodic timer processing in the ARP module
147 * and should be called at regular intervals. The recommended interval
148 * is 10 seconds between the calls.
149 *
150 */
151/*-----------------------------------------------------------------------------------*/
152void
153uip_arp_timer(void)
154{
155 struct arp_entry *tabptr;
156
157 ++arptime;
158 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
159 tabptr = &arp_table[i];
160 if(uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr) &&
161 arptime - tabptr->time >= UIP_ARP_MAXAGE) {
162 memset(&tabptr->ipaddr, 0, 4);
163 }
164 }
165
166}
167
168/*-----------------------------------------------------------------------------------*/
169static void
170uip_arp_update(uip_ipaddr_t *ipaddr, struct uip_eth_addr *ethaddr)
171{
172 register struct arp_entry *tabptr = arp_table;
173
174 /* Walk through the ARP mapping table and try to find an entry to
175 update. If none is found, the IP -> MAC address mapping is
176 inserted in the ARP table. */
177 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
178 tabptr = &arp_table[i];
179
180 /* Only check those entries that are actually in use. */
181 if(!uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
182
183 /* Check if the source IP address of the incoming packet matches
184 the IP address in this ARP table entry. */
185 if(uip_ipaddr_cmp(ipaddr, &tabptr->ipaddr)) {
186
187 /* An old entry found, update this and return. */
188 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
189 tabptr->time = arptime;
190
191 return;
192 }
193 }
194 }
195
196 /* If we get here, no existing ARP table entry was found, so we
197 create one. */
198
199 /* First, we try to find an unused entry in the ARP table. */
200 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
201 tabptr = &arp_table[i];
202 if(uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
203 break;
204 }
205 }
206
207 /* If no unused entry is found, we try to find the oldest entry and
208 throw it away. */
209 if(i == UIP_ARPTAB_SIZE) {
210 tmpage = 0;
211 c = 0;
212 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
213 tabptr = &arp_table[i];
214 if(arptime - tabptr->time > tmpage) {
215 tmpage = arptime - tabptr->time;
216 c = i;
217 }
218 }
219 i = c;
220 tabptr = &arp_table[i];
221 }
222
223 /* Now, i is the ARP table entry which we will fill with the new
224 information. */
225 uip_ipaddr_copy(&tabptr->ipaddr, ipaddr);
226 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
227 tabptr->time = arptime;
228}
229/*-----------------------------------------------------------------------------------*/
230/**
231 * ARP processing for incoming IP packets
232 *
233 * This function should be called by the device driver when an IP
234 * packet has been received. The function will check if the address is
235 * in the ARP cache, and if so the ARP cache entry will be
236 * refreshed. If no ARP cache entry was found, a new one is created.
237 *
238 * This function expects an IP packet with a prepended Ethernet header
239 * in the uip_buf[] buffer, and the length of the packet in the global
240 * variable uip_len.
241 */
242/*-----------------------------------------------------------------------------------*/
243#if 0
244void
245uip_arp_ipin(void)
246{
247 uip_len -= sizeof(struct uip_eth_hdr);
248
249 /* Only insert/update an entry if the source IP address of the
250 incoming IP packet comes from a host on the local network. */
251 if((IPBUF->srcipaddr[0] & uip_netmask[0]) !=
252 (uip_hostaddr[0] & uip_netmask[0])) {
253 return;
254 }
255 if((IPBUF->srcipaddr[1] & uip_netmask[1]) !=
256 (uip_hostaddr[1] & uip_netmask[1])) {
257 return;
258 }
259 uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
260
261 return;
262}
263#endif /* 0 */
264/*-----------------------------------------------------------------------------------*/
265/**
266 * ARP processing for incoming ARP packets.
267 *
268 * This function should be called by the device driver when an ARP
269 * packet has been received. The function will act differently
270 * depending on the ARP packet type: if it is a reply for a request
271 * that we previously sent out, the ARP cache will be filled in with
272 * the values from the ARP reply. If the incoming ARP packet is an ARP
273 * request for our IP address, an ARP reply packet is created and put
274 * into the uip_buf[] buffer.
275 *
276 * When the function returns, the value of the global variable uip_len
277 * indicates whether the device driver should send out a packet or
278 * not. If uip_len is zero, no packet should be sent. If uip_len is
279 * non-zero, it contains the length of the outbound packet that is
280 * present in the uip_buf[] buffer.
281 *
282 * This function expects an ARP packet with a prepended Ethernet
283 * header in the uip_buf[] buffer, and the length of the packet in the
284 * global variable uip_len.
285 */
286/*-----------------------------------------------------------------------------------*/
287void
288uip_arp_arpin(void)
289{
290
291 if(uip_len < sizeof(struct arp_hdr)) {
292 uip_len = 0;
293 return;
294 }
295 uip_len = 0;
296
297 switch(BUF->opcode) {
298 case UIP_HTONS(ARP_REQUEST):
299 /* ARP request. If it asked for our address, we send out a
300 reply. */
301 if(uip_ipaddr_cmp(&BUF->dipaddr, &uip_hostaddr)) {
302 /* First, we register the one who made the request in our ARP
303 table, since it is likely that we will do more communication
304 with this host in the future. */
305 uip_arp_update(&BUF->sipaddr, &BUF->shwaddr);
306
307 /* The reply opcode is 2. */
308 BUF->opcode = UIP_HTONS(2);
309
310 memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
311 memcpy(BUF->shwaddr.addr, uip_lladdr.addr, 6);
312 memcpy(BUF->ethhdr.src.addr, uip_lladdr.addr, 6);
313 memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
314
315 uip_ipaddr_copy(&BUF->dipaddr, &BUF->sipaddr);
316 uip_ipaddr_copy(&BUF->sipaddr, &uip_hostaddr);
317
318 BUF->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_ARP);
319 uip_len = sizeof(struct arp_hdr);
320 }
321 break;
322 case UIP_HTONS(ARP_REPLY):
323 /* ARP reply. We insert or update the ARP table if it was meant
324 for us. */
325 if(uip_ipaddr_cmp(&BUF->dipaddr, &uip_hostaddr)) {
326 uip_arp_update(&BUF->sipaddr, &BUF->shwaddr);
327 }
328 break;
329 }
330
331 return;
332}
333/*-----------------------------------------------------------------------------------*/
334/**
335 * Prepend Ethernet header to an outbound IP packet and see if we need
336 * to send out an ARP request.
337 *
338 * This function should be called before sending out an IP packet. The
339 * function checks the destination IP address of the IP packet to see
340 * what Ethernet MAC address that should be used as a destination MAC
341 * address on the Ethernet.
342 *
343 * If the destination IP address is in the local network (determined
344 * by logical ANDing of netmask and our IP address), the function
345 * checks the ARP cache to see if an entry for the destination IP
346 * address is found. If so, an Ethernet header is prepended and the
347 * function returns. If no ARP cache entry is found for the
348 * destination IP address, the packet in the uip_buf[] is replaced by
349 * an ARP request packet for the IP address. The IP packet is dropped
350 * and it is assumed that they higher level protocols (e.g., TCP)
351 * eventually will retransmit the dropped packet.
352 *
353 * If the destination IP address is not on the local network, the IP
354 * address of the default router is used instead.
355 *
356 * When the function returns, a packet is present in the uip_buf[]
357 * buffer, and the length of the packet is in the global variable
358 * uip_len.
359 */
360/*-----------------------------------------------------------------------------------*/
361void
362uip_arp_out(void)
363{
364 struct arp_entry *tabptr = NULL;
365
366 /* Find the destination IP address in the ARP table and construct
367 the Ethernet header. If the destination IP addres isn't on the
368 local network, we use the default router's IP address instead.
369
370 If not ARP table entry is found, we overwrite the original IP
371 packet with an ARP request for the IP address. */
372
373 /* First check if destination is a local broadcast. */
374 if(uip_ipaddr_cmp(&IPBUF->destipaddr, &uip_broadcast_addr)) {
375 memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
376 } else if(IPBUF->destipaddr.u8[0] == 224) {
377 /* Multicast. */
378 IPBUF->ethhdr.dest.addr[0] = 0x01;
379 IPBUF->ethhdr.dest.addr[1] = 0x00;
380 IPBUF->ethhdr.dest.addr[2] = 0x5e;
381 IPBUF->ethhdr.dest.addr[3] = IPBUF->destipaddr.u8[1];
382 IPBUF->ethhdr.dest.addr[4] = IPBUF->destipaddr.u8[2];
383 IPBUF->ethhdr.dest.addr[5] = IPBUF->destipaddr.u8[3];
384 } else {
385 /* Check if the destination address is on the local network. */
386 if(!uip_ipaddr_maskcmp(&IPBUF->destipaddr, &uip_hostaddr, &uip_netmask)) {
387 /* Destination address was not on the local network, so we need to
388 use the default router's IP address instead of the destination
389 address when determining the MAC address. */
390 uip_ipaddr_copy(&ipaddr, &uip_draddr);
391 } else {
392 /* Else, we use the destination IP address. */
393 uip_ipaddr_copy(&ipaddr, &IPBUF->destipaddr);
394 }
395 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
396 tabptr = &arp_table[i];
397 if(uip_ipaddr_cmp(&ipaddr, &tabptr->ipaddr)) {
398 break;
399 }
400 }
401
402 if(i == UIP_ARPTAB_SIZE) {
403 /* The destination address was not in our ARP table, so we
404 overwrite the IP packet with an ARP request. */
405
406 memset(BUF->ethhdr.dest.addr, 0xff, 6);
407 memset(BUF->dhwaddr.addr, 0x00, 6);
408 memcpy(BUF->ethhdr.src.addr, uip_lladdr.addr, 6);
409 memcpy(BUF->shwaddr.addr, uip_lladdr.addr, 6);
410
411 uip_ipaddr_copy(&BUF->dipaddr, &ipaddr);
412 uip_ipaddr_copy(&BUF->sipaddr, &uip_hostaddr);
413 BUF->opcode = UIP_HTONS(ARP_REQUEST); /* ARP request. */
414 BUF->hwtype = UIP_HTONS(ARP_HWTYPE_ETH);
415 BUF->protocol = UIP_HTONS(UIP_ETHTYPE_IP);
416 BUF->hwlen = 6;
417 BUF->protolen = 4;
418 BUF->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_ARP);
419
420 uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
421
422 uip_len = sizeof(struct arp_hdr);
423 return;
424 }
425
426 /* Build an ethernet header. */
427 memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
428 }
429 memcpy(IPBUF->ethhdr.src.addr, uip_lladdr.addr, 6);
430
431 IPBUF->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_IP);
432
433 uip_len += sizeof(struct uip_eth_hdr);
434}
435/*-----------------------------------------------------------------------------------*/
436
437/** @} */
438/** @} */
439
Note: See TracBrowser for help on using the repository browser.