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 Belgium NV
Date:
Mon Dec 16 11:25:54 2013 +0100
Revision:
131:4758606c9316
Parent:
128:ae39e6e81531
Child:
149:5f4cb161cec3
Syncronized with master branch

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