Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass picotcp@tass.be
Date:
Wed Apr 09 14:31:41 2014 +0200
Revision:
149:5f4cb161cec3
Parent:
131:4758606c9316
Child:
152:a3d286bf94e5
Update from git masterbranch

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 68:0847e35d08a6 1 /*********************************************************************
TASS Belgium NV 131:4758606c9316 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
TASS Belgium NV 131:4758606c9316 3 See LICENSE and COPYING for usage.
tass 68:0847e35d08a6 4
TASS Belgium NV 131:4758606c9316 5 .
tass 68:0847e35d08a6 6
TASS Belgium NV 131:4758606c9316 7 Authors: Kristof Roelants, Brecht Van Cauwenberghe,
tass 68:0847e35d08a6 8 Simon Maes, Philippe Mariman
TASS Belgium NV 131:4758606c9316 9 *********************************************************************/
tass 68:0847e35d08a6 10
tass 68:0847e35d08a6 11 #include "pico_stack.h"
tass 68:0847e35d08a6 12 #include "pico_frame.h"
tass 68:0847e35d08a6 13 #include "pico_tcp.h"
tass 68:0847e35d08a6 14 #include "pico_udp.h"
tass 68:0847e35d08a6 15 #include "pico_ipv4.h"
tass 68:0847e35d08a6 16 #include "pico_addressing.h"
tass 68:0847e35d08a6 17 #include "pico_nat.h"
tass 68:0847e35d08a6 18
tass 68:0847e35d08a6 19 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 20 #ifdef PICO_SUPPORT_NAT
tass 68:0847e35d08a6 21
TASS Belgium NV 131:4758606c9316 22 #define nat_dbg(...) do {} while(0)
TASS Belgium NV 131:4758606c9316 23 /* #define nat_dbg dbg */
tass 68:0847e35d08a6 24 #define PICO_NAT_TIMEWAIT 240000 /* msec (4 mins) */
tass 68:0847e35d08a6 25
tass 68:0847e35d08a6 26 #define PICO_NAT_INBOUND 0
tass 68:0847e35d08a6 27 #define PICO_NAT_OUTBOUND 1
tass 68:0847e35d08a6 28
tass 68:0847e35d08a6 29 struct pico_nat_tuple {
TASS Belgium NV 131:4758606c9316 30 uint8_t proto;
TASS Belgium NV 131:4758606c9316 31 uint16_t conn_active : 11;
TASS Belgium NV 131:4758606c9316 32 uint16_t portforward : 1;
TASS Belgium NV 131:4758606c9316 33 uint16_t rst : 1;
TASS Belgium NV 131:4758606c9316 34 uint16_t syn : 1;
TASS Belgium NV 131:4758606c9316 35 uint16_t fin_in : 1;
TASS Belgium NV 131:4758606c9316 36 uint16_t fin_out : 1;
TASS Belgium NV 131:4758606c9316 37 uint16_t src_port;
TASS Belgium NV 131:4758606c9316 38 uint16_t dst_port;
TASS Belgium NV 131:4758606c9316 39 uint16_t nat_port;
TASS Belgium NV 131:4758606c9316 40 struct pico_ip4 src_addr;
TASS Belgium NV 131:4758606c9316 41 struct pico_ip4 dst_addr;
TASS Belgium NV 131:4758606c9316 42 struct pico_ip4 nat_addr;
tass 68:0847e35d08a6 43 };
tass 68:0847e35d08a6 44
tass 68:0847e35d08a6 45 static struct pico_ipv4_link *nat_link = NULL;
tass 68:0847e35d08a6 46
TASS Belgium NV 131:4758606c9316 47 static int nat_cmp_inbound(void *ka, void *kb)
tass 68:0847e35d08a6 48 {
TASS Belgium NV 131:4758606c9316 49 struct pico_nat_tuple *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 50
TASS Belgium NV 131:4758606c9316 51 if (a->nat_port < b->nat_port)
TASS Belgium NV 131:4758606c9316 52 return -1;
tass 68:0847e35d08a6 53
TASS Belgium NV 131:4758606c9316 54 if (a->nat_port > b->nat_port)
TASS Belgium NV 131:4758606c9316 55 return 1;
TASS Belgium NV 131:4758606c9316 56
TASS Belgium NV 131:4758606c9316 57 if (a->proto < b->proto)
TASS Belgium NV 131:4758606c9316 58 return -1;
TASS Belgium NV 131:4758606c9316 59
TASS Belgium NV 131:4758606c9316 60 if (a->proto > b->proto)
TASS Belgium NV 131:4758606c9316 61 return 1;
TASS Belgium NV 131:4758606c9316 62
TASS Belgium NV 131:4758606c9316 63 return 0; /* identical */
tass 68:0847e35d08a6 64 }
tass 68:0847e35d08a6 65
TASS Belgium NV 131:4758606c9316 66 static int nat_cmp_outbound(void *ka, void *kb)
tass 68:0847e35d08a6 67 {
TASS Belgium NV 131:4758606c9316 68 struct pico_nat_tuple *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 69
TASS Belgium NV 131:4758606c9316 70 if (a->src_addr.addr < b->src_addr.addr)
TASS Belgium NV 131:4758606c9316 71 return -1;
TASS Belgium NV 131:4758606c9316 72
TASS Belgium NV 131:4758606c9316 73 if (a->src_addr.addr > b->src_addr.addr)
TASS Belgium NV 131:4758606c9316 74 return 1;
tass 68:0847e35d08a6 75
TASS Belgium NV 131:4758606c9316 76 if (a->src_port < b->src_port)
TASS Belgium NV 131:4758606c9316 77 return -1;
TASS Belgium NV 131:4758606c9316 78
TASS Belgium NV 131:4758606c9316 79 if (a->src_port > b->src_port)
TASS Belgium NV 131:4758606c9316 80 return 1;
TASS Belgium NV 131:4758606c9316 81
TASS Belgium NV 131:4758606c9316 82 if (a->proto < b->proto)
TASS Belgium NV 131:4758606c9316 83 return -1;
TASS Belgium NV 131:4758606c9316 84
TASS Belgium NV 131:4758606c9316 85 if (a->proto > b->proto)
TASS Belgium NV 131:4758606c9316 86 return 1;
TASS Belgium NV 131:4758606c9316 87
TASS Belgium NV 131:4758606c9316 88 return 0; /* identical */
tass 68:0847e35d08a6 89 }
tass 68:0847e35d08a6 90
tass 68:0847e35d08a6 91 PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound);
tass 68:0847e35d08a6 92 PICO_TREE_DECLARE(NATInbound, nat_cmp_inbound);
tass 68:0847e35d08a6 93
tass 68:0847e35d08a6 94 void pico_ipv4_nat_print_table(void)
tass 68:0847e35d08a6 95 {
tass picotcp@tass.be 149:5f4cb161cec3 96 struct pico_nat_tuple *t = NULL;
TASS Belgium NV 131:4758606c9316 97 struct pico_tree_node *index = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 98 (void)t;
tass 68:0847e35d08a6 99
TASS Belgium NV 131:4758606c9316 100 nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
TASS Belgium NV 131:4758606c9316 101 nat_dbg("+ NAT table +\n");
TASS Belgium NV 131:4758606c9316 102 nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
TASS Belgium NV 131:4758606c9316 103 nat_dbg("+ src_addr | src_port | dst_addr | dst_port | nat_addr | nat_port | proto | conn active | FIN1 | FIN2 | SYN | RST | FORW +\n");
TASS Belgium NV 131:4758606c9316 104 nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
tass 68:0847e35d08a6 105
TASS Belgium NV 131:4758606c9316 106 pico_tree_foreach(index, &NATOutbound)
TASS Belgium NV 131:4758606c9316 107 {
TASS Belgium NV 131:4758606c9316 108 t = index->keyValue;
TASS Belgium NV 131:4758606c9316 109 nat_dbg("+ %08X | %05u | %08X | %05u | %08X | %05u | %03u | %03u | %u | %u | %u | %u | %u +\n",
TASS Belgium NV 131:4758606c9316 110 long_be(t->src_addr.addr), t->src_port, long_be(t->dst_addr.addr), t->dst_port, long_be(t->nat_addr.addr), t->nat_port,
TASS Belgium NV 131:4758606c9316 111 t->proto, t->conn_active, t->fin_in, t->fin_out, t->syn, t->rst, t->portforward);
TASS Belgium NV 131:4758606c9316 112 }
TASS Belgium NV 131:4758606c9316 113 nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
tass 68:0847e35d08a6 114 }
tass 68:0847e35d08a6 115
TASS Belgium NV 131:4758606c9316 116 /*
TASS Belgium NV 131:4758606c9316 117 2 options:
tass 68:0847e35d08a6 118 find on nat_port and proto
TASS Belgium NV 131:4758606c9316 119 find on src_addr, src_port and proto
TASS Belgium NV 131:4758606c9316 120 zero the unused parameters
TASS Belgium NV 131:4758606c9316 121 */
tass 68:0847e35d08a6 122 static struct pico_nat_tuple *pico_ipv4_nat_find_tuple(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
tass 68:0847e35d08a6 123 {
TASS Belgium NV 131:4758606c9316 124 struct pico_nat_tuple *found = NULL, test = {
TASS Belgium NV 131:4758606c9316 125 0
TASS Belgium NV 131:4758606c9316 126 };
tass 68:0847e35d08a6 127
TASS Belgium NV 131:4758606c9316 128 test.nat_port = nat_port;
TASS Belgium NV 131:4758606c9316 129 test.src_port = src_port;
TASS Belgium NV 131:4758606c9316 130 test.proto = proto;
TASS Belgium NV 131:4758606c9316 131 if (src_addr)
TASS Belgium NV 131:4758606c9316 132 test.src_addr = *src_addr;
tass 68:0847e35d08a6 133
TASS Belgium NV 131:4758606c9316 134 if (nat_port)
TASS Belgium NV 131:4758606c9316 135 found = pico_tree_findKey(&NATInbound, &test);
TASS Belgium NV 131:4758606c9316 136 else
TASS Belgium NV 131:4758606c9316 137 found = pico_tree_findKey(&NATOutbound, &test);
tass 68:0847e35d08a6 138
TASS Belgium NV 131:4758606c9316 139 if (found)
TASS Belgium NV 131:4758606c9316 140 return found;
TASS Belgium NV 131:4758606c9316 141 else
TASS Belgium NV 131:4758606c9316 142 return NULL;
tass 68:0847e35d08a6 143 }
tass 68:0847e35d08a6 144
tass 68:0847e35d08a6 145 int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
tass 68:0847e35d08a6 146 {
TASS Belgium NV 131:4758606c9316 147 struct pico_nat_tuple *t = NULL;
tass 68:0847e35d08a6 148
TASS Belgium NV 131:4758606c9316 149 t = pico_ipv4_nat_find_tuple(nat_port, src_addr, src_port, proto);
TASS Belgium NV 131:4758606c9316 150 if (t)
TASS Belgium NV 131:4758606c9316 151 return 1;
TASS Belgium NV 131:4758606c9316 152 else
TASS Belgium NV 131:4758606c9316 153 return 0;
tass 68:0847e35d08a6 154 }
tass 68:0847e35d08a6 155
TASS Belgium NV 131:4758606c9316 156 static struct pico_nat_tuple *pico_ipv4_nat_add(struct pico_ip4 dst_addr, uint16_t dst_port, struct pico_ip4 src_addr, uint16_t src_port,
tass 68:0847e35d08a6 157 struct pico_ip4 nat_addr, uint16_t nat_port, uint8_t proto)
tass 68:0847e35d08a6 158 {
tass picotcp@tass.be 149:5f4cb161cec3 159 struct pico_nat_tuple *t = PICO_ZALLOC(sizeof(struct pico_nat_tuple));
TASS Belgium NV 131:4758606c9316 160 if (!t) {
TASS Belgium NV 131:4758606c9316 161 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 162 return NULL;
TASS Belgium NV 131:4758606c9316 163 }
tass 68:0847e35d08a6 164
TASS Belgium NV 131:4758606c9316 165 t->dst_addr = dst_addr;
TASS Belgium NV 131:4758606c9316 166 t->dst_port = dst_port;
TASS Belgium NV 131:4758606c9316 167 t->src_addr = src_addr;
TASS Belgium NV 131:4758606c9316 168 t->src_port = src_port;
TASS Belgium NV 131:4758606c9316 169 t->nat_addr = nat_addr;
TASS Belgium NV 131:4758606c9316 170 t->nat_port = nat_port;
TASS Belgium NV 131:4758606c9316 171 t->proto = proto;
TASS Belgium NV 131:4758606c9316 172 t->conn_active = 1;
TASS Belgium NV 131:4758606c9316 173 t->portforward = 0;
TASS Belgium NV 131:4758606c9316 174 t->rst = 0;
TASS Belgium NV 131:4758606c9316 175 t->syn = 0;
TASS Belgium NV 131:4758606c9316 176 t->fin_in = 0;
TASS Belgium NV 131:4758606c9316 177 t->fin_out = 0;
tass 68:0847e35d08a6 178
TASS Belgium NV 131:4758606c9316 179 if (pico_tree_insert(&NATOutbound, t)) {
tass picotcp@tass.be 149:5f4cb161cec3 180 PICO_FREE(t);
TASS Belgium NV 131:4758606c9316 181 return NULL;
TASS Belgium NV 131:4758606c9316 182 }
tass 68:0847e35d08a6 183
TASS Belgium NV 131:4758606c9316 184 if (pico_tree_insert(&NATInbound, t)) {
TASS Belgium NV 131:4758606c9316 185 pico_tree_delete(&NATOutbound, t);
tass picotcp@tass.be 149:5f4cb161cec3 186 PICO_FREE(t);
TASS Belgium NV 131:4758606c9316 187 return NULL;
TASS Belgium NV 131:4758606c9316 188 }
TASS Belgium NV 131:4758606c9316 189
TASS Belgium NV 131:4758606c9316 190 return t;
tass 68:0847e35d08a6 191 }
tass 68:0847e35d08a6 192
tass 68:0847e35d08a6 193 static int pico_ipv4_nat_del(uint16_t nat_port, uint8_t proto)
tass 68:0847e35d08a6 194 {
TASS Belgium NV 131:4758606c9316 195 struct pico_nat_tuple *t = NULL;
TASS Belgium NV 131:4758606c9316 196 t = pico_ipv4_nat_find_tuple(nat_port, NULL, 0, proto);
TASS Belgium NV 131:4758606c9316 197 if (t) {
TASS Belgium NV 131:4758606c9316 198 pico_tree_delete(&NATOutbound, t);
TASS Belgium NV 131:4758606c9316 199 pico_tree_delete(&NATInbound, t);
tass picotcp@tass.be 149:5f4cb161cec3 200 PICO_FREE(t);
TASS Belgium NV 131:4758606c9316 201 }
TASS Belgium NV 131:4758606c9316 202
TASS Belgium NV 131:4758606c9316 203 return 0;
tass 68:0847e35d08a6 204 }
tass 68:0847e35d08a6 205
tass 68:0847e35d08a6 206 static struct pico_nat_tuple *pico_ipv4_nat_generate_tuple(struct pico_frame *f)
tass 68:0847e35d08a6 207 {
TASS Belgium NV 131:4758606c9316 208 struct pico_trans *trans = NULL;
TASS Belgium NV 131:4758606c9316 209 struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
TASS Belgium NV 131:4758606c9316 210 uint16_t nport = 0;
TASS Belgium NV 131:4758606c9316 211 uint8_t retry = 32;
tass 68:0847e35d08a6 212
TASS Belgium NV 131:4758606c9316 213 /* generate NAT port */
TASS Belgium NV 131:4758606c9316 214 do {
TASS Belgium NV 131:4758606c9316 215 uint32_t rand = pico_rand();
TASS Belgium NV 131:4758606c9316 216 nport = (uint16_t) (rand & 0xFFFFU);
TASS Belgium NV 131:4758606c9316 217 nport = (uint16_t)((nport % (65535 - 1024)) + 1024U);
TASS Belgium NV 131:4758606c9316 218 nport = short_be(nport);
tass 68:0847e35d08a6 219
TASS Belgium NV 131:4758606c9316 220 if (pico_is_port_free(net->proto, nport, NULL, &pico_proto_ipv4))
TASS Belgium NV 131:4758606c9316 221 break;
TASS Belgium NV 131:4758606c9316 222 } while (--retry);
tass 68:0847e35d08a6 223
TASS Belgium NV 131:4758606c9316 224 if (!retry)
TASS Belgium NV 131:4758606c9316 225 return NULL;
TASS Belgium NV 131:4758606c9316 226
TASS Belgium NV 131:4758606c9316 227 switch (net->proto) {
tass 68:0847e35d08a6 228 case PICO_PROTO_TCP:
tass 68:0847e35d08a6 229 {
TASS Belgium NV 131:4758606c9316 230 struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 231 trans = (struct pico_trans *)&tcp->trans;
TASS Belgium NV 131:4758606c9316 232 break;
tass 68:0847e35d08a6 233 }
tass 68:0847e35d08a6 234 case PICO_PROTO_UDP:
tass 68:0847e35d08a6 235 {
TASS Belgium NV 131:4758606c9316 236 struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 237 trans = (struct pico_trans *)&udp->trans;
TASS Belgium NV 131:4758606c9316 238 break;
tass 68:0847e35d08a6 239 }
tass 68:0847e35d08a6 240 case PICO_PROTO_ICMP4:
TASS Belgium NV 131:4758606c9316 241 /* XXX: implement */
TASS Belgium NV 131:4758606c9316 242 break;
tass 68:0847e35d08a6 243
tass 68:0847e35d08a6 244 default:
TASS Belgium NV 131:4758606c9316 245 return NULL;
TASS Belgium NV 131:4758606c9316 246 }
tass 68:0847e35d08a6 247
TASS Belgium NV 131:4758606c9316 248 return pico_ipv4_nat_add(net->dst, trans->dport, net->src, trans->sport, nat_link->address, nport, net->proto);
TASS Belgium NV 131:4758606c9316 249 /* XXX return pico_ipv4_nat_add(nat_link->address, port, net->src, trans->sport, net->proto); */
tass 68:0847e35d08a6 250 }
tass 68:0847e35d08a6 251
tass 68:0847e35d08a6 252 static int pico_ipv4_nat_snif_session(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
tass 68:0847e35d08a6 253 {
TASS Belgium NV 131:4758606c9316 254 struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
TASS Belgium NV 131:4758606c9316 255
TASS Belgium NV 131:4758606c9316 256 switch (net->proto) {
tass 68:0847e35d08a6 257 case PICO_PROTO_TCP:
tass 68:0847e35d08a6 258 {
TASS Belgium NV 131:4758606c9316 259 struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
TASS Belgium NV 131:4758606c9316 260 if (tcp->flags & PICO_TCP_SYN)
TASS Belgium NV 131:4758606c9316 261 t->syn = 1;
TASS Belgium NV 131:4758606c9316 262
TASS Belgium NV 131:4758606c9316 263 if (tcp->flags & PICO_TCP_RST)
TASS Belgium NV 131:4758606c9316 264 t->rst = 1;
TASS Belgium NV 131:4758606c9316 265
TASS Belgium NV 131:4758606c9316 266 if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_INBOUND))
TASS Belgium NV 131:4758606c9316 267 t->fin_in = 1;
TASS Belgium NV 131:4758606c9316 268
TASS Belgium NV 131:4758606c9316 269 if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_OUTBOUND))
TASS Belgium NV 131:4758606c9316 270 t->fin_out = 1;
TASS Belgium NV 131:4758606c9316 271
TASS Belgium NV 131:4758606c9316 272 break;
tass 68:0847e35d08a6 273 }
tass 68:0847e35d08a6 274
tass 68:0847e35d08a6 275 case PICO_PROTO_UDP:
TASS Belgium NV 131:4758606c9316 276 t->conn_active = 1;
TASS Belgium NV 131:4758606c9316 277 break;
tass 68:0847e35d08a6 278
tass 68:0847e35d08a6 279 case PICO_PROTO_ICMP4:
TASS Belgium NV 131:4758606c9316 280 /* XXX: implement */
TASS Belgium NV 131:4758606c9316 281 break;
tass 68:0847e35d08a6 282
tass 68:0847e35d08a6 283 default:
TASS Belgium NV 131:4758606c9316 284 return -1;
TASS Belgium NV 131:4758606c9316 285 }
tass 68:0847e35d08a6 286
TASS Belgium NV 131:4758606c9316 287 return 0;
tass 68:0847e35d08a6 288 }
tass 68:0847e35d08a6 289
tass 128:ae39e6e81531 290 static void pico_ipv4_nat_table_cleanup(pico_time now, void *_unused)
tass 68:0847e35d08a6 291 {
TASS Belgium NV 131:4758606c9316 292 struct pico_tree_node *index = NULL, *_tmp = NULL;
TASS Belgium NV 131:4758606c9316 293 struct pico_nat_tuple *t = NULL;
TASS Belgium NV 131:4758606c9316 294 IGNORE_PARAMETER(now);
TASS Belgium NV 131:4758606c9316 295 IGNORE_PARAMETER(_unused);
TASS Belgium NV 131:4758606c9316 296 nat_dbg("NAT: before table cleanup:\n");
TASS Belgium NV 131:4758606c9316 297 pico_ipv4_nat_print_table();
tass 68:0847e35d08a6 298
TASS Belgium NV 131:4758606c9316 299 pico_tree_foreach_reverse_safe(index, &NATOutbound, _tmp)
tass 68:0847e35d08a6 300 {
TASS Belgium NV 131:4758606c9316 301 t = index->keyValue;
TASS Belgium NV 131:4758606c9316 302 switch (t->proto)
TASS Belgium NV 131:4758606c9316 303 {
TASS Belgium NV 131:4758606c9316 304 case PICO_PROTO_TCP:
TASS Belgium NV 131:4758606c9316 305 if (t->portforward)
TASS Belgium NV 131:4758606c9316 306 break;
TASS Belgium NV 131:4758606c9316 307 else if (t->conn_active == 0 || t->conn_active > 360) /* conn active for > 24 hours */
TASS Belgium NV 131:4758606c9316 308 pico_ipv4_nat_del(t->nat_port, t->proto);
TASS Belgium NV 131:4758606c9316 309 else if (t->rst || (t->fin_in && t->fin_out))
TASS Belgium NV 131:4758606c9316 310 t->conn_active = 0;
TASS Belgium NV 131:4758606c9316 311 else
TASS Belgium NV 131:4758606c9316 312 t->conn_active++;
TASS Belgium NV 131:4758606c9316 313
TASS Belgium NV 131:4758606c9316 314 break;
tass 68:0847e35d08a6 315
TASS Belgium NV 131:4758606c9316 316 case PICO_PROTO_UDP:
TASS Belgium NV 131:4758606c9316 317 if (t->portforward)
TASS Belgium NV 131:4758606c9316 318 break;
TASS Belgium NV 131:4758606c9316 319 else if (t->conn_active > 1)
TASS Belgium NV 131:4758606c9316 320 pico_ipv4_nat_del(t->nat_port, t->proto);
TASS Belgium NV 131:4758606c9316 321 else
TASS Belgium NV 131:4758606c9316 322 t->conn_active++;
TASS Belgium NV 131:4758606c9316 323
TASS Belgium NV 131:4758606c9316 324 break;
tass 68:0847e35d08a6 325
TASS Belgium NV 131:4758606c9316 326 case PICO_PROTO_ICMP4:
TASS Belgium NV 131:4758606c9316 327 if (t->conn_active > 1)
TASS Belgium NV 131:4758606c9316 328 pico_ipv4_nat_del(t->nat_port, t->proto);
TASS Belgium NV 131:4758606c9316 329 else
TASS Belgium NV 131:4758606c9316 330 t->conn_active++;
tass 68:0847e35d08a6 331
TASS Belgium NV 131:4758606c9316 332 default:
TASS Belgium NV 131:4758606c9316 333 /* unknown protocol in NAT table, delete when it has existed NAT_TIMEWAIT */
TASS Belgium NV 131:4758606c9316 334 if (t->conn_active > 1)
TASS Belgium NV 131:4758606c9316 335 pico_ipv4_nat_del(t->nat_port, t->proto);
TASS Belgium NV 131:4758606c9316 336 else
TASS Belgium NV 131:4758606c9316 337 t->conn_active++;
TASS Belgium NV 131:4758606c9316 338 }
tass 68:0847e35d08a6 339 }
tass 68:0847e35d08a6 340
TASS Belgium NV 131:4758606c9316 341 nat_dbg("NAT: after table cleanup:\n");
TASS Belgium NV 131:4758606c9316 342 pico_ipv4_nat_print_table();
TASS Belgium NV 131:4758606c9316 343 pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
tass 68:0847e35d08a6 344 }
tass 68:0847e35d08a6 345
tass 68:0847e35d08a6 346 int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
tass 68:0847e35d08a6 347 {
TASS Belgium NV 131:4758606c9316 348 struct pico_nat_tuple *t = NULL;
TASS Belgium NV 131:4758606c9316 349 struct pico_ip4 any_addr = {
TASS Belgium NV 131:4758606c9316 350 0
TASS Belgium NV 131:4758606c9316 351 };
TASS Belgium NV 131:4758606c9316 352 uint16_t any_port = 0;
tass 68:0847e35d08a6 353
TASS Belgium NV 131:4758606c9316 354 switch (flag)
TASS Belgium NV 131:4758606c9316 355 {
tass 68:0847e35d08a6 356 case PICO_NAT_PORT_FORWARD_ADD:
TASS Belgium NV 131:4758606c9316 357 t = pico_ipv4_nat_add(any_addr, any_port, src_addr, src_port, nat_addr, nat_port, proto);
TASS Belgium NV 131:4758606c9316 358 if (!t) {
TASS Belgium NV 131:4758606c9316 359 pico_err = PICO_ERR_EAGAIN;
TASS Belgium NV 131:4758606c9316 360 return -1;
TASS Belgium NV 131:4758606c9316 361 }
TASS Belgium NV 131:4758606c9316 362
TASS Belgium NV 131:4758606c9316 363 t->portforward = 1;
TASS Belgium NV 131:4758606c9316 364 break;
tass 68:0847e35d08a6 365
tass 68:0847e35d08a6 366 case PICO_NAT_PORT_FORWARD_DEL:
TASS Belgium NV 131:4758606c9316 367 return pico_ipv4_nat_del(nat_port, proto);
tass 68:0847e35d08a6 368
tass 68:0847e35d08a6 369 default:
TASS Belgium NV 131:4758606c9316 370 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 371 return -1;
TASS Belgium NV 131:4758606c9316 372 }
tass 68:0847e35d08a6 373
TASS Belgium NV 131:4758606c9316 374 pico_ipv4_nat_print_table();
TASS Belgium NV 131:4758606c9316 375 return 0;
tass 68:0847e35d08a6 376 }
tass 68:0847e35d08a6 377
tass 68:0847e35d08a6 378 int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
tass 68:0847e35d08a6 379 {
TASS Belgium NV 131:4758606c9316 380 struct pico_nat_tuple *tuple = NULL;
TASS Belgium NV 131:4758606c9316 381 struct pico_trans *trans = NULL;
TASS Belgium NV 131:4758606c9316 382 struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
tass 68:0847e35d08a6 383
TASS Belgium NV 131:4758606c9316 384 if (!pico_ipv4_nat_is_enabled(link_addr))
TASS Belgium NV 131:4758606c9316 385 return -1;
tass 68:0847e35d08a6 386
TASS Belgium NV 131:4758606c9316 387 switch (net->proto) {
tass picotcp@tass.be 149:5f4cb161cec3 388 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 389 case PICO_PROTO_TCP:
tass 68:0847e35d08a6 390 {
TASS Belgium NV 131:4758606c9316 391 struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 392 trans = (struct pico_trans *)&tcp->trans;
TASS Belgium NV 131:4758606c9316 393 tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
TASS Belgium NV 131:4758606c9316 394 if (!tuple)
TASS Belgium NV 131:4758606c9316 395 return -1;
TASS Belgium NV 131:4758606c9316 396
TASS Belgium NV 131:4758606c9316 397 /* replace dst IP and dst PORT */
TASS Belgium NV 131:4758606c9316 398 net->dst = tuple->src_addr;
TASS Belgium NV 131:4758606c9316 399 trans->dport = tuple->src_port;
TASS Belgium NV 131:4758606c9316 400 /* recalculate CRC */
TASS Belgium NV 131:4758606c9316 401 tcp->crc = 0;
TASS Belgium NV 131:4758606c9316 402 tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
TASS Belgium NV 131:4758606c9316 403 break;
tass 68:0847e35d08a6 404 }
tass picotcp@tass.be 149:5f4cb161cec3 405 #endif
tass picotcp@tass.be 149:5f4cb161cec3 406 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 407 case PICO_PROTO_UDP:
tass 68:0847e35d08a6 408 {
TASS Belgium NV 131:4758606c9316 409 struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 410 trans = (struct pico_trans *)&udp->trans;
TASS Belgium NV 131:4758606c9316 411 tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
TASS Belgium NV 131:4758606c9316 412 if (!tuple)
TASS Belgium NV 131:4758606c9316 413 return -1;
TASS Belgium NV 131:4758606c9316 414
TASS Belgium NV 131:4758606c9316 415 /* replace dst IP and dst PORT */
TASS Belgium NV 131:4758606c9316 416 net->dst = tuple->src_addr;
TASS Belgium NV 131:4758606c9316 417 trans->dport = tuple->src_port;
TASS Belgium NV 131:4758606c9316 418 /* recalculate CRC */
TASS Belgium NV 131:4758606c9316 419 udp->crc = 0;
TASS Belgium NV 131:4758606c9316 420 udp->crc = short_be(pico_udp_checksum_ipv4(f));
TASS Belgium NV 131:4758606c9316 421 break;
tass 68:0847e35d08a6 422 }
tass picotcp@tass.be 149:5f4cb161cec3 423 #endif
tass 68:0847e35d08a6 424 case PICO_PROTO_ICMP4:
TASS Belgium NV 131:4758606c9316 425 /* XXX reimplement */
TASS Belgium NV 131:4758606c9316 426 break;
tass 68:0847e35d08a6 427
tass 68:0847e35d08a6 428 default:
TASS Belgium NV 131:4758606c9316 429 nat_dbg("NAT ERROR: inbound NAT on erroneous protocol\n");
TASS Belgium NV 131:4758606c9316 430 return -1;
TASS Belgium NV 131:4758606c9316 431 }
tass 68:0847e35d08a6 432
TASS Belgium NV 131:4758606c9316 433 pico_ipv4_nat_snif_session(tuple, f, PICO_NAT_INBOUND);
TASS Belgium NV 131:4758606c9316 434 net->crc = 0;
TASS Belgium NV 131:4758606c9316 435 net->crc = short_be(pico_checksum(net, f->net_len));
tass 68:0847e35d08a6 436
TASS Belgium NV 131:4758606c9316 437 nat_dbg("NAT: inbound translation {dst.addr, dport}: {%08X,%u} -> {%08X,%u}\n",
tass 68:0847e35d08a6 438 tuple->nat_addr.addr, short_be(tuple->nat_port), tuple->src_addr.addr, short_be(tuple->src_port));
tass 68:0847e35d08a6 439
TASS Belgium NV 131:4758606c9316 440 return 0;
tass 68:0847e35d08a6 441 }
tass 68:0847e35d08a6 442
tass 68:0847e35d08a6 443 int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
tass 68:0847e35d08a6 444 {
TASS Belgium NV 131:4758606c9316 445 struct pico_nat_tuple *tuple = NULL;
TASS Belgium NV 131:4758606c9316 446 struct pico_trans *trans = NULL;
TASS Belgium NV 131:4758606c9316 447 struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
tass 68:0847e35d08a6 448
TASS Belgium NV 131:4758606c9316 449 if (!pico_ipv4_nat_is_enabled(link_addr))
TASS Belgium NV 131:4758606c9316 450 return -1;
tass 68:0847e35d08a6 451
TASS Belgium NV 131:4758606c9316 452 switch (net->proto) {
tass picotcp@tass.be 149:5f4cb161cec3 453 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 454 case PICO_PROTO_TCP:
tass 68:0847e35d08a6 455 {
TASS Belgium NV 131:4758606c9316 456 struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 457 trans = (struct pico_trans *)&tcp->trans;
TASS Belgium NV 131:4758606c9316 458 tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
TASS Belgium NV 131:4758606c9316 459 if (!tuple)
TASS Belgium NV 131:4758606c9316 460 tuple = pico_ipv4_nat_generate_tuple(f);
TASS Belgium NV 131:4758606c9316 461
TASS Belgium NV 131:4758606c9316 462 /* replace src IP and src PORT */
TASS Belgium NV 131:4758606c9316 463 net->src = tuple->nat_addr;
TASS Belgium NV 131:4758606c9316 464 trans->sport = tuple->nat_port;
TASS Belgium NV 131:4758606c9316 465 /* recalculate CRC */
TASS Belgium NV 131:4758606c9316 466 tcp->crc = 0;
TASS Belgium NV 131:4758606c9316 467 tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
TASS Belgium NV 131:4758606c9316 468 break;
tass 68:0847e35d08a6 469 }
tass picotcp@tass.be 149:5f4cb161cec3 470 #endif
tass picotcp@tass.be 149:5f4cb161cec3 471 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 472 case PICO_PROTO_UDP:
tass 68:0847e35d08a6 473 {
TASS Belgium NV 131:4758606c9316 474 struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 475 trans = (struct pico_trans *)&udp->trans;
TASS Belgium NV 131:4758606c9316 476 tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
TASS Belgium NV 131:4758606c9316 477 if (!tuple)
TASS Belgium NV 131:4758606c9316 478 tuple = pico_ipv4_nat_generate_tuple(f);
TASS Belgium NV 131:4758606c9316 479
TASS Belgium NV 131:4758606c9316 480 /* replace src IP and src PORT */
TASS Belgium NV 131:4758606c9316 481 net->src = tuple->nat_addr;
TASS Belgium NV 131:4758606c9316 482 trans->sport = tuple->nat_port;
TASS Belgium NV 131:4758606c9316 483 /* recalculate CRC */
TASS Belgium NV 131:4758606c9316 484 udp->crc = 0;
TASS Belgium NV 131:4758606c9316 485 udp->crc = short_be(pico_udp_checksum_ipv4(f));
TASS Belgium NV 131:4758606c9316 486 break;
tass 68:0847e35d08a6 487 }
tass picotcp@tass.be 149:5f4cb161cec3 488 #endif
tass 68:0847e35d08a6 489 case PICO_PROTO_ICMP4:
TASS Belgium NV 131:4758606c9316 490 /* XXX reimplement */
TASS Belgium NV 131:4758606c9316 491 break;
tass 68:0847e35d08a6 492
tass 68:0847e35d08a6 493 default:
TASS Belgium NV 131:4758606c9316 494 nat_dbg("NAT ERROR: outbound NAT on erroneous protocol\n");
TASS Belgium NV 131:4758606c9316 495 return -1;
TASS Belgium NV 131:4758606c9316 496 }
tass 68:0847e35d08a6 497
TASS Belgium NV 131:4758606c9316 498 pico_ipv4_nat_snif_session(tuple, f, PICO_NAT_OUTBOUND);
TASS Belgium NV 131:4758606c9316 499 net->crc = 0;
TASS Belgium NV 131:4758606c9316 500 net->crc = short_be(pico_checksum(net, f->net_len));
tass 68:0847e35d08a6 501
TASS Belgium NV 131:4758606c9316 502 nat_dbg("NAT: outbound translation {src.addr, sport}: {%08X,%u} -> {%08X,%u}\n",
tass 68:0847e35d08a6 503 tuple->src_addr.addr, short_be(tuple->src_port), tuple->nat_addr.addr, short_be(tuple->nat_port));
tass 68:0847e35d08a6 504
TASS Belgium NV 131:4758606c9316 505 return 0;
tass 68:0847e35d08a6 506 }
tass 68:0847e35d08a6 507
tass 68:0847e35d08a6 508 int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
tass 68:0847e35d08a6 509 {
TASS Belgium NV 131:4758606c9316 510 if (link == NULL) {
TASS Belgium NV 131:4758606c9316 511 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 512 return -1;
TASS Belgium NV 131:4758606c9316 513 }
tass 68:0847e35d08a6 514
TASS Belgium NV 131:4758606c9316 515 nat_link = link;
TASS Belgium NV 131:4758606c9316 516 pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
TASS Belgium NV 131:4758606c9316 517 return 0;
tass 68:0847e35d08a6 518 }
TASS Belgium NV 131:4758606c9316 519
tass 68:0847e35d08a6 520 int pico_ipv4_nat_disable(void)
tass 68:0847e35d08a6 521 {
TASS Belgium NV 131:4758606c9316 522 nat_link = NULL;
TASS Belgium NV 131:4758606c9316 523 return 0;
tass 68:0847e35d08a6 524 }
tass 68:0847e35d08a6 525
tass 68:0847e35d08a6 526 int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
tass 68:0847e35d08a6 527 {
TASS Belgium NV 131:4758606c9316 528 if (!nat_link)
TASS Belgium NV 131:4758606c9316 529 return 0;
TASS Belgium NV 131:4758606c9316 530
TASS Belgium NV 131:4758606c9316 531 if (nat_link->address.addr != link_addr->addr)
TASS Belgium NV 131:4758606c9316 532 return 0;
TASS Belgium NV 131:4758606c9316 533
TASS Belgium NV 131:4758606c9316 534 return 1;
tass 68:0847e35d08a6 535 }
tass 68:0847e35d08a6 536
tass 68:0847e35d08a6 537 #endif
tass 68:0847e35d08a6 538 #endif