adamdunkels | ca9ddcb | 2003-03-19 14:13:31 +0000 | [diff] [blame^] | 1 | /* |
| 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 | |
| 41 | struct 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 | |
| 54 | struct 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 | |
| 74 | u16_t uip_arp_draddr[2], uip_arp_netmask[2]; |
| 75 | |
| 76 | struct arp_entry { |
| 77 | u16_t ipaddr[2]; |
| 78 | struct uip_eth_addr ethaddr; |
| 79 | u8_t time; |
| 80 | }; |
| 81 | |
| 82 | static const struct uip_eth_addr ethaddr = {{UIP_ETHADDR0, |
| 83 | UIP_ETHADDR1, |
| 84 | UIP_ETHADDR2, |
| 85 | UIP_ETHADDR3, |
| 86 | UIP_ETHADDR4, |
| 87 | UIP_ETHADDR5}}; |
| 88 | |
| 89 | static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; |
| 90 | static u16_t ipaddr[2]; |
| 91 | static u8_t i, c; |
| 92 | |
| 93 | static u8_t arptime; |
| 94 | static u8_t tmpage; |
| 95 | |
| 96 | #define BUF ((struct arp_hdr *)&uip_buf[0]) |
| 97 | #define IPBUF ((struct ethip_hdr *)&uip_buf[0]) |
| 98 | /*-----------------------------------------------------------------------------------*/ |
| 99 | void |
| 100 | uip_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 | /*-----------------------------------------------------------------------------------*/ |
| 108 | void |
| 109 | uip_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 | /*-----------------------------------------------------------------------------------*/ |
| 122 | static void |
| 123 | uip_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 | /*-----------------------------------------------------------------------------------*/ |
| 185 | void |
| 186 | uip_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 | /*-----------------------------------------------------------------------------------*/ |
| 213 | void |
| 214 | uip_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 | /*-----------------------------------------------------------------------------------*/ |
| 263 | void |
| 264 | uip_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 | |