Contiki 2.6

uip-fw.c

Go to the documentation of this file.
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 /** @} */