Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2004, Swedish Institute of Computer Science. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * Author: Adam Dunkels <adam@sics.se> 00032 * 00033 * $Id: uip-fw.c,v 1.12 2010/10/19 18:29:04 adamdunkels Exp $ 00034 */ 00035 /** 00036 * \addtogroup uip 00037 * @{ 00038 */ 00039 00040 /** 00041 * \defgroup uipfw uIP packet forwarding 00042 * @{ 00043 * 00044 */ 00045 00046 /** 00047 * \file 00048 * uIP packet forwarding. 00049 * \author Adam Dunkels <adam@sics.se> 00050 * 00051 * This file implements a number of simple functions which do packet 00052 * forwarding over multiple network interfaces with uIP. 00053 * 00054 */ 00055 00056 #include <string.h> 00057 00058 #include "contiki-conf.h" 00059 00060 #include "net/uip.h" 00061 #include "net/uip_arch.h" 00062 #include "net/uip-fw.h" 00063 #ifdef AODV_COMPLIANCE 00064 #include "net/uaodv-def.h" 00065 #endif 00066 00067 /* 00068 * The list of registered network interfaces. 00069 */ 00070 static struct uip_fw_netif *netifs = NULL; 00071 00072 /* 00073 * A pointer to the default network interface. 00074 */ 00075 static struct uip_fw_netif *defaultnetif = NULL; 00076 00077 struct tcpip_hdr { 00078 /* IP header. */ 00079 uint8_t vhl, 00080 tos; 00081 uint16_t len, 00082 ipid, 00083 ipoffset; 00084 uint8_t ttl, 00085 proto; 00086 uint16_t ipchksum; 00087 uip_ipaddr_t srcipaddr, destipaddr; 00088 00089 /* TCP header. */ 00090 uint16_t srcport, 00091 destport; 00092 uint8_t seqno[4], 00093 ackno[4], 00094 tcpoffset, 00095 flags, 00096 wnd[2]; 00097 uint16_t tcpchksum; 00098 uint8_t urgp[2]; 00099 uint8_t optdata[4]; 00100 }; 00101 00102 struct icmpip_hdr { 00103 /* IP header. */ 00104 uint8_t vhl, 00105 tos, 00106 len[2], 00107 ipid[2], 00108 ipoffset[2], 00109 ttl, 00110 proto; 00111 uint16_t ipchksum; 00112 uip_ipaddr_t srcipaddr, destipaddr; 00113 /* ICMP (echo) header. */ 00114 uint8_t type, icode; 00115 uint16_t icmpchksum; 00116 uint16_t id, seqno; 00117 uint8_t payload[1]; 00118 }; 00119 00120 /* ICMP ECHO. */ 00121 #define ICMP_ECHO 8 00122 00123 /* ICMP TIME-EXCEEDED. */ 00124 #define ICMP_TE 11 00125 00126 /* 00127 * Pointer to the TCP/IP headers of the packet in the uip_buf buffer. 00128 */ 00129 #define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) 00130 00131 /* 00132 * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer. 00133 */ 00134 #define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) 00135 00136 /* 00137 * Certain fields of an IP packet that are used for identifying 00138 * duplicate packets. 00139 */ 00140 struct fwcache_entry { 00141 uint16_t timer; 00142 00143 uip_ipaddr_t srcipaddr; 00144 uip_ipaddr_t destipaddr; 00145 uint16_t ipid; 00146 uint8_t proto; 00147 uint8_t unused; 00148 00149 #if notdef 00150 uint16_t payload[2]; 00151 #endif 00152 00153 #if UIP_REASSEMBLY > 0 00154 uint16_t len, offset; 00155 #endif 00156 }; 00157 00158 /* 00159 * The number of packets to remember when looking for duplicates. 00160 */ 00161 #ifdef UIP_CONF_FWCACHE_SIZE 00162 #define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE 00163 #else 00164 #define FWCACHE_SIZE 2 00165 #endif 00166 00167 00168 /* 00169 * A cache of packet header fields which are used for 00170 * identifying duplicate packets. 00171 */ 00172 static struct fwcache_entry fwcache[FWCACHE_SIZE]; 00173 00174 /** 00175 * \internal 00176 * The time that a packet cache is active. 00177 */ 00178 #define FW_TIME 20 00179 00180 /*------------------------------------------------------------------------------*/ 00181 /** 00182 * Initialize the uIP packet forwarding module. 00183 */ 00184 /*------------------------------------------------------------------------------*/ 00185 void 00186 uip_fw_init(void) 00187 { 00188 struct uip_fw_netif *t; 00189 defaultnetif = NULL; 00190 while(netifs != NULL) { 00191 t = netifs; 00192 netifs = netifs->next; 00193 t->next = NULL; 00194 } 00195 } 00196 /*------------------------------------------------------------------------------*/ 00197 /** 00198 * \internal 00199 * Check if an IP address is within the network defined by an IP 00200 * address and a netmask. 00201 * 00202 * \param ipaddr The IP address to be checked. 00203 * \param netipaddr The IP address of the network. 00204 * \param netmask The netmask of the network. 00205 * 00206 * \return Non-zero if IP address is in network, zero otherwise. 00207 */ 00208 /*------------------------------------------------------------------------------*/ 00209 static unsigned char 00210 ipaddr_maskcmp(uip_ipaddr_t *ipaddr, 00211 uip_ipaddr_t *netipaddr, 00212 uip_ipaddr_t *netmask) 00213 { 00214 return (ipaddr->u16[0] & netmask->u16[0]) == (netipaddr->u16[0] & netmask->u16[0]) && 00215 (ipaddr->u16[1] & netmask->u16[1]) == (netipaddr->u16[1] & netmask->u16[1]); 00216 } 00217 /*------------------------------------------------------------------------------*/ 00218 /** 00219 * \internal 00220 * Send out an ICMP TIME-EXCEEDED message. 00221 * 00222 * This function replaces the packet in the uip_buf buffer with the 00223 * ICMP packet. 00224 */ 00225 /*------------------------------------------------------------------------------*/ 00226 static void 00227 time_exceeded(void) 00228 { 00229 00230 /* We don't send out ICMP errors for ICMP messages (unless they are pings). */ 00231 if(ICMPBUF->proto == UIP_PROTO_ICMP && 00232 ICMPBUF->type != ICMP_ECHO) { 00233 uip_len = 0; 00234 return; 00235 } 00236 /* Copy fields from packet header into payload of this ICMP packet. */ 00237 memcpy(&(ICMPBUF->payload[0]), ICMPBUF, UIP_IPH_LEN + 8); 00238 00239 /* Set the ICMP type and code. */ 00240 ICMPBUF->type = ICMP_TE; 00241 ICMPBUF->icode = 0; 00242 00243 /* Calculate the ICMP checksum. */ 00244 ICMPBUF->icmpchksum = 0; 00245 ICMPBUF->icmpchksum = ~uip_chksum((uint16_t *)&(ICMPBUF->type), 36); 00246 00247 /* Set the IP destination address to be the source address of the 00248 original packet. */ 00249 uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr); 00250 00251 /* Set our IP address as the source address. */ 00252 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr); 00253 00254 /* The size of the ICMP time exceeded packet is 36 + the size of the 00255 IP header (20) = 56. */ 00256 uip_len = 56; 00257 ICMPBUF->len[0] = 0; 00258 ICMPBUF->len[1] = (uint8_t)uip_len; 00259 00260 /* Fill in the other fields in the IP header. */ 00261 ICMPBUF->vhl = 0x45; 00262 ICMPBUF->tos = 0; 00263 ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0; 00264 ICMPBUF->ttl = UIP_TTL; 00265 ICMPBUF->proto = UIP_PROTO_ICMP; 00266 00267 /* Calculate IP checksum. */ 00268 ICMPBUF->ipchksum = 0; 00269 ICMPBUF->ipchksum = ~(uip_ipchksum()); 00270 00271 00272 } 00273 /*------------------------------------------------------------------------------*/ 00274 /** 00275 * \internal 00276 * Register a packet in the forwarding cache so that it won't be 00277 * forwarded again. 00278 */ 00279 /*------------------------------------------------------------------------------*/ 00280 static void 00281 fwcache_register(void) 00282 { 00283 struct fwcache_entry *fw; 00284 int i, oldest; 00285 00286 oldest = FW_TIME; 00287 fw = NULL; 00288 00289 /* Find the oldest entry in the cache. */ 00290 for(i = 0; i < FWCACHE_SIZE; ++i) { 00291 if(fwcache[i].timer == 0) { 00292 fw = &fwcache[i]; 00293 break; 00294 } else if(fwcache[i].timer <= oldest) { 00295 fw = &fwcache[i]; 00296 oldest = fwcache[i].timer; 00297 } 00298 } 00299 00300 fw->timer = FW_TIME; 00301 fw->ipid = BUF->ipid; 00302 uip_ipaddr_copy(&fw->srcipaddr, &BUF->srcipaddr); 00303 uip_ipaddr_copy(&fw->destipaddr, &BUF->destipaddr); 00304 fw->proto = BUF->proto; 00305 #if notdef 00306 fw->payload[0] = BUF->srcport; 00307 fw->payload[1] = BUF->destport; 00308 #endif 00309 #if UIP_REASSEMBLY > 0 00310 fw->len = BUF->len; 00311 fw->offset = BUF->ipoffset; 00312 #endif 00313 } 00314 /*------------------------------------------------------------------------------*/ 00315 /** 00316 * \internal 00317 * Find a network interface for the IP packet in uip_buf. 00318 */ 00319 /*------------------------------------------------------------------------------*/ 00320 static struct uip_fw_netif * 00321 find_netif(void) 00322 { 00323 struct uip_fw_netif *netif; 00324 00325 /* Walk through every network interface to check for a match. */ 00326 for(netif = netifs; netif != NULL; netif = netif->next) { 00327 if(ipaddr_maskcmp(&BUF->destipaddr, &netif->ipaddr, 00328 &netif->netmask)) { 00329 /* If there was a match, we break the loop. */ 00330 return netif; 00331 } 00332 } 00333 00334 /* If no matching netif was found, we use default netif. */ 00335 return defaultnetif; 00336 } 00337 /*------------------------------------------------------------------------------*/ 00338 /** 00339 * Output an IP packet on the correct network interface. 00340 * 00341 * The IP packet should be present in the uip_buf buffer and its 00342 * length in the global uip_len variable. 00343 * 00344 * \retval UIP_FW_ZEROLEN Indicates that a zero-length packet 00345 * transmission was attempted and that no packet was sent. 00346 * 00347 * \retval UIP_FW_NOROUTE No suitable network interface could be found 00348 * for the outbound packet, and the packet was not sent. 00349 * 00350 * \return The return value from the actual network interface output 00351 * function is passed unmodified as a return value. 00352 */ 00353 /*------------------------------------------------------------------------------*/ 00354 uint8_t 00355 uip_fw_output(void) 00356 { 00357 struct uip_fw_netif *netif; 00358 #if UIP_BROADCAST 00359 const struct uip_udpip_hdr *udp = (void *)BUF; 00360 #endif /* UIP_BROADCAST */ 00361 00362 if(uip_len == 0) { 00363 return UIP_FW_ZEROLEN; 00364 } 00365 00366 fwcache_register(); 00367 00368 #if UIP_BROADCAST 00369 /* Link local broadcasts go out on all interfaces. */ 00370 if(uip_ipaddr_cmp(&udp->destipaddr, &uip_broadcast_addr)) { 00371 if(defaultnetif != NULL) { 00372 defaultnetif->output(); 00373 } 00374 for(netif = netifs; netif != NULL; netif = netif->next) { 00375 netif->output(); 00376 } 00377 return UIP_FW_OK; 00378 } 00379 #endif /* UIP_BROADCAST */ 00380 00381 netif = find_netif(); 00382 /* printf("uip_fw_output: netif %p ->output %p len %d\n", netif, 00383 netif->output, 00384 uip_len);*/ 00385 00386 if(netif == NULL) { 00387 return UIP_FW_NOROUTE; 00388 } 00389 /* If we now have found a suitable network interface, we call its 00390 output function to send out the packet. */ 00391 return netif->output(); 00392 } 00393 /*------------------------------------------------------------------------------*/ 00394 /** 00395 * Forward an IP packet in the uip_buf buffer. 00396 * 00397 * 00398 * 00399 * \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if 00400 * the packet should be processed locally. 00401 */ 00402 /*------------------------------------------------------------------------------*/ 00403 uint8_t 00404 uip_fw_forward(void) 00405 { 00406 struct fwcache_entry *fw; 00407 00408 /* First check if the packet is destined for ourselves and return 0 00409 to indicate that the packet should be processed locally. */ 00410 if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr)) { 00411 return UIP_FW_LOCAL; 00412 } 00413 00414 #ifdef AODV_COMPLIANCE 00415 #define udp ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) 00416 if(udp->proto == UIP_PROTO_UDP && udp->destport == UIP_HTONS(UAODV_UDPPORT)) { 00417 return UIP_FW_LOCAL; 00418 } 00419 #endif 00420 00421 /* If we use ping IP address configuration, and our IP address is 00422 not yet configured, we should intercept all ICMP echo packets. */ 00423 #if UIP_PINGADDRCONF 00424 if(uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr) && 00425 BUF->proto == UIP_PROTO_ICMP && 00426 ICMPBUF->type == ICMP_ECHO) { 00427 return UIP_FW_LOCAL; 00428 } 00429 #endif /* UIP_PINGADDRCONF */ 00430 00431 /* Check if the packet is in the forwarding cache already, and if so 00432 we drop it. */ 00433 00434 for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { 00435 if(fw->timer != 0 && 00436 #if UIP_REASSEMBLY > 0 00437 fw->len == BUF->len && 00438 fw->offset == BUF->ipoffset && 00439 #endif 00440 fw->ipid == BUF->ipid && 00441 uip_ipaddr_cmp(&fw->srcipaddr, &BUF->srcipaddr) && 00442 uip_ipaddr_cmp(&fw->destipaddr, &BUF->destipaddr) && 00443 #if notdef 00444 fw->payload[0] == BUF->srcport && 00445 fw->payload[1] == BUF->destport && 00446 #endif 00447 fw->proto == BUF->proto) { 00448 /* Drop packet. */ 00449 return UIP_FW_FORWARDED; 00450 } 00451 } 00452 00453 /* If the TTL reaches zero we produce an ICMP time exceeded message 00454 in the uip_buf buffer and forward that packet back to the sender 00455 of the packet. */ 00456 00457 if(BUF->ttl <= 1) { 00458 /* No time exceeded for broadcasts and multicasts! */ 00459 if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr)) { 00460 return UIP_FW_LOCAL; 00461 } 00462 time_exceeded(); 00463 } 00464 00465 /* Decrement the TTL (time-to-live) value in the IP header */ 00466 BUF->ttl = BUF->ttl - 1; 00467 00468 /* Update the IP checksum. */ 00469 if(BUF->ipchksum >= UIP_HTONS(0xffff - 0x0100)) { 00470 BUF->ipchksum = BUF->ipchksum + UIP_HTONS(0x0100) + 1; 00471 } else { 00472 BUF->ipchksum = BUF->ipchksum + UIP_HTONS(0x0100); 00473 } 00474 00475 if(uip_len > 0) { 00476 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]; 00477 uip_fw_output(); 00478 } 00479 00480 #if UIP_BROADCAST 00481 if(uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr)) { 00482 return UIP_FW_LOCAL; 00483 } 00484 #endif /* UIP_BROADCAST */ 00485 00486 /* Return non-zero to indicate that the packet was forwarded and that no 00487 other processing should be made. */ 00488 return UIP_FW_FORWARDED; 00489 } 00490 /*------------------------------------------------------------------------------*/ 00491 /** 00492 * Register a network interface with the forwarding module. 00493 * 00494 * \param netif A pointer to the network interface that is to be 00495 * registered. 00496 */ 00497 /*------------------------------------------------------------------------------*/ 00498 void 00499 uip_fw_register(struct uip_fw_netif *netif) 00500 { 00501 netif->next = netifs; 00502 netifs = netif; 00503 } 00504 /*------------------------------------------------------------------------------*/ 00505 /** 00506 * Register a default network interface. 00507 * 00508 * All packets that don't go out on any of the other interfaces will 00509 * be routed to the default interface. 00510 * 00511 * \param netif A pointer to the network interface that is to be 00512 * registered. 00513 */ 00514 /*------------------------------------------------------------------------------*/ 00515 void 00516 uip_fw_default(struct uip_fw_netif *netif) 00517 { 00518 defaultnetif = netif; 00519 } 00520 /*------------------------------------------------------------------------------*/ 00521 /** 00522 * Perform periodic processing. 00523 */ 00524 /*------------------------------------------------------------------------------*/ 00525 void 00526 uip_fw_periodic(void) 00527 { 00528 struct fwcache_entry *fw; 00529 for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { 00530 if(fw->timer > 0) { 00531 --fw->timer; 00532 } 00533 } 00534 } 00535 /*------------------------------------------------------------------------------*/ 00536 /** @} */ 00537 /** @} */