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:
Fri Feb 07 11:21:12 2014 +0100
Revision:
137:a1c8bfa9d691
Parent:
131:4758606c9316
Child:
149:5f4cb161cec3
Update from 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 Authors: Daniele Lacamera, Markian Yskout
TASS Belgium NV 131:4758606c9316 6 *********************************************************************/
tass 68:0847e35d08a6 7
tass 68:0847e35d08a6 8
tass 68:0847e35d08a6 9 #include "pico_config.h"
tass 68:0847e35d08a6 10 #include "pico_ipfilter.h"
tass 68:0847e35d08a6 11 #include "pico_ipv4.h"
tass 68:0847e35d08a6 12 #include "pico_icmp4.h"
tass 68:0847e35d08a6 13 #include "pico_stack.h"
tass 68:0847e35d08a6 14 #include "pico_eth.h"
tass 68:0847e35d08a6 15 #include "pico_udp.h"
tass 68:0847e35d08a6 16 #include "pico_tcp.h"
tass 68:0847e35d08a6 17 #include "pico_socket.h"
tass 68:0847e35d08a6 18 #include "pico_device.h"
tass 68:0847e35d08a6 19 #include "pico_nat.h"
tass 68:0847e35d08a6 20 #include "pico_igmp.h"
tass 68:0847e35d08a6 21 #include "pico_tree.h"
tass 68:0847e35d08a6 22
tass 68:0847e35d08a6 23 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 24
tass 68:0847e35d08a6 25 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 26 # define ip_mcast_dbg(...) do {} while(0) /* so_mcast_dbg in pico_socket.c */
tass 68:0847e35d08a6 27 # define PICO_MCAST_ALL_HOSTS long_be(0xE0000001) /* 224.0.0.1 */
tass 68:0847e35d08a6 28 /* Default network interface for multicast transmission */
tass 68:0847e35d08a6 29 static struct pico_ipv4_link *mcast_default_link = NULL;
tass 68:0847e35d08a6 30 #endif
tass 68:0847e35d08a6 31 #ifdef PICO_SUPPORT_IPFRAG
TASS Belgium NV 131:4758606c9316 32 # define reassembly_dbg(...) do {} while(0)
tass 68:0847e35d08a6 33 #endif
tass 68:0847e35d08a6 34
tass 68:0847e35d08a6 35 /* Queues */
TASS Belgium NV 131:4758606c9316 36 static struct pico_queue in = {
TASS Belgium NV 131:4758606c9316 37 0
TASS Belgium NV 131:4758606c9316 38 };
TASS Belgium NV 131:4758606c9316 39 static struct pico_queue out = {
TASS Belgium NV 131:4758606c9316 40 0
TASS Belgium NV 131:4758606c9316 41 };
tass 68:0847e35d08a6 42
tass 68:0847e35d08a6 43 /* Functions */
TASS Belgium NV 131:4758606c9316 44 static int ipv4_route_compare(void *ka, void *kb);
tass 68:0847e35d08a6 45
tass 68:0847e35d08a6 46 int pico_ipv4_to_string(char *ipbuf, const uint32_t ip)
tass 68:0847e35d08a6 47 {
TASS Belgium NV 131:4758606c9316 48 const unsigned char *addr = (const unsigned char *) &ip;
TASS Belgium NV 131:4758606c9316 49 int i;
tass 68:0847e35d08a6 50
TASS Belgium NV 131:4758606c9316 51 if (!ipbuf) {
TASS Belgium NV 131:4758606c9316 52 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 53 return -1;
TASS Belgium NV 131:4758606c9316 54 }
tass 68:0847e35d08a6 55
TASS Belgium NV 131:4758606c9316 56 for(i = 0; i < 4; i++)
TASS Belgium NV 131:4758606c9316 57 {
TASS Belgium NV 131:4758606c9316 58 if(addr[i] > 99) {
TASS Belgium NV 131:4758606c9316 59 *ipbuf++ = (char)('0' + (addr[i] / 100));
TASS Belgium NV 131:4758606c9316 60 *ipbuf++ = (char)('0' + ((addr[i] % 100) / 10));
TASS Belgium NV 131:4758606c9316 61 *ipbuf++ = (char)('0' + ((addr[i] % 100) % 10));
TASS Belgium NV 131:4758606c9316 62 }else if(addr[i] > 9) {
TASS Belgium NV 131:4758606c9316 63 *ipbuf++ = (char)('0' + (addr[i] / 10));
TASS Belgium NV 131:4758606c9316 64 *ipbuf++ = (char)('0' + (addr[i] % 10));
TASS Belgium NV 131:4758606c9316 65 }else{
TASS Belgium NV 131:4758606c9316 66 *ipbuf++ = (char)('0' + addr[i]);
TASS Belgium NV 131:4758606c9316 67 }
TASS Belgium NV 131:4758606c9316 68
TASS Belgium NV 131:4758606c9316 69 if(i < 3)
TASS Belgium NV 131:4758606c9316 70 *ipbuf++ = '.';
tass 68:0847e35d08a6 71 }
TASS Belgium NV 131:4758606c9316 72 *ipbuf = '\0';
TASS Belgium NV 131:4758606c9316 73
TASS Belgium NV 131:4758606c9316 74 return 0;
tass 68:0847e35d08a6 75 }
TASS Belgium NV 131:4758606c9316 76
tass 68:0847e35d08a6 77 int pico_string_to_ipv4(const char *ipstr, uint32_t *ip)
tass 68:0847e35d08a6 78 {
TASS Belgium NV 131:4758606c9316 79 unsigned char buf[4] = {
TASS Belgium NV 131:4758606c9316 80 0
TASS Belgium NV 131:4758606c9316 81 };
TASS Belgium NV 131:4758606c9316 82 int cnt = 0;
TASS Belgium NV 131:4758606c9316 83 char p;
tass 68:0847e35d08a6 84
TASS Belgium NV 131:4758606c9316 85 if(!ipstr || !ip) {
TASS Belgium NV 131:4758606c9316 86 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 87 return -1;
tass 68:0847e35d08a6 88 }
tass 68:0847e35d08a6 89
TASS Belgium NV 131:4758606c9316 90 while((p = *ipstr++) != 0)
TASS Belgium NV 131:4758606c9316 91 {
TASS Belgium NV 131:4758606c9316 92 if(pico_is_digit(p)) {
TASS Belgium NV 131:4758606c9316 93 buf[cnt] = (uint8_t)((10 * buf[cnt]) + (p - '0'));
TASS Belgium NV 131:4758606c9316 94 }else if(p == '.') {
TASS Belgium NV 131:4758606c9316 95 cnt++;
TASS Belgium NV 131:4758606c9316 96 }else{
TASS Belgium NV 131:4758606c9316 97 return -1;
TASS Belgium NV 131:4758606c9316 98 }
TASS Belgium NV 131:4758606c9316 99 }
TASS Belgium NV 131:4758606c9316 100 /* Handle short notation */
TASS Belgium NV 131:4758606c9316 101 if(cnt == 1) {
TASS Belgium NV 131:4758606c9316 102 buf[3] = buf[1];
TASS Belgium NV 131:4758606c9316 103 buf[1] = 0;
TASS Belgium NV 131:4758606c9316 104 buf[2] = 0;
TASS Belgium NV 131:4758606c9316 105 }else if (cnt == 2) {
TASS Belgium NV 131:4758606c9316 106 buf[3] = buf[2];
TASS Belgium NV 131:4758606c9316 107 buf[2] = 0;
TASS Belgium NV 131:4758606c9316 108 }else if(cnt != 3) {
TASS Belgium NV 131:4758606c9316 109 /* String could not be parsed, return error */
TASS Belgium NV 131:4758606c9316 110 return -1;
TASS Belgium NV 131:4758606c9316 111 }
tass 68:0847e35d08a6 112
TASS Belgium NV 131:4758606c9316 113 *ip = long_from(buf);
tass 68:0847e35d08a6 114
TASS Belgium NV 131:4758606c9316 115 return 0;
TASS Belgium NV 131:4758606c9316 116
TASS Belgium NV 131:4758606c9316 117 }
tass 68:0847e35d08a6 118
tass 68:0847e35d08a6 119 int pico_ipv4_valid_netmask(uint32_t mask)
tass 68:0847e35d08a6 120 {
TASS Belgium NV 131:4758606c9316 121 int cnt = 0;
TASS Belgium NV 131:4758606c9316 122 int end = 0;
TASS Belgium NV 131:4758606c9316 123 int i;
TASS Belgium NV 131:4758606c9316 124 uint32_t mask_swap = long_be(mask);
tass 68:0847e35d08a6 125
TASS Belgium NV 131:4758606c9316 126 /*
TASS Belgium NV 131:4758606c9316 127 * Swap bytes for convenient parsing
TASS Belgium NV 131:4758606c9316 128 * e.g. 0x..f8ff will become 0xfff8..
TASS Belgium NV 131:4758606c9316 129 * Then, we count the consecutive bits
TASS Belgium NV 131:4758606c9316 130 *
TASS Belgium NV 131:4758606c9316 131 * */
tass 68:0847e35d08a6 132
TASS Belgium NV 131:4758606c9316 133 for(i = 0; i < 32; i++) {
TASS Belgium NV 131:4758606c9316 134 if((mask_swap << i) & 0x80000000) {
TASS Belgium NV 131:4758606c9316 135 if(end) {
TASS Belgium NV 131:4758606c9316 136 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 137 return -1;
TASS Belgium NV 131:4758606c9316 138 }
TASS Belgium NV 131:4758606c9316 139
TASS Belgium NV 131:4758606c9316 140 cnt++;
TASS Belgium NV 131:4758606c9316 141 }else{
TASS Belgium NV 131:4758606c9316 142 end = 1;
TASS Belgium NV 131:4758606c9316 143 }
TASS Belgium NV 131:4758606c9316 144 }
TASS Belgium NV 131:4758606c9316 145 return cnt;
tass 68:0847e35d08a6 146 }
tass 68:0847e35d08a6 147
TASS Belgium NV 131:4758606c9316 148 int pico_ipv4_is_unicast(uint32_t address)
tass 68:0847e35d08a6 149 {
TASS Belgium NV 131:4758606c9316 150 const unsigned char *addr = (unsigned char *) &address;
TASS Belgium NV 131:4758606c9316 151 if((addr[0] & 0xe0) == 0xe0)
TASS Belgium NV 131:4758606c9316 152 return 0; /* multicast */
TASS Belgium NV 131:4758606c9316 153
TASS Belgium NV 131:4758606c9316 154 return 1;
tass 68:0847e35d08a6 155 }
tass 68:0847e35d08a6 156
TASS Belgium NV 131:4758606c9316 157 int pico_ipv4_is_multicast(uint32_t address)
tass 68:0847e35d08a6 158 {
TASS Belgium NV 131:4758606c9316 159 const unsigned char *addr = (unsigned char *) &address;
TASS Belgium NV 131:4758606c9316 160 if((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0))
TASS Belgium NV 131:4758606c9316 161 return 1; /* multicast */
TASS Belgium NV 131:4758606c9316 162
TASS Belgium NV 131:4758606c9316 163 return 0;
tass 68:0847e35d08a6 164 }
tass 68:0847e35d08a6 165
tass picotcp@tass.be 137:a1c8bfa9d691 166 int pico_ipv4_is_loopback(uint32_t address)
tass picotcp@tass.be 137:a1c8bfa9d691 167 {
tass picotcp@tass.be 137:a1c8bfa9d691 168 const unsigned char *addr = (unsigned char *) &address;
tass picotcp@tass.be 137:a1c8bfa9d691 169 if(addr[0] == 0x7f)
tass picotcp@tass.be 137:a1c8bfa9d691 170 return 1;
tass picotcp@tass.be 137:a1c8bfa9d691 171
tass picotcp@tass.be 137:a1c8bfa9d691 172 return 0;
tass picotcp@tass.be 137:a1c8bfa9d691 173 }
tass picotcp@tass.be 137:a1c8bfa9d691 174
tass picotcp@tass.be 137:a1c8bfa9d691 175 int pico_ipv4_is_valid_src(uint32_t address)
tass picotcp@tass.be 137:a1c8bfa9d691 176 {
tass picotcp@tass.be 137:a1c8bfa9d691 177 if (pico_ipv4_is_broadcast(address)) {
tass picotcp@tass.be 137:a1c8bfa9d691 178 dbg("Source is a broadcast address, discard packet\n");
tass picotcp@tass.be 137:a1c8bfa9d691 179 return 0;
tass picotcp@tass.be 137:a1c8bfa9d691 180 }
tass picotcp@tass.be 137:a1c8bfa9d691 181 else if( pico_ipv4_is_multicast(address)) {
tass picotcp@tass.be 137:a1c8bfa9d691 182 dbg("Source is a multicast address, discard packet\n");
tass picotcp@tass.be 137:a1c8bfa9d691 183 return 0;
tass picotcp@tass.be 137:a1c8bfa9d691 184 }
tass picotcp@tass.be 137:a1c8bfa9d691 185 else if (pico_ipv4_is_loopback(address)) {
tass picotcp@tass.be 137:a1c8bfa9d691 186 dbg("Source is a loopback address, discard packet\n");
tass picotcp@tass.be 137:a1c8bfa9d691 187 return 0;
tass picotcp@tass.be 137:a1c8bfa9d691 188 }
tass picotcp@tass.be 137:a1c8bfa9d691 189 else {
tass picotcp@tass.be 137:a1c8bfa9d691 190 return 1;
tass picotcp@tass.be 137:a1c8bfa9d691 191 }
tass picotcp@tass.be 137:a1c8bfa9d691 192 }
tass picotcp@tass.be 137:a1c8bfa9d691 193
tass 68:0847e35d08a6 194 static int pico_ipv4_checksum(struct pico_frame *f)
tass 68:0847e35d08a6 195 {
TASS Belgium NV 131:4758606c9316 196 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
TASS Belgium NV 131:4758606c9316 197 if (!hdr)
TASS Belgium NV 131:4758606c9316 198 return -1;
TASS Belgium NV 131:4758606c9316 199
TASS Belgium NV 131:4758606c9316 200 hdr->crc = 0;
TASS Belgium NV 131:4758606c9316 201 hdr->crc = short_be(pico_checksum(hdr, f->net_len));
TASS Belgium NV 131:4758606c9316 202 return 0;
tass 68:0847e35d08a6 203 }
tass 68:0847e35d08a6 204
tass 68:0847e35d08a6 205 #ifdef PICO_SUPPORT_IPFRAG
tass 68:0847e35d08a6 206 struct pico_ipv4_fragmented_packet {
TASS Belgium NV 131:4758606c9316 207 uint16_t id;
TASS Belgium NV 131:4758606c9316 208 uint8_t proto;
TASS Belgium NV 131:4758606c9316 209 struct pico_ip4 src;
TASS Belgium NV 131:4758606c9316 210 struct pico_ip4 dst;
TASS Belgium NV 131:4758606c9316 211 uint16_t total_len;
TASS Belgium NV 131:4758606c9316 212 struct pico_tree *t;
tass 68:0847e35d08a6 213 };
tass 68:0847e35d08a6 214
tass 68:0847e35d08a6 215 static int pico_ipv4_fragmented_packet_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 216 {
TASS Belgium NV 131:4758606c9316 217 struct pico_ipv4_fragmented_packet *a = ka, *b = kb;
tass 68:0847e35d08a6 218
TASS Belgium NV 131:4758606c9316 219 if (a->id < b->id)
tass 68:0847e35d08a6 220 return -1;
TASS Belgium NV 131:4758606c9316 221 else if (a->id > b->id)
tass 68:0847e35d08a6 222 return 1;
TASS Belgium NV 131:4758606c9316 223 else {
TASS Belgium NV 131:4758606c9316 224 if (a->proto < b->proto)
TASS Belgium NV 131:4758606c9316 225 return -1;
TASS Belgium NV 131:4758606c9316 226 else if (a->proto > b->proto)
TASS Belgium NV 131:4758606c9316 227 return 1;
TASS Belgium NV 131:4758606c9316 228 else {
TASS Belgium NV 131:4758606c9316 229 if (a->src.addr < b->src.addr)
TASS Belgium NV 131:4758606c9316 230 return -1;
TASS Belgium NV 131:4758606c9316 231 else if (a->src.addr > b->src.addr)
TASS Belgium NV 131:4758606c9316 232 return 1;
TASS Belgium NV 131:4758606c9316 233 else {
TASS Belgium NV 131:4758606c9316 234 if (a->dst.addr < b->dst.addr)
TASS Belgium NV 131:4758606c9316 235 return -1;
TASS Belgium NV 131:4758606c9316 236 else if (a->dst.addr > b->dst.addr)
TASS Belgium NV 131:4758606c9316 237 return 1;
TASS Belgium NV 131:4758606c9316 238 else
TASS Belgium NV 131:4758606c9316 239 return 0;
TASS Belgium NV 131:4758606c9316 240 }
TASS Belgium NV 131:4758606c9316 241 }
tass 68:0847e35d08a6 242 }
TASS Belgium NV 131:4758606c9316 243 }
tass 68:0847e35d08a6 244
tass 68:0847e35d08a6 245 static int pico_ipv4_fragmented_element_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 246 {
TASS Belgium NV 131:4758606c9316 247 struct pico_frame *frame_a = ka, *frame_b = kb;
TASS Belgium NV 131:4758606c9316 248 struct pico_ipv4_hdr *a, *b;
TASS Belgium NV 131:4758606c9316 249 a = (struct pico_ipv4_hdr *) frame_a->net_hdr;
TASS Belgium NV 131:4758606c9316 250 b = (struct pico_ipv4_hdr *) frame_b->net_hdr;
tass 68:0847e35d08a6 251
TASS Belgium NV 131:4758606c9316 252 if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) < short_be((b->frag & PICO_IPV4_FRAG_MASK)))
TASS Belgium NV 131:4758606c9316 253 return -1;
TASS Belgium NV 131:4758606c9316 254 else if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) > short_be((b->frag & PICO_IPV4_FRAG_MASK)))
TASS Belgium NV 131:4758606c9316 255 return 1;
TASS Belgium NV 131:4758606c9316 256 else
TASS Belgium NV 131:4758606c9316 257 return 0;
TASS Belgium NV 131:4758606c9316 258 }
TASS Belgium NV 131:4758606c9316 259
tass 68:0847e35d08a6 260 PICO_TREE_DECLARE(pico_ipv4_fragmented_tree, pico_ipv4_fragmented_packet_cmp);
tass 68:0847e35d08a6 261
tass 68:0847e35d08a6 262 static inline void pico_ipv4_fragmented_cleanup(struct pico_ipv4_fragmented_packet *pfrag)
tass 68:0847e35d08a6 263 {
TASS Belgium NV 131:4758606c9316 264 struct pico_tree_node *index = NULL, *_tmp = NULL;
TASS Belgium NV 131:4758606c9316 265 struct pico_frame *f_frag = NULL;
tass 68:0847e35d08a6 266
TASS Belgium NV 131:4758606c9316 267 pico_tree_foreach_safe(index, pfrag->t, _tmp) {
TASS Belgium NV 131:4758606c9316 268 f_frag = index->keyValue;
TASS Belgium NV 131:4758606c9316 269 reassembly_dbg("REASSEMBLY: remove packet with offset %u\n", short_be(((struct pico_ipv4_hdr *)f_frag->net_hdr)->frag) & PICO_IPV4_FRAG_MASK);
TASS Belgium NV 131:4758606c9316 270 pico_tree_delete(pfrag->t, f_frag);
TASS Belgium NV 131:4758606c9316 271 pico_frame_discard(f_frag);
TASS Belgium NV 131:4758606c9316 272 }
TASS Belgium NV 131:4758606c9316 273 pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag);
TASS Belgium NV 131:4758606c9316 274 pico_free(pfrag->t);
TASS Belgium NV 131:4758606c9316 275 pico_free(pfrag);
tass 68:0847e35d08a6 276 }
tass 68:0847e35d08a6 277 #endif /* PICO_SUPPORT_IPFRAG */
tass 68:0847e35d08a6 278
tass 68:0847e35d08a6 279 #ifdef PICO_SUPPORT_IPFRAG
tass 74:c146c4e346c4 280
tass 74:c146c4e346c4 281 static inline struct pico_ipv4_fragmented_packet *fragment_find_by_hdr(struct pico_ipv4_hdr *hdr)
tass 74:c146c4e346c4 282 {
TASS Belgium NV 131:4758606c9316 283 struct pico_ipv4_fragmented_packet frag = {
TASS Belgium NV 131:4758606c9316 284 0
TASS Belgium NV 131:4758606c9316 285 };
TASS Belgium NV 131:4758606c9316 286 frag.id = short_be(hdr->id);
TASS Belgium NV 131:4758606c9316 287 frag.proto = hdr->proto;
TASS Belgium NV 131:4758606c9316 288 frag.src.addr = long_be(hdr->src.addr);
TASS Belgium NV 131:4758606c9316 289 frag.dst.addr = long_be(hdr->dst.addr);
TASS Belgium NV 131:4758606c9316 290 return pico_tree_findKey(&pico_ipv4_fragmented_tree, &frag);
tass 74:c146c4e346c4 291 }
tass 74:c146c4e346c4 292
tass 74:c146c4e346c4 293
tass 70:cd218dd180e5 294 static inline int8_t pico_ipv4_fragmented_check(struct pico_protocol *self, struct pico_frame **f)
tass 68:0847e35d08a6 295 {
TASS Belgium NV 131:4758606c9316 296 uint8_t *running_pointer = NULL;
TASS Belgium NV 131:4758606c9316 297 uint16_t running_offset = 0;
TASS Belgium NV 131:4758606c9316 298 uint16_t offset = 0;
TASS Belgium NV 131:4758606c9316 299 uint16_t data_len = 0;
TASS Belgium NV 131:4758606c9316 300 struct pico_ipv4_hdr *f_frag_hdr = NULL, *hdr = (struct pico_ipv4_hdr *) (*f)->net_hdr;
TASS Belgium NV 131:4758606c9316 301 struct pico_udp_hdr *udp_hdr = NULL;
TASS Belgium NV 131:4758606c9316 302 struct pico_tcp_hdr *tcp_hdr = NULL;
TASS Belgium NV 131:4758606c9316 303 struct pico_ipv4_fragmented_packet *pfrag = NULL;
TASS Belgium NV 131:4758606c9316 304 struct pico_frame *f_new = NULL, *f_frag = NULL;
TASS Belgium NV 131:4758606c9316 305 struct pico_tree_node *index, *_tmp;
TASS Belgium NV 131:4758606c9316 306
TASS Belgium NV 131:4758606c9316 307 data_len = (uint16_t)(short_be(hdr->len) - (*f)->net_len);
TASS Belgium NV 131:4758606c9316 308 offset = short_be(hdr->frag) & PICO_IPV4_FRAG_MASK;
TASS Belgium NV 131:4758606c9316 309 if (short_be(hdr->frag) & PICO_IPV4_MOREFRAG) {
TASS Belgium NV 131:4758606c9316 310 if (!offset) {
TASS Belgium NV 131:4758606c9316 311 reassembly_dbg("REASSEMBLY: first element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset);
TASS Belgium NV 131:4758606c9316 312 if (!pico_tree_empty(&pico_ipv4_fragmented_tree)) {
TASS Belgium NV 131:4758606c9316 313 reassembly_dbg("REASSEMBLY: cleanup tree\n");
TASS Belgium NV 131:4758606c9316 314 /* only one entry allowed in this tree */
TASS Belgium NV 131:4758606c9316 315 pfrag = pico_tree_first(&pico_ipv4_fragmented_tree);
TASS Belgium NV 131:4758606c9316 316 pico_ipv4_fragmented_cleanup(pfrag);
TASS Belgium NV 131:4758606c9316 317 }
TASS Belgium NV 131:4758606c9316 318
TASS Belgium NV 131:4758606c9316 319 /* add entry in tree for this ID and create secondary tree to contain fragmented elements */
TASS Belgium NV 131:4758606c9316 320 pfrag = pico_zalloc(sizeof(struct pico_ipv4_fragmented_packet));
TASS Belgium NV 131:4758606c9316 321 if (!pfrag) {
TASS Belgium NV 131:4758606c9316 322 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 323 return -1;
TASS Belgium NV 131:4758606c9316 324 }
TASS Belgium NV 131:4758606c9316 325
TASS Belgium NV 131:4758606c9316 326 pfrag->id = short_be(hdr->id);
TASS Belgium NV 131:4758606c9316 327 pfrag->proto = hdr->proto;
TASS Belgium NV 131:4758606c9316 328 pfrag->src.addr = long_be(hdr->src.addr);
TASS Belgium NV 131:4758606c9316 329 pfrag->dst.addr = long_be(hdr->dst.addr);
TASS Belgium NV 131:4758606c9316 330 pfrag->total_len = (uint16_t)(short_be(hdr->len) - (*f)->net_len);
TASS Belgium NV 131:4758606c9316 331 pfrag->t = pico_zalloc(sizeof(struct pico_tree));
TASS Belgium NV 131:4758606c9316 332 if (!pfrag->t) {
TASS Belgium NV 131:4758606c9316 333 pico_free(pfrag);
TASS Belgium NV 131:4758606c9316 334 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 335 return -1;
TASS Belgium NV 131:4758606c9316 336 }
TASS Belgium NV 131:4758606c9316 337
TASS Belgium NV 131:4758606c9316 338 pfrag->t->root = &LEAF;
TASS Belgium NV 131:4758606c9316 339 pfrag->t->compare = pico_ipv4_fragmented_element_cmp;
TASS Belgium NV 131:4758606c9316 340
TASS Belgium NV 131:4758606c9316 341 pico_tree_insert(pfrag->t, *f);
TASS Belgium NV 131:4758606c9316 342 pico_tree_insert(&pico_ipv4_fragmented_tree, pfrag);
TASS Belgium NV 131:4758606c9316 343 return 0;
TASS Belgium NV 131:4758606c9316 344 }
TASS Belgium NV 131:4758606c9316 345 else {
TASS Belgium NV 131:4758606c9316 346 reassembly_dbg("REASSEMBLY: intermediate element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset);
TASS Belgium NV 131:4758606c9316 347 pfrag = fragment_find_by_hdr(hdr);
TASS Belgium NV 131:4758606c9316 348 if (pfrag) {
TASS Belgium NV 131:4758606c9316 349 pfrag->total_len = (uint16_t)(pfrag->total_len + (short_be(hdr->len) - (*f)->net_len));
TASS Belgium NV 131:4758606c9316 350 if (pfrag->total_len > PICO_IPV4_FRAG_MAX_SIZE) {
TASS Belgium NV 131:4758606c9316 351 reassembly_dbg("BIG frame!!!\n");
TASS Belgium NV 131:4758606c9316 352 pfrag = pico_tree_first(&pico_ipv4_fragmented_tree);
TASS Belgium NV 131:4758606c9316 353 pico_ipv4_fragmented_cleanup(pfrag);
TASS Belgium NV 131:4758606c9316 354 pico_frame_discard(*f);
TASS Belgium NV 131:4758606c9316 355 return 0;
TASS Belgium NV 131:4758606c9316 356 }
tass 68:0847e35d08a6 357
TASS Belgium NV 131:4758606c9316 358 pico_tree_insert(pfrag->t, *f);
TASS Belgium NV 131:4758606c9316 359 return 0;
TASS Belgium NV 131:4758606c9316 360 } else {
TASS Belgium NV 131:4758606c9316 361 reassembly_dbg("REASSEMBLY: silently discard intermediate frame, first packet was lost or disallowed (one fragmented packet at a time)\n");
TASS Belgium NV 131:4758606c9316 362 pico_frame_discard(*f);
TASS Belgium NV 131:4758606c9316 363 return 0;
TASS Belgium NV 131:4758606c9316 364 }
TASS Belgium NV 131:4758606c9316 365 }
TASS Belgium NV 131:4758606c9316 366 } else if (offset) {
TASS Belgium NV 131:4758606c9316 367 reassembly_dbg("REASSEMBLY: last element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset);
TASS Belgium NV 131:4758606c9316 368 pfrag = fragment_find_by_hdr(hdr);
TASS Belgium NV 131:4758606c9316 369 if (pfrag) {
TASS Belgium NV 131:4758606c9316 370 pfrag->total_len = (uint16_t)(pfrag->total_len + (short_be(hdr->len) - (*f)->net_len));
TASS Belgium NV 131:4758606c9316 371 reassembly_dbg("REASSEMBLY: fragmented packet in tree, reassemble packet of %u data bytes\n", pfrag->total_len);
TASS Belgium NV 131:4758606c9316 372 if (pfrag->total_len > PICO_IPV4_FRAG_MAX_SIZE) {
TASS Belgium NV 131:4758606c9316 373 reassembly_dbg("BIG frame!!!\n");
TASS Belgium NV 131:4758606c9316 374 pfrag = pico_tree_first(&pico_ipv4_fragmented_tree);
TASS Belgium NV 131:4758606c9316 375 pico_ipv4_fragmented_cleanup(pfrag);
TASS Belgium NV 131:4758606c9316 376 pico_frame_discard(*f);
TASS Belgium NV 131:4758606c9316 377 return 0;
TASS Belgium NV 131:4758606c9316 378 }
TASS Belgium NV 131:4758606c9316 379
TASS Belgium NV 131:4758606c9316 380 f_new = self->alloc(self, pfrag->total_len);
TASS Belgium NV 131:4758606c9316 381
TASS Belgium NV 131:4758606c9316 382 f_frag = pico_tree_first(pfrag->t);
TASS Belgium NV 131:4758606c9316 383 reassembly_dbg("REASSEMBLY: copy IP header information len = %lu\n", f_frag->net_len);
TASS Belgium NV 131:4758606c9316 384 f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr;
TASS Belgium NV 131:4758606c9316 385 data_len = (uint16_t)(short_be(f_frag_hdr->len) - f_frag->net_len);
TASS Belgium NV 131:4758606c9316 386 memcpy(f_new->net_hdr, f_frag->net_hdr, f_frag->net_len);
TASS Belgium NV 131:4758606c9316 387 memcpy(f_new->transport_hdr, f_frag->transport_hdr, data_len);
TASS Belgium NV 131:4758606c9316 388 running_pointer = f_new->transport_hdr + data_len;
TASS Belgium NV 131:4758606c9316 389 offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK;
TASS Belgium NV 131:4758606c9316 390 running_offset = data_len / 8;
TASS Belgium NV 131:4758606c9316 391 pico_tree_delete(pfrag->t, f_frag);
TASS Belgium NV 131:4758606c9316 392 pico_frame_discard(f_frag);
TASS Belgium NV 131:4758606c9316 393 reassembly_dbg("REASSEMBLY: reassembled first packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset);
tass 68:0847e35d08a6 394
TASS Belgium NV 131:4758606c9316 395 pico_tree_foreach_safe(index, pfrag->t, _tmp)
TASS Belgium NV 131:4758606c9316 396 {
TASS Belgium NV 131:4758606c9316 397 f_frag = index->keyValue;
TASS Belgium NV 131:4758606c9316 398 f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr;
TASS Belgium NV 131:4758606c9316 399 data_len = (uint16_t)(short_be(f_frag_hdr->len) - f_frag->net_len);
TASS Belgium NV 131:4758606c9316 400 memcpy(running_pointer, f_frag->transport_hdr, data_len);
TASS Belgium NV 131:4758606c9316 401 running_pointer += data_len;
TASS Belgium NV 131:4758606c9316 402 offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK;
TASS Belgium NV 131:4758606c9316 403 if (offset != running_offset) {
TASS Belgium NV 131:4758606c9316 404 reassembly_dbg("REASSEMBLY: error reassembling intermediate packet: offset %u != expected offset %u (missing fragment)\n", offset, running_offset);
TASS Belgium NV 131:4758606c9316 405 pico_ipv4_fragmented_cleanup(pfrag);
TASS Belgium NV 131:4758606c9316 406 return -1;
TASS Belgium NV 131:4758606c9316 407 }
tass 68:0847e35d08a6 408
TASS Belgium NV 131:4758606c9316 409 running_offset = (uint16_t)(running_offset + (data_len / 8));
TASS Belgium NV 131:4758606c9316 410 pico_tree_delete(pfrag->t, f_frag);
TASS Belgium NV 131:4758606c9316 411 pico_frame_discard(f_frag);
TASS Belgium NV 131:4758606c9316 412 reassembly_dbg("REASSEMBLY: reassembled intermediate packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset);
TASS Belgium NV 131:4758606c9316 413 }
TASS Belgium NV 131:4758606c9316 414 pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag);
TASS Belgium NV 131:4758606c9316 415 pico_free(pfrag);
tass 68:0847e35d08a6 416
TASS Belgium NV 131:4758606c9316 417 data_len = (uint16_t)(short_be(hdr->len) - (*f)->net_len);
TASS Belgium NV 131:4758606c9316 418 memcpy(running_pointer, (*f)->transport_hdr, data_len);
TASS Belgium NV 131:4758606c9316 419 offset = short_be(hdr->frag) & PICO_IPV4_FRAG_MASK;
TASS Belgium NV 131:4758606c9316 420 pico_frame_discard(*f);
TASS Belgium NV 131:4758606c9316 421 reassembly_dbg("REASSEMBLY: reassembled last packet of %u data bytes, offset = %u\n", data_len, offset);
TASS Belgium NV 131:4758606c9316 422
TASS Belgium NV 131:4758606c9316 423 hdr = (struct pico_ipv4_hdr *)f_new->net_hdr;
TASS Belgium NV 131:4758606c9316 424 hdr->len = pfrag->total_len;
TASS Belgium NV 131:4758606c9316 425 hdr->frag = 0; /* flags cleared and no offset */
TASS Belgium NV 131:4758606c9316 426 hdr->crc = 0;
TASS Belgium NV 131:4758606c9316 427 hdr->crc = short_be(pico_checksum(hdr, f_new->net_len));
TASS Belgium NV 131:4758606c9316 428 /* Optional, the UDP/TCP CRC should already be correct */
TASS Belgium NV 131:4758606c9316 429 if (0) {
tass 68:0847e35d08a6 430 #ifdef PICO_SUPPORT_TCP
TASS Belgium NV 131:4758606c9316 431 } else if (hdr->proto == PICO_PROTO_TCP) {
TASS Belgium NV 131:4758606c9316 432 tcp_hdr = (struct pico_tcp_hdr *) f_new->transport_hdr;
TASS Belgium NV 131:4758606c9316 433 tcp_hdr->crc = 0;
TASS Belgium NV 131:4758606c9316 434 tcp_hdr->crc = short_be(pico_tcp_checksum_ipv4(f_new));
tass 68:0847e35d08a6 435 #endif
tass 68:0847e35d08a6 436 #ifdef PICO_SUPPORT_UDP
TASS Belgium NV 131:4758606c9316 437 } else if (hdr->proto == PICO_PROTO_UDP) {
TASS Belgium NV 131:4758606c9316 438 udp_hdr = (struct pico_udp_hdr *) f_new->transport_hdr;
TASS Belgium NV 131:4758606c9316 439 udp_hdr->crc = 0;
TASS Belgium NV 131:4758606c9316 440 udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f_new));
tass 68:0847e35d08a6 441 #endif
TASS Belgium NV 131:4758606c9316 442 }
TASS Belgium NV 131:4758606c9316 443
TASS Belgium NV 131:4758606c9316 444 reassembly_dbg("REASSEMBLY: packet with id %X reassembled correctly\n", short_be(hdr->id));
TASS Belgium NV 131:4758606c9316 445 *f = f_new;
TASS Belgium NV 131:4758606c9316 446 return 1;
TASS Belgium NV 131:4758606c9316 447 } else {
TASS Belgium NV 131:4758606c9316 448 reassembly_dbg("REASSEMBLY: silently discard last frame, first packet was lost or disallowed (one fragmented packet at a time)\n");
TASS Belgium NV 131:4758606c9316 449 pico_frame_discard(*f);
TASS Belgium NV 131:4758606c9316 450 return 0;
TASS Belgium NV 131:4758606c9316 451 }
tass 68:0847e35d08a6 452 } else {
TASS Belgium NV 131:4758606c9316 453 return 1;
tass 68:0847e35d08a6 454 }
tass 68:0847e35d08a6 455 }
tass 68:0847e35d08a6 456 #else
tass 70:cd218dd180e5 457 static inline int8_t pico_ipv4_fragmented_check(struct pico_protocol *self, struct pico_frame **f)
tass 68:0847e35d08a6 458 {
TASS Belgium NV 131:4758606c9316 459 return 1;
tass 68:0847e35d08a6 460 }
tass 68:0847e35d08a6 461 #endif /* PICO_SUPPORT_IPFRAG */
tass 68:0847e35d08a6 462
tass 68:0847e35d08a6 463 #ifdef PICO_SUPPORT_CRC
tass 68:0847e35d08a6 464 static inline int pico_ipv4_crc_check(struct pico_frame *f)
tass 68:0847e35d08a6 465 {
TASS Belgium NV 131:4758606c9316 466 uint16_t checksum_invalid = 1;
TASS Belgium NV 131:4758606c9316 467 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
tass 68:0847e35d08a6 468
TASS Belgium NV 131:4758606c9316 469 checksum_invalid = short_be(pico_checksum(hdr, f->net_len));
TASS Belgium NV 131:4758606c9316 470 if (checksum_invalid) {
TASS Belgium NV 131:4758606c9316 471 dbg("IP: checksum failed!\n");
TASS Belgium NV 131:4758606c9316 472 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 473 return 0;
TASS Belgium NV 131:4758606c9316 474 }
TASS Belgium NV 131:4758606c9316 475
TASS Belgium NV 131:4758606c9316 476 return 1;
tass 68:0847e35d08a6 477 }
tass 68:0847e35d08a6 478 #else
tass 68:0847e35d08a6 479 static inline int pico_ipv4_crc_check(struct pico_frame *f)
tass 68:0847e35d08a6 480 {
TASS Belgium NV 131:4758606c9316 481 IGNORE_PARAMETER(f);
TASS Belgium NV 131:4758606c9316 482 return 1;
tass 68:0847e35d08a6 483 }
tass 68:0847e35d08a6 484 #endif /* PICO_SUPPORT_CRC */
tass 68:0847e35d08a6 485
tass 68:0847e35d08a6 486 static int pico_ipv4_forward(struct pico_frame *f);
tass 68:0847e35d08a6 487 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 488 static int pico_ipv4_mcast_filter(struct pico_frame *f);
tass 68:0847e35d08a6 489 #endif
tass 68:0847e35d08a6 490
tass 68:0847e35d08a6 491 static int ipv4_link_compare(void *ka, void *kb)
tass 68:0847e35d08a6 492 {
TASS Belgium NV 131:4758606c9316 493 struct pico_ipv4_link *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 494 if (a->address.addr < b->address.addr)
TASS Belgium NV 131:4758606c9316 495 return -1;
TASS Belgium NV 131:4758606c9316 496
TASS Belgium NV 131:4758606c9316 497 if (a->address.addr > b->address.addr)
TASS Belgium NV 131:4758606c9316 498 return 1;
tass 68:0847e35d08a6 499
TASS Belgium NV 131:4758606c9316 500 /* zero can be assigned multiple times (e.g. for DHCP) */
TASS Belgium NV 131:4758606c9316 501 if (a->dev != NULL && b->dev != NULL && a->address.addr == PICO_IP4_ANY && b->address.addr == PICO_IP4_ANY) {
TASS Belgium NV 131:4758606c9316 502 if (a->dev < b->dev)
TASS Belgium NV 131:4758606c9316 503 return -1;
TASS Belgium NV 131:4758606c9316 504
TASS Belgium NV 131:4758606c9316 505 if (a->dev > b->dev)
TASS Belgium NV 131:4758606c9316 506 return 1;
TASS Belgium NV 131:4758606c9316 507 }
TASS Belgium NV 131:4758606c9316 508
TASS Belgium NV 131:4758606c9316 509 return 0;
tass 68:0847e35d08a6 510 }
tass 68:0847e35d08a6 511
tass 68:0847e35d08a6 512 PICO_TREE_DECLARE(Tree_dev_link, ipv4_link_compare);
tass 68:0847e35d08a6 513
tass 68:0847e35d08a6 514 static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f)
tass 68:0847e35d08a6 515 {
TASS Belgium NV 131:4758606c9316 516 uint8_t option_len = 0;
TASS Belgium NV 131:4758606c9316 517 int ret = 0;
TASS Belgium NV 131:4758606c9316 518 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
TASS Belgium NV 131:4758606c9316 519 struct pico_ipv4_link test = {
TASS Belgium NV 131:4758606c9316 520 .address = {.addr = PICO_IP4_ANY}, .dev = NULL
TASS Belgium NV 131:4758606c9316 521 };
tass 68:0847e35d08a6 522
TASS Belgium NV 131:4758606c9316 523 /* NAT needs transport header information */
TASS Belgium NV 131:4758606c9316 524 if(((hdr->vhl) & 0x0F) > 5) {
TASS Belgium NV 131:4758606c9316 525 option_len = (uint8_t)(4 * (((hdr->vhl) & 0x0F) - 5));
TASS Belgium NV 131:4758606c9316 526 }
TASS Belgium NV 131:4758606c9316 527
TASS Belgium NV 131:4758606c9316 528 f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR + option_len;
TASS Belgium NV 131:4758606c9316 529 f->transport_len = (uint16_t)(short_be(hdr->len) - PICO_SIZE_IP4HDR - option_len);
TASS Belgium NV 131:4758606c9316 530 f->net_len = (uint16_t)(PICO_SIZE_IP4HDR + option_len);
tass 68:0847e35d08a6 531
tass 68:0847e35d08a6 532 #ifdef PICO_SUPPORT_IPFILTER
TASS Belgium NV 131:4758606c9316 533 if (ipfilter(f)) {
TASS Belgium NV 131:4758606c9316 534 /*pico_frame is discarded as result of the filtering*/
TASS Belgium NV 131:4758606c9316 535 return 0;
TASS Belgium NV 131:4758606c9316 536 }
TASS Belgium NV 131:4758606c9316 537
tass 68:0847e35d08a6 538 #endif
tass 68:0847e35d08a6 539
TASS Belgium NV 131:4758606c9316 540 /* ret == 1 indicates to continue the function */
TASS Belgium NV 131:4758606c9316 541 ret = pico_ipv4_crc_check(f);
TASS Belgium NV 131:4758606c9316 542 if (ret < 1)
TASS Belgium NV 131:4758606c9316 543 return ret;
TASS Belgium NV 131:4758606c9316 544
TASS Belgium NV 131:4758606c9316 545 ret = pico_ipv4_fragmented_check(self, &f);
TASS Belgium NV 131:4758606c9316 546 if (ret < 1)
TASS Belgium NV 131:4758606c9316 547 return ret;
tass 68:0847e35d08a6 548
tass picotcp@tass.be 137:a1c8bfa9d691 549 /* Validate source IP address. Discard quietly if invalid */
tass picotcp@tass.be 137:a1c8bfa9d691 550 if (!pico_ipv4_is_valid_src(hdr->src.addr)) {
TASS Belgium NV 131:4758606c9316 551 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 552 return 0;
TASS Belgium NV 131:4758606c9316 553 }
TASS Belgium NV 131:4758606c9316 554
TASS Belgium NV 131:4758606c9316 555 if (hdr->frag & 0x80) {
TASS Belgium NV 131:4758606c9316 556 pico_frame_discard(f); /* RFC 3514 */
TASS Belgium NV 131:4758606c9316 557 return 0;
TASS Belgium NV 131:4758606c9316 558 }
TASS Belgium NV 131:4758606c9316 559
TASS Belgium NV 131:4758606c9316 560 if (0) {
tass 68:0847e35d08a6 561 #ifdef PICO_SUPPORT_UDP
TASS Belgium NV 131:4758606c9316 562 } else if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) {
TASS Belgium NV 131:4758606c9316 563 /* Receiving UDP broadcast datagram */
TASS Belgium NV 131:4758606c9316 564 f->flags |= PICO_FRAME_FLAG_BCAST;
TASS Belgium NV 131:4758606c9316 565 pico_enqueue(pico_proto_udp.q_in, f);
tass 68:0847e35d08a6 566 #endif
TASS Belgium NV 131:4758606c9316 567 } else if (pico_ipv4_is_multicast(hdr->dst.addr)) {
tass 68:0847e35d08a6 568 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 569 /* Receiving UDP multicast datagram TODO set f->flags? */
TASS Belgium NV 131:4758606c9316 570 if (hdr->proto == PICO_PROTO_IGMP) {
TASS Belgium NV 131:4758606c9316 571 ip_mcast_dbg("MCAST: received IGMP message\n");
TASS Belgium NV 131:4758606c9316 572 pico_transport_receive(f, PICO_PROTO_IGMP);
TASS Belgium NV 131:4758606c9316 573 } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) {
TASS Belgium NV 131:4758606c9316 574 pico_enqueue(pico_proto_udp.q_in, f);
TASS Belgium NV 131:4758606c9316 575 } else {
TASS Belgium NV 131:4758606c9316 576 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 577 }
TASS Belgium NV 131:4758606c9316 578
TASS Belgium NV 131:4758606c9316 579 #endif
TASS Belgium NV 131:4758606c9316 580 } else if (pico_ipv4_link_find(&hdr->dst)) {
TASS Belgium NV 131:4758606c9316 581 if (pico_ipv4_nat_inbound(f, &hdr->dst) == 0)
TASS Belgium NV 131:4758606c9316 582 pico_enqueue(pico_proto_ipv4.q_in, f); /* dst changed, reprocess */
TASS Belgium NV 131:4758606c9316 583 else
TASS Belgium NV 131:4758606c9316 584 pico_transport_receive(f, hdr->proto);
TASS Belgium NV 131:4758606c9316 585 } else if (pico_tree_findKey(&Tree_dev_link, &test)) {
TASS Belgium NV 131:4758606c9316 586 #ifdef PICO_SUPPORT_UDP
TASS Belgium NV 131:4758606c9316 587 /* address of this device is apparently 0.0.0.0; might be a DHCP packet */
TASS Belgium NV 131:4758606c9316 588 /* XXX KRO: is obsolete. Broadcast flag is set on outgoing DHCP messages.
TASS Belgium NV 131:4758606c9316 589 * incomming DHCP messages are to be broadcasted. Our current DHCP server
TASS Belgium NV 131:4758606c9316 590 * implementation does not take this flag into account yet though ... */
TASS Belgium NV 131:4758606c9316 591 pico_enqueue(pico_proto_udp.q_in, f);
TASS Belgium NV 131:4758606c9316 592 #endif
tass 68:0847e35d08a6 593 } else {
TASS Belgium NV 131:4758606c9316 594
TASS Belgium NV 131:4758606c9316 595 if((pico_ipv4_is_broadcast(hdr->dst.addr)))
TASS Belgium NV 131:4758606c9316 596 {
TASS Belgium NV 131:4758606c9316 597 /* don't forward broadcast frame, discard! */
TASS Belgium NV 131:4758606c9316 598 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 599 } else if (pico_ipv4_forward(f) != 0) {
TASS Belgium NV 131:4758606c9316 600 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 601 /* dbg("Forward failed.\n"); */
TASS Belgium NV 131:4758606c9316 602 }
tass 68:0847e35d08a6 603 }
TASS Belgium NV 131:4758606c9316 604
TASS Belgium NV 131:4758606c9316 605 return 0;
tass 68:0847e35d08a6 606 }
tass 68:0847e35d08a6 607
tass 68:0847e35d08a6 608 PICO_TREE_DECLARE(Routes, ipv4_route_compare);
tass 68:0847e35d08a6 609
tass 68:0847e35d08a6 610
tass 68:0847e35d08a6 611 static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f)
tass 68:0847e35d08a6 612 {
TASS Belgium NV 131:4758606c9316 613 IGNORE_PARAMETER(self);
TASS Belgium NV 131:4758606c9316 614 f->start = (uint8_t*) f->net_hdr;
tass 68:0847e35d08a6 615 #ifdef PICO_SUPPORT_IPFILTER
TASS Belgium NV 131:4758606c9316 616 if (ipfilter(f)) {
TASS Belgium NV 131:4758606c9316 617 /*pico_frame is discarded as result of the filtering*/
TASS Belgium NV 131:4758606c9316 618 return 0;
TASS Belgium NV 131:4758606c9316 619 }
TASS Belgium NV 131:4758606c9316 620
tass 68:0847e35d08a6 621 #endif
TASS Belgium NV 131:4758606c9316 622 return pico_sendto_dev(f);
tass 68:0847e35d08a6 623 }
tass 68:0847e35d08a6 624
tass 68:0847e35d08a6 625
tass 70:cd218dd180e5 626 static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size)
tass 68:0847e35d08a6 627 {
TASS Belgium NV 131:4758606c9316 628 struct pico_frame *f = pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR);
TASS Belgium NV 131:4758606c9316 629 IGNORE_PARAMETER(self);
TASS Belgium NV 131:4758606c9316 630
TASS Belgium NV 131:4758606c9316 631 if (!f)
TASS Belgium NV 131:4758606c9316 632 return NULL;
tass 68:0847e35d08a6 633
TASS Belgium NV 131:4758606c9316 634 f->datalink_hdr = f->buffer;
TASS Belgium NV 131:4758606c9316 635 f->net_hdr = f->buffer + PICO_SIZE_ETHHDR;
TASS Belgium NV 131:4758606c9316 636 f->net_len = PICO_SIZE_IP4HDR;
TASS Belgium NV 131:4758606c9316 637 f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR;
TASS Belgium NV 131:4758606c9316 638 f->transport_len = size;
TASS Belgium NV 131:4758606c9316 639 f->len = size + PICO_SIZE_IP4HDR;
TASS Belgium NV 131:4758606c9316 640 return f;
tass 68:0847e35d08a6 641 }
tass 68:0847e35d08a6 642
tass 68:0847e35d08a6 643 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f);
tass 68:0847e35d08a6 644
tass 68:0847e35d08a6 645 /* Interface: protocol definition */
tass 68:0847e35d08a6 646 struct pico_protocol pico_proto_ipv4 = {
TASS Belgium NV 131:4758606c9316 647 .name = "ipv4",
TASS Belgium NV 131:4758606c9316 648 .proto_number = PICO_PROTO_IPV4,
TASS Belgium NV 131:4758606c9316 649 .layer = PICO_LAYER_NETWORK,
TASS Belgium NV 131:4758606c9316 650 .alloc = pico_ipv4_alloc,
TASS Belgium NV 131:4758606c9316 651 .process_in = pico_ipv4_process_in,
TASS Belgium NV 131:4758606c9316 652 .process_out = pico_ipv4_process_out,
TASS Belgium NV 131:4758606c9316 653 .push = pico_ipv4_frame_sock_push,
TASS Belgium NV 131:4758606c9316 654 .q_in = &in,
TASS Belgium NV 131:4758606c9316 655 .q_out = &out,
tass 68:0847e35d08a6 656 };
tass 68:0847e35d08a6 657
tass 68:0847e35d08a6 658 struct pico_ipv4_route
tass 68:0847e35d08a6 659 {
TASS Belgium NV 131:4758606c9316 660 struct pico_ip4 dest;
TASS Belgium NV 131:4758606c9316 661 struct pico_ip4 netmask;
TASS Belgium NV 131:4758606c9316 662 struct pico_ip4 gateway;
TASS Belgium NV 131:4758606c9316 663 struct pico_ipv4_link *link;
TASS Belgium NV 131:4758606c9316 664 uint32_t metric;
tass 68:0847e35d08a6 665 };
tass 68:0847e35d08a6 666
tass 68:0847e35d08a6 667
TASS Belgium NV 131:4758606c9316 668 static int ipv4_route_compare(void *ka, void *kb)
tass 68:0847e35d08a6 669 {
TASS Belgium NV 131:4758606c9316 670 struct pico_ipv4_route *a = ka, *b = kb;
tass 68:0847e35d08a6 671
TASS Belgium NV 131:4758606c9316 672 /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */
TASS Belgium NV 131:4758606c9316 673 if (long_be(a->netmask.addr) < long_be(b->netmask.addr))
TASS Belgium NV 131:4758606c9316 674 return -1;
tass 68:0847e35d08a6 675
TASS Belgium NV 131:4758606c9316 676 if (long_be(a->netmask.addr) > long_be(b->netmask.addr))
TASS Belgium NV 131:4758606c9316 677 return 1;
tass 68:0847e35d08a6 678
TASS Belgium NV 131:4758606c9316 679 if (a->dest.addr < b->dest.addr)
TASS Belgium NV 131:4758606c9316 680 return -1;
tass 68:0847e35d08a6 681
TASS Belgium NV 131:4758606c9316 682 if (a->dest.addr > b->dest.addr)
TASS Belgium NV 131:4758606c9316 683 return 1;
tass 68:0847e35d08a6 684
TASS Belgium NV 131:4758606c9316 685 if (a->metric < b->metric)
TASS Belgium NV 131:4758606c9316 686 return -1;
tass 68:0847e35d08a6 687
TASS Belgium NV 131:4758606c9316 688 if (a->metric > b->metric)
TASS Belgium NV 131:4758606c9316 689 return 1;
tass 68:0847e35d08a6 690
TASS Belgium NV 131:4758606c9316 691 return 0;
tass 68:0847e35d08a6 692 }
tass 68:0847e35d08a6 693
tass 68:0847e35d08a6 694 static struct pico_ipv4_route *route_find(const struct pico_ip4 *addr)
tass 68:0847e35d08a6 695 {
TASS Belgium NV 131:4758606c9316 696 struct pico_ipv4_route *r;
TASS Belgium NV 131:4758606c9316 697 struct pico_tree_node *index;
tass 68:0847e35d08a6 698
TASS Belgium NV 131:4758606c9316 699 if(addr->addr != PICO_IP4_BCAST)
tass 68:0847e35d08a6 700 {
TASS Belgium NV 131:4758606c9316 701 pico_tree_foreach_reverse(index, &Routes) {
TASS Belgium NV 131:4758606c9316 702 r = index->keyValue;
TASS Belgium NV 131:4758606c9316 703 if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) {
TASS Belgium NV 131:4758606c9316 704 return r;
TASS Belgium NV 131:4758606c9316 705 }
TASS Belgium NV 131:4758606c9316 706 }
tass 68:0847e35d08a6 707 }
tass 68:0847e35d08a6 708 else
tass 68:0847e35d08a6 709 {
TASS Belgium NV 131:4758606c9316 710 r = pico_tree_first(&Routes);
TASS Belgium NV 131:4758606c9316 711 if(!r->netmask.addr)
TASS Belgium NV 131:4758606c9316 712 {
TASS Belgium NV 131:4758606c9316 713 return r;
TASS Belgium NV 131:4758606c9316 714 }
TASS Belgium NV 131:4758606c9316 715 else
TASS Belgium NV 131:4758606c9316 716 {
TASS Belgium NV 131:4758606c9316 717 dbg("WARNING: no default route for a global broadcast found\n");
TASS Belgium NV 131:4758606c9316 718 }
tass 68:0847e35d08a6 719 }
tass 68:0847e35d08a6 720
TASS Belgium NV 131:4758606c9316 721 return NULL;
tass 68:0847e35d08a6 722 }
tass 68:0847e35d08a6 723
tass 68:0847e35d08a6 724 struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr)
tass 68:0847e35d08a6 725 {
TASS Belgium NV 131:4758606c9316 726 struct pico_ip4 nullip;
TASS Belgium NV 131:4758606c9316 727 struct pico_ipv4_route *route;
TASS Belgium NV 131:4758606c9316 728 nullip.addr = 0U;
tass 68:0847e35d08a6 729
TASS Belgium NV 131:4758606c9316 730 if(!addr) {
TASS Belgium NV 131:4758606c9316 731 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 732 return nullip;
TASS Belgium NV 131:4758606c9316 733 }
tass 68:0847e35d08a6 734
TASS Belgium NV 131:4758606c9316 735 route = route_find(addr);
TASS Belgium NV 131:4758606c9316 736 if (!route) {
TASS Belgium NV 131:4758606c9316 737 pico_err = PICO_ERR_EHOSTUNREACH;
TASS Belgium NV 131:4758606c9316 738 return nullip;
TASS Belgium NV 131:4758606c9316 739 }
TASS Belgium NV 131:4758606c9316 740 else
TASS Belgium NV 131:4758606c9316 741 return route->gateway;
tass 68:0847e35d08a6 742 }
tass 68:0847e35d08a6 743
tass 68:0847e35d08a6 744 struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst)
tass 68:0847e35d08a6 745 {
TASS Belgium NV 131:4758606c9316 746 struct pico_ip4 *myself = NULL;
TASS Belgium NV 131:4758606c9316 747 struct pico_ipv4_route *rt;
TASS Belgium NV 131:4758606c9316 748
TASS Belgium NV 131:4758606c9316 749 if(!dst) {
TASS Belgium NV 131:4758606c9316 750 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 751 return NULL;
TASS Belgium NV 131:4758606c9316 752 }
tass 68:0847e35d08a6 753
TASS Belgium NV 131:4758606c9316 754 rt = route_find(dst);
TASS Belgium NV 131:4758606c9316 755 if (rt) {
TASS Belgium NV 131:4758606c9316 756 myself = &rt->link->address;
TASS Belgium NV 131:4758606c9316 757 } else
TASS Belgium NV 131:4758606c9316 758 pico_err = PICO_ERR_EHOSTUNREACH;
tass 68:0847e35d08a6 759
TASS Belgium NV 131:4758606c9316 760 return myself;
tass 68:0847e35d08a6 761 }
tass 68:0847e35d08a6 762
tass 68:0847e35d08a6 763
tass 68:0847e35d08a6 764 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 765 /* link
TASS Belgium NV 131:4758606c9316 766 * |
tass 68:0847e35d08a6 767 * MCASTGroups
tass 68:0847e35d08a6 768 * | | |
tass 68:0847e35d08a6 769 * ------------ | ------------
tass 68:0847e35d08a6 770 * | | |
TASS Belgium NV 131:4758606c9316 771 * MCASTSources MCASTSources MCASTSources
tass 68:0847e35d08a6 772 * | | | | | | | | | | | |
tass 68:0847e35d08a6 773 * S S S S S S S S S S S S
tass 68:0847e35d08a6 774 *
tass 68:0847e35d08a6 775 * MCASTGroups: RBTree(mcast_group)
tass 68:0847e35d08a6 776 * MCASTSources: RBTree(source)
tass 68:0847e35d08a6 777 */
TASS Belgium NV 131:4758606c9316 778 static int ipv4_mcast_groups_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 779 {
TASS Belgium NV 131:4758606c9316 780 struct pico_mcast_group *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 781 if (a->mcast_addr.addr < b->mcast_addr.addr) {
TASS Belgium NV 131:4758606c9316 782 return -1;
TASS Belgium NV 131:4758606c9316 783 } else if (a->mcast_addr.addr > b->mcast_addr.addr) {
TASS Belgium NV 131:4758606c9316 784 return 1;
TASS Belgium NV 131:4758606c9316 785 } else {
TASS Belgium NV 131:4758606c9316 786 return 0;
TASS Belgium NV 131:4758606c9316 787 }
tass 68:0847e35d08a6 788 }
tass 68:0847e35d08a6 789
tass 68:0847e35d08a6 790 static int ipv4_mcast_sources_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 791 {
TASS Belgium NV 131:4758606c9316 792 struct pico_ip4 *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 793 if (a->addr < b->addr)
TASS Belgium NV 131:4758606c9316 794 return -1;
TASS Belgium NV 131:4758606c9316 795
TASS Belgium NV 131:4758606c9316 796 if (a->addr > b->addr)
TASS Belgium NV 131:4758606c9316 797 return 1;
TASS Belgium NV 131:4758606c9316 798
TASS Belgium NV 131:4758606c9316 799 return 0;
tass 68:0847e35d08a6 800 }
tass 68:0847e35d08a6 801
tass 68:0847e35d08a6 802 static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link)
tass 68:0847e35d08a6 803 {
TASS Belgium NV 131:4758606c9316 804 uint16_t i = 0;
TASS Belgium NV 131:4758606c9316 805 struct pico_mcast_group __attribute__ ((unused)) *g = NULL;
TASS Belgium NV 131:4758606c9316 806 struct pico_ip4 __attribute__ ((unused)) *source = NULL;
TASS Belgium NV 131:4758606c9316 807 struct pico_tree_node *index = NULL, *index2 = NULL;
tass 68:0847e35d08a6 808
TASS Belgium NV 131:4758606c9316 809 ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
TASS Belgium NV 131:4758606c9316 810 ip_mcast_dbg("+ MULTICAST list interface %-16s +\n", mcast_link->dev->name);
TASS Belgium NV 131:4758606c9316 811 ip_mcast_dbg("+---------------------------------------------------------------------------------+\n");
TASS Belgium NV 131:4758606c9316 812 ip_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n");
TASS Belgium NV 131:4758606c9316 813 ip_mcast_dbg("+---------------------------------------------------------------------------------+\n");
tass 68:0847e35d08a6 814
TASS Belgium NV 131:4758606c9316 815 pico_tree_foreach(index, mcast_link->MCASTGroups)
tass 68:0847e35d08a6 816 {
TASS Belgium NV 131:4758606c9316 817 g = index->keyValue;
TASS Belgium NV 131:4758606c9316 818 ip_mcast_dbg("+ %04d | %16s | %08X | %05u | %u | %8s +\n", i, mcast_link->dev->name, g->mcast_addr.addr, g->reference_count, g->filter_mode, "");
TASS Belgium NV 131:4758606c9316 819 pico_tree_foreach(index2, &g->MCASTSources)
TASS Belgium NV 131:4758606c9316 820 {
TASS Belgium NV 131:4758606c9316 821 source = index2->keyValue;
TASS Belgium NV 131:4758606c9316 822 ip_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %08X +\n", "", "", "", "", "", source->addr);
TASS Belgium NV 131:4758606c9316 823 }
TASS Belgium NV 131:4758606c9316 824 i++;
tass 68:0847e35d08a6 825 }
TASS Belgium NV 131:4758606c9316 826 ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
tass 68:0847e35d08a6 827 }
tass 68:0847e35d08a6 828
tass 70:cd218dd180e5 829 static int mcast_group_update(struct pico_mcast_group *g, struct pico_tree *MCASTFilter, uint8_t filter_mode)
tass 70:cd218dd180e5 830 {
TASS Belgium NV 131:4758606c9316 831 struct pico_tree_node *index = NULL, *_tmp = NULL;
TASS Belgium NV 131:4758606c9316 832 struct pico_ip4 *source = NULL;
TASS Belgium NV 131:4758606c9316 833 /* cleanup filter */
TASS Belgium NV 131:4758606c9316 834 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp)
tass 70:cd218dd180e5 835 {
TASS Belgium NV 131:4758606c9316 836 source = index->keyValue;
TASS Belgium NV 131:4758606c9316 837 pico_tree_delete(&g->MCASTSources, source);
TASS Belgium NV 131:4758606c9316 838 pico_free(source);
tass 70:cd218dd180e5 839 }
TASS Belgium NV 131:4758606c9316 840 /* insert new filter */
TASS Belgium NV 131:4758606c9316 841 if (MCASTFilter) {
TASS Belgium NV 131:4758606c9316 842 pico_tree_foreach(index, MCASTFilter)
TASS Belgium NV 131:4758606c9316 843 {
TASS Belgium NV 131:4758606c9316 844 source = pico_zalloc(sizeof(struct pico_ip4));
TASS Belgium NV 131:4758606c9316 845 if (!source) {
TASS Belgium NV 131:4758606c9316 846 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 847 return -1;
TASS Belgium NV 131:4758606c9316 848 }
TASS Belgium NV 131:4758606c9316 849
TASS Belgium NV 131:4758606c9316 850 source->addr = ((struct pico_ip4 *)index->keyValue)->addr;
TASS Belgium NV 131:4758606c9316 851 pico_tree_insert(&g->MCASTSources, source);
TASS Belgium NV 131:4758606c9316 852 }
TASS Belgium NV 131:4758606c9316 853 }
TASS Belgium NV 131:4758606c9316 854
TASS Belgium NV 131:4758606c9316 855 g->filter_mode = filter_mode;
TASS Belgium NV 131:4758606c9316 856 return 0;
tass 70:cd218dd180e5 857 }
tass 70:cd218dd180e5 858
tass 68:0847e35d08a6 859 int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter)
tass 68:0847e35d08a6 860 {
TASS Belgium NV 131:4758606c9316 861 struct pico_mcast_group *g = NULL, test = {
TASS Belgium NV 131:4758606c9316 862 0
TASS Belgium NV 131:4758606c9316 863 };
TASS Belgium NV 131:4758606c9316 864 struct pico_ipv4_link *link = NULL;
tass 68:0847e35d08a6 865
TASS Belgium NV 131:4758606c9316 866 if (mcast_link)
TASS Belgium NV 131:4758606c9316 867 link = pico_ipv4_link_get(mcast_link);
TASS Belgium NV 131:4758606c9316 868 else
TASS Belgium NV 131:4758606c9316 869 link = mcast_default_link;
TASS Belgium NV 131:4758606c9316 870
TASS Belgium NV 131:4758606c9316 871 test.mcast_addr = *mcast_group;
TASS Belgium NV 131:4758606c9316 872 g = pico_tree_findKey(link->MCASTGroups, &test);
TASS Belgium NV 131:4758606c9316 873 if (g) {
TASS Belgium NV 131:4758606c9316 874 if (reference_count)
TASS Belgium NV 131:4758606c9316 875 g->reference_count++;
tass 68:0847e35d08a6 876
TASS Belgium NV 131:4758606c9316 877 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE);
TASS Belgium NV 131:4758606c9316 878 } else {
TASS Belgium NV 131:4758606c9316 879 g = pico_zalloc(sizeof(struct pico_mcast_group));
TASS Belgium NV 131:4758606c9316 880 if (!g) {
TASS Belgium NV 131:4758606c9316 881 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 882 return -1;
TASS Belgium NV 131:4758606c9316 883 }
TASS Belgium NV 131:4758606c9316 884
TASS Belgium NV 131:4758606c9316 885 /* "non-existent" state of filter mode INCLUDE and empty source list */
TASS Belgium NV 131:4758606c9316 886 g->filter_mode = PICO_IP_MULTICAST_INCLUDE;
TASS Belgium NV 131:4758606c9316 887 g->reference_count = 1;
TASS Belgium NV 131:4758606c9316 888 g->mcast_addr = *mcast_group;
TASS Belgium NV 131:4758606c9316 889 g->MCASTSources.root = &LEAF;
TASS Belgium NV 131:4758606c9316 890 g->MCASTSources.compare = ipv4_mcast_sources_cmp;
TASS Belgium NV 131:4758606c9316 891 pico_tree_insert(link->MCASTGroups, g);
TASS Belgium NV 131:4758606c9316 892 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE);
tass 68:0847e35d08a6 893 }
TASS Belgium NV 131:4758606c9316 894
TASS Belgium NV 131:4758606c9316 895 if (mcast_group_update(g, MCASTFilter, filter_mode) < 0)
TASS Belgium NV 131:4758606c9316 896 return -1;
TASS Belgium NV 131:4758606c9316 897
TASS Belgium NV 131:4758606c9316 898 pico_ipv4_mcast_print_groups(link);
TASS Belgium NV 131:4758606c9316 899 return 0;
tass 68:0847e35d08a6 900 }
tass 68:0847e35d08a6 901
tass 68:0847e35d08a6 902 int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter)
tass 68:0847e35d08a6 903 {
tass 68:0847e35d08a6 904
TASS Belgium NV 131:4758606c9316 905 struct pico_mcast_group *g = NULL, test = {
TASS Belgium NV 131:4758606c9316 906 0
TASS Belgium NV 131:4758606c9316 907 };
TASS Belgium NV 131:4758606c9316 908 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 909 struct pico_tree_node *index = NULL, *_tmp = NULL;
TASS Belgium NV 131:4758606c9316 910 struct pico_ip4 *source = NULL;
tass 68:0847e35d08a6 911
TASS Belgium NV 131:4758606c9316 912 if (mcast_link)
TASS Belgium NV 131:4758606c9316 913 link = pico_ipv4_link_get(mcast_link);
TASS Belgium NV 131:4758606c9316 914 else
TASS Belgium NV 131:4758606c9316 915 link = mcast_default_link;
tass 68:0847e35d08a6 916
TASS Belgium NV 131:4758606c9316 917 test.mcast_addr = *mcast_group;
TASS Belgium NV 131:4758606c9316 918 g = pico_tree_findKey(link->MCASTGroups, &test);
TASS Belgium NV 131:4758606c9316 919 if (!g) {
TASS Belgium NV 131:4758606c9316 920 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 921 return -1;
tass 68:0847e35d08a6 922 } else {
TASS Belgium NV 131:4758606c9316 923 if (reference_count && (--(g->reference_count) < 1)) {
TASS Belgium NV 131:4758606c9316 924 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE);
TASS Belgium NV 131:4758606c9316 925 /* cleanup filter */
TASS Belgium NV 131:4758606c9316 926 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp)
TASS Belgium NV 131:4758606c9316 927 {
TASS Belgium NV 131:4758606c9316 928 source = index->keyValue;
TASS Belgium NV 131:4758606c9316 929 pico_tree_delete(&g->MCASTSources, source);
TASS Belgium NV 131:4758606c9316 930 pico_free(source);
TASS Belgium NV 131:4758606c9316 931 }
TASS Belgium NV 131:4758606c9316 932 pico_tree_delete(link->MCASTGroups, g);
TASS Belgium NV 131:4758606c9316 933 pico_free(g);
TASS Belgium NV 131:4758606c9316 934 } else {
TASS Belgium NV 131:4758606c9316 935 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE);
TASS Belgium NV 131:4758606c9316 936 if (mcast_group_update(g, MCASTFilter, filter_mode) < 0)
TASS Belgium NV 131:4758606c9316 937 return -1;
TASS Belgium NV 131:4758606c9316 938 }
tass 68:0847e35d08a6 939 }
tass 68:0847e35d08a6 940
TASS Belgium NV 131:4758606c9316 941 pico_ipv4_mcast_print_groups(link);
TASS Belgium NV 131:4758606c9316 942 return 0;
tass 68:0847e35d08a6 943 }
tass 68:0847e35d08a6 944
tass 68:0847e35d08a6 945 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void)
tass 68:0847e35d08a6 946 {
TASS Belgium NV 131:4758606c9316 947 return mcast_default_link;
tass 68:0847e35d08a6 948 }
tass 68:0847e35d08a6 949
tass 68:0847e35d08a6 950 static int pico_ipv4_mcast_filter(struct pico_frame *f)
tass 68:0847e35d08a6 951 {
TASS Belgium NV 131:4758606c9316 952 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 953 struct pico_tree_node *index = NULL, *index2 = NULL;
TASS Belgium NV 131:4758606c9316 954 struct pico_mcast_group *g = NULL, test = {
TASS Belgium NV 131:4758606c9316 955 0
TASS Belgium NV 131:4758606c9316 956 };
TASS Belgium NV 131:4758606c9316 957 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
tass 68:0847e35d08a6 958
TASS Belgium NV 131:4758606c9316 959 test.mcast_addr = hdr->dst;
tass 68:0847e35d08a6 960
TASS Belgium NV 131:4758606c9316 961 pico_tree_foreach(index, &Tree_dev_link)
TASS Belgium NV 131:4758606c9316 962 {
TASS Belgium NV 131:4758606c9316 963 link = index->keyValue;
TASS Belgium NV 131:4758606c9316 964 g = pico_tree_findKey(link->MCASTGroups, &test);
TASS Belgium NV 131:4758606c9316 965 if (g) {
TASS Belgium NV 131:4758606c9316 966 if (f->dev == link->dev) {
TASS Belgium NV 131:4758606c9316 967 ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name);
TASS Belgium NV 131:4758606c9316 968 /* perform source filtering */
TASS Belgium NV 131:4758606c9316 969 switch (g->filter_mode)
TASS Belgium NV 131:4758606c9316 970 {
TASS Belgium NV 131:4758606c9316 971 case PICO_IP_MULTICAST_INCLUDE:
TASS Belgium NV 131:4758606c9316 972 pico_tree_foreach(index2, &g->MCASTSources)
TASS Belgium NV 131:4758606c9316 973 {
TASS Belgium NV 131:4758606c9316 974 if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) {
TASS Belgium NV 131:4758606c9316 975 ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr);
TASS Belgium NV 131:4758606c9316 976 return 0;
TASS Belgium NV 131:4758606c9316 977 }
TASS Belgium NV 131:4758606c9316 978 }
TASS Belgium NV 131:4758606c9316 979 ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr);
TASS Belgium NV 131:4758606c9316 980 return -1;
TASS Belgium NV 131:4758606c9316 981
TASS Belgium NV 131:4758606c9316 982 case PICO_IP_MULTICAST_EXCLUDE:
TASS Belgium NV 131:4758606c9316 983 pico_tree_foreach(index2, &g->MCASTSources)
TASS Belgium NV 131:4758606c9316 984 {
TASS Belgium NV 131:4758606c9316 985 if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) {
TASS Belgium NV 131:4758606c9316 986 ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr);
TASS Belgium NV 131:4758606c9316 987 return -1;
TASS Belgium NV 131:4758606c9316 988 }
TASS Belgium NV 131:4758606c9316 989 }
TASS Belgium NV 131:4758606c9316 990 ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr);
TASS Belgium NV 131:4758606c9316 991 return 0;
TASS Belgium NV 131:4758606c9316 992
TASS Belgium NV 131:4758606c9316 993 default:
TASS Belgium NV 131:4758606c9316 994 return -1;
TASS Belgium NV 131:4758606c9316 995 }
TASS Belgium NV 131:4758606c9316 996 } else {
TASS Belgium NV 131:4758606c9316 997 ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name);
tass 68:0847e35d08a6 998 }
TASS Belgium NV 131:4758606c9316 999 } else {
TASS Belgium NV 131:4758606c9316 1000 ip_mcast_dbg("MCAST: IP %08X is not a group member of link %s\n", hdr->dst.addr, f->dev->name);
tass 68:0847e35d08a6 1001 }
tass 68:0847e35d08a6 1002 }
TASS Belgium NV 131:4758606c9316 1003 return -1;
tass 68:0847e35d08a6 1004 }
tass 68:0847e35d08a6 1005
TASS Belgium NV 131:4758606c9316 1006 #else
tass 68:0847e35d08a6 1007
tass 68:0847e35d08a6 1008 int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter)
tass 68:0847e35d08a6 1009 {
TASS Belgium NV 131:4758606c9316 1010 pico_err = PICO_ERR_EPROTONOSUPPORT;
TASS Belgium NV 131:4758606c9316 1011 return -1;
tass 68:0847e35d08a6 1012 }
tass 68:0847e35d08a6 1013 int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter)
tass 68:0847e35d08a6 1014 {
TASS Belgium NV 131:4758606c9316 1015 pico_err = PICO_ERR_EPROTONOSUPPORT;
TASS Belgium NV 131:4758606c9316 1016 return -1;
tass 68:0847e35d08a6 1017 }
tass 68:0847e35d08a6 1018 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void)
tass 68:0847e35d08a6 1019 {
TASS Belgium NV 131:4758606c9316 1020 pico_err = PICO_ERR_EPROTONOSUPPORT;
TASS Belgium NV 131:4758606c9316 1021 return NULL;
tass 68:0847e35d08a6 1022 }
tass 68:0847e35d08a6 1023 #endif /* PICO_SUPPORT_MCAST */
tass 68:0847e35d08a6 1024
tass 88:0e827d0d8017 1025 #ifdef DEBUG_ROUTE
tass 88:0e827d0d8017 1026 static void dbg_route(void)
tass 88:0e827d0d8017 1027 {
TASS Belgium NV 131:4758606c9316 1028 struct pico_ipv4_route *r;
TASS Belgium NV 131:4758606c9316 1029 struct pico_tree_node *index;
TASS Belgium NV 131:4758606c9316 1030 pico_tree_foreach(index, &Routes){
TASS Belgium NV 131:4758606c9316 1031 r = index->keyValue;
TASS Belgium NV 131:4758606c9316 1032 dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric);
TASS Belgium NV 131:4758606c9316 1033 }
tass 88:0e827d0d8017 1034 }
tass 88:0e827d0d8017 1035 #else
TASS Belgium NV 131:4758606c9316 1036 #define dbg_route() do { } while(0)
tass 88:0e827d0d8017 1037 #endif
tass 88:0e827d0d8017 1038
tass 68:0847e35d08a6 1039 int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto)
tass 68:0847e35d08a6 1040 {
tass 68:0847e35d08a6 1041
TASS Belgium NV 131:4758606c9316 1042 struct pico_ipv4_route *route;
TASS Belgium NV 131:4758606c9316 1043 struct pico_ipv4_link *link;
TASS Belgium NV 131:4758606c9316 1044 struct pico_ipv4_hdr *hdr;
TASS Belgium NV 131:4758606c9316 1045 uint8_t ttl = PICO_IPV4_DEFAULT_TTL;
TASS Belgium NV 131:4758606c9316 1046 uint8_t vhl = 0x45; /* version 4, header length 20 */
TASS Belgium NV 131:4758606c9316 1047 static uint16_t ipv4_progressive_id = 0x91c0;
tass 68:0847e35d08a6 1048 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 1049 struct pico_tree_node *index;
tass 68:0847e35d08a6 1050 #endif
tass 68:0847e35d08a6 1051
TASS Belgium NV 131:4758606c9316 1052 if(!f || !dst) {
TASS Belgium NV 131:4758606c9316 1053 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1054 return -1;
TASS Belgium NV 131:4758606c9316 1055 }
TASS Belgium NV 131:4758606c9316 1056
TASS Belgium NV 131:4758606c9316 1057 hdr = (struct pico_ipv4_hdr *) f->net_hdr;
TASS Belgium NV 131:4758606c9316 1058 if (!hdr) {
TASS Belgium NV 131:4758606c9316 1059 dbg("IP header error\n");
TASS Belgium NV 131:4758606c9316 1060 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1061 goto drop;
TASS Belgium NV 131:4758606c9316 1062 }
tass 68:0847e35d08a6 1063
TASS Belgium NV 131:4758606c9316 1064 if (dst->addr == 0) {
TASS Belgium NV 131:4758606c9316 1065 dbg("IP destination addr error\n");
TASS Belgium NV 131:4758606c9316 1066 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1067 goto drop;
TASS Belgium NV 131:4758606c9316 1068 }
tass 68:0847e35d08a6 1069
TASS Belgium NV 131:4758606c9316 1070 route = route_find(dst);
TASS Belgium NV 131:4758606c9316 1071 if (!route) {
TASS Belgium NV 131:4758606c9316 1072 /* dbg("Route to %08x not found.\n", long_be(dst->addr)); */
TASS Belgium NV 131:4758606c9316 1073
TASS Belgium NV 131:4758606c9316 1074
TASS Belgium NV 131:4758606c9316 1075 pico_err = PICO_ERR_EHOSTUNREACH;
TASS Belgium NV 131:4758606c9316 1076 goto drop;
TASS Belgium NV 131:4758606c9316 1077 } else {
TASS Belgium NV 131:4758606c9316 1078 link = route->link;
tass 68:0847e35d08a6 1079 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 1080 if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */
TASS Belgium NV 131:4758606c9316 1081 switch (proto) {
TASS Belgium NV 131:4758606c9316 1082 case PICO_PROTO_UDP:
TASS Belgium NV 131:4758606c9316 1083 if(pico_udp_get_mc_ttl(f->sock, &ttl) < 0)
TASS Belgium NV 131:4758606c9316 1084 ttl = PICO_IP_DEFAULT_MULTICAST_TTL;
TASS Belgium NV 131:4758606c9316 1085
tass 68:0847e35d08a6 1086 break;
TASS Belgium NV 131:4758606c9316 1087 case PICO_PROTO_IGMP:
TASS Belgium NV 131:4758606c9316 1088 vhl = 0x46; /* header length 24 */
TASS Belgium NV 131:4758606c9316 1089 ttl = 1;
TASS Belgium NV 131:4758606c9316 1090 /* router alert (RFC 2113) */
TASS Belgium NV 131:4758606c9316 1091 hdr->options[0] = 0x94;
TASS Belgium NV 131:4758606c9316 1092 hdr->options[1] = 0x04;
TASS Belgium NV 131:4758606c9316 1093 hdr->options[2] = 0x00;
TASS Belgium NV 131:4758606c9316 1094 hdr->options[3] = 0x00;
TASS Belgium NV 131:4758606c9316 1095 if (f->dev && link->dev != f->dev) { /* default link is not requested link */
TASS Belgium NV 131:4758606c9316 1096 pico_tree_foreach(index, &Tree_dev_link) {
TASS Belgium NV 131:4758606c9316 1097 link = index->keyValue;
TASS Belgium NV 131:4758606c9316 1098 if (link->dev == f->dev)
TASS Belgium NV 131:4758606c9316 1099 break;
TASS Belgium NV 131:4758606c9316 1100 }
TASS Belgium NV 131:4758606c9316 1101 }
TASS Belgium NV 131:4758606c9316 1102
TASS Belgium NV 131:4758606c9316 1103 break;
TASS Belgium NV 131:4758606c9316 1104 default:
TASS Belgium NV 131:4758606c9316 1105 ttl = PICO_IPV4_DEFAULT_TTL;
tass 68:0847e35d08a6 1106 }
TASS Belgium NV 131:4758606c9316 1107 }
TASS Belgium NV 131:4758606c9316 1108
TASS Belgium NV 131:4758606c9316 1109 #endif
tass 68:0847e35d08a6 1110 }
tass 68:0847e35d08a6 1111
TASS Belgium NV 131:4758606c9316 1112 hdr->vhl = vhl;
TASS Belgium NV 131:4758606c9316 1113 hdr->len = short_be((uint16_t)(f->transport_len + f->net_len));
TASS Belgium NV 131:4758606c9316 1114 if (f->transport_hdr != f->payload)
TASS Belgium NV 131:4758606c9316 1115 ipv4_progressive_id++;
TASS Belgium NV 131:4758606c9316 1116
TASS Belgium NV 131:4758606c9316 1117 hdr->id = short_be(ipv4_progressive_id);
TASS Belgium NV 131:4758606c9316 1118 hdr->dst.addr = dst->addr;
TASS Belgium NV 131:4758606c9316 1119 hdr->src.addr = link->address.addr;
TASS Belgium NV 131:4758606c9316 1120 hdr->ttl = ttl;
TASS Belgium NV 131:4758606c9316 1121 hdr->proto = proto;
TASS Belgium NV 131:4758606c9316 1122 hdr->frag = short_be(PICO_IPV4_DONTFRAG);
tass 68:0847e35d08a6 1123 #ifdef PICO_SUPPORT_IPFRAG
tass 68:0847e35d08a6 1124 # ifdef PICO_SUPPORT_UDP
TASS Belgium NV 131:4758606c9316 1125 if (proto == PICO_PROTO_UDP) {
TASS Belgium NV 131:4758606c9316 1126 /* first fragment, can not use transport_len to calculate IP length */
TASS Belgium NV 131:4758606c9316 1127 if (f->transport_hdr != f->payload)
TASS Belgium NV 131:4758606c9316 1128 hdr->len = short_be((uint16_t)(f->payload_len + sizeof(struct pico_udp_hdr) + f->net_len));
TASS Belgium NV 131:4758606c9316 1129
TASS Belgium NV 131:4758606c9316 1130 /* set fragmentation flags and offset calculated in socket layer */
TASS Belgium NV 131:4758606c9316 1131 hdr->frag = f->frag;
TASS Belgium NV 131:4758606c9316 1132 }
TASS Belgium NV 131:4758606c9316 1133
tass 68:0847e35d08a6 1134 # endif /* PICO_SUPPORT_UDP */
tass 68:0847e35d08a6 1135 #endif /* PICO_SUPPORT_IPFRAG */
TASS Belgium NV 131:4758606c9316 1136 pico_ipv4_checksum(f);
tass 68:0847e35d08a6 1137
TASS Belgium NV 131:4758606c9316 1138 if (f->sock && f->sock->dev) {
TASS Belgium NV 131:4758606c9316 1139 /* if the socket has its device set, use that (currently used for DHCP) */
TASS Belgium NV 131:4758606c9316 1140 f->dev = f->sock->dev;
TASS Belgium NV 131:4758606c9316 1141 } else {
TASS Belgium NV 131:4758606c9316 1142 f->dev = link->dev;
TASS Belgium NV 131:4758606c9316 1143 }
tass 68:0847e35d08a6 1144
tass 68:0847e35d08a6 1145 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 1146 if (pico_ipv4_is_multicast(hdr->dst.addr)) {
TASS Belgium NV 131:4758606c9316 1147 struct pico_frame *cpy;
TASS Belgium NV 131:4758606c9316 1148 /* Sending UDP multicast datagram, am I member? If so, loopback copy */
TASS Belgium NV 131:4758606c9316 1149 if ((proto != PICO_PROTO_IGMP) && (pico_ipv4_mcast_filter(f) == 0)) {
TASS Belgium NV 131:4758606c9316 1150 ip_mcast_dbg("MCAST: sender is member of group, loopback copy\n");
TASS Belgium NV 131:4758606c9316 1151 cpy = pico_frame_copy(f);
TASS Belgium NV 131:4758606c9316 1152 pico_enqueue(&in, cpy);
TASS Belgium NV 131:4758606c9316 1153 }
tass 68:0847e35d08a6 1154 }
TASS Belgium NV 131:4758606c9316 1155
tass 68:0847e35d08a6 1156 #endif
tass 68:0847e35d08a6 1157
TASS Belgium NV 131:4758606c9316 1158 if(pico_ipv4_link_get(&hdr->dst)) {
TASS Belgium NV 131:4758606c9316 1159 /* it's our own IP */
TASS Belgium NV 131:4758606c9316 1160 return pico_enqueue(&in, f);
TASS Belgium NV 131:4758606c9316 1161 }else{
TASS Belgium NV 131:4758606c9316 1162 /* TODO: Check if there are members subscribed here */
TASS Belgium NV 131:4758606c9316 1163 return pico_enqueue(&out, f);
TASS Belgium NV 131:4758606c9316 1164 }
tass 68:0847e35d08a6 1165
tass 68:0847e35d08a6 1166 drop:
TASS Belgium NV 131:4758606c9316 1167 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 1168 return -1;
tass 68:0847e35d08a6 1169 }
tass 68:0847e35d08a6 1170
tass 68:0847e35d08a6 1171
tass 68:0847e35d08a6 1172 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f)
tass 68:0847e35d08a6 1173 {
TASS Belgium NV 131:4758606c9316 1174 struct pico_ip4 *dst;
TASS Belgium NV 131:4758606c9316 1175 struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info;
TASS Belgium NV 131:4758606c9316 1176 IGNORE_PARAMETER(self);
tass 68:0847e35d08a6 1177
TASS Belgium NV 131:4758606c9316 1178 if (!f->sock) {
TASS Belgium NV 131:4758606c9316 1179 pico_frame_discard(f);
TASS Belgium NV 131:4758606c9316 1180 return -1;
TASS Belgium NV 131:4758606c9316 1181 }
tass 68:0847e35d08a6 1182
TASS Belgium NV 131:4758606c9316 1183 if (remote_duple) {
TASS Belgium NV 131:4758606c9316 1184 dst = &remote_duple->remote_addr.ip4;
TASS Belgium NV 131:4758606c9316 1185 } else {
TASS Belgium NV 131:4758606c9316 1186 dst = &f->sock->remote_addr.ip4;
TASS Belgium NV 131:4758606c9316 1187 }
tass 68:0847e35d08a6 1188
TASS Belgium NV 131:4758606c9316 1189 return pico_ipv4_frame_push(f, dst, (uint8_t)f->sock->proto->proto_number);
tass 68:0847e35d08a6 1190 }
tass 68:0847e35d08a6 1191
tass 68:0847e35d08a6 1192
tass 68:0847e35d08a6 1193 int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link)
tass 68:0847e35d08a6 1194 {
TASS Belgium NV 131:4758606c9316 1195 struct pico_ipv4_route test, *new;
TASS Belgium NV 131:4758606c9316 1196 test.dest.addr = address.addr;
TASS Belgium NV 131:4758606c9316 1197 test.netmask.addr = netmask.addr;
TASS Belgium NV 131:4758606c9316 1198 test.metric = (uint32_t)metric;
TASS Belgium NV 131:4758606c9316 1199
TASS Belgium NV 131:4758606c9316 1200 if(pico_tree_findKey(&Routes, &test)) {
TASS Belgium NV 131:4758606c9316 1201 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1202 return -1;
TASS Belgium NV 131:4758606c9316 1203 }
TASS Belgium NV 131:4758606c9316 1204
TASS Belgium NV 131:4758606c9316 1205 new = pico_zalloc(sizeof(struct pico_ipv4_route));
TASS Belgium NV 131:4758606c9316 1206 if (!new) {
TASS Belgium NV 131:4758606c9316 1207 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 1208 return -1;
TASS Belgium NV 131:4758606c9316 1209 }
tass 68:0847e35d08a6 1210
TASS Belgium NV 131:4758606c9316 1211 new->dest.addr = address.addr;
TASS Belgium NV 131:4758606c9316 1212 new->netmask.addr = netmask.addr;
TASS Belgium NV 131:4758606c9316 1213 new->gateway.addr = gateway.addr;
TASS Belgium NV 131:4758606c9316 1214 new->metric = (uint32_t)metric;
TASS Belgium NV 131:4758606c9316 1215 if (gateway.addr == 0) {
TASS Belgium NV 131:4758606c9316 1216 /* No gateway provided, use the link */
TASS Belgium NV 131:4758606c9316 1217 new->link = link;
TASS Belgium NV 131:4758606c9316 1218 } else {
TASS Belgium NV 131:4758606c9316 1219 struct pico_ipv4_route *r = route_find(&gateway);
TASS Belgium NV 131:4758606c9316 1220 if (!r ) { /* Specified Gateway is unreachable */
TASS Belgium NV 131:4758606c9316 1221 pico_err = PICO_ERR_EHOSTUNREACH;
TASS Belgium NV 131:4758606c9316 1222 pico_free(new);
TASS Belgium NV 131:4758606c9316 1223 return -1;
TASS Belgium NV 131:4758606c9316 1224 }
TASS Belgium NV 131:4758606c9316 1225
TASS Belgium NV 131:4758606c9316 1226 if (r->gateway.addr) { /* Specified Gateway is not a neighbor */
TASS Belgium NV 131:4758606c9316 1227 pico_err = PICO_ERR_ENETUNREACH;
TASS Belgium NV 131:4758606c9316 1228 pico_free(new);
TASS Belgium NV 131:4758606c9316 1229 return -1;
TASS Belgium NV 131:4758606c9316 1230 }
TASS Belgium NV 131:4758606c9316 1231
TASS Belgium NV 131:4758606c9316 1232 new->link = r->link;
tass 68:0847e35d08a6 1233 }
TASS Belgium NV 131:4758606c9316 1234
TASS Belgium NV 131:4758606c9316 1235 if (!new->link) {
TASS Belgium NV 131:4758606c9316 1236 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1237 pico_free(new);
TASS Belgium NV 131:4758606c9316 1238 return -1;
tass 68:0847e35d08a6 1239 }
tass 68:0847e35d08a6 1240
TASS Belgium NV 131:4758606c9316 1241 pico_tree_insert(&Routes, new);
TASS Belgium NV 131:4758606c9316 1242 /* dbg_route(); */
TASS Belgium NV 131:4758606c9316 1243 return 0;
tass 68:0847e35d08a6 1244 }
tass 68:0847e35d08a6 1245
tass 72:887bc44746ff 1246 int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric)
tass 68:0847e35d08a6 1247 {
TASS Belgium NV 131:4758606c9316 1248 struct pico_ipv4_route test, *found;
tass 68:0847e35d08a6 1249
TASS Belgium NV 131:4758606c9316 1250 test.dest.addr = address.addr;
TASS Belgium NV 131:4758606c9316 1251 test.netmask.addr = netmask.addr;
TASS Belgium NV 131:4758606c9316 1252 test.metric = (uint32_t)metric;
tass 68:0847e35d08a6 1253
TASS Belgium NV 131:4758606c9316 1254 found = pico_tree_findKey(&Routes, &test);
TASS Belgium NV 131:4758606c9316 1255 if (found) {
tass 68:0847e35d08a6 1256
TASS Belgium NV 131:4758606c9316 1257 pico_tree_delete(&Routes, found);
TASS Belgium NV 131:4758606c9316 1258 pico_free(found);
tass 68:0847e35d08a6 1259
TASS Belgium NV 131:4758606c9316 1260 /* dbg_route(); */
TASS Belgium NV 131:4758606c9316 1261 return 0;
TASS Belgium NV 131:4758606c9316 1262 }
TASS Belgium NV 131:4758606c9316 1263
TASS Belgium NV 131:4758606c9316 1264 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1265 return -1;
tass 68:0847e35d08a6 1266 }
tass 68:0847e35d08a6 1267
tass 68:0847e35d08a6 1268
tass 68:0847e35d08a6 1269 int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask)
tass 68:0847e35d08a6 1270 {
TASS Belgium NV 131:4758606c9316 1271 struct pico_ipv4_link test, *new;
TASS Belgium NV 131:4758606c9316 1272 struct pico_ip4 network, gateway;
TASS Belgium NV 131:4758606c9316 1273 char ipstr[30];
TASS Belgium NV 131:4758606c9316 1274
TASS Belgium NV 131:4758606c9316 1275 if(!dev) {
TASS Belgium NV 131:4758606c9316 1276 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1277 return -1;
TASS Belgium NV 131:4758606c9316 1278 }
tass 68:0847e35d08a6 1279
TASS Belgium NV 131:4758606c9316 1280 test.address.addr = address.addr;
TASS Belgium NV 131:4758606c9316 1281 test.netmask.addr = netmask.addr;
TASS Belgium NV 131:4758606c9316 1282 test.dev = dev;
TASS Belgium NV 131:4758606c9316 1283 /** XXX: Valid netmask / unicast address test **/
tass 68:0847e35d08a6 1284
TASS Belgium NV 131:4758606c9316 1285 if(pico_tree_findKey(&Tree_dev_link, &test)) {
TASS Belgium NV 131:4758606c9316 1286 dbg("IPv4: Trying to assign an invalid address (in use)\n");
TASS Belgium NV 131:4758606c9316 1287 pico_err = PICO_ERR_EADDRINUSE;
TASS Belgium NV 131:4758606c9316 1288 return -1;
TASS Belgium NV 131:4758606c9316 1289 }
tass 68:0847e35d08a6 1290
TASS Belgium NV 131:4758606c9316 1291 /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/
TASS Belgium NV 131:4758606c9316 1292 new = pico_zalloc(sizeof(struct pico_ipv4_link));
TASS Belgium NV 131:4758606c9316 1293 if (!new) {
TASS Belgium NV 131:4758606c9316 1294 dbg("IPv4: Out of memory!\n");
TASS Belgium NV 131:4758606c9316 1295 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 1296 return -1;
TASS Belgium NV 131:4758606c9316 1297 }
TASS Belgium NV 131:4758606c9316 1298
TASS Belgium NV 131:4758606c9316 1299 new->address.addr = address.addr;
TASS Belgium NV 131:4758606c9316 1300 new->netmask.addr = netmask.addr;
TASS Belgium NV 131:4758606c9316 1301 new->dev = dev;
tass 68:0847e35d08a6 1302 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 1303 new->MCASTGroups = pico_zalloc(sizeof(struct pico_tree));
TASS Belgium NV 131:4758606c9316 1304 if (!new->MCASTGroups) {
TASS Belgium NV 131:4758606c9316 1305 pico_free(new);
TASS Belgium NV 131:4758606c9316 1306 dbg("IPv4: Out of memory!\n");
TASS Belgium NV 131:4758606c9316 1307 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 1308 return -1;
TASS Belgium NV 131:4758606c9316 1309 }
tass 68:0847e35d08a6 1310
TASS Belgium NV 131:4758606c9316 1311 new->MCASTGroups->root = &LEAF;
TASS Belgium NV 131:4758606c9316 1312 new->MCASTGroups->compare = ipv4_mcast_groups_cmp;
TASS Belgium NV 131:4758606c9316 1313 new->mcast_compatibility = PICO_IGMPV3; /* default RFC 3376 $7.2.1 */
TASS Belgium NV 131:4758606c9316 1314 new->mcast_last_query_interval = PICO_IGMP_QUERY_INTERVAL;
tass 68:0847e35d08a6 1315 #endif
tass 68:0847e35d08a6 1316
TASS Belgium NV 131:4758606c9316 1317 pico_tree_insert(&Tree_dev_link, new);
tass 68:0847e35d08a6 1318 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 1319 do {
TASS Belgium NV 131:4758606c9316 1320 struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw;
TASS Belgium NV 131:4758606c9316 1321 if (!mcast_default_link) {
TASS Belgium NV 131:4758606c9316 1322 mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */
TASS Belgium NV 131:4758606c9316 1323 mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */
TASS Belgium NV 131:4758606c9316 1324 mcast_gw.addr = long_be(0x00000000);
TASS Belgium NV 131:4758606c9316 1325 mcast_default_link = new;
TASS Belgium NV 131:4758606c9316 1326 pico_ipv4_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new);
TASS Belgium NV 131:4758606c9316 1327 }
TASS Belgium NV 131:4758606c9316 1328
TASS Belgium NV 131:4758606c9316 1329 mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS;
TASS Belgium NV 131:4758606c9316 1330 pico_ipv4_mcast_join(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL);
TASS Belgium NV 131:4758606c9316 1331 } while(0);
tass 68:0847e35d08a6 1332 #endif
tass 68:0847e35d08a6 1333
TASS Belgium NV 131:4758606c9316 1334 network.addr = address.addr & netmask.addr;
TASS Belgium NV 131:4758606c9316 1335 gateway.addr = 0U;
TASS Belgium NV 131:4758606c9316 1336 pico_ipv4_route_add(network, netmask, gateway, 1, new);
TASS Belgium NV 131:4758606c9316 1337 pico_ipv4_to_string(ipstr, new->address.addr);
TASS Belgium NV 131:4758606c9316 1338 dbg("Assigned ipv4 %s to device %s\n", ipstr, new->dev->name);
TASS Belgium NV 131:4758606c9316 1339 return 0;
tass 68:0847e35d08a6 1340 }
tass 68:0847e35d08a6 1341
tass 72:887bc44746ff 1342 static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link)
tass 72:887bc44746ff 1343 {
TASS Belgium NV 131:4758606c9316 1344 struct pico_tree_node *index = NULL, *tmp = NULL;
TASS Belgium NV 131:4758606c9316 1345 struct pico_ipv4_route *route = NULL;
tass 72:887bc44746ff 1346
TASS Belgium NV 131:4758606c9316 1347 pico_tree_foreach_safe(index, &Routes, tmp)
TASS Belgium NV 131:4758606c9316 1348 {
TASS Belgium NV 131:4758606c9316 1349 route = index->keyValue;
TASS Belgium NV 131:4758606c9316 1350 if (link == route->link)
TASS Belgium NV 131:4758606c9316 1351 pico_ipv4_route_del(route->dest, route->netmask, (int)route->metric);
TASS Belgium NV 131:4758606c9316 1352 }
TASS Belgium NV 131:4758606c9316 1353 return 0;
tass 72:887bc44746ff 1354 }
tass 68:0847e35d08a6 1355
tass 68:0847e35d08a6 1356 int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address)
tass 68:0847e35d08a6 1357 {
TASS Belgium NV 131:4758606c9316 1358 struct pico_ipv4_link test, *found;
TASS Belgium NV 131:4758606c9316 1359
TASS Belgium NV 131:4758606c9316 1360 if(!dev) {
TASS Belgium NV 131:4758606c9316 1361 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1362 return -1;
TASS Belgium NV 131:4758606c9316 1363 }
tass 68:0847e35d08a6 1364
TASS Belgium NV 131:4758606c9316 1365 test.address.addr = address.addr;
TASS Belgium NV 131:4758606c9316 1366 test.dev = dev;
TASS Belgium NV 131:4758606c9316 1367 found = pico_tree_findKey(&Tree_dev_link, &test);
TASS Belgium NV 131:4758606c9316 1368 if (!found) {
TASS Belgium NV 131:4758606c9316 1369 pico_err = PICO_ERR_ENXIO;
TASS Belgium NV 131:4758606c9316 1370 return -1;
TASS Belgium NV 131:4758606c9316 1371 }
tass 68:0847e35d08a6 1372
tass 68:0847e35d08a6 1373 #ifdef PICO_SUPPORT_MCAST
TASS Belgium NV 131:4758606c9316 1374 do {
TASS Belgium NV 131:4758606c9316 1375 struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm;
TASS Belgium NV 131:4758606c9316 1376 struct pico_mcast_group *g = NULL;
TASS Belgium NV 131:4758606c9316 1377 struct pico_tree_node *index, *_tmp;
TASS Belgium NV 131:4758606c9316 1378 if (found == mcast_default_link) {
TASS Belgium NV 131:4758606c9316 1379 mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */
TASS Belgium NV 131:4758606c9316 1380 mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */
TASS Belgium NV 131:4758606c9316 1381 mcast_default_link = NULL;
TASS Belgium NV 131:4758606c9316 1382 pico_ipv4_route_del(mcast_addr, mcast_nm, 1);
TASS Belgium NV 131:4758606c9316 1383 }
TASS Belgium NV 131:4758606c9316 1384
TASS Belgium NV 131:4758606c9316 1385 mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS;
TASS Belgium NV 131:4758606c9316 1386 pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL);
TASS Belgium NV 131:4758606c9316 1387 pico_tree_foreach_safe(index, found->MCASTGroups, _tmp)
TASS Belgium NV 131:4758606c9316 1388 {
TASS Belgium NV 131:4758606c9316 1389 g = index->keyValue;
TASS Belgium NV 131:4758606c9316 1390 pico_tree_delete(found->MCASTGroups, g);
TASS Belgium NV 131:4758606c9316 1391 pico_free(g);
TASS Belgium NV 131:4758606c9316 1392 }
TASS Belgium NV 131:4758606c9316 1393 } while(0);
tass 68:0847e35d08a6 1394 #endif
tass 68:0847e35d08a6 1395
TASS Belgium NV 131:4758606c9316 1396 pico_ipv4_cleanup_routes(found);
TASS Belgium NV 131:4758606c9316 1397 pico_tree_delete(&Tree_dev_link, found);
TASS Belgium NV 131:4758606c9316 1398 pico_free(found);
tass 72:887bc44746ff 1399
TASS Belgium NV 131:4758606c9316 1400 return 0;
tass 68:0847e35d08a6 1401 }
tass 68:0847e35d08a6 1402
tass 68:0847e35d08a6 1403
tass 68:0847e35d08a6 1404 struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address)
tass 68:0847e35d08a6 1405 {
TASS Belgium NV 131:4758606c9316 1406 struct pico_ipv4_link test = {
TASS Belgium NV 131:4758606c9316 1407 0
TASS Belgium NV 131:4758606c9316 1408 }, *found = NULL;
TASS Belgium NV 131:4758606c9316 1409 test.address.addr = address->addr;
tass 68:0847e35d08a6 1410
TASS Belgium NV 131:4758606c9316 1411 found = pico_tree_findKey(&Tree_dev_link, &test);
TASS Belgium NV 131:4758606c9316 1412 if (!found)
TASS Belgium NV 131:4758606c9316 1413 return NULL;
TASS Belgium NV 131:4758606c9316 1414 else
TASS Belgium NV 131:4758606c9316 1415 return found;
tass 68:0847e35d08a6 1416 }
tass 68:0847e35d08a6 1417
tass 68:0847e35d08a6 1418 struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev)
tass 68:0847e35d08a6 1419 {
TASS Belgium NV 131:4758606c9316 1420 struct pico_tree_node *index = NULL;
TASS Belgium NV 131:4758606c9316 1421 struct pico_ipv4_link *link = NULL;
tass 68:0847e35d08a6 1422
TASS Belgium NV 131:4758606c9316 1423 pico_tree_foreach(index, &Tree_dev_link)
TASS Belgium NV 131:4758606c9316 1424 {
TASS Belgium NV 131:4758606c9316 1425 link = index->keyValue;
TASS Belgium NV 131:4758606c9316 1426 if (link->dev == dev)
TASS Belgium NV 131:4758606c9316 1427 return link;
TASS Belgium NV 131:4758606c9316 1428 }
TASS Belgium NV 131:4758606c9316 1429 return NULL;
tass 68:0847e35d08a6 1430 }
tass 68:0847e35d08a6 1431
tass 74:c146c4e346c4 1432 struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last)
tass 74:c146c4e346c4 1433 {
TASS Belgium NV 131:4758606c9316 1434 struct pico_tree_node *index = NULL;
TASS Belgium NV 131:4758606c9316 1435 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 1436 int valid = 0;
tass 74:c146c4e346c4 1437
TASS Belgium NV 131:4758606c9316 1438 if (last == NULL)
TASS Belgium NV 131:4758606c9316 1439 valid = 1;
tass 74:c146c4e346c4 1440
TASS Belgium NV 131:4758606c9316 1441 pico_tree_foreach(index, &Tree_dev_link)
TASS Belgium NV 131:4758606c9316 1442 {
TASS Belgium NV 131:4758606c9316 1443 link = index->keyValue;
TASS Belgium NV 131:4758606c9316 1444 if (link->dev == dev) {
TASS Belgium NV 131:4758606c9316 1445 if (last == link)
TASS Belgium NV 131:4758606c9316 1446 valid = 1;
TASS Belgium NV 131:4758606c9316 1447 else if (valid > 0)
TASS Belgium NV 131:4758606c9316 1448 return link;
TASS Belgium NV 131:4758606c9316 1449 }
tass 74:c146c4e346c4 1450 }
TASS Belgium NV 131:4758606c9316 1451 return NULL;
tass 74:c146c4e346c4 1452 }
tass 68:0847e35d08a6 1453
tass 68:0847e35d08a6 1454 struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address)
tass 68:0847e35d08a6 1455 {
TASS Belgium NV 131:4758606c9316 1456 struct pico_ipv4_link test, *found;
TASS Belgium NV 131:4758606c9316 1457 if(!address) {
TASS Belgium NV 131:4758606c9316 1458 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1459 return NULL;
TASS Belgium NV 131:4758606c9316 1460 }
TASS Belgium NV 131:4758606c9316 1461
TASS Belgium NV 131:4758606c9316 1462 test.dev = NULL;
TASS Belgium NV 131:4758606c9316 1463 test.address.addr = address->addr;
TASS Belgium NV 131:4758606c9316 1464 found = pico_tree_findKey(&Tree_dev_link, &test);
TASS Belgium NV 131:4758606c9316 1465 if (!found) {
TASS Belgium NV 131:4758606c9316 1466 pico_err = PICO_ERR_ENXIO;
TASS Belgium NV 131:4758606c9316 1467 return NULL;
TASS Belgium NV 131:4758606c9316 1468 }
TASS Belgium NV 131:4758606c9316 1469
TASS Belgium NV 131:4758606c9316 1470 return found->dev;
tass 68:0847e35d08a6 1471 }
tass 68:0847e35d08a6 1472
tass 68:0847e35d08a6 1473 int pico_ipv4_rebound(struct pico_frame *f)
tass 68:0847e35d08a6 1474 {
TASS Belgium NV 131:4758606c9316 1475 struct pico_ip4 dst;
TASS Belgium NV 131:4758606c9316 1476 struct pico_ipv4_hdr *hdr;
TASS Belgium NV 131:4758606c9316 1477 if(!f) {
TASS Belgium NV 131:4758606c9316 1478 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1479 return -1;
TASS Belgium NV 131:4758606c9316 1480 }
tass 68:0847e35d08a6 1481
TASS Belgium NV 131:4758606c9316 1482 hdr = (struct pico_ipv4_hdr *) f->net_hdr;
TASS Belgium NV 131:4758606c9316 1483 if (!hdr) {
TASS Belgium NV 131:4758606c9316 1484 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 1485 return -1;
TASS Belgium NV 131:4758606c9316 1486 }
TASS Belgium NV 131:4758606c9316 1487
TASS Belgium NV 131:4758606c9316 1488 dst.addr = hdr->src.addr;
TASS Belgium NV 131:4758606c9316 1489 return pico_ipv4_frame_push(f, &dst, hdr->proto);
tass 68:0847e35d08a6 1490 }
tass 68:0847e35d08a6 1491
tass 68:0847e35d08a6 1492 static int pico_ipv4_forward(struct pico_frame *f)
tass 68:0847e35d08a6 1493 {
TASS Belgium NV 131:4758606c9316 1494 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
TASS Belgium NV 131:4758606c9316 1495 struct pico_ipv4_route *rt;
TASS Belgium NV 131:4758606c9316 1496 if (!hdr) {
TASS Belgium NV 131:4758606c9316 1497 return -1;
TASS Belgium NV 131:4758606c9316 1498 }
tass 68:0847e35d08a6 1499
TASS Belgium NV 131:4758606c9316 1500 rt = route_find(&hdr->dst);
TASS Belgium NV 131:4758606c9316 1501 if (!rt) {
TASS Belgium NV 131:4758606c9316 1502 pico_notify_dest_unreachable(f);
TASS Belgium NV 131:4758606c9316 1503 return -1;
TASS Belgium NV 131:4758606c9316 1504 }
tass 110:0ece1bbbd36e 1505
TASS Belgium NV 131:4758606c9316 1506 if (f->dev == rt->link->dev)
TASS Belgium NV 131:4758606c9316 1507 return -1;
tass 110:0ece1bbbd36e 1508
TASS Belgium NV 131:4758606c9316 1509 f->dev = rt->link->dev;
TASS Belgium NV 131:4758606c9316 1510 hdr->ttl = (uint8_t)(hdr->ttl - 1);
TASS Belgium NV 131:4758606c9316 1511 if (hdr->ttl < 1) {
TASS Belgium NV 131:4758606c9316 1512 pico_notify_ttl_expired(f);
TASS Belgium NV 131:4758606c9316 1513 dbg(" ------------------- TTL EXPIRED\n");
TASS Belgium NV 131:4758606c9316 1514 return -1;
TASS Belgium NV 131:4758606c9316 1515 }
tass 68:0847e35d08a6 1516
TASS Belgium NV 131:4758606c9316 1517 hdr->crc++;
TASS Belgium NV 131:4758606c9316 1518
TASS Belgium NV 131:4758606c9316 1519 pico_ipv4_nat_outbound(f, &rt->link->address);
tass 68:0847e35d08a6 1520
TASS Belgium NV 131:4758606c9316 1521 f->start = f->net_hdr;
TASS Belgium NV 131:4758606c9316 1522 if(f->dev->eth != NULL)
TASS Belgium NV 131:4758606c9316 1523 f->len -= PICO_SIZE_ETHHDR;
TASS Belgium NV 131:4758606c9316 1524
TASS Belgium NV 131:4758606c9316 1525 pico_sendto_dev(f);
TASS Belgium NV 131:4758606c9316 1526 return 0;
tass 68:0847e35d08a6 1527
tass 68:0847e35d08a6 1528 }
tass 68:0847e35d08a6 1529
tass 68:0847e35d08a6 1530 int pico_ipv4_is_broadcast(uint32_t addr)
tass 68:0847e35d08a6 1531 {
TASS Belgium NV 131:4758606c9316 1532 struct pico_ipv4_link *link;
TASS Belgium NV 131:4758606c9316 1533 struct pico_tree_node *index;
TASS Belgium NV 131:4758606c9316 1534 if (addr == PICO_IP4_BCAST)
TASS Belgium NV 131:4758606c9316 1535 return 1;
TASS Belgium NV 131:4758606c9316 1536
TASS Belgium NV 131:4758606c9316 1537 pico_tree_foreach(index, &Tree_dev_link) {
TASS Belgium NV 131:4758606c9316 1538 link = index->keyValue;
TASS Belgium NV 131:4758606c9316 1539 if ((link->address.addr | (~link->netmask.addr)) == addr)
TASS Belgium NV 131:4758606c9316 1540 return 1;
TASS Belgium NV 131:4758606c9316 1541 }
TASS Belgium NV 131:4758606c9316 1542 return 0;
tass 68:0847e35d08a6 1543 }
tass 68:0847e35d08a6 1544
tass 68:0847e35d08a6 1545 void pico_ipv4_unreachable(struct pico_frame *f, int err)
tass 68:0847e35d08a6 1546 {
TASS Belgium NV 131:4758606c9316 1547 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
tass 68:0847e35d08a6 1548 #if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP
TASS Belgium NV 131:4758606c9316 1549 f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR;
TASS Belgium NV 131:4758606c9316 1550 pico_transport_error(f, hdr->proto, err);
tass 68:0847e35d08a6 1551 #endif
tass 68:0847e35d08a6 1552 }
tass 68:0847e35d08a6 1553
tass 68:0847e35d08a6 1554 #endif