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 uIP TCP/IP stack
00030  *
00031  * Author: Adam Dunkels <adam@sics.se>
00032  *
00033  * $Id: uip-fw.c,v 1.2 2006/06/12 08:00:30 adam Exp $
00034  */
00056 #include "uip.h"
00057 #include "uip_arch.h"
00058 #include "uip-fw.h"
00059 
00060 #include <string.h> /* for memcpy() */
00061 
00062 /*
00063  * The list of registered network interfaces.
00064  */
00065 static struct uip_fw_netif *netifs = NULL;
00066 
00067 /*
00068  * A pointer to the default network interface.
00069  */
00070 static struct uip_fw_netif *defaultnetif = NULL;
00071 
00072 struct tcpip_hdr {
00073   /* IP header. */
00074   u8_t vhl,
00075     tos;
00076   u16_t len,
00077     ipid,
00078     ipoffset;
00079   u8_t ttl,
00080     proto;
00081   u16_t ipchksum;
00082   u16_t srcipaddr[2],
00083     destipaddr[2];
00084   
00085   /* TCP header. */
00086   u16_t srcport,
00087     destport;
00088   u8_t seqno[4],
00089     ackno[4],
00090     tcpoffset,
00091     flags,
00092     wnd[2];
00093   u16_t tcpchksum;
00094   u8_t urgp[2];
00095   u8_t optdata[4];
00096 } PACK_STRUCT_END;
00097 
00098 struct icmpip_hdr {
00099   /* IP header. */
00100   u8_t vhl,
00101     tos,
00102     len[2],
00103     ipid[2],
00104     ipoffset[2],
00105     ttl,
00106     proto;
00107   u16_t ipchksum;
00108   u16_t srcipaddr[2],
00109     destipaddr[2];
00110   /* ICMP (echo) header. */
00111   u8_t type, icode;
00112   u16_t icmpchksum;
00113   u16_t id, seqno;
00114   u8_t payload[1];
00115 } PACK_STRUCT_END;
00116 
00117 /* ICMP ECHO. */
00118 #define ICMP_ECHO 8
00119 
00120 /* ICMP TIME-EXCEEDED. */
00121 #define ICMP_TE 11
00122 
00123 /*
00124  * Pointer to the TCP/IP headers of the packet in the uip_buf buffer.
00125  */
00126 #define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
00127 
00128 /*
00129  * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer.
00130  */
00131 #define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
00132 
00133 /*
00134  * Certain fields of an IP packet that are used for identifying
00135  * duplicate packets.
00136  */
00137 struct fwcache_entry {
00138   u16_t timer;
00139   
00140   u16_t srcipaddr[2];
00141   u16_t destipaddr[2];
00142   u16_t ipid;
00143   u8_t proto;
00144   u8_t unused;
00145 
00146 #if notdef
00147   u16_t payload[2];
00148 #endif
00149 
00150 #if UIP_REASSEMBLY > 0
00151   u16_t len, offset;
00152 #endif
00153 };
00154 
00155 /*
00156  * The number of packets to remember when looking for duplicates.
00157  */
00158 #ifdef UIP_CONF_FWCACHE_SIZE
00159 #define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE
00160 #else
00161 #define FWCACHE_SIZE 2
00162 #endif
00163 
00164 
00165 /*
00166  * A cache of packet header fields which are used for
00167  * identifying duplicate packets.
00168  */
00169 static struct fwcache_entry fwcache[FWCACHE_SIZE];
00170 
00175 #define FW_TIME 20
00176 
00177 /*------------------------------------------------------------------------------*/
00181 /*------------------------------------------------------------------------------*/
00182 void
00183 uip_fw_init(void)
00184 {
00185   struct uip_fw_netif *t;
00186   defaultnetif = NULL;
00187   while(netifs != NULL) {
00188     t = netifs;
00189     netifs = netifs->next;
00190     t->next = NULL;
00191   }
00192 }
00193 /*------------------------------------------------------------------------------*/
00205 /*------------------------------------------------------------------------------*/
00206 static unsigned char
00207 ipaddr_maskcmp(u16_t *ipaddr, u16_t *netipaddr, u16_t *netmask)
00208 {
00209   return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) &&
00210     (ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]);
00211 }
00212 /*------------------------------------------------------------------------------*/
00220 /*------------------------------------------------------------------------------*/
00221 static void
00222 time_exceeded(void)
00223 {
00224   u16_t tmp16;
00225 
00226   /* We don't send out ICMP errors for ICMP messages. */
00227   if(ICMPBUF->proto == UIP_PROTO_ICMP) {
00228     uip_len = 0;
00229     return;
00230   }
00231   /* Copy fields from packet header into payload of this ICMP packet. */
00232   memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28);
00233 
00234   /* Set the ICMP type and code. */
00235   ICMPBUF->type = ICMP_TE;
00236   ICMPBUF->icode = 0;
00237 
00238   /* Calculate the ICMP checksum. */
00239   ICMPBUF->icmpchksum = 0;
00240   ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36);
00241 
00242   /* Set the IP destination address to be the source address of the
00243      original packet. */
00244   tmp16= BUF->destipaddr[0];
00245   BUF->destipaddr[0] = BUF->srcipaddr[0];
00246   BUF->srcipaddr[0] = tmp16;
00247   tmp16 = BUF->destipaddr[1];
00248   BUF->destipaddr[1] = BUF->srcipaddr[1];
00249   BUF->srcipaddr[1] = tmp16;
00250 
00251   /* Set our IP address as the source address. */
00252   BUF->srcipaddr[0] = uip_hostaddr[0];
00253   BUF->srcipaddr[1] = uip_hostaddr[1];
00254 
00255   /* The size of the ICMP time exceeded packet is 36 + the size of the
00256      IP header (20) = 56. */
00257   uip_len = 56;
00258   ICMPBUF->len[0] = 0;
00259   ICMPBUF->len[1] = uip_len;
00260 
00261   /* Fill in the other fields in the IP header. */
00262   ICMPBUF->vhl = 0x45;
00263   ICMPBUF->tos = 0;
00264   ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0;
00265   ICMPBUF->ttl  = UIP_TTL;
00266   ICMPBUF->proto = UIP_PROTO_ICMP;
00267   
00268   /* Calculate IP checksum. */
00269   ICMPBUF->ipchksum = 0;
00270   ICMPBUF->ipchksum = ~(uip_ipchksum());
00271 
00272 
00273 }
00274 /*------------------------------------------------------------------------------*/
00280 /*------------------------------------------------------------------------------*/
00281 static void
00282 fwcache_register(void)
00283 {
00284   struct fwcache_entry *fw;
00285   int i, oldest;
00286 
00287   oldest = FW_TIME;
00288   fw = NULL;
00289   
00290   /* Find the oldest entry in the cache. */
00291   for(i = 0; i < FWCACHE_SIZE; ++i) {
00292     if(fwcache[i].timer == 0) {
00293       fw = &fwcache[i];
00294       break;
00295     } else if(fwcache[i].timer <= oldest) {
00296       fw = &fwcache[i];
00297       oldest = fwcache[i].timer;
00298     }
00299   }
00300 
00301   fw->timer = FW_TIME;
00302   fw->ipid = BUF->ipid;
00303   fw->srcipaddr[0] = BUF->srcipaddr[0];
00304   fw->srcipaddr[1] = BUF->srcipaddr[1];
00305   fw->destipaddr[0] = BUF->destipaddr[0];
00306   fw->destipaddr[1] = BUF->destipaddr[1];
00307   fw->proto = BUF->proto;
00308 #if notdef
00309   fw->payload[0] = BUF->srcport;
00310   fw->payload[1] = BUF->destport;
00311 #endif
00312 #if UIP_REASSEMBLY > 0
00313   fw->len = BUF->len;
00314   fw->offset = BUF->ipoffset;
00315 #endif
00316 }
00317 /*------------------------------------------------------------------------------*/
00322 /*------------------------------------------------------------------------------*/
00323 static struct uip_fw_netif *
00324 find_netif(void)
00325 {
00326   struct uip_fw_netif *netif;
00327   
00328   /* Walk through every network interface to check for a match. */
00329   for(netif = netifs; netif != NULL; netif = netif->next) {
00330     if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr,
00331                       netif->netmask)) {
00332       /* If there was a match, we break the loop. */
00333       return netif;
00334     }
00335   }
00336   
00337   /* If no matching netif was found, we use default netif. */
00338   return defaultnetif;
00339 }
00340 /*------------------------------------------------------------------------------*/
00356 /*------------------------------------------------------------------------------*/
00357 u8_t
00358 uip_fw_output(void)
00359 {
00360   struct uip_fw_netif *netif;
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(/*BUF->proto == UIP_PROTO_UDP &&*/
00371      BUF->destipaddr[0] == 0xffff &&
00372      BUF->destipaddr[1] == 0xffff) {
00373     if(defaultnetif != NULL) {
00374       defaultnetif->output();
00375     }
00376     for(netif = netifs; netif != NULL; netif = netif->next) {
00377       netif->output();
00378     }
00379     return UIP_FW_OK;
00380   }
00381 #endif /* UIP_BROADCAST */
00382   
00383   netif = find_netif();
00384   /*  printf("uip_fw_output: netif %p ->output %p len %d\n", netif,
00385          netif->output,
00386          uip_len);*/
00387 
00388   if(netif == NULL) {
00389     return UIP_FW_NOROUTE;
00390   }
00391   /* If we now have found a suitable network interface, we call its
00392      output function to send out the packet. */
00393   return netif->output();
00394 }
00395 /*------------------------------------------------------------------------------*/
00404 /*------------------------------------------------------------------------------*/
00405 u8_t
00406 uip_fw_forward(void)
00407 {
00408   struct fwcache_entry *fw;
00409 
00410   /* First check if the packet is destined for ourselves and return 0
00411      to indicate that the packet should be processed locally. */
00412   if(BUF->destipaddr[0] == uip_hostaddr[0] &&
00413      BUF->destipaddr[1] == uip_hostaddr[1]) {
00414     return UIP_FW_LOCAL;
00415   }
00416 
00417   /* If we use ping IP address configuration, and our IP address is
00418      not yet configured, we should intercept all ICMP echo packets. */
00419 #if UIP_PINGADDRCONF
00420   if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 &&
00421      BUF->proto == UIP_PROTO_ICMP &&
00422      ICMPBUF->type == ICMP_ECHO) {
00423     return UIP_FW_LOCAL;
00424   }
00425 #endif /* UIP_PINGADDRCONF */
00426 
00427   /* Check if the packet is in the forwarding cache already, and if so
00428      we drop it. */
00429 
00430   for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
00431     if(fw->timer != 0 &&
00432 #if UIP_REASSEMBLY > 0
00433        fw->len == BUF->len &&
00434        fw->offset == BUF->ipoffset &&
00435 #endif
00436        fw->ipid == BUF->ipid &&
00437        fw->srcipaddr[0] == BUF->srcipaddr[0] &&
00438        fw->srcipaddr[1] == BUF->srcipaddr[1] &&
00439        fw->destipaddr[0] == BUF->destipaddr[0] &&
00440        fw->destipaddr[1] == BUF->destipaddr[1] &&
00441 #if notdef
00442        fw->payload[0] == BUF->srcport &&
00443        fw->payload[1] == BUF->destport &&
00444 #endif
00445        fw->proto == BUF->proto) {
00446       /* Drop packet. */
00447       return UIP_FW_FORWARDED;
00448     }
00449   }
00450 
00451   /* If the TTL reaches zero we produce an ICMP time exceeded message
00452      in the uip_buf buffer and forward that packet back to the sender
00453      of the packet. */
00454   if(BUF->ttl <= 1) {
00455     /* No time exceeded for broadcasts and multicasts! */
00456     if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
00457       return UIP_FW_LOCAL;
00458     }
00459     time_exceeded();
00460   }
00461   
00462   /* Decrement the TTL (time-to-live) value in the IP header */
00463   BUF->ttl = BUF->ttl - 1;
00464   
00465   /* Update the IP checksum. */
00466   if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) {
00467     BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1;
00468   } else {
00469     BUF->ipchksum = BUF->ipchksum + HTONS(0x0100);
00470   }
00471 
00472   if(uip_len > 0) {
00473     uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN];
00474     uip_fw_output();
00475   }
00476 
00477 #if UIP_BROADCAST
00478   if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
00479     return UIP_FW_LOCAL;
00480   }
00481 #endif /* UIP_BROADCAST */
00482 
00483   /* Return non-zero to indicate that the packet was forwarded and that no
00484      other processing should be made. */
00485   return UIP_FW_FORWARDED;
00486 }
00487 /*------------------------------------------------------------------------------*/
00494 /*------------------------------------------------------------------------------*/
00495 void
00496 uip_fw_register(struct uip_fw_netif *netif)
00497 {
00498   netif->next = netifs;
00499   netifs = netif;
00500 }
00501 /*------------------------------------------------------------------------------*/
00511 /*------------------------------------------------------------------------------*/
00512 void
00513 uip_fw_default(struct uip_fw_netif *netif)
00514 {
00515   defaultnetif = netif;
00516 }
00517 /*------------------------------------------------------------------------------*/
00521 /*------------------------------------------------------------------------------*/
00522 void
00523 uip_fw_periodic(void)
00524 {
00525   struct fwcache_entry *fw;
00526   for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
00527     if(fw->timer > 0) {
00528       --fw->timer;
00529     }
00530   }
00531 }
00532 /*------------------------------------------------------------------------------*/