blob: e7586102d02b0d873ee5b8a96f455eb7b4253735 [file] [log] [blame]
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001/*
2 * Copyright (c) 2001-2002, 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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Adam Dunkels.
16 * 4. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior
18 * written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * This file is part of the uIP TCP/IP stack.
33 *
34 * $Id: uip_arp.c,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
35 *
36 */
37
38
39#include "uip_arp.h"
40
41struct arp_hdr {
42 struct uip_eth_hdr ethhdr;
43 u16_t hwtype;
44 u16_t protocol;
45 u8_t hwlen;
46 u8_t protolen;
47 u16_t opcode;
48 struct uip_eth_addr shwaddr;
49 u16_t sipaddr[2];
50 struct uip_eth_addr dhwaddr;
51 u16_t dipaddr[2];
52};
53
54struct ethip_hdr {
55 struct uip_eth_hdr ethhdr;
56 /* IP header. */
57 u8_t vhl,
58 tos,
59 len[2],
60 ipid[2],
61 ipoffset[2],
62 ttl,
63 proto;
64 u16_t ipchksum;
65 u16_t srcipaddr[2],
66 destipaddr[2];
67};
68
69#define ARP_REQUEST 1
70#define ARP_REPLY 2
71
72#define ARP_HWTYPE_ETH 1
73
74u16_t uip_arp_draddr[2], uip_arp_netmask[2];
75
76struct arp_entry {
77 u16_t ipaddr[2];
78 struct uip_eth_addr ethaddr;
79 u8_t time;
80};
81
82static const struct uip_eth_addr ethaddr = {{UIP_ETHADDR0,
83 UIP_ETHADDR1,
84 UIP_ETHADDR2,
85 UIP_ETHADDR3,
86 UIP_ETHADDR4,
87 UIP_ETHADDR5}};
88
89static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
90static u16_t ipaddr[2];
91static u8_t i, c;
92
93static u8_t arptime;
94static u8_t tmpage;
95
96#define BUF ((struct arp_hdr *)&uip_buf[0])
97#define IPBUF ((struct ethip_hdr *)&uip_buf[0])
98/*-----------------------------------------------------------------------------------*/
99void
100uip_arp_init(void)
101{
102 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
103 arp_table[i].ipaddr[0] =
104 arp_table[i].ipaddr[1] = 0;
105 }
106}
107/*-----------------------------------------------------------------------------------*/
108void
109uip_arp_timer(void)
110{
111 ++arptime;
112 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
113 if((arp_table[i].ipaddr[0] | arp_table[i].ipaddr[1]) != 0 &&
114 arptime - arp_table[i].time >= UIP_ARP_MAXAGE) {
115 arp_table[i].ipaddr[0] =
116 arp_table[i].ipaddr[1] = 0;
117 }
118 }
119
120}
121/*-----------------------------------------------------------------------------------*/
122static void
123uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
124{
125 /* Walk through the ARP mapping table and try to find an entry to
126 update. If none is found, the IP -> MAC address mapping is
127 inserted in the ARP table. */
128 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
129
130 /* Only check those entries that are actually in use. */
131 if(arp_table[i].ipaddr[0] != 0 &&
132 arp_table[i].ipaddr[1] != 0) {
133
134 /* Check if the source IP address of the incoming packet matches
135 the IP address in this ARP table entry. */
136 if(ipaddr[0] == arp_table[i].ipaddr[0] &&
137 ipaddr[1] == arp_table[i].ipaddr[1]) {
138
139 /* An old entry found, update this and return. */
140 for(c = 0; c < 6; ++c) {
141 arp_table[i].ethaddr.addr[c] = ethaddr->addr[c];
142 }
143 arp_table[i].time = arptime;
144
145 return;
146 }
147 }
148 }
149
150 /* If we get here, no existing ARP table entry was found, so we
151 create one. */
152
153 /* First, we try to find an unused entry in the ARP table. */
154 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
155 if(arp_table[i].ipaddr[0] == 0 &&
156 arp_table[i].ipaddr[1] == 0) {
157 break;
158 }
159 }
160
161 /* If no unused entry is found, we try to find the oldest entry and
162 throw it away. */
163 if(i == UIP_ARPTAB_SIZE) {
164 tmpage = 0;
165 c = 0;
166 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
167 if(arptime - arp_table[i].time > tmpage) {
168 tmpage = arptime - arp_table[i].time;
169 c = i;
170 }
171 }
172 i = c;
173 }
174
175 /* Now, i is the ARP table entry which we will fill with the new
176 information. */
177 arp_table[i].ipaddr[0] = ipaddr[0];
178 arp_table[i].ipaddr[1] = ipaddr[1];
179 for(c = 0; c < 6; ++c) {
180 arp_table[i].ethaddr.addr[c] = ethaddr->addr[c];
181 }
182 arp_table[i].time = arptime;
183}
184/*-----------------------------------------------------------------------------------*/
185void
186uip_arp_ipin(void)
187{
188
189 /* Only insert/update an entry if the source IP address of the
190 incoming IP packet comes from a host on the local network. */
191 /* if((IPBUF->srcipaddr[0] & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)) !=
192 (uip_hostaddr[0]
193 & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)))
194 return;
195 if((IPBUF->srcipaddr[1] & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3)) !=
196 (uip_hostaddr[1]
197 & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3)))
198 return;
199 */
200 if((IPBUF->srcipaddr[0] & uip_arp_netmask[0]) !=
201 (uip_hostaddr[0] & uip_arp_netmask[0])) {
202 return;
203 }
204 if((IPBUF->srcipaddr[1] & uip_arp_netmask[1]) !=
205 (uip_hostaddr[1] & uip_arp_netmask[1])) {
206 return;
207 }
208 uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
209
210 return;
211}
212/*-----------------------------------------------------------------------------------*/
213void
214uip_arp_arpin(void)
215{
216
217 if(uip_len < sizeof(struct arp_hdr)) {
218 uip_len = 0;
219 return;
220 }
221
222 uip_len = 0;
223
224 switch(BUF->opcode) {
225 case htons(ARP_REQUEST):
226 /* ARP request. If it asked for our address, we send out a
227 reply. */
228 if(BUF->dipaddr[0] == uip_hostaddr[0] &&
229 BUF->dipaddr[1] == uip_hostaddr[1]) {
230 /* The reply opcode is 2. */
231 BUF->opcode = htons(2);
232
233 for(c = 0; c < 6; ++c) {
234 BUF->dhwaddr.addr[c] = BUF->shwaddr.addr[c];
235 BUF->shwaddr.addr[c] =
236 BUF->ethhdr.src.addr[c] = ethaddr.addr[c];
237 BUF->ethhdr.dest.addr[c] = BUF->dhwaddr.addr[c];
238 }
239
240 BUF->dipaddr[0] = BUF->sipaddr[0];
241 BUF->dipaddr[1] = BUF->sipaddr[1];
242 BUF->sipaddr[0] = uip_hostaddr[0];
243 BUF->sipaddr[1] = uip_hostaddr[1];
244
245 BUF->ethhdr.type = htons(UIP_ETHTYPE_ARP);
246 uip_len = sizeof(struct arp_hdr);
247 }
248 break;
249 case htons(ARP_REPLY):
250 /* ARP reply. We insert or update the ARP table if it was meant
251 for us. */
252 if(BUF->dipaddr[0] == uip_hostaddr[0] &&
253 BUF->dipaddr[1] == uip_hostaddr[1]) {
254
255 uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
256 }
257 break;
258 }
259
260 return;
261}
262/*-----------------------------------------------------------------------------------*/
263void
264uip_arp_out(void)
265{
266 /* Find the destination IP address in the ARP table and construct
267 the Ethernet header. If the destination IP addres isn't on the
268 local network, we use the default router's IP address instead.
269
270 If not ARP table entry is found, we overwrite the original IP
271 packet with an ARP request for the IP address. */
272
273 /* Check if the destination address is on the local network. */
274 /* if((IPBUF->destipaddr[0] & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)) !=
275 (uip_hostaddr[0]
276 & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)) ||
277 (IPBUF->destipaddr[1] & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3)) !=
278 (uip_hostaddr[1]
279 & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3))) {*/
280 if((IPBUF->destipaddr[0] & uip_arp_netmask[0]) !=
281 (uip_hostaddr[0] & uip_arp_netmask[0]) ||
282 (IPBUF->destipaddr[1] & uip_arp_netmask[1]) !=
283 (uip_hostaddr[1] & uip_arp_netmask[1])) {
284 /* Destination address was not on the local network, so we need to
285 use the default router's IP address instead of the destination
286 address when determining the MAC address. */
287 /* ipaddr[0] = htons((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1);
288 ipaddr[1] = htons((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3);*/
289 ipaddr[0] = uip_arp_draddr[0];
290 ipaddr[1] = uip_arp_draddr[1];
291 } else {
292 /* Else, we use the destination IP address. */
293 ipaddr[0] = IPBUF->destipaddr[0];
294 ipaddr[1] = IPBUF->destipaddr[1];
295 }
296
297 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
298 if(ipaddr[0] == arp_table[i].ipaddr[0] &&
299 ipaddr[1] == arp_table[i].ipaddr[1])
300 break;
301 }
302
303 if(i == UIP_ARPTAB_SIZE) {
304 /* The destination address was not in our ARP table, so we
305 overwrite the IP packet with an ARP request. */
306
307 for(c = 0; c < 6; ++c) {
308 BUF->ethhdr.dest.addr[c] = 0xff; /* Broadcast ARP request. */
309 BUF->ethhdr.src.addr[c] =
310 BUF->shwaddr.addr[c] = ethaddr.addr[c];
311 BUF->dhwaddr.addr[c] = 0;
312 }
313
314 BUF->dipaddr[0] = ipaddr[0];
315 BUF->dipaddr[1] = ipaddr[1];
316 BUF->sipaddr[0] = uip_hostaddr[0];
317 BUF->sipaddr[1] = uip_hostaddr[1];
318 BUF->opcode = htons(ARP_REQUEST); /* ARP request. */
319 BUF->hwtype = htons(ARP_HWTYPE_ETH);
320 BUF->protocol = htons(UIP_ETHTYPE_IP);
321 BUF->hwlen = 6;
322 BUF->protolen = 4;
323 BUF->ethhdr.type = htons(UIP_ETHTYPE_ARP);
324
325 uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
326
327 uip_len = sizeof(struct arp_hdr);
328 return;
329 }
330
331 /* Build an ethernet header. */
332 for(c = 0; c < 6; ++c) {
333 IPBUF->ethhdr.dest.addr[c] = arp_table[i].ethaddr.addr[c];
334 IPBUF->ethhdr.src.addr[c] = ethaddr.addr[c];
335 }
336 IPBUF->ethhdr.type = htons(UIP_ETHTYPE_IP);
337
338 uip_len += sizeof(struct uip_eth_hdr);
339}
340/*-----------------------------------------------------------------------------------*/
341
342
343
344