uip-fw.c 14 KB

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