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 RTOSgeneric mbed Ethernet driverhigh performance NXP LPC1768 specific Ethernet driverMulti-threading support for mbed RTOSBerkeley sockets and integration with the New Socket APIFork of the apps running on top of the New Socket APIScheduling 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.
modules/pico_ipv4.c@137:a1c8bfa9d691, 2014-02-07 (annotated)
- 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?
User | Revision | Line number | New 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 |