uIP 1.0 based webserver for LPC1114 + ENC28J60

Dependencies:   mbed TMP102

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers uip-fw.c Source File

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