Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / net / uip-fw.c
1 /*
2  * Copyright (c) 2004, Swedish Institute of Computer Science.
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. Neither the name of the Institute nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the uIP TCP/IP stack
30  *
31  * Author: Adam Dunkels <adam@sics.se>
32  *
33  * $Id: uip-fw.c,v 1.1 2008/08/06 23:21:19 andrewlxia Exp $
34  */
35 /**
36  * \addtogroup uip
37  * @{
38  */
39
40 /**
41  * \defgroup uipfw uIP packet forwarding
42  * @{
43  *
44  */
45
46 /**
47  * \file
48  * uIP packet forwarding.
49  * \author Adam Dunkels <adam@sics.se>
50  *
51  * This file implements a number of simple functions which do packet
52  * forwarding over multiple network interfaces with uIP.
53  *
54  */
55
56 #include <uip/uip.h>
57 #include <uip/uip_arch.h>
58 #include <uip/uip-fw.h>
59
60 #include <string.h> /* for memcpy() */
61
62 /*
63  * The list of registered network interfaces.
64  */
65 static struct uip_fw_netif *netifs = NULL;
66
67 /*
68  * A pointer to the default network interface.
69  */
70 static struct uip_fw_netif *defaultnetif = NULL;
71
72 struct tcpip_hdr {
73   /* IP header. */
74   u8_t vhl,
75     tos;
76   u16_t len,
77     ipid,
78     ipoffset;
79   u8_t ttl,
80     proto;
81   u16_t ipchksum;
82   u16_t srcipaddr[2],
83     destipaddr[2];
84   
85   /* TCP header. */
86   u16_t srcport,
87     destport;
88   u8_t seqno[4],
89     ackno[4],
90     tcpoffset,
91     flags,
92     wnd[2];
93   u16_t tcpchksum;
94   u8_t urgp[2];
95   u8_t optdata[4];
96 };
97
98 struct icmpip_hdr {
99   /* IP header. */
100   u8_t vhl,
101     tos,
102     len[2],
103     ipid[2],
104     ipoffset[2],
105     ttl,
106     proto;
107   u16_t ipchksum;
108   u16_t srcipaddr[2],
109     destipaddr[2];
110   /* ICMP (echo) header. */
111   u8_t type, icode;
112   u16_t icmpchksum;
113   u16_t id, seqno;
114   u8_t payload[1];
115 };
116
117 /* ICMP ECHO. */
118 #define ICMP_ECHO 8
119
120 /* ICMP TIME-EXCEEDED. */
121 #define ICMP_TE 11
122
123 /*
124  * Pointer to the TCP/IP headers of the packet in the uip_buf buffer.
125  */
126 #define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
127
128 /*
129  * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer.
130  */
131 #define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
132
133 /*
134  * Certain fields of an IP packet that are used for identifying
135  * duplicate packets.
136  */
137 struct fwcache_entry {
138   u16_t timer;
139   
140   u16_t srcipaddr[2];
141   u16_t destipaddr[2];
142   u16_t ipid;
143   u8_t proto;
144   u8_t unused;
145
146 #if notdef
147   u16_t payload[2];
148 #endif
149
150 #if UIP_REASSEMBLY > 0
151   u16_t len, offset;
152 #endif
153 };
154
155 /*
156  * The number of packets to remember when looking for duplicates.
157  */
158 #ifdef UIP_CONF_FWCACHE_SIZE
159 #define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE
160 #else
161 #define FWCACHE_SIZE 2
162 #endif
163
164
165 /*
166  * A cache of packet header fields which are used for
167  * identifying duplicate packets.
168  */
169 static struct fwcache_entry fwcache[FWCACHE_SIZE];
170
171 /**
172  * \internal
173  * The time that a packet cache is active.
174  */
175 #define FW_TIME 20
176
177 /*------------------------------------------------------------------------------*/
178 /**
179  * Initialize the uIP packet forwarding module.
180  */
181 /*------------------------------------------------------------------------------*/
182 void
183 uip_fw_init(void)
184 {
185   struct uip_fw_netif *t;
186   defaultnetif = NULL;
187   while(netifs != NULL) {
188     t = netifs;
189     netifs = netifs->next;
190     t->next = NULL;
191   }
192 }
193 /*------------------------------------------------------------------------------*/
194 /**
195  * \internal
196  * Check if an IP address is within the network defined by an IP
197  * address and a netmask.
198  *
199  * \param ipaddr The IP address to be checked.
200  * \param netipaddr The IP address of the network.
201  * \param netmask The netmask of the network.
202  *
203  * \return Non-zero if IP address is in network, zero otherwise.
204  */
205 /*------------------------------------------------------------------------------*/
206 static unsigned char
207 ipaddr_maskcmp(u16_t *ipaddr, u16_t *netipaddr, u16_t *netmask)
208 {
209   return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) &&
210     (ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]);
211 }
212 /*------------------------------------------------------------------------------*/
213 /**
214  * \internal
215  * Send out an ICMP TIME-EXCEEDED message.
216  *
217  * This function replaces the packet in the uip_buf buffer with the
218  * ICMP packet.
219  */
220 /*------------------------------------------------------------------------------*/
221 static void
222 time_exceeded(void)
223 {
224   u16_t tmp16;
225
226   /* We don't send out ICMP errors for ICMP messages. */
227   if(ICMPBUF->proto == UIP_PROTO_ICMP) {
228     uip_len = 0;
229     return;
230   }
231   /* Copy fields from packet header into payload of this ICMP packet. */
232   memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28);
233
234   /* Set the ICMP type and code. */
235   ICMPBUF->type = ICMP_TE;
236   ICMPBUF->icode = 0;
237
238   /* Calculate the ICMP checksum. */
239   ICMPBUF->icmpchksum = 0;
240   ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36);
241
242   /* Set the IP destination address to be the source address of the
243      original packet. */
244   tmp16= BUF->destipaddr[0];
245   BUF->destipaddr[0] = BUF->srcipaddr[0];
246   BUF->srcipaddr[0] = tmp16;
247   tmp16 = BUF->destipaddr[1];
248   BUF->destipaddr[1] = BUF->srcipaddr[1];
249   BUF->srcipaddr[1] = tmp16;
250
251   /* Set our IP address as the source address. */
252   BUF->srcipaddr[0] = uip_hostaddr[0];
253   BUF->srcipaddr[1] = uip_hostaddr[1];
254
255   /* The size of the ICMP time exceeded packet is 36 + the size of the
256      IP header (20) = 56. */
257   uip_len = 56;
258   ICMPBUF->len[0] = 0;
259   ICMPBUF->len[1] = uip_len;
260
261   /* Fill in the other fields in the IP header. */
262   ICMPBUF->vhl = 0x45;
263   ICMPBUF->tos = 0;
264   ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0;
265   ICMPBUF->ttl  = UIP_TTL;
266   ICMPBUF->proto = UIP_PROTO_ICMP;
267   
268   /* Calculate IP checksum. */
269   ICMPBUF->ipchksum = 0;
270   ICMPBUF->ipchksum = ~(uip_ipchksum());
271
272
273 }
274 /*------------------------------------------------------------------------------*/
275 /**
276  * \internal
277  * Register a packet in the forwarding cache so that it won't be
278  * forwarded again.
279  */
280 /*------------------------------------------------------------------------------*/
281 static void
282 fwcache_register(void)
283 {
284   struct fwcache_entry *fw;
285   int i, oldest;
286
287   oldest = FW_TIME;
288   fw = NULL;
289   
290   /* Find the oldest entry in the cache. */
291   for(i = 0; i < FWCACHE_SIZE; ++i) {
292     if(fwcache[i].timer == 0) {
293       fw = &fwcache[i];
294       break;
295     } else if(fwcache[i].timer <= oldest) {
296       fw = &fwcache[i];
297       oldest = fwcache[i].timer;
298     }
299   }
300
301   fw->timer = FW_TIME;
302   fw->ipid = BUF->ipid;
303   fw->srcipaddr[0] = BUF->srcipaddr[0];
304   fw->srcipaddr[1] = BUF->srcipaddr[1];
305   fw->destipaddr[0] = BUF->destipaddr[0];
306   fw->destipaddr[1] = BUF->destipaddr[1];
307   fw->proto = BUF->proto;
308 #if notdef
309   fw->payload[0] = BUF->srcport;
310   fw->payload[1] = BUF->destport;
311 #endif
312 #if UIP_REASSEMBLY > 0
313   fw->len = BUF->len;
314   fw->offset = BUF->ipoffset;
315 #endif
316 }
317 /*------------------------------------------------------------------------------*/
318 /**
319  * \internal
320  * Find a network interface for the IP packet in uip_buf.
321  */
322 /*------------------------------------------------------------------------------*/
323 static struct uip_fw_netif *
324 find_netif(void)
325 {
326   struct uip_fw_netif *netif;
327   
328   /* Walk through every network interface to check for a match. */
329   for(netif = netifs; netif != NULL; netif = netif->next) {
330     if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr,
331                       netif->netmask)) {
332       /* If there was a match, we break the loop. */
333       return netif;
334     }
335   }
336   
337   /* If no matching netif was found, we use default netif. */
338   return defaultnetif;
339 }
340 /*------------------------------------------------------------------------------*/
341 /**
342  * Output an IP packet on the correct network interface.
343  *
344  * The IP packet should be present in the uip_buf buffer and its
345  * length in the global uip_len variable.
346  *
347  * \retval UIP_FW_ZEROLEN Indicates that a zero-length packet
348  * transmission was attempted and that no packet was sent.
349  *
350  * \retval UIP_FW_NOROUTE No suitable network interface could be found
351  * for the outbound packet, and the packet was not sent.
352  *
353  * \return The return value from the actual network interface output
354  * function is passed unmodified as a return value.
355  */
356 /*------------------------------------------------------------------------------*/
357 u8_t
358 uip_fw_output(void)
359 {
360   struct uip_fw_netif *netif;
361
362   if(uip_len == 0) {
363     return UIP_FW_ZEROLEN;
364   }
365
366   fwcache_register();
367
368 #if UIP_BROADCAST
369   /* Link local broadcasts go out on all interfaces. */
370   if(/*BUF->proto == UIP_PROTO_UDP &&*/
371      BUF->destipaddr[0] == 0xffff &&
372      BUF->destipaddr[1] == 0xffff) {
373     if(defaultnetif != NULL) {
374       defaultnetif->output();
375     }
376     for(netif = netifs; netif != NULL; netif = netif->next) {
377       netif->output();
378     }
379     return UIP_FW_OK;
380   }
381 #endif /* UIP_BROADCAST */
382   
383   netif = find_netif();
384   /*  printf("uip_fw_output: netif %p ->output %p len %d\n", netif,
385          netif->output,
386          uip_len);*/
387
388   if(netif == NULL) {
389     return UIP_FW_NOROUTE;
390   }
391   /* If we now have found a suitable network interface, we call its
392      output function to send out the packet. */
393   return netif->output();
394 }
395 /*------------------------------------------------------------------------------*/
396 /**
397  * Forward an IP packet in the uip_buf buffer.
398  *
399  *
400  *
401  * \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if
402  * the packet should be processed locally.
403  */
404 /*------------------------------------------------------------------------------*/
405 u8_t
406 uip_fw_forward(void)
407 {
408   struct fwcache_entry *fw;
409
410   /* First check if the packet is destined for ourselves and return 0
411      to indicate that the packet should be processed locally. */
412   if(BUF->destipaddr[0] == uip_hostaddr[0] &&
413      BUF->destipaddr[1] == uip_hostaddr[1]) {
414     return UIP_FW_LOCAL;
415   }
416
417   /* If we use ping IP address configuration, and our IP address is
418      not yet configured, we should intercept all ICMP echo packets. */
419 #if UIP_PINGADDRCONF
420   if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 &&
421      BUF->proto == UIP_PROTO_ICMP &&
422      ICMPBUF->type == ICMP_ECHO) {
423     return UIP_FW_LOCAL;
424   }
425 #endif /* UIP_PINGADDRCONF */
426
427   /* Check if the packet is in the forwarding cache already, and if so
428      we drop it. */
429
430   for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
431     if(fw->timer != 0 &&
432 #if UIP_REASSEMBLY > 0
433        fw->len == BUF->len &&
434        fw->offset == BUF->ipoffset &&
435 #endif
436        fw->ipid == BUF->ipid &&
437        fw->srcipaddr[0] == BUF->srcipaddr[0] &&
438        fw->srcipaddr[1] == BUF->srcipaddr[1] &&
439        fw->destipaddr[0] == BUF->destipaddr[0] &&
440        fw->destipaddr[1] == BUF->destipaddr[1] &&
441 #if notdef
442        fw->payload[0] == BUF->srcport &&
443        fw->payload[1] == BUF->destport &&
444 #endif
445        fw->proto == BUF->proto) {
446       /* Drop packet. */
447       return UIP_FW_FORWARDED;
448     }
449   }
450
451   /* If the TTL reaches zero we produce an ICMP time exceeded message
452      in the uip_buf buffer and forward that packet back to the sender
453      of the packet. */
454   if(BUF->ttl <= 1) {
455     /* No time exceeded for broadcasts and multicasts! */
456     if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
457       return UIP_FW_LOCAL;
458     }
459     time_exceeded();
460   }
461   
462   /* Decrement the TTL (time-to-live) value in the IP header */
463   BUF->ttl = BUF->ttl - 1;
464   
465   /* Update the IP checksum. */
466   if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) {
467     BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1;
468   } else {
469     BUF->ipchksum = BUF->ipchksum + HTONS(0x0100);
470   }
471
472   if(uip_len > 0) {
473     uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN];
474     uip_fw_output();
475   }
476
477 #if UIP_BROADCAST
478   if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
479     return UIP_FW_LOCAL;
480   }
481 #endif /* UIP_BROADCAST */
482
483   /* Return non-zero to indicate that the packet was forwarded and that no
484      other processing should be made. */
485   return UIP_FW_FORWARDED;
486 }
487 /*------------------------------------------------------------------------------*/
488 /**
489  * Register a network interface with the forwarding module.
490  *
491  * \param netif A pointer to the network interface that is to be
492  * registered.
493  */
494 /*------------------------------------------------------------------------------*/
495 void
496 uip_fw_register(struct uip_fw_netif *netif)
497 {
498   netif->next = netifs;
499   netifs = netif;
500 }
501 /*------------------------------------------------------------------------------*/
502 /**
503  * Register a default network interface.
504  *
505  * All packets that don't go out on any of the other interfaces will
506  * be routed to the default interface.
507  *
508  * \param netif A pointer to the network interface that is to be
509  * registered.
510  */
511 /*------------------------------------------------------------------------------*/
512 void
513 uip_fw_default(struct uip_fw_netif *netif)
514 {
515   defaultnetif = netif;
516 }
517 /*------------------------------------------------------------------------------*/
518 /**
519  * Perform periodic processing.
520  */
521 /*------------------------------------------------------------------------------*/
522 void
523 uip_fw_periodic(void)
524 {
525   struct fwcache_entry *fw;
526   for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
527     if(fw->timer > 0) {
528       --fw->timer;
529     }
530   }
531 }
532 /*------------------------------------------------------------------------------*/