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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

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

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 68:0847e35d08a6 1 /*********************************************************************
TASS Belgium NV 131:4758606c9316 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
TASS Belgium NV 131:4758606c9316 3 See LICENSE and COPYING for usage.
tass 68:0847e35d08a6 4
TASS Belgium NV 131:4758606c9316 5 RFC 1112, 2236, 3376, 3569, 3678, 4607
tass 68:0847e35d08a6 6
TASS Belgium NV 131:4758606c9316 7 Authors: Kristof Roelants (IGMPv3), Simon Maes, Brecht Van Cauwenberghe
TASS Belgium NV 131:4758606c9316 8 *********************************************************************/
tass 68:0847e35d08a6 9
tass 68:0847e35d08a6 10 #include "pico_stack.h"
tass 68:0847e35d08a6 11 #include "pico_ipv4.h"
tass 68:0847e35d08a6 12 #include "pico_igmp.h"
tass 68:0847e35d08a6 13 #include "pico_config.h"
tass 68:0847e35d08a6 14 #include "pico_eth.h"
tass 68:0847e35d08a6 15 #include "pico_addressing.h"
tass 68:0847e35d08a6 16 #include "pico_frame.h"
tass 68:0847e35d08a6 17 #include "pico_tree.h"
tass 68:0847e35d08a6 18 #include "pico_device.h"
tass 68:0847e35d08a6 19 #include "pico_socket.h"
tass 68:0847e35d08a6 20
TASS Belgium NV 131:4758606c9316 21 #define igmp_dbg(...) do {} while(0)
TASS Belgium NV 131:4758606c9316 22 /* #define igmp_dbg dbg */
tass 68:0847e35d08a6 23
tass 68:0847e35d08a6 24 /* membership states */
tass 68:0847e35d08a6 25 #define IGMP_STATE_NON_MEMBER (0x0)
tass 68:0847e35d08a6 26 #define IGMP_STATE_DELAYING_MEMBER (0x1)
tass 68:0847e35d08a6 27 #define IGMP_STATE_IDLE_MEMBER (0x2)
tass 68:0847e35d08a6 28
TASS Belgium NV 131:4758606c9316 29 /* events */
tass 68:0847e35d08a6 30 #define IGMP_EVENT_DELETE_GROUP (0x0)
tass 68:0847e35d08a6 31 #define IGMP_EVENT_CREATE_GROUP (0x1)
tass 68:0847e35d08a6 32 #define IGMP_EVENT_UPDATE_GROUP (0x2)
tass 68:0847e35d08a6 33 #define IGMP_EVENT_QUERY_RECV (0x3)
tass 68:0847e35d08a6 34 #define IGMP_EVENT_REPORT_RECV (0x4)
tass 68:0847e35d08a6 35 #define IGMP_EVENT_TIMER_EXPIRED (0x5)
tass 68:0847e35d08a6 36
tass 68:0847e35d08a6 37 /* message types */
tass 68:0847e35d08a6 38 #define IGMP_TYPE_MEM_QUERY (0x11)
tass 68:0847e35d08a6 39 #define IGMP_TYPE_MEM_REPORT_V1 (0x12)
tass 68:0847e35d08a6 40 #define IGMP_TYPE_MEM_REPORT_V2 (0x16)
tass 68:0847e35d08a6 41 #define IGMP_TYPE_LEAVE_GROUP (0x17)
tass 68:0847e35d08a6 42 #define IGMP_TYPE_MEM_REPORT_V3 (0x22)
tass 68:0847e35d08a6 43
tass 68:0847e35d08a6 44 /* group record types */
tass 68:0847e35d08a6 45 #define IGMP_MODE_IS_INCLUDE (1)
tass 68:0847e35d08a6 46 #define IGMP_MODE_IS_EXCLUDE (2)
tass 68:0847e35d08a6 47 #define IGMP_CHANGE_TO_INCLUDE_MODE (3)
tass 68:0847e35d08a6 48 #define IGMP_CHANGE_TO_EXCLUDE_MODE (4)
tass 68:0847e35d08a6 49 #define IGMP_ALLOW_NEW_SOURCES (5)
tass 68:0847e35d08a6 50 #define IGMP_BLOCK_OLD_SOURCES (6)
tass 68:0847e35d08a6 51
tass 68:0847e35d08a6 52 /* host flag */
tass 68:0847e35d08a6 53 #define IGMP_HOST_LAST (0x1)
tass 68:0847e35d08a6 54 #define IGMP_HOST_NOT_LAST (0x0)
tass 68:0847e35d08a6 55
tass 68:0847e35d08a6 56 /* list of timers, counters and their default values */
tass 70:cd218dd180e5 57 #define IGMP_ROBUSTNESS (2u)
tass 68:0847e35d08a6 58 #define IGMP_QUERY_INTERVAL (125) /* secs */
tass 70:cd218dd180e5 59 #define IGMP_QUERY_RESPONSE_INTERVAL (10u) /* secs */
tass 68:0847e35d08a6 60 #define IGMP_STARTUP_QUERY_INTERVAL (IGMPV3_QUERY_INTERVAL / 4)
tass 68:0847e35d08a6 61 #define IGMP_STARTUP_QUERY_COUNT (IGMPV3_ROBUSTNESS)
tass 68:0847e35d08a6 62 #define IGMP_LAST_MEMBER_QUERY_INTERVAL (1) /* secs */
tass 68:0847e35d08a6 63 #define IGMP_LAST_MEMBER_QUERY_COUNT (IGMPV3_ROBUSTNESS)
tass 68:0847e35d08a6 64 #define IGMP_UNSOLICITED_REPORT_INTERVAL (1) /* secs */
tass 68:0847e35d08a6 65 #define IGMP_DEFAULT_MAX_RESPONSE_TIME (100)
tass 68:0847e35d08a6 66
tass 68:0847e35d08a6 67 /* custom timers types */
tass 68:0847e35d08a6 68 #define IGMP_TIMER_GROUP_REPORT (1)
tass 68:0847e35d08a6 69 #define IGMP_TIMER_V1_QUERIER (2)
tass 68:0847e35d08a6 70 #define IGMP_TIMER_V2_QUERIER (3)
tass 68:0847e35d08a6 71
tass 68:0847e35d08a6 72 /* IGMP groups */
tass 68:0847e35d08a6 73 #define IGMP_ALL_HOST_GROUP long_be(0xE0000001) /* 224.0.0.1 */
tass 68:0847e35d08a6 74 #define IGMP_ALL_ROUTER_GROUP long_be(0xE0000002) /* 224.0.0.2 */
tass 68:0847e35d08a6 75 #define IGMPV3_ALL_ROUTER_GROUP long_be(0xE0000016) /* 224.0.0.22 */
tass 68:0847e35d08a6 76
tass 68:0847e35d08a6 77 /* misc */
tass 68:0847e35d08a6 78 #define IGMP_TIMER_STOPPED (1)
tass 70:cd218dd180e5 79 #define IP_OPTION_ROUTER_ALERT_LEN (4u)
tass 68:0847e35d08a6 80 #define IGMP_MAX_GROUPS (32) /* max 255 */
tass 68:0847e35d08a6 81
tass picotcp@tass.be 149:5f4cb161cec3 82 PACKED_STRUCT_DEF igmp_message {
TASS Belgium NV 131:4758606c9316 83 uint8_t type;
TASS Belgium NV 131:4758606c9316 84 uint8_t max_resp_time;
TASS Belgium NV 131:4758606c9316 85 uint16_t crc;
TASS Belgium NV 131:4758606c9316 86 uint32_t mcast_group;
tass 68:0847e35d08a6 87 };
tass 68:0847e35d08a6 88
tass picotcp@tass.be 149:5f4cb161cec3 89 PACKED_STRUCT_DEF igmpv3_query {
TASS Belgium NV 131:4758606c9316 90 uint8_t type;
TASS Belgium NV 131:4758606c9316 91 uint8_t max_resp_time;
TASS Belgium NV 131:4758606c9316 92 uint16_t crc;
TASS Belgium NV 131:4758606c9316 93 uint32_t mcast_group;
TASS Belgium NV 131:4758606c9316 94 uint8_t rsq;
TASS Belgium NV 131:4758606c9316 95 uint8_t qqic;
TASS Belgium NV 131:4758606c9316 96 uint16_t sources;
TASS Belgium NV 131:4758606c9316 97 uint32_t source_addr[];
tass 68:0847e35d08a6 98 };
tass 68:0847e35d08a6 99
tass picotcp@tass.be 149:5f4cb161cec3 100 PACKED_STRUCT_DEF igmpv3_group_record {
TASS Belgium NV 131:4758606c9316 101 uint8_t type;
TASS Belgium NV 131:4758606c9316 102 uint8_t aux;
TASS Belgium NV 131:4758606c9316 103 uint16_t sources;
TASS Belgium NV 131:4758606c9316 104 uint32_t mcast_group;
TASS Belgium NV 131:4758606c9316 105 uint32_t source_addr[];
tass 68:0847e35d08a6 106 };
tass 68:0847e35d08a6 107
tass picotcp@tass.be 149:5f4cb161cec3 108 PACKED_STRUCT_DEF igmpv3_report {
TASS Belgium NV 131:4758606c9316 109 uint8_t type;
TASS Belgium NV 131:4758606c9316 110 uint8_t res0;
TASS Belgium NV 131:4758606c9316 111 uint16_t crc;
TASS Belgium NV 131:4758606c9316 112 uint16_t res1;
TASS Belgium NV 131:4758606c9316 113 uint16_t groups;
TASS Belgium NV 131:4758606c9316 114 struct igmpv3_group_record record[];
tass 68:0847e35d08a6 115 };
tass 68:0847e35d08a6 116
tass 68:0847e35d08a6 117 struct igmp_parameters {
TASS Belgium NV 131:4758606c9316 118 uint8_t event;
TASS Belgium NV 131:4758606c9316 119 uint8_t state;
TASS Belgium NV 131:4758606c9316 120 uint8_t last_host;
TASS Belgium NV 131:4758606c9316 121 uint8_t filter_mode;
TASS Belgium NV 131:4758606c9316 122 uint8_t max_resp_time;
TASS Belgium NV 131:4758606c9316 123 struct pico_ip4 mcast_link;
TASS Belgium NV 131:4758606c9316 124 struct pico_ip4 mcast_group;
TASS Belgium NV 131:4758606c9316 125 struct pico_tree *MCASTFilter;
TASS Belgium NV 131:4758606c9316 126 struct pico_frame *f;
tass 68:0847e35d08a6 127 };
tass 68:0847e35d08a6 128
tass 68:0847e35d08a6 129 struct igmp_timer {
TASS Belgium NV 131:4758606c9316 130 uint8_t type;
TASS Belgium NV 131:4758606c9316 131 uint8_t stopped;
TASS Belgium NV 131:4758606c9316 132 pico_time start;
TASS Belgium NV 131:4758606c9316 133 pico_time delay;
TASS Belgium NV 131:4758606c9316 134 struct pico_ip4 mcast_link;
TASS Belgium NV 131:4758606c9316 135 struct pico_ip4 mcast_group;
TASS Belgium NV 131:4758606c9316 136 struct pico_frame *f;
TASS Belgium NV 131:4758606c9316 137 void (*callback)(struct igmp_timer *t);
tass 68:0847e35d08a6 138 };
tass 68:0847e35d08a6 139
tass 68:0847e35d08a6 140 /* queues */
TASS Belgium NV 131:4758606c9316 141 static struct pico_queue igmp_in = {
TASS Belgium NV 131:4758606c9316 142 0
TASS Belgium NV 131:4758606c9316 143 };
TASS Belgium NV 131:4758606c9316 144 static struct pico_queue igmp_out = {
TASS Belgium NV 131:4758606c9316 145 0
TASS Belgium NV 131:4758606c9316 146 };
tass 68:0847e35d08a6 147
tass 68:0847e35d08a6 148 /* finite state machine caller */
tass 68:0847e35d08a6 149 static int pico_igmp_process_event(struct igmp_parameters *p);
tass 68:0847e35d08a6 150
tass 68:0847e35d08a6 151 /* state callback prototype */
tass 68:0847e35d08a6 152 typedef int (*callback)(struct igmp_parameters *);
tass 68:0847e35d08a6 153
tass 68:0847e35d08a6 154 /* redblack trees */
tass 68:0847e35d08a6 155 static int igmp_timer_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 156 {
TASS Belgium NV 131:4758606c9316 157 struct igmp_timer *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 158 if (a->type < b->type)
TASS Belgium NV 131:4758606c9316 159 return -1;
TASS Belgium NV 131:4758606c9316 160
TASS Belgium NV 131:4758606c9316 161 if (a->type > b->type)
TASS Belgium NV 131:4758606c9316 162 return 1;
TASS Belgium NV 131:4758606c9316 163
TASS Belgium NV 131:4758606c9316 164 if (a->mcast_group.addr < b->mcast_group.addr)
TASS Belgium NV 131:4758606c9316 165 return -1;
TASS Belgium NV 131:4758606c9316 166
TASS Belgium NV 131:4758606c9316 167 if (a->mcast_group.addr > b->mcast_group.addr)
TASS Belgium NV 131:4758606c9316 168 return 1;
TASS Belgium NV 131:4758606c9316 169
TASS Belgium NV 131:4758606c9316 170 if (a->mcast_link.addr < b->mcast_link.addr)
TASS Belgium NV 131:4758606c9316 171 return -1;
TASS Belgium NV 131:4758606c9316 172
TASS Belgium NV 131:4758606c9316 173 if (a->mcast_link.addr > b->mcast_link.addr)
TASS Belgium NV 131:4758606c9316 174 return 1;
TASS Belgium NV 131:4758606c9316 175
TASS Belgium NV 131:4758606c9316 176 return 0;
tass 68:0847e35d08a6 177 }
tass 68:0847e35d08a6 178 PICO_TREE_DECLARE(IGMPTimers, igmp_timer_cmp);
tass 68:0847e35d08a6 179
tass 68:0847e35d08a6 180 static int igmp_parameters_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 181 {
TASS Belgium NV 131:4758606c9316 182 struct igmp_parameters *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 183 if (a->mcast_group.addr < b->mcast_group.addr)
TASS Belgium NV 131:4758606c9316 184 return -1;
TASS Belgium NV 131:4758606c9316 185
TASS Belgium NV 131:4758606c9316 186 if (a->mcast_group.addr > b->mcast_group.addr)
TASS Belgium NV 131:4758606c9316 187 return 1;
TASS Belgium NV 131:4758606c9316 188
TASS Belgium NV 131:4758606c9316 189 if (a->mcast_link.addr < b->mcast_link.addr)
TASS Belgium NV 131:4758606c9316 190 return -1;
TASS Belgium NV 131:4758606c9316 191
TASS Belgium NV 131:4758606c9316 192 if (a->mcast_link.addr > b->mcast_link.addr)
TASS Belgium NV 131:4758606c9316 193 return 1;
TASS Belgium NV 131:4758606c9316 194
TASS Belgium NV 131:4758606c9316 195 return 0;
tass 68:0847e35d08a6 196 }
tass 68:0847e35d08a6 197 PICO_TREE_DECLARE(IGMPParameters, igmp_parameters_cmp);
tass 68:0847e35d08a6 198
tass 68:0847e35d08a6 199 static int igmp_sources_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 200 {
TASS Belgium NV 131:4758606c9316 201 struct pico_ip4 *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 202 if (a->addr < b->addr)
TASS Belgium NV 131:4758606c9316 203 return -1;
TASS Belgium NV 131:4758606c9316 204
TASS Belgium NV 131:4758606c9316 205 if (a->addr > b->addr)
TASS Belgium NV 131:4758606c9316 206 return 1;
TASS Belgium NV 131:4758606c9316 207
TASS Belgium NV 131:4758606c9316 208 return 0;
tass 68:0847e35d08a6 209 }
tass 68:0847e35d08a6 210 PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp);
tass 68:0847e35d08a6 211 PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp);
tass 68:0847e35d08a6 212
tass 68:0847e35d08a6 213 static struct igmp_parameters *pico_igmp_find_parameter(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group)
tass 68:0847e35d08a6 214 {
TASS Belgium NV 131:4758606c9316 215 struct igmp_parameters test = {
TASS Belgium NV 131:4758606c9316 216 0
TASS Belgium NV 131:4758606c9316 217 };
tass picotcp@tass.be 149:5f4cb161cec3 218 if (!mcast_link || !mcast_group)
tass picotcp@tass.be 149:5f4cb161cec3 219 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 220
TASS Belgium NV 131:4758606c9316 221 test.mcast_link.addr = mcast_link->addr;
TASS Belgium NV 131:4758606c9316 222 test.mcast_group.addr = mcast_group->addr;
TASS Belgium NV 131:4758606c9316 223 return pico_tree_findKey(&IGMPParameters, &test);
tass 68:0847e35d08a6 224 }
tass 68:0847e35d08a6 225
tass 68:0847e35d08a6 226 static int pico_igmp_delete_parameter(struct igmp_parameters *p)
tass 68:0847e35d08a6 227 {
TASS Belgium NV 131:4758606c9316 228 if (pico_tree_delete(&IGMPParameters, p))
tass picotcp@tass.be 149:5f4cb161cec3 229 PICO_FREE(p);
TASS Belgium NV 131:4758606c9316 230 else
TASS Belgium NV 131:4758606c9316 231 return -1;
tass 68:0847e35d08a6 232
TASS Belgium NV 131:4758606c9316 233 return 0;
tass 68:0847e35d08a6 234 }
tass 68:0847e35d08a6 235
tass 128:ae39e6e81531 236 static void pico_igmp_timer_expired(pico_time now, void *arg)
tass 68:0847e35d08a6 237 {
TASS Belgium NV 131:4758606c9316 238 struct igmp_timer *t = NULL, *timer = NULL, test = {
TASS Belgium NV 131:4758606c9316 239 0
TASS Belgium NV 131:4758606c9316 240 };
TASS Belgium NV 131:4758606c9316 241
TASS Belgium NV 131:4758606c9316 242 IGNORE_PARAMETER(now);
TASS Belgium NV 131:4758606c9316 243 t = (struct igmp_timer *)arg;
TASS Belgium NV 131:4758606c9316 244 test.type = t->type;
TASS Belgium NV 131:4758606c9316 245 test.mcast_link = t->mcast_link;
TASS Belgium NV 131:4758606c9316 246 test.mcast_group = t->mcast_group;
TASS Belgium NV 131:4758606c9316 247 igmp_dbg("IGMP: timer expired for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay);
TASS Belgium NV 131:4758606c9316 248 timer = pico_tree_findKey(&IGMPTimers, &test);
TASS Belgium NV 131:4758606c9316 249 if (!timer) {
TASS Belgium NV 131:4758606c9316 250 return;
TASS Belgium NV 131:4758606c9316 251 }
tass 68:0847e35d08a6 252
TASS Belgium NV 131:4758606c9316 253 if (timer->stopped == IGMP_TIMER_STOPPED) {
tass picotcp@tass.be 149:5f4cb161cec3 254 PICO_FREE(t);
TASS Belgium NV 131:4758606c9316 255 return;
TASS Belgium NV 131:4758606c9316 256 }
TASS Belgium NV 131:4758606c9316 257
TASS Belgium NV 131:4758606c9316 258 if (timer->start + timer->delay < PICO_TIME_MS()) {
TASS Belgium NV 131:4758606c9316 259 pico_tree_delete(&IGMPTimers, timer);
TASS Belgium NV 131:4758606c9316 260 if (timer->callback)
TASS Belgium NV 131:4758606c9316 261 timer->callback(timer);
TASS Belgium NV 131:4758606c9316 262
tass picotcp@tass.be 149:5f4cb161cec3 263 PICO_FREE(timer);
TASS Belgium NV 131:4758606c9316 264 } else {
TASS Belgium NV 131:4758606c9316 265 igmp_dbg("IGMP: restart timer for %08X, delay %lu, new delay %lu\n", t->mcast_group.addr, t->delay, (timer->start + timer->delay) - PICO_TIME_MS());
TASS Belgium NV 131:4758606c9316 266 pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_igmp_timer_expired, timer);
TASS Belgium NV 131:4758606c9316 267 }
TASS Belgium NV 131:4758606c9316 268
tass 68:0847e35d08a6 269 return;
tass 68:0847e35d08a6 270 }
tass 68:0847e35d08a6 271
tass 68:0847e35d08a6 272 static int pico_igmp_timer_reset(struct igmp_timer *t)
tass 68:0847e35d08a6 273 {
TASS Belgium NV 131:4758606c9316 274 struct igmp_timer *timer = NULL, test = {
TASS Belgium NV 131:4758606c9316 275 0
TASS Belgium NV 131:4758606c9316 276 };
tass 68:0847e35d08a6 277
TASS Belgium NV 131:4758606c9316 278 igmp_dbg("IGMP: reset timer for %08X, delay %lu\n", t->mcast_group.addr, t->delay);
TASS Belgium NV 131:4758606c9316 279 test.type = t->type;
TASS Belgium NV 131:4758606c9316 280 test.mcast_link = t->mcast_link;
TASS Belgium NV 131:4758606c9316 281 test.mcast_group = t->mcast_group;
TASS Belgium NV 131:4758606c9316 282 timer = pico_tree_findKey(&IGMPTimers, &test);
TASS Belgium NV 131:4758606c9316 283 if (!timer)
TASS Belgium NV 131:4758606c9316 284 return -1;
tass 68:0847e35d08a6 285
TASS Belgium NV 131:4758606c9316 286 *timer = *t;
TASS Belgium NV 131:4758606c9316 287 timer->start = PICO_TIME_MS();
TASS Belgium NV 131:4758606c9316 288 return 0;
tass 68:0847e35d08a6 289 }
tass 68:0847e35d08a6 290
tass 68:0847e35d08a6 291 static int pico_igmp_timer_start(struct igmp_timer *t)
tass 68:0847e35d08a6 292 {
TASS Belgium NV 131:4758606c9316 293 struct igmp_timer *timer = NULL, test = {
TASS Belgium NV 131:4758606c9316 294 0
TASS Belgium NV 131:4758606c9316 295 };
tass 68:0847e35d08a6 296
TASS Belgium NV 131:4758606c9316 297 igmp_dbg("IGMP: start timer for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay);
TASS Belgium NV 131:4758606c9316 298 test.type = t->type;
TASS Belgium NV 131:4758606c9316 299 test.mcast_link = t->mcast_link;
TASS Belgium NV 131:4758606c9316 300 test.mcast_group = t->mcast_group;
TASS Belgium NV 131:4758606c9316 301 timer = pico_tree_findKey(&IGMPTimers, &test);
TASS Belgium NV 131:4758606c9316 302 if (timer)
TASS Belgium NV 131:4758606c9316 303 return pico_igmp_timer_reset(t);
tass 68:0847e35d08a6 304
tass picotcp@tass.be 149:5f4cb161cec3 305 timer = PICO_ZALLOC(sizeof(struct igmp_timer));
TASS Belgium NV 131:4758606c9316 306 if (!timer) {
TASS Belgium NV 131:4758606c9316 307 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 308 return -1;
TASS Belgium NV 131:4758606c9316 309 }
tass 68:0847e35d08a6 310
TASS Belgium NV 131:4758606c9316 311 *timer = *t;
TASS Belgium NV 131:4758606c9316 312 timer->start = PICO_TIME_MS();
TASS Belgium NV 131:4758606c9316 313
TASS Belgium NV 131:4758606c9316 314 pico_tree_insert(&IGMPTimers, timer);
TASS Belgium NV 131:4758606c9316 315 pico_timer_add(timer->delay, &pico_igmp_timer_expired, timer);
TASS Belgium NV 131:4758606c9316 316 return 0;
tass 68:0847e35d08a6 317 }
tass 68:0847e35d08a6 318
tass 68:0847e35d08a6 319 static int pico_igmp_timer_stop(struct igmp_timer *t)
tass 68:0847e35d08a6 320 {
TASS Belgium NV 131:4758606c9316 321 struct igmp_timer *timer = NULL, test = {
TASS Belgium NV 131:4758606c9316 322 0
TASS Belgium NV 131:4758606c9316 323 };
tass 68:0847e35d08a6 324
TASS Belgium NV 131:4758606c9316 325 test.type = t->type;
TASS Belgium NV 131:4758606c9316 326 test.mcast_link = t->mcast_link;
TASS Belgium NV 131:4758606c9316 327 test.mcast_group = t->mcast_group;
TASS Belgium NV 131:4758606c9316 328 timer = pico_tree_findKey(&IGMPTimers, &test);
TASS Belgium NV 131:4758606c9316 329 if (!timer)
TASS Belgium NV 131:4758606c9316 330 return 0;
TASS Belgium NV 131:4758606c9316 331
TASS Belgium NV 131:4758606c9316 332 igmp_dbg("IGMP: stop timer for %08X, delay %lu\n", timer->mcast_group.addr, timer->delay);
TASS Belgium NV 131:4758606c9316 333 timer->stopped = IGMP_TIMER_STOPPED;
tass 68:0847e35d08a6 334 return 0;
tass 68:0847e35d08a6 335 }
tass 68:0847e35d08a6 336
tass 68:0847e35d08a6 337 static int pico_igmp_timer_is_running(struct igmp_timer *t)
tass 68:0847e35d08a6 338 {
TASS Belgium NV 131:4758606c9316 339 struct igmp_timer *timer = NULL, test = {
TASS Belgium NV 131:4758606c9316 340 0
TASS Belgium NV 131:4758606c9316 341 };
tass 68:0847e35d08a6 342
TASS Belgium NV 131:4758606c9316 343 test.type = t->type;
TASS Belgium NV 131:4758606c9316 344 test.mcast_link = t->mcast_link;
TASS Belgium NV 131:4758606c9316 345 test.mcast_group = t->mcast_group;
TASS Belgium NV 131:4758606c9316 346 timer = pico_tree_findKey(&IGMPTimers, &test);
TASS Belgium NV 131:4758606c9316 347 if (timer)
TASS Belgium NV 131:4758606c9316 348 return 1;
TASS Belgium NV 131:4758606c9316 349
TASS Belgium NV 131:4758606c9316 350 return 0;
tass 68:0847e35d08a6 351 }
tass 68:0847e35d08a6 352
tass 68:0847e35d08a6 353 static struct igmp_timer *pico_igmp_find_timer(uint8_t type, struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group)
tass 68:0847e35d08a6 354 {
TASS Belgium NV 131:4758606c9316 355 struct igmp_timer test = {
TASS Belgium NV 131:4758606c9316 356 0
TASS Belgium NV 131:4758606c9316 357 };
tass 68:0847e35d08a6 358
TASS Belgium NV 131:4758606c9316 359 test.type = type;
TASS Belgium NV 131:4758606c9316 360 test.mcast_link = *mcast_link;
TASS Belgium NV 131:4758606c9316 361 test.mcast_group = *mcast_group;
TASS Belgium NV 131:4758606c9316 362 return pico_tree_findKey(&IGMPTimers, &test);
tass 68:0847e35d08a6 363 }
tass 68:0847e35d08a6 364
tass 68:0847e35d08a6 365 static void pico_igmp_report_expired(struct igmp_timer *t)
tass 68:0847e35d08a6 366 {
TASS Belgium NV 131:4758606c9316 367 struct igmp_parameters *p = NULL;
tass 68:0847e35d08a6 368
TASS Belgium NV 131:4758606c9316 369 p = pico_igmp_find_parameter(&t->mcast_link, &t->mcast_group);
TASS Belgium NV 131:4758606c9316 370 if (!p)
TASS Belgium NV 131:4758606c9316 371 return;
tass 68:0847e35d08a6 372
TASS Belgium NV 131:4758606c9316 373 p->event = IGMP_EVENT_TIMER_EXPIRED;
TASS Belgium NV 131:4758606c9316 374 pico_igmp_process_event(p);
tass 68:0847e35d08a6 375 }
tass 68:0847e35d08a6 376
tass 68:0847e35d08a6 377 static void pico_igmp_v2querier_expired(struct igmp_timer *t)
tass 68:0847e35d08a6 378 {
TASS Belgium NV 131:4758606c9316 379 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 380 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass 68:0847e35d08a6 381
TASS Belgium NV 131:4758606c9316 382 link = pico_ipv4_link_by_dev(t->f->dev);
TASS Belgium NV 131:4758606c9316 383 if (!link)
TASS Belgium NV 131:4758606c9316 384 return;
tass 68:0847e35d08a6 385
TASS Belgium NV 131:4758606c9316 386 /* When changing compatibility mode, cancel all pending response
TASS Belgium NV 131:4758606c9316 387 * and retransmission timers.
TASS Belgium NV 131:4758606c9316 388 */
TASS Belgium NV 131:4758606c9316 389 pico_tree_foreach_safe(index, &IGMPTimers, _tmp)
TASS Belgium NV 131:4758606c9316 390 {
TASS Belgium NV 131:4758606c9316 391 ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED;
TASS Belgium NV 131:4758606c9316 392 pico_tree_delete(&IGMPTimers, index->keyValue);
TASS Belgium NV 131:4758606c9316 393 }
TASS Belgium NV 131:4758606c9316 394 igmp_dbg("IGMP: switch to compatibility mode IGMPv3\n");
TASS Belgium NV 131:4758606c9316 395 link->mcast_compatibility = PICO_IGMPV3;
TASS Belgium NV 131:4758606c9316 396 return;
tass 68:0847e35d08a6 397 }
tass 68:0847e35d08a6 398
tass 68:0847e35d08a6 399 static int pico_igmp_is_checksum_valid(struct pico_frame *f)
tass 68:0847e35d08a6 400 {
TASS Belgium NV 131:4758606c9316 401 struct pico_ipv4_hdr *hdr = NULL;
TASS Belgium NV 131:4758606c9316 402 uint8_t ihl = 24, datalen = 0;
tass 68:0847e35d08a6 403
TASS Belgium NV 131:4758606c9316 404 hdr = (struct pico_ipv4_hdr *)f->net_hdr;
TASS Belgium NV 131:4758606c9316 405 ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */
TASS Belgium NV 131:4758606c9316 406 datalen = (uint8_t)(short_be(hdr->len) - ihl);
tass 68:0847e35d08a6 407
TASS Belgium NV 131:4758606c9316 408 if (short_be(pico_checksum(f->transport_hdr, datalen)) == 0)
TASS Belgium NV 131:4758606c9316 409 return 1;
TASS Belgium NV 131:4758606c9316 410
TASS Belgium NV 131:4758606c9316 411 igmp_dbg("IGMP: invalid checksum\n");
TASS Belgium NV 131:4758606c9316 412 return 0;
tass 68:0847e35d08a6 413 }
tass 68:0847e35d08a6 414
tass 68:0847e35d08a6 415 /* RFC 3376 $7.1 */
tass 68:0847e35d08a6 416 static int pico_igmp_compatibility_mode(struct pico_frame *f)
tass 68:0847e35d08a6 417 {
TASS Belgium NV 131:4758606c9316 418 struct pico_ipv4_hdr *hdr = NULL;
TASS Belgium NV 131:4758606c9316 419 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 420 struct pico_tree_node *index = NULL, *_tmp = NULL;
TASS Belgium NV 131:4758606c9316 421 struct igmp_timer t = {
TASS Belgium NV 131:4758606c9316 422 0
TASS Belgium NV 131:4758606c9316 423 };
TASS Belgium NV 131:4758606c9316 424 uint8_t ihl = 24, datalen = 0;
tass 68:0847e35d08a6 425
TASS Belgium NV 131:4758606c9316 426 link = pico_ipv4_link_by_dev(f->dev);
TASS Belgium NV 131:4758606c9316 427 if (!link)
TASS Belgium NV 131:4758606c9316 428 return -1;
TASS Belgium NV 131:4758606c9316 429
TASS Belgium NV 131:4758606c9316 430 hdr = (struct pico_ipv4_hdr *) f->net_hdr;
TASS Belgium NV 131:4758606c9316 431 ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */
TASS Belgium NV 131:4758606c9316 432 datalen = (uint8_t)(short_be(hdr->len) - ihl);
TASS Belgium NV 131:4758606c9316 433 igmp_dbg("IGMP: IHL = %u, LEN = %u, OCTETS = %u\n", ihl, short_be(hdr->len), datalen);
tass 68:0847e35d08a6 434
TASS Belgium NV 131:4758606c9316 435 if (datalen > 12) {
TASS Belgium NV 131:4758606c9316 436 /* IGMPv3 query */
TASS Belgium NV 131:4758606c9316 437 t.type = IGMP_TIMER_V2_QUERIER;
TASS Belgium NV 131:4758606c9316 438 if (pico_igmp_timer_is_running(&t)) { /* IGMPv2 querier present timer still running */
TASS Belgium NV 131:4758606c9316 439 return -1;
TASS Belgium NV 131:4758606c9316 440 } else {
TASS Belgium NV 131:4758606c9316 441 link->mcast_compatibility = PICO_IGMPV3;
TASS Belgium NV 131:4758606c9316 442 return 0;
TASS Belgium NV 131:4758606c9316 443 }
TASS Belgium NV 131:4758606c9316 444 } else if (datalen == 8) {
TASS Belgium NV 131:4758606c9316 445 struct igmp_message *query = (struct igmp_message *)f->transport_hdr;
TASS Belgium NV 131:4758606c9316 446 if (query->max_resp_time != 0) {
TASS Belgium NV 131:4758606c9316 447 /* IGMPv2 query */
TASS Belgium NV 131:4758606c9316 448 /* When changing compatibility mode, cancel all pending response
TASS Belgium NV 131:4758606c9316 449 * and retransmission timers.
TASS Belgium NV 131:4758606c9316 450 */
TASS Belgium NV 131:4758606c9316 451 pico_tree_foreach_safe(index, &IGMPTimers, _tmp)
TASS Belgium NV 131:4758606c9316 452 {
TASS Belgium NV 131:4758606c9316 453 ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED;
TASS Belgium NV 131:4758606c9316 454 pico_tree_delete(&IGMPTimers, index->keyValue);
TASS Belgium NV 131:4758606c9316 455 }
TASS Belgium NV 131:4758606c9316 456 igmp_dbg("IGMP: switch to compatibility mode IGMPv2\n");
TASS Belgium NV 131:4758606c9316 457 link->mcast_compatibility = PICO_IGMPV2;
TASS Belgium NV 131:4758606c9316 458 t.type = IGMP_TIMER_V2_QUERIER;
TASS Belgium NV 131:4758606c9316 459 t.delay = ((IGMP_ROBUSTNESS * link->mcast_last_query_interval) + IGMP_QUERY_RESPONSE_INTERVAL) * 1000;
TASS Belgium NV 131:4758606c9316 460 t.f = f;
TASS Belgium NV 131:4758606c9316 461 t.callback = pico_igmp_v2querier_expired;
TASS Belgium NV 131:4758606c9316 462 /* only one of this type of timer may exist! */
TASS Belgium NV 131:4758606c9316 463 pico_igmp_timer_start(&t);
TASS Belgium NV 131:4758606c9316 464 } else {
TASS Belgium NV 131:4758606c9316 465 /* IGMPv1 query, not supported */
TASS Belgium NV 131:4758606c9316 466 return -1;
TASS Belgium NV 131:4758606c9316 467 }
tass 68:0847e35d08a6 468 } else {
TASS Belgium NV 131:4758606c9316 469 /* invalid query, silently ignored */
TASS Belgium NV 131:4758606c9316 470 return -1;
tass 68:0847e35d08a6 471 }
TASS Belgium NV 131:4758606c9316 472
TASS Belgium NV 131:4758606c9316 473 return 0;
tass 68:0847e35d08a6 474 }
tass 68:0847e35d08a6 475
tass 68:0847e35d08a6 476 static struct igmp_parameters *pico_igmp_analyse_packet(struct pico_frame *f)
tass 68:0847e35d08a6 477 {
TASS Belgium NV 131:4758606c9316 478 struct igmp_message *message = NULL;
TASS Belgium NV 131:4758606c9316 479 struct igmp_parameters *p = NULL;
TASS Belgium NV 131:4758606c9316 480 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 481 struct pico_ip4 mcast_group = {
TASS Belgium NV 131:4758606c9316 482 0
TASS Belgium NV 131:4758606c9316 483 };
tass 68:0847e35d08a6 484
TASS Belgium NV 131:4758606c9316 485 link = pico_ipv4_link_by_dev(f->dev);
TASS Belgium NV 131:4758606c9316 486 if (!link)
TASS Belgium NV 131:4758606c9316 487 return NULL;
TASS Belgium NV 131:4758606c9316 488
TASS Belgium NV 131:4758606c9316 489 /* IGMPv2 and IGMPv3 have a similar structure for the first 8 bytes */
TASS Belgium NV 131:4758606c9316 490 message = (struct igmp_message *)f->transport_hdr;
TASS Belgium NV 131:4758606c9316 491 mcast_group.addr = message->mcast_group;
TASS Belgium NV 131:4758606c9316 492 p = pico_igmp_find_parameter(&link->address, &mcast_group);
TASS Belgium NV 131:4758606c9316 493 if (!p && mcast_group.addr == 0) { /* general query */
tass picotcp@tass.be 149:5f4cb161cec3 494 p = PICO_ZALLOC(sizeof(struct igmp_parameters));
TASS Belgium NV 131:4758606c9316 495 if (!p)
TASS Belgium NV 131:4758606c9316 496 return NULL;
tass 68:0847e35d08a6 497
TASS Belgium NV 131:4758606c9316 498 p->state = IGMP_STATE_NON_MEMBER;
TASS Belgium NV 131:4758606c9316 499 p->mcast_link.addr = link->address.addr;
TASS Belgium NV 131:4758606c9316 500 p->mcast_group.addr = mcast_group.addr;
TASS Belgium NV 131:4758606c9316 501 pico_tree_insert(&IGMPParameters, p);
TASS Belgium NV 131:4758606c9316 502 } else if (!p) {
TASS Belgium NV 131:4758606c9316 503 return NULL;
TASS Belgium NV 131:4758606c9316 504 }
tass 68:0847e35d08a6 505
TASS Belgium NV 131:4758606c9316 506 switch (message->type) {
tass 68:0847e35d08a6 507 case IGMP_TYPE_MEM_QUERY:
TASS Belgium NV 131:4758606c9316 508 p->event = IGMP_EVENT_QUERY_RECV;
TASS Belgium NV 131:4758606c9316 509 break;
tass 68:0847e35d08a6 510 case IGMP_TYPE_MEM_REPORT_V1:
TASS Belgium NV 131:4758606c9316 511 p->event = IGMP_EVENT_REPORT_RECV;
TASS Belgium NV 131:4758606c9316 512 break;
tass 68:0847e35d08a6 513 case IGMP_TYPE_MEM_REPORT_V2:
TASS Belgium NV 131:4758606c9316 514 p->event = IGMP_EVENT_REPORT_RECV;
TASS Belgium NV 131:4758606c9316 515 break;
tass 68:0847e35d08a6 516 case IGMP_TYPE_MEM_REPORT_V3:
TASS Belgium NV 131:4758606c9316 517 p->event = IGMP_EVENT_REPORT_RECV;
TASS Belgium NV 131:4758606c9316 518 break;
tass 68:0847e35d08a6 519 default:
TASS Belgium NV 131:4758606c9316 520 return NULL;
TASS Belgium NV 131:4758606c9316 521 }
TASS Belgium NV 131:4758606c9316 522 p->max_resp_time = message->max_resp_time; /* if IGMPv3 report this will be 0 (res0 field) */
TASS Belgium NV 131:4758606c9316 523 p->f = f;
tass 68:0847e35d08a6 524
TASS Belgium NV 131:4758606c9316 525 return p;
tass 68:0847e35d08a6 526 }
tass 68:0847e35d08a6 527
tass 68:0847e35d08a6 528 static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f)
tass 68:0847e35d08a6 529 {
TASS Belgium NV 131:4758606c9316 530 struct igmp_parameters *p = NULL;
TASS Belgium NV 131:4758606c9316 531 IGNORE_PARAMETER(self);
TASS Belgium NV 131:4758606c9316 532
TASS Belgium NV 131:4758606c9316 533 if (!pico_igmp_is_checksum_valid(f))
TASS Belgium NV 131:4758606c9316 534 goto out;
tass 68:0847e35d08a6 535
TASS Belgium NV 131:4758606c9316 536 if (pico_igmp_compatibility_mode(f) < 0)
TASS Belgium NV 131:4758606c9316 537 goto out;
tass 68:0847e35d08a6 538
TASS Belgium NV 131:4758606c9316 539 p = pico_igmp_analyse_packet(f);
TASS Belgium NV 131:4758606c9316 540 if (!p)
TASS Belgium NV 131:4758606c9316 541 goto out;
tass 68:0847e35d08a6 542
TASS Belgium NV 131:4758606c9316 543 return pico_igmp_process_event(p);
TASS Belgium NV 131:4758606c9316 544
TASS Belgium NV 131:4758606c9316 545 out:
tass 68:0847e35d08a6 546 pico_frame_discard(f);
tass 68:0847e35d08a6 547 return 0;
tass 68:0847e35d08a6 548 }
tass 68:0847e35d08a6 549
TASS Belgium NV 131:4758606c9316 550 static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f)
TASS Belgium NV 131:4758606c9316 551 {
TASS Belgium NV 131:4758606c9316 552 /* packets are directly transferred to the IP layer by calling pico_ipv4_frame_push */
TASS Belgium NV 131:4758606c9316 553 IGNORE_PARAMETER(self);
TASS Belgium NV 131:4758606c9316 554 IGNORE_PARAMETER(f);
TASS Belgium NV 131:4758606c9316 555 return 0;
tass 68:0847e35d08a6 556 }
tass 68:0847e35d08a6 557
tass 68:0847e35d08a6 558 /* Interface: protocol definition */
tass 68:0847e35d08a6 559 struct pico_protocol pico_proto_igmp = {
TASS Belgium NV 131:4758606c9316 560 .name = "igmp",
TASS Belgium NV 131:4758606c9316 561 .proto_number = PICO_PROTO_IGMP,
TASS Belgium NV 131:4758606c9316 562 .layer = PICO_LAYER_TRANSPORT,
TASS Belgium NV 131:4758606c9316 563 .process_in = pico_igmp_process_in,
TASS Belgium NV 131:4758606c9316 564 .process_out = pico_igmp_process_out,
TASS Belgium NV 131:4758606c9316 565 .q_in = &igmp_in,
TASS Belgium NV 131:4758606c9316 566 .q_out = &igmp_out,
tass 68:0847e35d08a6 567 };
tass 68:0847e35d08a6 568
TASS Belgium NV 131:4758606c9316 569 int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *MCASTFilter, uint8_t state)
tass 68:0847e35d08a6 570 {
TASS Belgium NV 131:4758606c9316 571 struct igmp_parameters *p = NULL;
TASS Belgium NV 131:4758606c9316 572
TASS Belgium NV 131:4758606c9316 573 if (mcast_group->addr == IGMP_ALL_HOST_GROUP)
TASS Belgium NV 131:4758606c9316 574 return 0;
tass 68:0847e35d08a6 575
TASS Belgium NV 131:4758606c9316 576 p = pico_igmp_find_parameter(mcast_link, mcast_group);
TASS Belgium NV 131:4758606c9316 577 if (!p && state == PICO_IGMP_STATE_CREATE) {
tass picotcp@tass.be 149:5f4cb161cec3 578 p = PICO_ZALLOC(sizeof(struct igmp_parameters));
TASS Belgium NV 131:4758606c9316 579 if (!p) {
TASS Belgium NV 131:4758606c9316 580 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 581 return -1;
TASS Belgium NV 131:4758606c9316 582 }
TASS Belgium NV 131:4758606c9316 583
tass picotcp@tass.be 149:5f4cb161cec3 584 if (!mcast_link || !mcast_group) {
tass picotcp@tass.be 149:5f4cb161cec3 585 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 586 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 587 }
tass picotcp@tass.be 149:5f4cb161cec3 588
TASS Belgium NV 131:4758606c9316 589 p->state = IGMP_STATE_NON_MEMBER;
TASS Belgium NV 131:4758606c9316 590 p->mcast_link = *mcast_link;
TASS Belgium NV 131:4758606c9316 591 p->mcast_group = *mcast_group;
TASS Belgium NV 131:4758606c9316 592 pico_tree_insert(&IGMPParameters, p);
TASS Belgium NV 131:4758606c9316 593 } else if (!p) {
TASS Belgium NV 131:4758606c9316 594 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 595 return -1;
tass 68:0847e35d08a6 596 }
tass 68:0847e35d08a6 597
TASS Belgium NV 131:4758606c9316 598 switch (state) {
tass 68:0847e35d08a6 599 case PICO_IGMP_STATE_CREATE:
TASS Belgium NV 131:4758606c9316 600 p->event = IGMP_EVENT_CREATE_GROUP;
TASS Belgium NV 131:4758606c9316 601 break;
tass 68:0847e35d08a6 602
tass 68:0847e35d08a6 603 case PICO_IGMP_STATE_UPDATE:
TASS Belgium NV 131:4758606c9316 604 p->event = IGMP_EVENT_UPDATE_GROUP;
TASS Belgium NV 131:4758606c9316 605 break;
TASS Belgium NV 131:4758606c9316 606
tass 68:0847e35d08a6 607 case PICO_IGMP_STATE_DELETE:
TASS Belgium NV 131:4758606c9316 608 p->event = IGMP_EVENT_DELETE_GROUP;
TASS Belgium NV 131:4758606c9316 609 break;
tass 68:0847e35d08a6 610
tass 68:0847e35d08a6 611 default:
TASS Belgium NV 131:4758606c9316 612 return -1;
TASS Belgium NV 131:4758606c9316 613 }
TASS Belgium NV 131:4758606c9316 614 p->filter_mode = filter_mode;
TASS Belgium NV 131:4758606c9316 615 p->MCASTFilter = MCASTFilter;
tass 68:0847e35d08a6 616
TASS Belgium NV 131:4758606c9316 617 return pico_igmp_process_event(p);
tass 68:0847e35d08a6 618 }
tass 68:0847e35d08a6 619
tass 68:0847e35d08a6 620 static int pico_igmp_send_report(struct igmp_parameters *p, struct pico_frame *f)
tass 68:0847e35d08a6 621 {
TASS Belgium NV 131:4758606c9316 622 struct pico_ip4 dst = {
TASS Belgium NV 131:4758606c9316 623 0
TASS Belgium NV 131:4758606c9316 624 };
TASS Belgium NV 131:4758606c9316 625 struct pico_ip4 mcast_group = {
TASS Belgium NV 131:4758606c9316 626 0
TASS Belgium NV 131:4758606c9316 627 };
TASS Belgium NV 131:4758606c9316 628 struct pico_ipv4_link *link = NULL;
tass 68:0847e35d08a6 629
TASS Belgium NV 131:4758606c9316 630 link = pico_ipv4_link_get(&p->mcast_link);
TASS Belgium NV 131:4758606c9316 631 if (!link)
TASS Belgium NV 131:4758606c9316 632 return -1;
TASS Belgium NV 131:4758606c9316 633
TASS Belgium NV 131:4758606c9316 634 mcast_group.addr = p->mcast_group.addr;
TASS Belgium NV 131:4758606c9316 635 switch (link->mcast_compatibility) {
tass 68:0847e35d08a6 636 case PICO_IGMPV2:
TASS Belgium NV 131:4758606c9316 637 if (p->event == IGMP_EVENT_DELETE_GROUP)
TASS Belgium NV 131:4758606c9316 638 dst.addr = IGMP_ALL_ROUTER_GROUP;
TASS Belgium NV 131:4758606c9316 639 else
TASS Belgium NV 131:4758606c9316 640 dst.addr = mcast_group.addr;
TASS Belgium NV 131:4758606c9316 641
TASS Belgium NV 131:4758606c9316 642 break;
tass 68:0847e35d08a6 643
tass 68:0847e35d08a6 644 case PICO_IGMPV3:
TASS Belgium NV 131:4758606c9316 645 dst.addr = IGMPV3_ALL_ROUTER_GROUP;
TASS Belgium NV 131:4758606c9316 646 break;
tass 68:0847e35d08a6 647
tass 68:0847e35d08a6 648 default:
TASS Belgium NV 131:4758606c9316 649 pico_err = PICO_ERR_EPROTONOSUPPORT;
TASS Belgium NV 131:4758606c9316 650 return -1;
TASS Belgium NV 131:4758606c9316 651 }
tass 68:0847e35d08a6 652
TASS Belgium NV 131:4758606c9316 653 igmp_dbg("IGMP: send membership report on group %08X to %08X\n", mcast_group.addr, dst.addr);
TASS Belgium NV 131:4758606c9316 654 pico_ipv4_frame_push(f, &dst, PICO_PROTO_IGMP);
TASS Belgium NV 131:4758606c9316 655 return 0;
tass 68:0847e35d08a6 656 }
tass 68:0847e35d08a6 657
tass 70:cd218dd180e5 658 static int8_t pico_igmp_generate_report(struct igmp_parameters *p)
tass 68:0847e35d08a6 659 {
TASS Belgium NV 131:4758606c9316 660 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 661 int i = 0;
tass 68:0847e35d08a6 662
TASS Belgium NV 131:4758606c9316 663 link = pico_ipv4_link_get(&p->mcast_link);
TASS Belgium NV 131:4758606c9316 664 if (!link) {
TASS Belgium NV 131:4758606c9316 665 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 666 return -1;
TASS Belgium NV 131:4758606c9316 667 }
tass 68:0847e35d08a6 668
TASS Belgium NV 131:4758606c9316 669 switch (link->mcast_compatibility) {
tass 68:0847e35d08a6 670 case PICO_IGMPV1:
TASS Belgium NV 131:4758606c9316 671 pico_err = PICO_ERR_EPROTONOSUPPORT;
TASS Belgium NV 131:4758606c9316 672 return -1;
TASS Belgium NV 131:4758606c9316 673
tass 68:0847e35d08a6 674 case PICO_IGMPV2:
tass 68:0847e35d08a6 675 {
TASS Belgium NV 131:4758606c9316 676 struct igmp_message *report = NULL;
TASS Belgium NV 131:4758606c9316 677 uint8_t report_type = IGMP_TYPE_MEM_REPORT_V2;
TASS Belgium NV 131:4758606c9316 678 if (p->event == IGMP_EVENT_DELETE_GROUP)
TASS Belgium NV 131:4758606c9316 679 report_type = IGMP_TYPE_LEAVE_GROUP;
tass 68:0847e35d08a6 680
TASS Belgium NV 131:4758606c9316 681 p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + sizeof(struct igmp_message));
TASS Belgium NV 131:4758606c9316 682 p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN);
TASS Belgium NV 131:4758606c9316 683 p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN;
TASS Belgium NV 131:4758606c9316 684 p->f->transport_len = (uint16_t)(p->f->transport_len - IP_OPTION_ROUTER_ALERT_LEN);
TASS Belgium NV 131:4758606c9316 685 p->f->dev = pico_ipv4_link_find(&p->mcast_link);
TASS Belgium NV 131:4758606c9316 686 /* p->f->len is correctly set by alloc */
tass 68:0847e35d08a6 687
TASS Belgium NV 131:4758606c9316 688 report = (struct igmp_message *)p->f->transport_hdr;
TASS Belgium NV 131:4758606c9316 689 report->type = report_type;
TASS Belgium NV 131:4758606c9316 690 report->max_resp_time = IGMP_DEFAULT_MAX_RESPONSE_TIME;
TASS Belgium NV 131:4758606c9316 691 report->mcast_group = p->mcast_group.addr;
tass 68:0847e35d08a6 692
TASS Belgium NV 131:4758606c9316 693 report->crc = 0;
TASS Belgium NV 131:4758606c9316 694 report->crc = short_be(pico_checksum(report, sizeof(struct igmp_message)));
TASS Belgium NV 131:4758606c9316 695 break;
tass 68:0847e35d08a6 696 }
tass 68:0847e35d08a6 697 case PICO_IGMPV3:
tass 68:0847e35d08a6 698 {
TASS Belgium NV 131:4758606c9316 699 struct igmpv3_report *report = NULL;
TASS Belgium NV 131:4758606c9316 700 struct igmpv3_group_record *record = NULL;
TASS Belgium NV 131:4758606c9316 701 struct pico_mcast_group *g = NULL, test = {
TASS Belgium NV 131:4758606c9316 702 0
TASS Belgium NV 131:4758606c9316 703 };
TASS Belgium NV 131:4758606c9316 704 struct pico_tree_node *index = NULL, *_tmp = NULL;
TASS Belgium NV 131:4758606c9316 705 struct pico_tree *IGMPFilter = NULL;
TASS Belgium NV 131:4758606c9316 706 struct pico_ip4 *source = NULL;
TASS Belgium NV 131:4758606c9316 707 uint8_t record_type = 0;
TASS Belgium NV 131:4758606c9316 708 uint8_t sources = 0;
TASS Belgium NV 131:4758606c9316 709 uint16_t len = 0;
tass 68:0847e35d08a6 710
TASS Belgium NV 131:4758606c9316 711 test.mcast_addr = p->mcast_group;
TASS Belgium NV 131:4758606c9316 712 g = pico_tree_findKey(link->MCASTGroups, &test);
TASS Belgium NV 131:4758606c9316 713 if (!g) {
TASS Belgium NV 131:4758606c9316 714 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 715 return -1;
TASS Belgium NV 131:4758606c9316 716 }
TASS Belgium NV 131:4758606c9316 717
TASS Belgium NV 131:4758606c9316 718 if (p->event == IGMP_EVENT_DELETE_GROUP) { /* "non-existent" state of filter mode INCLUDE and empty source list */
TASS Belgium NV 131:4758606c9316 719 p->filter_mode = PICO_IP_MULTICAST_INCLUDE;
TASS Belgium NV 131:4758606c9316 720 p->MCASTFilter = NULL;
TASS Belgium NV 131:4758606c9316 721 }
tass 68:0847e35d08a6 722
TASS Belgium NV 131:4758606c9316 723 /* cleanup filters */
TASS Belgium NV 131:4758606c9316 724 pico_tree_foreach_safe(index, &IGMPAllow, _tmp)
TASS Belgium NV 131:4758606c9316 725 {
TASS Belgium NV 131:4758606c9316 726 pico_tree_delete(&IGMPAllow, index->keyValue);
TASS Belgium NV 131:4758606c9316 727 }
TASS Belgium NV 131:4758606c9316 728 pico_tree_foreach_safe(index, &IGMPBlock, _tmp)
TASS Belgium NV 131:4758606c9316 729 {
TASS Belgium NV 131:4758606c9316 730 pico_tree_delete(&IGMPBlock, index->keyValue);
TASS Belgium NV 131:4758606c9316 731 }
tass 68:0847e35d08a6 732
TASS Belgium NV 131:4758606c9316 733 switch (g->filter_mode) {
tass 68:0847e35d08a6 734
tass 68:0847e35d08a6 735 case PICO_IP_MULTICAST_INCLUDE:
TASS Belgium NV 131:4758606c9316 736 switch (p->filter_mode) {
tass 68:0847e35d08a6 737 case PICO_IP_MULTICAST_INCLUDE:
TASS Belgium NV 131:4758606c9316 738 if (p->event == IGMP_EVENT_DELETE_GROUP) { /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */
TASS Belgium NV 131:4758606c9316 739 /* TO_IN (B) */
TASS Belgium NV 131:4758606c9316 740 record_type = IGMP_CHANGE_TO_INCLUDE_MODE;
TASS Belgium NV 131:4758606c9316 741 IGMPFilter = &IGMPAllow;
TASS Belgium NV 131:4758606c9316 742 if (p->MCASTFilter) {
TASS Belgium NV 131:4758606c9316 743 pico_tree_foreach(index, p->MCASTFilter) /* B */
TASS Belgium NV 131:4758606c9316 744 {
TASS Belgium NV 131:4758606c9316 745 pico_tree_insert(&IGMPAllow, index->keyValue);
TASS Belgium NV 131:4758606c9316 746 sources++;
TASS Belgium NV 131:4758606c9316 747 }
TASS Belgium NV 131:4758606c9316 748 } /* else { IGMPAllow stays empty } */
TASS Belgium NV 131:4758606c9316 749
TASS Belgium NV 131:4758606c9316 750 break;
TASS Belgium NV 131:4758606c9316 751 }
TASS Belgium NV 131:4758606c9316 752
TASS Belgium NV 131:4758606c9316 753 /* ALLOW (B-A) */
TASS Belgium NV 131:4758606c9316 754 /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */
TASS Belgium NV 131:4758606c9316 755 if (p->event == IGMP_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */
TASS Belgium NV 131:4758606c9316 756 record_type = IGMP_CHANGE_TO_INCLUDE_MODE;
TASS Belgium NV 131:4758606c9316 757 else
TASS Belgium NV 131:4758606c9316 758 record_type = IGMP_ALLOW_NEW_SOURCES;
TASS Belgium NV 131:4758606c9316 759
TASS Belgium NV 131:4758606c9316 760 IGMPFilter = &IGMPAllow;
TASS Belgium NV 131:4758606c9316 761 pico_tree_foreach(index, p->MCASTFilter) /* B */
TASS Belgium NV 131:4758606c9316 762 {
TASS Belgium NV 131:4758606c9316 763 pico_tree_insert(&IGMPAllow, index->keyValue);
TASS Belgium NV 131:4758606c9316 764 sources++;
TASS Belgium NV 131:4758606c9316 765 }
TASS Belgium NV 131:4758606c9316 766 pico_tree_foreach(index, &g->MCASTSources) /* A */
TASS Belgium NV 131:4758606c9316 767 {
TASS Belgium NV 131:4758606c9316 768 source = pico_tree_findKey(&IGMPAllow, index->keyValue);
TASS Belgium NV 131:4758606c9316 769 if (source) {
TASS Belgium NV 131:4758606c9316 770 pico_tree_delete(&IGMPAllow, source);
TASS Belgium NV 131:4758606c9316 771 sources--;
TASS Belgium NV 131:4758606c9316 772 }
TASS Belgium NV 131:4758606c9316 773 }
TASS Belgium NV 131:4758606c9316 774 if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */
TASS Belgium NV 131:4758606c9316 775 break;
TASS Belgium NV 131:4758606c9316 776
TASS Belgium NV 131:4758606c9316 777 /* BLOCK (A-B) */
TASS Belgium NV 131:4758606c9316 778 record_type = IGMP_BLOCK_OLD_SOURCES;
TASS Belgium NV 131:4758606c9316 779 IGMPFilter = &IGMPBlock;
TASS Belgium NV 131:4758606c9316 780 pico_tree_foreach(index, &g->MCASTSources) /* A */
TASS Belgium NV 131:4758606c9316 781 {
TASS Belgium NV 131:4758606c9316 782 pico_tree_insert(&IGMPBlock, index->keyValue);
TASS Belgium NV 131:4758606c9316 783 sources++;
TASS Belgium NV 131:4758606c9316 784 }
TASS Belgium NV 131:4758606c9316 785 pico_tree_foreach(index, p->MCASTFilter) /* B */
TASS Belgium NV 131:4758606c9316 786 {
TASS Belgium NV 131:4758606c9316 787 source = pico_tree_findKey(&IGMPBlock, index->keyValue);
TASS Belgium NV 131:4758606c9316 788 if (source) {
TASS Belgium NV 131:4758606c9316 789 pico_tree_delete(&IGMPBlock, source);
TASS Belgium NV 131:4758606c9316 790 sources--;
TASS Belgium NV 131:4758606c9316 791 }
TASS Belgium NV 131:4758606c9316 792 }
TASS Belgium NV 131:4758606c9316 793 if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */
TASS Belgium NV 131:4758606c9316 794 break;
TASS Belgium NV 131:4758606c9316 795
TASS Belgium NV 131:4758606c9316 796 /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report (RFC 3376 $5.1) */
TASS Belgium NV 131:4758606c9316 797 p->f = NULL;
TASS Belgium NV 131:4758606c9316 798 return 0;
TASS Belgium NV 131:4758606c9316 799
TASS Belgium NV 131:4758606c9316 800 case PICO_IP_MULTICAST_EXCLUDE:
TASS Belgium NV 131:4758606c9316 801 /* TO_EX (B) */
TASS Belgium NV 131:4758606c9316 802 record_type = IGMP_CHANGE_TO_EXCLUDE_MODE;
TASS Belgium NV 131:4758606c9316 803 IGMPFilter = &IGMPBlock;
TASS Belgium NV 131:4758606c9316 804 pico_tree_foreach(index, p->MCASTFilter) /* B */
TASS Belgium NV 131:4758606c9316 805 {
TASS Belgium NV 131:4758606c9316 806 pico_tree_insert(&IGMPBlock, index->keyValue);
TASS Belgium NV 131:4758606c9316 807 sources++;
TASS Belgium NV 131:4758606c9316 808 }
TASS Belgium NV 131:4758606c9316 809 break;
TASS Belgium NV 131:4758606c9316 810
TASS Belgium NV 131:4758606c9316 811 default:
TASS Belgium NV 131:4758606c9316 812 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 813 return -1;
TASS Belgium NV 131:4758606c9316 814 }
TASS Belgium NV 131:4758606c9316 815 break;
TASS Belgium NV 131:4758606c9316 816
TASS Belgium NV 131:4758606c9316 817 case PICO_IP_MULTICAST_EXCLUDE:
TASS Belgium NV 131:4758606c9316 818 switch (p->filter_mode) {
TASS Belgium NV 131:4758606c9316 819 case PICO_IP_MULTICAST_INCLUDE:
tass 68:0847e35d08a6 820 /* TO_IN (B) */
tass 68:0847e35d08a6 821 record_type = IGMP_CHANGE_TO_INCLUDE_MODE;
tass 68:0847e35d08a6 822 IGMPFilter = &IGMPAllow;
tass 68:0847e35d08a6 823 if (p->MCASTFilter) {
TASS Belgium NV 131:4758606c9316 824 pico_tree_foreach(index, p->MCASTFilter) /* B */
TASS Belgium NV 131:4758606c9316 825 {
TASS Belgium NV 131:4758606c9316 826 pico_tree_insert(&IGMPAllow, index->keyValue);
TASS Belgium NV 131:4758606c9316 827 sources++;
TASS Belgium NV 131:4758606c9316 828 }
tass 68:0847e35d08a6 829 } /* else { IGMPAllow stays empty } */
tass 68:0847e35d08a6 830
tass 68:0847e35d08a6 831 break;
tass 68:0847e35d08a6 832
TASS Belgium NV 131:4758606c9316 833 case PICO_IP_MULTICAST_EXCLUDE:
TASS Belgium NV 131:4758606c9316 834 /* BLOCK (B-A) */
TASS Belgium NV 131:4758606c9316 835 record_type = IGMP_BLOCK_OLD_SOURCES;
TASS Belgium NV 131:4758606c9316 836 IGMPFilter = &IGMPBlock;
TASS Belgium NV 131:4758606c9316 837 pico_tree_foreach(index, p->MCASTFilter)
TASS Belgium NV 131:4758606c9316 838 {
TASS Belgium NV 131:4758606c9316 839 pico_tree_insert(&IGMPBlock, index->keyValue);
TASS Belgium NV 131:4758606c9316 840 sources++;
tass 68:0847e35d08a6 841 }
TASS Belgium NV 131:4758606c9316 842 pico_tree_foreach(index, &g->MCASTSources) /* A */
TASS Belgium NV 131:4758606c9316 843 {
TASS Belgium NV 131:4758606c9316 844 source = pico_tree_findKey(&IGMPBlock, index->keyValue); /* B */
TASS Belgium NV 131:4758606c9316 845 if (source) {
TASS Belgium NV 131:4758606c9316 846 pico_tree_delete(&IGMPBlock, source);
TASS Belgium NV 131:4758606c9316 847 sources--;
TASS Belgium NV 131:4758606c9316 848 }
TASS Belgium NV 131:4758606c9316 849 }
TASS Belgium NV 131:4758606c9316 850 if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */
TASS Belgium NV 131:4758606c9316 851 break;
tass 68:0847e35d08a6 852
TASS Belgium NV 131:4758606c9316 853 /* ALLOW (A-B) */
TASS Belgium NV 131:4758606c9316 854 record_type = IGMP_ALLOW_NEW_SOURCES;
TASS Belgium NV 131:4758606c9316 855 IGMPFilter = &IGMPAllow;
TASS Belgium NV 131:4758606c9316 856 pico_tree_foreach(index, &g->MCASTSources)
TASS Belgium NV 131:4758606c9316 857 {
TASS Belgium NV 131:4758606c9316 858 pico_tree_insert(&IGMPAllow, index->keyValue);
TASS Belgium NV 131:4758606c9316 859 sources++;
TASS Belgium NV 131:4758606c9316 860 }
tass 68:0847e35d08a6 861 pico_tree_foreach(index, p->MCASTFilter) /* B */
tass 68:0847e35d08a6 862 {
TASS Belgium NV 131:4758606c9316 863 source = pico_tree_findKey(&IGMPAllow, index->keyValue); /* A */
TASS Belgium NV 131:4758606c9316 864 if (source) {
TASS Belgium NV 131:4758606c9316 865 pico_tree_delete(&IGMPAllow, source);
TASS Belgium NV 131:4758606c9316 866 sources--;
TASS Belgium NV 131:4758606c9316 867 }
tass 68:0847e35d08a6 868 }
TASS Belgium NV 131:4758606c9316 869 if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */
TASS Belgium NV 131:4758606c9316 870 break;
tass 68:0847e35d08a6 871
TASS Belgium NV 131:4758606c9316 872 /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report (RFC 3376 $5.1) */
TASS Belgium NV 131:4758606c9316 873 p->f = NULL;
TASS Belgium NV 131:4758606c9316 874 return 0;
tass 68:0847e35d08a6 875
tass 68:0847e35d08a6 876 default:
TASS Belgium NV 131:4758606c9316 877 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 878 return -1;
TASS Belgium NV 131:4758606c9316 879 }
TASS Belgium NV 131:4758606c9316 880 break;
tass 68:0847e35d08a6 881
tass 68:0847e35d08a6 882 default:
TASS Belgium NV 131:4758606c9316 883 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 884 return -1;
TASS Belgium NV 131:4758606c9316 885 }
tass 68:0847e35d08a6 886
TASS Belgium NV 131:4758606c9316 887 len = (uint16_t)(sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (sources * sizeof(struct pico_ip4)));
TASS Belgium NV 131:4758606c9316 888 p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(IP_OPTION_ROUTER_ALERT_LEN + len));
TASS Belgium NV 131:4758606c9316 889 p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN);
TASS Belgium NV 131:4758606c9316 890 p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN;
TASS Belgium NV 131:4758606c9316 891 p->f->transport_len = (uint16_t)(p->f->transport_len - IP_OPTION_ROUTER_ALERT_LEN);
TASS Belgium NV 131:4758606c9316 892 p->f->dev = pico_ipv4_link_find(&p->mcast_link);
TASS Belgium NV 131:4758606c9316 893 /* p->f->len is correctly set by alloc */
tass 68:0847e35d08a6 894
TASS Belgium NV 131:4758606c9316 895 report = (struct igmpv3_report *)p->f->transport_hdr;
TASS Belgium NV 131:4758606c9316 896 report->type = IGMP_TYPE_MEM_REPORT_V3;
TASS Belgium NV 131:4758606c9316 897 report->res0 = 0;
TASS Belgium NV 131:4758606c9316 898 report->crc = 0;
TASS Belgium NV 131:4758606c9316 899 report->res1 = 0;
TASS Belgium NV 131:4758606c9316 900 report->groups = short_be(1);
tass 68:0847e35d08a6 901
TASS Belgium NV 131:4758606c9316 902 record = &report->record[0];
TASS Belgium NV 131:4758606c9316 903 record->type = record_type;
TASS Belgium NV 131:4758606c9316 904 record->aux = 0;
TASS Belgium NV 131:4758606c9316 905 record->sources = short_be(sources);
TASS Belgium NV 131:4758606c9316 906 record->mcast_group = p->mcast_group.addr;
TASS Belgium NV 131:4758606c9316 907 if (!pico_tree_empty(IGMPFilter)) {
TASS Belgium NV 131:4758606c9316 908 i = 0;
TASS Belgium NV 131:4758606c9316 909 pico_tree_foreach(index, IGMPFilter)
TASS Belgium NV 131:4758606c9316 910 {
TASS Belgium NV 131:4758606c9316 911 record->source_addr[i] = ((struct pico_ip4 *)index->keyValue)->addr;
TASS Belgium NV 131:4758606c9316 912 i++;
TASS Belgium NV 131:4758606c9316 913 }
tass 68:0847e35d08a6 914 }
TASS Belgium NV 131:4758606c9316 915
TASS Belgium NV 131:4758606c9316 916 report->crc = short_be(pico_checksum(report, len));
TASS Belgium NV 131:4758606c9316 917 break;
tass 68:0847e35d08a6 918 }
tass 68:0847e35d08a6 919
tass 68:0847e35d08a6 920 default:
TASS Belgium NV 131:4758606c9316 921 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 922 return -1;
TASS Belgium NV 131:4758606c9316 923 }
TASS Belgium NV 131:4758606c9316 924 return 0;
tass 68:0847e35d08a6 925 }
tass 68:0847e35d08a6 926
tass 68:0847e35d08a6 927 /* stop timer, send leave if flag set */
tass 68:0847e35d08a6 928 static int stslifs(struct igmp_parameters *p)
tass 68:0847e35d08a6 929 {
TASS Belgium NV 131:4758606c9316 930 struct igmp_timer t = {
TASS Belgium NV 131:4758606c9316 931 0
TASS Belgium NV 131:4758606c9316 932 };
tass 68:0847e35d08a6 933
TASS Belgium NV 131:4758606c9316 934 igmp_dbg("IGMP: event = leave group | action = stop timer, send leave if flag set\n");
tass 68:0847e35d08a6 935
TASS Belgium NV 131:4758606c9316 936 t.type = IGMP_TIMER_GROUP_REPORT;
TASS Belgium NV 131:4758606c9316 937 t.mcast_link = p->mcast_link;
TASS Belgium NV 131:4758606c9316 938 t.mcast_group = p->mcast_group;
TASS Belgium NV 131:4758606c9316 939 if (pico_igmp_timer_stop(&t) < 0)
TASS Belgium NV 131:4758606c9316 940 return -1;
tass 68:0847e35d08a6 941
TASS Belgium NV 131:4758606c9316 942 /* always send leave, even if not last host */
TASS Belgium NV 131:4758606c9316 943 if (pico_igmp_send_report(p, p->f) < 0)
TASS Belgium NV 131:4758606c9316 944 return -1;
tass 68:0847e35d08a6 945
TASS Belgium NV 131:4758606c9316 946 pico_igmp_delete_parameter(p);
TASS Belgium NV 131:4758606c9316 947 igmp_dbg("IGMP: new state = non-member\n");
TASS Belgium NV 131:4758606c9316 948 return 0;
tass 68:0847e35d08a6 949 }
tass 68:0847e35d08a6 950
tass 68:0847e35d08a6 951 /* send report, set flag, start timer */
tass 68:0847e35d08a6 952 static int srsfst(struct igmp_parameters *p)
tass 68:0847e35d08a6 953 {
TASS Belgium NV 131:4758606c9316 954 struct igmp_timer t = {
TASS Belgium NV 131:4758606c9316 955 0
TASS Belgium NV 131:4758606c9316 956 };
TASS Belgium NV 131:4758606c9316 957 struct pico_frame *copy_frame = NULL;
TASS Belgium NV 131:4758606c9316 958
TASS Belgium NV 131:4758606c9316 959 igmp_dbg("IGMP: event = join group | action = send report, set flag, start timer\n");
tass 68:0847e35d08a6 960
TASS Belgium NV 131:4758606c9316 961 p->last_host = IGMP_HOST_LAST;
TASS Belgium NV 131:4758606c9316 962
TASS Belgium NV 131:4758606c9316 963 if (pico_igmp_generate_report(p) < 0)
TASS Belgium NV 131:4758606c9316 964 return -1;
TASS Belgium NV 131:4758606c9316 965
TASS Belgium NV 131:4758606c9316 966 if (!p->f)
TASS Belgium NV 131:4758606c9316 967 return 0;
tass 68:0847e35d08a6 968
TASS Belgium NV 131:4758606c9316 969 copy_frame = pico_frame_copy(p->f);
TASS Belgium NV 131:4758606c9316 970 if (!copy_frame) {
TASS Belgium NV 131:4758606c9316 971 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 972 return -1;
TASS Belgium NV 131:4758606c9316 973 }
TASS Belgium NV 131:4758606c9316 974
TASS Belgium NV 131:4758606c9316 975 if (pico_igmp_send_report(p, copy_frame) < 0)
TASS Belgium NV 131:4758606c9316 976 return -1;
tass 68:0847e35d08a6 977
TASS Belgium NV 131:4758606c9316 978 t.type = IGMP_TIMER_GROUP_REPORT;
TASS Belgium NV 131:4758606c9316 979 t.mcast_link = p->mcast_link;
TASS Belgium NV 131:4758606c9316 980 t.mcast_group = p->mcast_group;
TASS Belgium NV 131:4758606c9316 981 t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000));
TASS Belgium NV 131:4758606c9316 982 t.f = p->f;
TASS Belgium NV 131:4758606c9316 983 t.callback = pico_igmp_report_expired;
TASS Belgium NV 131:4758606c9316 984 pico_igmp_timer_start(&t);
TASS Belgium NV 131:4758606c9316 985
TASS Belgium NV 131:4758606c9316 986 p->state = IGMP_STATE_DELAYING_MEMBER;
TASS Belgium NV 131:4758606c9316 987 igmp_dbg("IGMP: new state = delaying member\n");
tass 68:0847e35d08a6 988 return 0;
tass 68:0847e35d08a6 989 }
tass 68:0847e35d08a6 990
tass 68:0847e35d08a6 991 /* merge report, send report, reset timer (IGMPv3 only) */
tass 68:0847e35d08a6 992 static int mrsrrt(struct igmp_parameters *p)
tass 68:0847e35d08a6 993 {
TASS Belgium NV 131:4758606c9316 994 struct igmp_timer *t = NULL;
TASS Belgium NV 131:4758606c9316 995 struct pico_frame *copy_frame = NULL;
TASS Belgium NV 131:4758606c9316 996 struct pico_ipv4_link *link = NULL;
tass 68:0847e35d08a6 997
TASS Belgium NV 131:4758606c9316 998 igmp_dbg("IGMP: event = update group | action = merge report, send report, reset timer (IGMPv3 only)\n");
tass 68:0847e35d08a6 999
TASS Belgium NV 131:4758606c9316 1000 link = pico_ipv4_link_get(&p->mcast_link);
TASS Belgium NV 131:4758606c9316 1001 if (!link)
TASS Belgium NV 131:4758606c9316 1002 return -1;
tass 68:0847e35d08a6 1003
TASS Belgium NV 131:4758606c9316 1004 if (link->mcast_compatibility != PICO_IGMPV3) {
TASS Belgium NV 131:4758606c9316 1005 igmp_dbg("IGMP: no IGMPv3 compatible router on network\n");
TASS Belgium NV 131:4758606c9316 1006 return -1;
TASS Belgium NV 131:4758606c9316 1007 }
TASS Belgium NV 131:4758606c9316 1008
TASS Belgium NV 131:4758606c9316 1009 /* XXX: merge with pending report rfc 3376 $5.1 */
tass 68:0847e35d08a6 1010
TASS Belgium NV 131:4758606c9316 1011 copy_frame = pico_frame_copy(p->f);
TASS Belgium NV 131:4758606c9316 1012 if (!copy_frame)
TASS Belgium NV 131:4758606c9316 1013 return -1;
tass 68:0847e35d08a6 1014
TASS Belgium NV 131:4758606c9316 1015 if (pico_igmp_send_report(p, copy_frame) < 0)
TASS Belgium NV 131:4758606c9316 1016 return -1;
tass 68:0847e35d08a6 1017
TASS Belgium NV 131:4758606c9316 1018 t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group);
TASS Belgium NV 131:4758606c9316 1019 if (!t)
TASS Belgium NV 131:4758606c9316 1020 return -1;
tass 68:0847e35d08a6 1021
TASS Belgium NV 131:4758606c9316 1022 t->delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000));
TASS Belgium NV 131:4758606c9316 1023 pico_igmp_timer_reset(t);
TASS Belgium NV 131:4758606c9316 1024
TASS Belgium NV 131:4758606c9316 1025 p->state = IGMP_STATE_DELAYING_MEMBER;
TASS Belgium NV 131:4758606c9316 1026 igmp_dbg("IGMP: new state = delaying member\n");
TASS Belgium NV 131:4758606c9316 1027 return 0;
tass 68:0847e35d08a6 1028 }
tass 68:0847e35d08a6 1029
tass 68:0847e35d08a6 1030 /* send report, start timer (IGMPv3 only) */
tass 68:0847e35d08a6 1031 static int srst(struct igmp_parameters *p)
tass 68:0847e35d08a6 1032 {
TASS Belgium NV 131:4758606c9316 1033 struct igmp_timer t = {
TASS Belgium NV 131:4758606c9316 1034 0
TASS Belgium NV 131:4758606c9316 1035 };
TASS Belgium NV 131:4758606c9316 1036 struct pico_frame *copy_frame = NULL;
TASS Belgium NV 131:4758606c9316 1037 struct pico_ipv4_link *link = NULL;
tass 68:0847e35d08a6 1038
TASS Belgium NV 131:4758606c9316 1039 igmp_dbg("IGMP: event = update group | action = send report, start timer (IGMPv3 only)\n");
tass 68:0847e35d08a6 1040
TASS Belgium NV 131:4758606c9316 1041 link = pico_ipv4_link_get(&p->mcast_link);
TASS Belgium NV 131:4758606c9316 1042 if (!link)
TASS Belgium NV 131:4758606c9316 1043 return -1;
tass 68:0847e35d08a6 1044
TASS Belgium NV 131:4758606c9316 1045 if (link->mcast_compatibility != PICO_IGMPV3) {
TASS Belgium NV 131:4758606c9316 1046 igmp_dbg("IGMP: no IGMPv3 compatible router on network\n");
TASS Belgium NV 131:4758606c9316 1047 return -1;
TASS Belgium NV 131:4758606c9316 1048 }
TASS Belgium NV 131:4758606c9316 1049
TASS Belgium NV 131:4758606c9316 1050 if (pico_igmp_generate_report(p) < 0)
TASS Belgium NV 131:4758606c9316 1051 return -1;
tass 68:0847e35d08a6 1052
TASS Belgium NV 131:4758606c9316 1053 if (!p->f)
TASS Belgium NV 131:4758606c9316 1054 return 0;
TASS Belgium NV 131:4758606c9316 1055
TASS Belgium NV 131:4758606c9316 1056 copy_frame = pico_frame_copy(p->f);
TASS Belgium NV 131:4758606c9316 1057 if (!copy_frame)
TASS Belgium NV 131:4758606c9316 1058 return -1;
TASS Belgium NV 131:4758606c9316 1059
TASS Belgium NV 131:4758606c9316 1060 if (pico_igmp_send_report(p, copy_frame) < 0)
TASS Belgium NV 131:4758606c9316 1061 return -1;
tass 68:0847e35d08a6 1062
TASS Belgium NV 131:4758606c9316 1063 t.type = IGMP_TIMER_GROUP_REPORT;
TASS Belgium NV 131:4758606c9316 1064 t.mcast_link = p->mcast_link;
TASS Belgium NV 131:4758606c9316 1065 t.mcast_group = p->mcast_group;
TASS Belgium NV 131:4758606c9316 1066 t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000));
TASS Belgium NV 131:4758606c9316 1067 t.f = p->f;
TASS Belgium NV 131:4758606c9316 1068 t.callback = pico_igmp_report_expired;
TASS Belgium NV 131:4758606c9316 1069 pico_igmp_timer_start(&t);
tass 68:0847e35d08a6 1070
TASS Belgium NV 131:4758606c9316 1071 p->state = IGMP_STATE_DELAYING_MEMBER;
TASS Belgium NV 131:4758606c9316 1072 igmp_dbg("IGMP: new state = delaying member\n");
TASS Belgium NV 131:4758606c9316 1073 return 0;
tass 68:0847e35d08a6 1074 }
tass 68:0847e35d08a6 1075
tass 68:0847e35d08a6 1076 /* send leave if flag set */
tass 68:0847e35d08a6 1077 static int slifs(struct igmp_parameters *p)
tass 68:0847e35d08a6 1078 {
TASS Belgium NV 131:4758606c9316 1079 igmp_dbg("IGMP: event = leave group | action = send leave if flag set\n");
tass 68:0847e35d08a6 1080
TASS Belgium NV 131:4758606c9316 1081 /* always send leave, even if not last host */
TASS Belgium NV 131:4758606c9316 1082 if (pico_igmp_send_report(p, p->f) < 0)
TASS Belgium NV 131:4758606c9316 1083 return -1;
tass 68:0847e35d08a6 1084
TASS Belgium NV 131:4758606c9316 1085 pico_igmp_delete_parameter(p);
TASS Belgium NV 131:4758606c9316 1086 igmp_dbg("IGMP: new state = non-member\n");
TASS Belgium NV 131:4758606c9316 1087 return 0;
tass 68:0847e35d08a6 1088 }
tass 68:0847e35d08a6 1089
tass 68:0847e35d08a6 1090 /* start timer */
tass 68:0847e35d08a6 1091 static int st(struct igmp_parameters *p)
tass 68:0847e35d08a6 1092 {
TASS Belgium NV 131:4758606c9316 1093 struct igmp_timer t = {
TASS Belgium NV 131:4758606c9316 1094 0
TASS Belgium NV 131:4758606c9316 1095 };
tass 68:0847e35d08a6 1096
TASS Belgium NV 131:4758606c9316 1097 igmp_dbg("IGMP: event = query received | action = start timer\n");
tass 68:0847e35d08a6 1098
TASS Belgium NV 131:4758606c9316 1099 if (pico_igmp_generate_report(p) < 0)
TASS Belgium NV 131:4758606c9316 1100 return -1;
TASS Belgium NV 131:4758606c9316 1101
TASS Belgium NV 131:4758606c9316 1102 if (!p->f)
TASS Belgium NV 131:4758606c9316 1103 return -1;
tass 68:0847e35d08a6 1104
TASS Belgium NV 131:4758606c9316 1105 t.type = IGMP_TIMER_GROUP_REPORT;
TASS Belgium NV 131:4758606c9316 1106 t.mcast_link = p->mcast_link;
TASS Belgium NV 131:4758606c9316 1107 t.mcast_group = p->mcast_group;
TASS Belgium NV 131:4758606c9316 1108 t.delay = (pico_rand() % (p->max_resp_time * 100u));
TASS Belgium NV 131:4758606c9316 1109 t.f = p->f;
TASS Belgium NV 131:4758606c9316 1110 t.callback = pico_igmp_report_expired;
TASS Belgium NV 131:4758606c9316 1111 pico_igmp_timer_start(&t);
tass 68:0847e35d08a6 1112
TASS Belgium NV 131:4758606c9316 1113 p->state = IGMP_STATE_DELAYING_MEMBER;
TASS Belgium NV 131:4758606c9316 1114 igmp_dbg("IGMP: new state = delaying member\n");
TASS Belgium NV 131:4758606c9316 1115 return 0;
tass 68:0847e35d08a6 1116 }
tass 68:0847e35d08a6 1117
tass 68:0847e35d08a6 1118 /* stop timer, clear flag */
tass 68:0847e35d08a6 1119 static int stcl(struct igmp_parameters *p)
tass 68:0847e35d08a6 1120 {
TASS Belgium NV 131:4758606c9316 1121 struct igmp_timer t = {
TASS Belgium NV 131:4758606c9316 1122 0
TASS Belgium NV 131:4758606c9316 1123 };
tass 68:0847e35d08a6 1124
TASS Belgium NV 131:4758606c9316 1125 igmp_dbg("IGMP: event = report received | action = stop timer, clear flag\n");
tass 68:0847e35d08a6 1126
TASS Belgium NV 131:4758606c9316 1127 t.type = IGMP_TIMER_GROUP_REPORT;
TASS Belgium NV 131:4758606c9316 1128 t.mcast_link = p->mcast_link;
TASS Belgium NV 131:4758606c9316 1129 t.mcast_group = p->mcast_group;
TASS Belgium NV 131:4758606c9316 1130 if (pico_igmp_timer_stop(&t) < 0)
TASS Belgium NV 131:4758606c9316 1131 return -1;
tass 68:0847e35d08a6 1132
TASS Belgium NV 131:4758606c9316 1133 p->last_host = IGMP_HOST_NOT_LAST;
TASS Belgium NV 131:4758606c9316 1134 p->state = IGMP_STATE_IDLE_MEMBER;
TASS Belgium NV 131:4758606c9316 1135 igmp_dbg("IGMP: new state = idle member\n");
TASS Belgium NV 131:4758606c9316 1136 return 0;
tass 68:0847e35d08a6 1137 }
tass 68:0847e35d08a6 1138
tass 68:0847e35d08a6 1139 /* send report, set flag */
tass 68:0847e35d08a6 1140 static int srsf(struct igmp_parameters *p)
tass 68:0847e35d08a6 1141 {
TASS Belgium NV 131:4758606c9316 1142 igmp_dbg("IGMP: event = timer expired | action = send report, set flag\n");
tass 68:0847e35d08a6 1143
TASS Belgium NV 131:4758606c9316 1144 if (pico_igmp_send_report(p, p->f) < 0)
TASS Belgium NV 131:4758606c9316 1145 return -1;
tass 68:0847e35d08a6 1146
TASS Belgium NV 131:4758606c9316 1147 p->state = IGMP_STATE_IDLE_MEMBER;
TASS Belgium NV 131:4758606c9316 1148 igmp_dbg("IGMP: new state = idle member\n");
TASS Belgium NV 131:4758606c9316 1149 return 0;
tass 68:0847e35d08a6 1150 }
tass 68:0847e35d08a6 1151
tass 68:0847e35d08a6 1152 /* reset timer if max response time < current timer */
tass 68:0847e35d08a6 1153 static int rtimrtct(struct igmp_parameters *p)
tass 68:0847e35d08a6 1154 {
TASS Belgium NV 131:4758606c9316 1155 struct igmp_timer *t = NULL;
TASS Belgium NV 131:4758606c9316 1156 uint32_t time_to_run = 0;
tass 68:0847e35d08a6 1157
TASS Belgium NV 131:4758606c9316 1158 igmp_dbg("IGMP: event = query received | action = reset timer if max response time < current timer\n");
tass 68:0847e35d08a6 1159
TASS Belgium NV 131:4758606c9316 1160 t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group);
TASS Belgium NV 131:4758606c9316 1161 if (!t)
TASS Belgium NV 131:4758606c9316 1162 return -1;
tass 68:0847e35d08a6 1163
TASS Belgium NV 131:4758606c9316 1164 time_to_run = (uint32_t)(t->start + t->delay - PICO_TIME_MS());
tass picotcp@tass.be 149:5f4cb161cec3 1165 if ((p->max_resp_time * 100u) < time_to_run) { /* max_resp_time in units of 1/10 seconds */
TASS Belgium NV 131:4758606c9316 1166 t->delay = pico_rand() % (p->max_resp_time * 100u);
TASS Belgium NV 131:4758606c9316 1167 pico_igmp_timer_reset(t);
TASS Belgium NV 131:4758606c9316 1168 }
tass 68:0847e35d08a6 1169
TASS Belgium NV 131:4758606c9316 1170 p->state = IGMP_STATE_DELAYING_MEMBER;
TASS Belgium NV 131:4758606c9316 1171 igmp_dbg("IGMP: new state = delaying member\n");
TASS Belgium NV 131:4758606c9316 1172 return 0;
tass 68:0847e35d08a6 1173 }
tass 68:0847e35d08a6 1174
TASS Belgium NV 131:4758606c9316 1175 static int discard(struct igmp_parameters *p)
TASS Belgium NV 131:4758606c9316 1176 {
TASS Belgium NV 131:4758606c9316 1177 igmp_dbg("IGMP: ignore and discard frame\n");
TASS Belgium NV 131:4758606c9316 1178 pico_frame_discard(p->f);
TASS Belgium NV 131:4758606c9316 1179 return 0;
tass 68:0847e35d08a6 1180 }
tass 68:0847e35d08a6 1181
tass 68:0847e35d08a6 1182 /* finite state machine table */
tass 68:0847e35d08a6 1183 const callback host_membership_diagram_table[3][6] =
tass 68:0847e35d08a6 1184 { /* event |Delete Group |Create Group |Update Group |Query Received |Report Received |Timer Expired */
TASS Belgium NV 131:4758606c9316 1185 /* state Non-Member */
TASS Belgium NV 131:4758606c9316 1186 { discard, srsfst, srsfst, discard, discard, discard },
tass 68:0847e35d08a6 1187 /* state Delaying Member */ { stslifs, mrsrrt, mrsrrt, rtimrtct, stcl, srsf },
tass 68:0847e35d08a6 1188 /* state Idle Member */ { slifs, srst, srst, st, discard, discard }
tass 68:0847e35d08a6 1189 };
tass 68:0847e35d08a6 1190
tass 68:0847e35d08a6 1191 static int pico_igmp_process_event(struct igmp_parameters *p)
tass 68:0847e35d08a6 1192 {
TASS Belgium NV 131:4758606c9316 1193 struct pico_tree_node *index = NULL;
TASS Belgium NV 131:4758606c9316 1194 struct igmp_parameters *_p = NULL;
tass 68:0847e35d08a6 1195
TASS Belgium NV 131:4758606c9316 1196 igmp_dbg("IGMP: process event on group address %08X\n", p->mcast_group.addr);
TASS Belgium NV 131:4758606c9316 1197 if (p->event == IGMP_EVENT_QUERY_RECV && p->mcast_group.addr == 0) { /* general query */
TASS Belgium NV 131:4758606c9316 1198 pico_tree_foreach(index, &IGMPParameters) {
TASS Belgium NV 131:4758606c9316 1199 _p = index->keyValue;
TASS Belgium NV 131:4758606c9316 1200 _p->max_resp_time = p->max_resp_time;
TASS Belgium NV 131:4758606c9316 1201 _p->event = IGMP_EVENT_QUERY_RECV;
TASS Belgium NV 131:4758606c9316 1202 igmp_dbg("IGMP: for each mcast_group = %08X | state = %u\n", _p->mcast_group.addr, _p->state);
TASS Belgium NV 131:4758606c9316 1203 host_membership_diagram_table[_p->state][_p->event](_p);
TASS Belgium NV 131:4758606c9316 1204 }
TASS Belgium NV 131:4758606c9316 1205 } else {
TASS Belgium NV 131:4758606c9316 1206 igmp_dbg("IGMP: state = %u (0: non-member - 1: delaying member - 2: idle member)\n", p->state);
TASS Belgium NV 131:4758606c9316 1207 host_membership_diagram_table[p->state][p->event](p);
tass 68:0847e35d08a6 1208 }
TASS Belgium NV 131:4758606c9316 1209
TASS Belgium NV 131:4758606c9316 1210 return 0;
tass 68:0847e35d08a6 1211 }
tass 68:0847e35d08a6 1212