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