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:
daniele
Date:
Fri May 24 12:53:24 2013 +0000
Revision:
2:d12a891f2eca
Updated from main repository

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 2:d12a891f2eca 1 /*********************************************************************
daniele 2:d12a891f2eca 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 2:d12a891f2eca 3 See LICENSE and COPYING for usage.
daniele 2:d12a891f2eca 4
daniele 2:d12a891f2eca 5 RFC 1112, 2236, 3376, 3569, 3678, 4607
daniele 2:d12a891f2eca 6
daniele 2:d12a891f2eca 7 Authors: Kristof Roelants (IGMPv3), Simon Maes, Brecht Van Cauwenberghe
daniele 2:d12a891f2eca 8 *********************************************************************/
daniele 2:d12a891f2eca 9
daniele 2:d12a891f2eca 10 #include "pico_stack.h"
daniele 2:d12a891f2eca 11 #include "pico_ipv4.h"
daniele 2:d12a891f2eca 12 #include "pico_igmp.h"
daniele 2:d12a891f2eca 13 #include "pico_config.h"
daniele 2:d12a891f2eca 14 #include "pico_eth.h"
daniele 2:d12a891f2eca 15 #include "pico_addressing.h"
daniele 2:d12a891f2eca 16 #include "pico_frame.h"
daniele 2:d12a891f2eca 17 #include "pico_tree.h"
daniele 2:d12a891f2eca 18 #include "pico_device.h"
daniele 2:d12a891f2eca 19 #include "pico_socket.h"
daniele 2:d12a891f2eca 20
daniele 2:d12a891f2eca 21 /* membership states */
daniele 2:d12a891f2eca 22 #define IGMP_STATE_NON_MEMBER (0x0)
daniele 2:d12a891f2eca 23 #define IGMP_STATE_DELAYING_MEMBER (0x1)
daniele 2:d12a891f2eca 24 #define IGMP_STATE_IDLE_MEMBER (0x2)
daniele 2:d12a891f2eca 25
daniele 2:d12a891f2eca 26 /* events */
daniele 2:d12a891f2eca 27 #define IGMP_EVENT_DELETE_GROUP (0x0)
daniele 2:d12a891f2eca 28 #define IGMP_EVENT_CREATE_GROUP (0x1)
daniele 2:d12a891f2eca 29 #define IGMP_EVENT_UPDATE_GROUP (0x2)
daniele 2:d12a891f2eca 30 #define IGMP_EVENT_QUERY_RECV (0x3)
daniele 2:d12a891f2eca 31 #define IGMP_EVENT_REPORT_RECV (0x4)
daniele 2:d12a891f2eca 32 #define IGMP_EVENT_TIMER_EXPIRED (0x5)
daniele 2:d12a891f2eca 33
daniele 2:d12a891f2eca 34 /* message types */
daniele 2:d12a891f2eca 35 #define IGMP_TYPE_MEM_QUERY (0x11)
daniele 2:d12a891f2eca 36 #define IGMP_TYPE_MEM_REPORT_V1 (0x12)
daniele 2:d12a891f2eca 37 #define IGMP_TYPE_MEM_REPORT_V2 (0x16)
daniele 2:d12a891f2eca 38 #define IGMP_TYPE_LEAVE_GROUP (0x17)
daniele 2:d12a891f2eca 39 #define IGMP_TYPE_MEM_REPORT_V3 (0x22)
daniele 2:d12a891f2eca 40
daniele 2:d12a891f2eca 41 /* group record types */
daniele 2:d12a891f2eca 42 #define IGMP_MODE_IS_INCLUDE (1)
daniele 2:d12a891f2eca 43 #define IGMP_MODE_IS_EXCLUDE (2)
daniele 2:d12a891f2eca 44 #define IGMP_CHANGE_TO_INCLUDE_MODE (3)
daniele 2:d12a891f2eca 45 #define IGMP_CHANGE_TO_EXCLUDE_MODE (4)
daniele 2:d12a891f2eca 46 #define IGMP_ALLOW_NEW_SOURCES (5)
daniele 2:d12a891f2eca 47 #define IGMP_BLOCK_OLD_SOURCES (6)
daniele 2:d12a891f2eca 48
daniele 2:d12a891f2eca 49 /* host flag */
daniele 2:d12a891f2eca 50 #define IGMP_HOST_LAST (0x1)
daniele 2:d12a891f2eca 51 #define IGMP_HOST_NOT_LAST (0x0)
daniele 2:d12a891f2eca 52
daniele 2:d12a891f2eca 53 /* misc */
daniele 2:d12a891f2eca 54 #define TIMER_NOT_ACTIVE (0)
daniele 2:d12a891f2eca 55 #define IP_OPTION_ROUTER_ALERT_LEN (4)
daniele 2:d12a891f2eca 56 #define IGMP_DEFAULT_MAX_RESPONSE_TIME (100)
daniele 2:d12a891f2eca 57 #define IGMP_UNSOLICITED_REPORT_INTERVAL (100)
daniele 2:d12a891f2eca 58 #define IGMP_MAX_GROUPS (32) /* max 255 */
daniele 2:d12a891f2eca 59 #define IGMP_ALL_HOST_GROUP long_be(0xE0000001) /* 224.0.0.1 */
daniele 2:d12a891f2eca 60 #define IGMP_ALL_ROUTER_GROUP long_be(0xE0000002) /* 224.0.0.2 */
daniele 2:d12a891f2eca 61 #define IGMPV3_ALL_ROUTER_GROUP long_be(0xE0000016) /* 224.0.0.22 */
daniele 2:d12a891f2eca 62
daniele 2:d12a891f2eca 63 struct __attribute__((packed)) igmpv2_message {
daniele 2:d12a891f2eca 64 uint8_t type;
daniele 2:d12a891f2eca 65 uint8_t max_resp_time;
daniele 2:d12a891f2eca 66 uint16_t crc;
daniele 2:d12a891f2eca 67 uint32_t mcast_group;
daniele 2:d12a891f2eca 68 };
daniele 2:d12a891f2eca 69
daniele 2:d12a891f2eca 70 struct __attribute__((packed)) igmpv3_query {
daniele 2:d12a891f2eca 71 uint8_t type;
daniele 2:d12a891f2eca 72 uint8_t max_resp_time;
daniele 2:d12a891f2eca 73 uint16_t crc;
daniele 2:d12a891f2eca 74 uint32_t mcast_group;
daniele 2:d12a891f2eca 75 uint8_t rsq;
daniele 2:d12a891f2eca 76 uint8_t qqic;
daniele 2:d12a891f2eca 77 uint16_t sources;
daniele 2:d12a891f2eca 78 uint32_t source_addr[0];
daniele 2:d12a891f2eca 79 };
daniele 2:d12a891f2eca 80
daniele 2:d12a891f2eca 81 struct __attribute__((packed)) igmpv3_group_record {
daniele 2:d12a891f2eca 82 uint8_t type;
daniele 2:d12a891f2eca 83 uint8_t aux;
daniele 2:d12a891f2eca 84 uint16_t sources;
daniele 2:d12a891f2eca 85 uint32_t mcast_group;
daniele 2:d12a891f2eca 86 uint32_t source_addr[0];
daniele 2:d12a891f2eca 87 };
daniele 2:d12a891f2eca 88
daniele 2:d12a891f2eca 89 struct __attribute__((packed)) igmpv3_report {
daniele 2:d12a891f2eca 90 uint8_t type;
daniele 2:d12a891f2eca 91 uint8_t res0;
daniele 2:d12a891f2eca 92 uint16_t crc;
daniele 2:d12a891f2eca 93 uint16_t res1;
daniele 2:d12a891f2eca 94 uint16_t groups;
daniele 2:d12a891f2eca 95 struct igmpv3_group_record record[0];
daniele 2:d12a891f2eca 96 };
daniele 2:d12a891f2eca 97
daniele 2:d12a891f2eca 98 struct igmp_parameters {
daniele 2:d12a891f2eca 99 uint8_t event;
daniele 2:d12a891f2eca 100 uint8_t state;
daniele 2:d12a891f2eca 101 uint8_t last_host;
daniele 2:d12a891f2eca 102 uint8_t filter_mode;
daniele 2:d12a891f2eca 103 uint8_t max_resp_time;
daniele 2:d12a891f2eca 104 uint8_t mcast_router_version;
daniele 2:d12a891f2eca 105 uint16_t delay;
daniele 2:d12a891f2eca 106 unsigned long timer_start;
daniele 2:d12a891f2eca 107 struct pico_ip4 mcast_link;
daniele 2:d12a891f2eca 108 struct pico_ip4 mcast_group;
daniele 2:d12a891f2eca 109 struct pico_tree *MCASTFilter;
daniele 2:d12a891f2eca 110 struct pico_frame *f;
daniele 2:d12a891f2eca 111 };
daniele 2:d12a891f2eca 112
daniele 2:d12a891f2eca 113 struct timer_callback_info {
daniele 2:d12a891f2eca 114 unsigned long timer_start;
daniele 2:d12a891f2eca 115 struct pico_frame *f;
daniele 2:d12a891f2eca 116 };
daniele 2:d12a891f2eca 117
daniele 2:d12a891f2eca 118 static int igmp_parameters_cmp(void *ka,void *kb)
daniele 2:d12a891f2eca 119 {
daniele 2:d12a891f2eca 120 struct igmp_parameters *a = ka, *b = kb;
daniele 2:d12a891f2eca 121 if (a->mcast_group.addr < b->mcast_group.addr)
daniele 2:d12a891f2eca 122 return -1;
daniele 2:d12a891f2eca 123 if (a->mcast_group.addr > b->mcast_group.addr)
daniele 2:d12a891f2eca 124 return 1;
daniele 2:d12a891f2eca 125 return 0;
daniele 2:d12a891f2eca 126 }
daniele 2:d12a891f2eca 127 PICO_TREE_DECLARE(IGMPParameters, igmp_parameters_cmp);
daniele 2:d12a891f2eca 128
daniele 2:d12a891f2eca 129 static int igmp_sources_cmp(void *ka, void *kb)
daniele 2:d12a891f2eca 130 {
daniele 2:d12a891f2eca 131 struct pico_ip4 *a = ka, *b = kb;
daniele 2:d12a891f2eca 132 if (a->addr < b->addr)
daniele 2:d12a891f2eca 133 return -1;
daniele 2:d12a891f2eca 134 if (a->addr > b->addr)
daniele 2:d12a891f2eca 135 return 1;
daniele 2:d12a891f2eca 136 return 0;
daniele 2:d12a891f2eca 137 }
daniele 2:d12a891f2eca 138 PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp);
daniele 2:d12a891f2eca 139 PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp);
daniele 2:d12a891f2eca 140
daniele 2:d12a891f2eca 141 static struct igmp_parameters *pico_igmp_find_parameters(struct pico_ip4 *mcast_group)
daniele 2:d12a891f2eca 142 {
daniele 2:d12a891f2eca 143 struct igmp_parameters test = {0};
daniele 2:d12a891f2eca 144 test.mcast_group.addr = mcast_group->addr;
daniele 2:d12a891f2eca 145 return pico_tree_findKey(&IGMPParameters,&test);
daniele 2:d12a891f2eca 146 }
daniele 2:d12a891f2eca 147
daniele 2:d12a891f2eca 148 static int pico_igmp_delete_parameters(struct igmp_parameters *info)
daniele 2:d12a891f2eca 149 {
daniele 2:d12a891f2eca 150 if(!info){
daniele 2:d12a891f2eca 151 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 152 return -1;
daniele 2:d12a891f2eca 153 }
daniele 2:d12a891f2eca 154 else {
daniele 2:d12a891f2eca 155 if(pico_tree_delete(&IGMPParameters, info)) {
daniele 2:d12a891f2eca 156 pico_free(info);
daniele 2:d12a891f2eca 157 } else {
daniele 2:d12a891f2eca 158 pico_err = PICO_ERR_EEXIST;
daniele 2:d12a891f2eca 159 return -1; /* do not free, error on removing element from tree */
daniele 2:d12a891f2eca 160 }
daniele 2:d12a891f2eca 161 }
daniele 2:d12a891f2eca 162 return 0;
daniele 2:d12a891f2eca 163 }
daniele 2:d12a891f2eca 164
daniele 2:d12a891f2eca 165 static int pico_igmp_process_event(struct igmp_parameters *params);
daniele 2:d12a891f2eca 166 static void generate_event_timer_expired(long unsigned int empty, void *info);
daniele 2:d12a891f2eca 167
daniele 2:d12a891f2eca 168 #ifdef PICO_UNIT_TEST_IGMP
daniele 2:d12a891f2eca 169 #define igmp_dbg dbg
daniele 2:d12a891f2eca 170 static int pico_igmp_process_event(struct igmp_parameters *params);
daniele 2:d12a891f2eca 171 static int pico_igmp_analyse_packet(struct pico_frame *f, struct igmp_parameters *params);
daniele 2:d12a891f2eca 172 static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f);
daniele 2:d12a891f2eca 173
daniele 2:d12a891f2eca 174 int test_pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f){
daniele 2:d12a891f2eca 175 pico_igmp_process_in(self, f);
daniele 2:d12a891f2eca 176 return 0;
daniele 2:d12a891f2eca 177 }
daniele 2:d12a891f2eca 178 int test_pico_igmp_set_membershipState(struct pico_ip4 *mcast_group ,uint8_t state){
daniele 2:d12a891f2eca 179 struct igmp_parameters *info = pico_igmp_find_parameters(mcast_group);
daniele 2:d12a891f2eca 180 info->state = state;
daniele 2:d12a891f2eca 181 igmp_dbg("DEBUG_IGMP:STATE = %s\n", (info->state == 0 ? "Non-Member" : (info->state == 1 ? "Delaying MEMBER" : "Idle MEMBER")));
daniele 2:d12a891f2eca 182 return 0;
daniele 2:d12a891f2eca 183 }
daniele 2:d12a891f2eca 184 uint8_t test_pico_igmp_get_membershipState(struct pico_ip4 *mcast_group){
daniele 2:d12a891f2eca 185 struct igmp_parameters *info = pico_igmp_find_parameters(mcast_group);
daniele 2:d12a891f2eca 186 igmp_dbg("DEBUG_IGMP:STATE = %s\n", (info->state == 0 ? "Non-Member" : (info->state == 1 ? "Delaying Member" : "Idle Member")));
daniele 2:d12a891f2eca 187 return info->state;
daniele 2:d12a891f2eca 188 }
daniele 2:d12a891f2eca 189 int test_pico_igmp_process_event(struct igmp_parameters *params) {
daniele 2:d12a891f2eca 190 pico_igmp_process_event(params);
daniele 2:d12a891f2eca 191 return 0;
daniele 2:d12a891f2eca 192 }
daniele 2:d12a891f2eca 193
daniele 2:d12a891f2eca 194 int test_pico_igmp_analyse_packet(struct pico_frame *f, struct igmp_parameters *params){
daniele 2:d12a891f2eca 195 pico_igmp_analyse_packet(f, params);
daniele 2:d12a891f2eca 196 return 0;
daniele 2:d12a891f2eca 197 }
daniele 2:d12a891f2eca 198 #else
daniele 2:d12a891f2eca 199 //#define igmp_dbg(...) do{}while(0)
daniele 2:d12a891f2eca 200 #define igmp_dbg dbg
daniele 2:d12a891f2eca 201 #endif
daniele 2:d12a891f2eca 202
daniele 2:d12a891f2eca 203 /* queues */
daniele 2:d12a891f2eca 204 static struct pico_queue igmp_in = {};
daniele 2:d12a891f2eca 205 static struct pico_queue igmp_out = {};
daniele 2:d12a891f2eca 206
daniele 2:d12a891f2eca 207 static int pico_igmp_analyse_packet(struct pico_frame *f, struct igmp_parameters *params)
daniele 2:d12a891f2eca 208 {
daniele 2:d12a891f2eca 209 struct igmpv2_message *hdr = (struct igmpv2_message *) f->transport_hdr;
daniele 2:d12a891f2eca 210 switch (hdr->type) {
daniele 2:d12a891f2eca 211 case IGMP_TYPE_MEM_QUERY:
daniele 2:d12a891f2eca 212 params->event = IGMP_EVENT_QUERY_RECV;
daniele 2:d12a891f2eca 213 break;
daniele 2:d12a891f2eca 214 case IGMP_TYPE_MEM_REPORT_V1:
daniele 2:d12a891f2eca 215 params->event = IGMP_EVENT_REPORT_RECV;
daniele 2:d12a891f2eca 216 break;
daniele 2:d12a891f2eca 217 case IGMP_TYPE_MEM_REPORT_V2:
daniele 2:d12a891f2eca 218 params->event = IGMP_EVENT_REPORT_RECV;
daniele 2:d12a891f2eca 219 break;
daniele 2:d12a891f2eca 220 default:
daniele 2:d12a891f2eca 221 pico_frame_discard(f);
daniele 2:d12a891f2eca 222 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 223 return -1;
daniele 2:d12a891f2eca 224 }
daniele 2:d12a891f2eca 225 params->mcast_group.addr = hdr->mcast_group;
daniele 2:d12a891f2eca 226 params->max_resp_time = hdr->max_resp_time;
daniele 2:d12a891f2eca 227 params->f = f;
daniele 2:d12a891f2eca 228 return 0;
daniele 2:d12a891f2eca 229 }
daniele 2:d12a891f2eca 230
daniele 2:d12a891f2eca 231 static int check_igmp_checksum(struct pico_frame *f)
daniele 2:d12a891f2eca 232 {
daniele 2:d12a891f2eca 233 struct igmpv2_message *igmp_hdr = (struct igmpv2_message *) f->transport_hdr;
daniele 2:d12a891f2eca 234 uint16_t header_checksum;
daniele 2:d12a891f2eca 235
daniele 2:d12a891f2eca 236 if (!igmp_hdr) {
daniele 2:d12a891f2eca 237 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 238 return -1;
daniele 2:d12a891f2eca 239 }
daniele 2:d12a891f2eca 240 header_checksum = igmp_hdr->crc;
daniele 2:d12a891f2eca 241 igmp_hdr->crc=0;
daniele 2:d12a891f2eca 242
daniele 2:d12a891f2eca 243 if (header_checksum == short_be(pico_checksum(igmp_hdr, sizeof(struct igmpv2_message)))) {
daniele 2:d12a891f2eca 244 igmp_hdr->crc = header_checksum;
daniele 2:d12a891f2eca 245 return 0;
daniele 2:d12a891f2eca 246 } else {
daniele 2:d12a891f2eca 247 igmp_hdr->crc = header_checksum;
daniele 2:d12a891f2eca 248 pico_err = PICO_ERR_EFAULT;
daniele 2:d12a891f2eca 249 return -1;
daniele 2:d12a891f2eca 250 }
daniele 2:d12a891f2eca 251 }
daniele 2:d12a891f2eca 252
daniele 2:d12a891f2eca 253 static int pico_igmp_checksum(struct igmp_parameters *params)
daniele 2:d12a891f2eca 254 {
daniele 2:d12a891f2eca 255 struct igmpv2_message *igmp_hdr = (struct igmpv2_message *) params->f->transport_hdr;
daniele 2:d12a891f2eca 256 if (!igmp_hdr) {
daniele 2:d12a891f2eca 257 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 258 return -1;
daniele 2:d12a891f2eca 259 }
daniele 2:d12a891f2eca 260 igmp_hdr->crc = 0;
daniele 2:d12a891f2eca 261 igmp_hdr->crc = short_be(pico_checksum(igmp_hdr, sizeof(struct igmpv2_message)));
daniele 2:d12a891f2eca 262 return 0;
daniele 2:d12a891f2eca 263 }
daniele 2:d12a891f2eca 264
daniele 2:d12a891f2eca 265 static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f)
daniele 2:d12a891f2eca 266 {
daniele 2:d12a891f2eca 267 struct igmp_parameters params;
daniele 2:d12a891f2eca 268
daniele 2:d12a891f2eca 269 if (check_igmp_checksum(f) == 0) {
daniele 2:d12a891f2eca 270 if (!pico_igmp_analyse_packet(f, &params)) {
daniele 2:d12a891f2eca 271 pico_igmp_process_event(&params);
daniele 2:d12a891f2eca 272 }
daniele 2:d12a891f2eca 273 } else {
daniele 2:d12a891f2eca 274 igmp_dbg("IGMP: failure on checksum\n");
daniele 2:d12a891f2eca 275 pico_frame_discard(f);
daniele 2:d12a891f2eca 276 }
daniele 2:d12a891f2eca 277 return 0;
daniele 2:d12a891f2eca 278 }
daniele 2:d12a891f2eca 279
daniele 2:d12a891f2eca 280 static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) {
daniele 2:d12a891f2eca 281 /* packets are directly transferred to the IP layer by calling pico_ipv4_frame_push */
daniele 2:d12a891f2eca 282 return 0;
daniele 2:d12a891f2eca 283 }
daniele 2:d12a891f2eca 284
daniele 2:d12a891f2eca 285 /* Interface: protocol definition */
daniele 2:d12a891f2eca 286 struct pico_protocol pico_proto_igmp = {
daniele 2:d12a891f2eca 287 .name = "igmp",
daniele 2:d12a891f2eca 288 .proto_number = PICO_PROTO_IGMP,
daniele 2:d12a891f2eca 289 .layer = PICO_LAYER_TRANSPORT,
daniele 2:d12a891f2eca 290 .process_in = pico_igmp_process_in,
daniele 2:d12a891f2eca 291 .process_out = pico_igmp_process_out,
daniele 2:d12a891f2eca 292 .q_in = &igmp_in,
daniele 2:d12a891f2eca 293 .q_out = &igmp_out,
daniele 2:d12a891f2eca 294 };
daniele 2:d12a891f2eca 295
daniele 2:d12a891f2eca 296 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)
daniele 2:d12a891f2eca 297 {
daniele 2:d12a891f2eca 298 struct igmp_parameters *rbtparams = NULL, params = {0};
daniele 2:d12a891f2eca 299
daniele 2:d12a891f2eca 300 if (mcast_group->addr == IGMP_ALL_HOST_GROUP)
daniele 2:d12a891f2eca 301 return 0;
daniele 2:d12a891f2eca 302
daniele 2:d12a891f2eca 303 switch (state) {
daniele 2:d12a891f2eca 304 case PICO_IGMP_STATE_CREATE:
daniele 2:d12a891f2eca 305 params.event = IGMP_EVENT_CREATE_GROUP;
daniele 2:d12a891f2eca 306 break;
daniele 2:d12a891f2eca 307
daniele 2:d12a891f2eca 308 case PICO_IGMP_STATE_UPDATE:
daniele 2:d12a891f2eca 309 params.event = IGMP_EVENT_UPDATE_GROUP;
daniele 2:d12a891f2eca 310 break;
daniele 2:d12a891f2eca 311
daniele 2:d12a891f2eca 312 case PICO_IGMP_STATE_DELETE:
daniele 2:d12a891f2eca 313 params.event = IGMP_EVENT_DELETE_GROUP;
daniele 2:d12a891f2eca 314 break;
daniele 2:d12a891f2eca 315
daniele 2:d12a891f2eca 316 default:
daniele 2:d12a891f2eca 317 return -1;
daniele 2:d12a891f2eca 318 }
daniele 2:d12a891f2eca 319
daniele 2:d12a891f2eca 320 params.mcast_router_version = PICO_IGMPV2; /* init value, can change when generating frame */
daniele 2:d12a891f2eca 321 params.mcast_group = *mcast_group;
daniele 2:d12a891f2eca 322 params.mcast_link = *mcast_link;
daniele 2:d12a891f2eca 323 params.filter_mode = filter_mode;
daniele 2:d12a891f2eca 324 params.MCASTFilter = MCASTFilter;
daniele 2:d12a891f2eca 325
daniele 2:d12a891f2eca 326 rbtparams = pico_igmp_find_parameters(mcast_group);
daniele 2:d12a891f2eca 327 if (rbtparams) {
daniele 2:d12a891f2eca 328 rbtparams->event = params.event;
daniele 2:d12a891f2eca 329 rbtparams->mcast_link = params.mcast_link;
daniele 2:d12a891f2eca 330 rbtparams->filter_mode = params.filter_mode;
daniele 2:d12a891f2eca 331 rbtparams->MCASTFilter = params.MCASTFilter;
daniele 2:d12a891f2eca 332 }
daniele 2:d12a891f2eca 333
daniele 2:d12a891f2eca 334 return pico_igmp_process_event(&params);
daniele 2:d12a891f2eca 335 }
daniele 2:d12a891f2eca 336
daniele 2:d12a891f2eca 337 static int start_timer(struct igmp_parameters *params,const uint16_t delay)
daniele 2:d12a891f2eca 338 {
daniele 2:d12a891f2eca 339 struct igmp_parameters *info = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 340 struct timer_callback_info *timer_info= pico_zalloc(sizeof(struct timer_callback_info));
daniele 2:d12a891f2eca 341
daniele 2:d12a891f2eca 342 timer_info->timer_start = PICO_TIME_MS();
daniele 2:d12a891f2eca 343 timer_info->f = params->f;
daniele 2:d12a891f2eca 344 info->delay = delay;
daniele 2:d12a891f2eca 345 info->timer_start = timer_info->timer_start;
daniele 2:d12a891f2eca 346 pico_timer_add(delay, &generate_event_timer_expired, timer_info);
daniele 2:d12a891f2eca 347 return 0;
daniele 2:d12a891f2eca 348 }
daniele 2:d12a891f2eca 349
daniele 2:d12a891f2eca 350 static int stop_timer(struct pico_ip4 *mcast_group)
daniele 2:d12a891f2eca 351 {
daniele 2:d12a891f2eca 352 struct igmp_parameters *info = pico_igmp_find_parameters(mcast_group);
daniele 2:d12a891f2eca 353 if (!info)
daniele 2:d12a891f2eca 354 return -1;
daniele 2:d12a891f2eca 355 info->timer_start = TIMER_NOT_ACTIVE;
daniele 2:d12a891f2eca 356 return 0;
daniele 2:d12a891f2eca 357 }
daniele 2:d12a891f2eca 358
daniele 2:d12a891f2eca 359 static int reset_timer(struct igmp_parameters *params)
daniele 2:d12a891f2eca 360 {
daniele 2:d12a891f2eca 361 uint8_t ret = 0;
daniele 2:d12a891f2eca 362 uint16_t delay = pico_rand() % (params->max_resp_time*100);
daniele 2:d12a891f2eca 363
daniele 2:d12a891f2eca 364 ret |= stop_timer(&(params->mcast_group));
daniele 2:d12a891f2eca 365 ret |= start_timer(params, delay);
daniele 2:d12a891f2eca 366 return ret;
daniele 2:d12a891f2eca 367 }
daniele 2:d12a891f2eca 368
daniele 2:d12a891f2eca 369 static int send_membership_report(struct igmp_parameters *params, struct pico_frame *f)
daniele 2:d12a891f2eca 370 {
daniele 2:d12a891f2eca 371 struct pico_ip4 dst = {0};
daniele 2:d12a891f2eca 372 struct pico_ip4 mcast_group = {0};
daniele 2:d12a891f2eca 373
daniele 2:d12a891f2eca 374 mcast_group.addr = params->mcast_group.addr;
daniele 2:d12a891f2eca 375 switch (params->mcast_router_version) {
daniele 2:d12a891f2eca 376 case PICO_IGMPV2:
daniele 2:d12a891f2eca 377 {
daniele 2:d12a891f2eca 378 if (params->event == IGMP_EVENT_DELETE_GROUP)
daniele 2:d12a891f2eca 379 dst.addr = IGMP_ALL_ROUTER_GROUP;
daniele 2:d12a891f2eca 380 else
daniele 2:d12a891f2eca 381 dst.addr = mcast_group.addr;
daniele 2:d12a891f2eca 382 break;
daniele 2:d12a891f2eca 383 }
daniele 2:d12a891f2eca 384
daniele 2:d12a891f2eca 385 case PICO_IGMPV3:
daniele 2:d12a891f2eca 386 dst.addr = IGMPV3_ALL_ROUTER_GROUP;
daniele 2:d12a891f2eca 387 break;
daniele 2:d12a891f2eca 388
daniele 2:d12a891f2eca 389 default:
daniele 2:d12a891f2eca 390 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 2:d12a891f2eca 391 return -1;
daniele 2:d12a891f2eca 392 }
daniele 2:d12a891f2eca 393
daniele 2:d12a891f2eca 394 igmp_dbg("IGMP: send membership report on group %08X to %08X\n", mcast_group.addr, dst.addr);
daniele 2:d12a891f2eca 395 pico_ipv4_frame_push(f, &dst, PICO_PROTO_IGMP);
daniele 2:d12a891f2eca 396 stop_timer(&mcast_group);
daniele 2:d12a891f2eca 397 return 0;
daniele 2:d12a891f2eca 398 }
daniele 2:d12a891f2eca 399
daniele 2:d12a891f2eca 400 static int generate_igmp_report(struct igmp_parameters *params)
daniele 2:d12a891f2eca 401 {
daniele 2:d12a891f2eca 402 struct pico_ipv4_link *link = NULL;
daniele 2:d12a891f2eca 403 int i = 0;
daniele 2:d12a891f2eca 404
daniele 2:d12a891f2eca 405 link = pico_ipv4_link_get(&params->mcast_link);
daniele 2:d12a891f2eca 406 if (!link) {
daniele 2:d12a891f2eca 407 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 408 return -1;
daniele 2:d12a891f2eca 409 }
daniele 2:d12a891f2eca 410 params->mcast_router_version = link->mcast_router_version;
daniele 2:d12a891f2eca 411
daniele 2:d12a891f2eca 412 switch (params->mcast_router_version) {
daniele 2:d12a891f2eca 413 case PICO_IGMPV1:
daniele 2:d12a891f2eca 414 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 2:d12a891f2eca 415 return -1;
daniele 2:d12a891f2eca 416
daniele 2:d12a891f2eca 417 case PICO_IGMPV2:
daniele 2:d12a891f2eca 418 {
daniele 2:d12a891f2eca 419 struct igmpv2_message *report = NULL;
daniele 2:d12a891f2eca 420 uint8_t report_type = IGMP_TYPE_MEM_REPORT_V2;
daniele 2:d12a891f2eca 421 if (params->event == IGMP_EVENT_DELETE_GROUP)
daniele 2:d12a891f2eca 422 report_type = IGMP_TYPE_LEAVE_GROUP;
daniele 2:d12a891f2eca 423
daniele 2:d12a891f2eca 424 params->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + sizeof(struct igmpv2_message));
daniele 2:d12a891f2eca 425 params->f->net_len += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 426 params->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 427 params->f->transport_len -= IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 428 params->f->dev = pico_ipv4_link_find(&params->mcast_link);
daniele 2:d12a891f2eca 429 /* params->f->len is correctly set by alloc */
daniele 2:d12a891f2eca 430
daniele 2:d12a891f2eca 431 report = (struct igmpv2_message *)params->f->transport_hdr;
daniele 2:d12a891f2eca 432 report->type = report_type;
daniele 2:d12a891f2eca 433 report->max_resp_time = IGMP_DEFAULT_MAX_RESPONSE_TIME;
daniele 2:d12a891f2eca 434 report->mcast_group = params->mcast_group.addr;
daniele 2:d12a891f2eca 435
daniele 2:d12a891f2eca 436 pico_igmp_checksum(params);
daniele 2:d12a891f2eca 437 break;
daniele 2:d12a891f2eca 438 }
daniele 2:d12a891f2eca 439 case PICO_IGMPV3:
daniele 2:d12a891f2eca 440 {
daniele 2:d12a891f2eca 441 struct igmpv3_report *report = NULL;
daniele 2:d12a891f2eca 442 struct igmpv3_group_record *record = NULL;
daniele 2:d12a891f2eca 443 struct pico_mcast_group *g = NULL, test = {0};
daniele 2:d12a891f2eca 444 struct pico_tree_node *index = NULL, *_tmp = NULL;
daniele 2:d12a891f2eca 445 struct pico_tree *IGMPFilter = NULL;
daniele 2:d12a891f2eca 446 struct pico_ip4 *source = NULL;
daniele 2:d12a891f2eca 447 uint8_t record_type = 0;
daniele 2:d12a891f2eca 448 uint8_t sources = 0;
daniele 2:d12a891f2eca 449 int len = 0;
daniele 2:d12a891f2eca 450
daniele 2:d12a891f2eca 451 test.mcast_addr = params->mcast_group;
daniele 2:d12a891f2eca 452 g = pico_tree_findKey(link->MCASTGroups, &test);
daniele 2:d12a891f2eca 453 if (!g) {
daniele 2:d12a891f2eca 454 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 455 return -1;
daniele 2:d12a891f2eca 456 }
daniele 2:d12a891f2eca 457
daniele 2:d12a891f2eca 458 if (params->event == IGMP_EVENT_DELETE_GROUP) { /* "non-existent" state of filter mode INCLUDE and empty source list */
daniele 2:d12a891f2eca 459 params->filter_mode = PICO_IP_MULTICAST_INCLUDE;
daniele 2:d12a891f2eca 460 params->MCASTFilter = NULL;
daniele 2:d12a891f2eca 461 }
daniele 2:d12a891f2eca 462
daniele 2:d12a891f2eca 463 /* cleanup filters */
daniele 2:d12a891f2eca 464 pico_tree_foreach_safe(index, &IGMPAllow, _tmp)
daniele 2:d12a891f2eca 465 {
daniele 2:d12a891f2eca 466 pico_tree_delete(&IGMPAllow, index->keyValue);
daniele 2:d12a891f2eca 467 }
daniele 2:d12a891f2eca 468 pico_tree_foreach_safe(index, &IGMPBlock, _tmp)
daniele 2:d12a891f2eca 469 {
daniele 2:d12a891f2eca 470 pico_tree_delete(&IGMPBlock, index->keyValue);
daniele 2:d12a891f2eca 471 }
daniele 2:d12a891f2eca 472
daniele 2:d12a891f2eca 473 switch (g->filter_mode) {
daniele 2:d12a891f2eca 474
daniele 2:d12a891f2eca 475 case PICO_IP_MULTICAST_INCLUDE:
daniele 2:d12a891f2eca 476 switch (params->filter_mode) {
daniele 2:d12a891f2eca 477 case PICO_IP_MULTICAST_INCLUDE:
daniele 2:d12a891f2eca 478 if (params->event == IGMP_EVENT_DELETE_GROUP) { /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */
daniele 2:d12a891f2eca 479 /* TO_IN (B) */
daniele 2:d12a891f2eca 480 record_type = IGMP_CHANGE_TO_INCLUDE_MODE;
daniele 2:d12a891f2eca 481 IGMPFilter = &IGMPAllow;
daniele 2:d12a891f2eca 482 if (params->MCASTFilter) {
daniele 2:d12a891f2eca 483 pico_tree_foreach(index, params->MCASTFilter) /* B */
daniele 2:d12a891f2eca 484 {
daniele 2:d12a891f2eca 485 pico_tree_insert(&IGMPAllow, index->keyValue);
daniele 2:d12a891f2eca 486 sources++;
daniele 2:d12a891f2eca 487 }
daniele 2:d12a891f2eca 488 } /* else { IGMPAllow stays empty } */
daniele 2:d12a891f2eca 489 break;
daniele 2:d12a891f2eca 490 }
daniele 2:d12a891f2eca 491
daniele 2:d12a891f2eca 492 /* ALLOW (B-A) */
daniele 2:d12a891f2eca 493 /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */
daniele 2:d12a891f2eca 494 if (params->event == IGMP_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */
daniele 2:d12a891f2eca 495 record_type = IGMP_CHANGE_TO_INCLUDE_MODE;
daniele 2:d12a891f2eca 496 else
daniele 2:d12a891f2eca 497 record_type = IGMP_ALLOW_NEW_SOURCES;
daniele 2:d12a891f2eca 498 IGMPFilter = &IGMPAllow;
daniele 2:d12a891f2eca 499 pico_tree_foreach(index, params->MCASTFilter) /* B */
daniele 2:d12a891f2eca 500 {
daniele 2:d12a891f2eca 501 pico_tree_insert(&IGMPAllow, index->keyValue);
daniele 2:d12a891f2eca 502 sources++;
daniele 2:d12a891f2eca 503 }
daniele 2:d12a891f2eca 504 pico_tree_foreach(index, &g->MCASTSources) /* A */
daniele 2:d12a891f2eca 505 {
daniele 2:d12a891f2eca 506 source = pico_tree_findKey(&IGMPAllow, index->keyValue);
daniele 2:d12a891f2eca 507 if (source) {
daniele 2:d12a891f2eca 508 pico_tree_delete(&IGMPAllow, source);
daniele 2:d12a891f2eca 509 sources--;
daniele 2:d12a891f2eca 510 }
daniele 2:d12a891f2eca 511 }
daniele 2:d12a891f2eca 512 if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */
daniele 2:d12a891f2eca 513 break;
daniele 2:d12a891f2eca 514
daniele 2:d12a891f2eca 515 /* BLOCK (A-B) */
daniele 2:d12a891f2eca 516 record_type = IGMP_BLOCK_OLD_SOURCES;
daniele 2:d12a891f2eca 517 IGMPFilter = &IGMPBlock;
daniele 2:d12a891f2eca 518 pico_tree_foreach(index, &g->MCASTSources) /* A */
daniele 2:d12a891f2eca 519 {
daniele 2:d12a891f2eca 520 pico_tree_insert(&IGMPBlock, index->keyValue);
daniele 2:d12a891f2eca 521 sources++;
daniele 2:d12a891f2eca 522 }
daniele 2:d12a891f2eca 523 pico_tree_foreach(index, params->MCASTFilter) /* B */
daniele 2:d12a891f2eca 524 {
daniele 2:d12a891f2eca 525 source = pico_tree_findKey(&IGMPBlock, index->keyValue);
daniele 2:d12a891f2eca 526 if (source) {
daniele 2:d12a891f2eca 527 pico_tree_delete(&IGMPBlock, source);
daniele 2:d12a891f2eca 528 sources--;
daniele 2:d12a891f2eca 529 }
daniele 2:d12a891f2eca 530 }
daniele 2:d12a891f2eca 531 if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */
daniele 2:d12a891f2eca 532 break;
daniele 2:d12a891f2eca 533
daniele 2:d12a891f2eca 534 /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report (RFC 3376 $5.1) */
daniele 2:d12a891f2eca 535 params->f = NULL;
daniele 2:d12a891f2eca 536 return 0;
daniele 2:d12a891f2eca 537
daniele 2:d12a891f2eca 538 case PICO_IP_MULTICAST_EXCLUDE:
daniele 2:d12a891f2eca 539 /* TO_EX (B) */
daniele 2:d12a891f2eca 540 record_type = IGMP_CHANGE_TO_EXCLUDE_MODE;
daniele 2:d12a891f2eca 541 IGMPFilter = &IGMPBlock;
daniele 2:d12a891f2eca 542 pico_tree_foreach(index, params->MCASTFilter) /* B */
daniele 2:d12a891f2eca 543 {
daniele 2:d12a891f2eca 544 pico_tree_insert(&IGMPBlock, index->keyValue);
daniele 2:d12a891f2eca 545 sources++;
daniele 2:d12a891f2eca 546 }
daniele 2:d12a891f2eca 547 break;
daniele 2:d12a891f2eca 548
daniele 2:d12a891f2eca 549 default:
daniele 2:d12a891f2eca 550 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 551 return -1;
daniele 2:d12a891f2eca 552 }
daniele 2:d12a891f2eca 553 break;
daniele 2:d12a891f2eca 554
daniele 2:d12a891f2eca 555 case PICO_IP_MULTICAST_EXCLUDE:
daniele 2:d12a891f2eca 556 switch (params->filter_mode) {
daniele 2:d12a891f2eca 557 case PICO_IP_MULTICAST_INCLUDE:
daniele 2:d12a891f2eca 558 /* TO_IN (B) */
daniele 2:d12a891f2eca 559 record_type = IGMP_CHANGE_TO_INCLUDE_MODE;
daniele 2:d12a891f2eca 560 IGMPFilter = &IGMPAllow;
daniele 2:d12a891f2eca 561 if (params->MCASTFilter) {
daniele 2:d12a891f2eca 562 pico_tree_foreach(index, params->MCASTFilter) /* B */
daniele 2:d12a891f2eca 563 {
daniele 2:d12a891f2eca 564 pico_tree_insert(&IGMPAllow, index->keyValue);
daniele 2:d12a891f2eca 565 sources++;
daniele 2:d12a891f2eca 566 }
daniele 2:d12a891f2eca 567 } /* else { IGMPAllow stays empty } */
daniele 2:d12a891f2eca 568 break;
daniele 2:d12a891f2eca 569
daniele 2:d12a891f2eca 570 case PICO_IP_MULTICAST_EXCLUDE:
daniele 2:d12a891f2eca 571 /* BLOCK (B-A) */
daniele 2:d12a891f2eca 572 record_type = IGMP_BLOCK_OLD_SOURCES;
daniele 2:d12a891f2eca 573 IGMPFilter = &IGMPBlock;
daniele 2:d12a891f2eca 574 pico_tree_foreach(index, params->MCASTFilter)
daniele 2:d12a891f2eca 575 {
daniele 2:d12a891f2eca 576 pico_tree_insert(&IGMPBlock, index->keyValue);
daniele 2:d12a891f2eca 577 sources++;
daniele 2:d12a891f2eca 578 }
daniele 2:d12a891f2eca 579 pico_tree_foreach(index, &g->MCASTSources) /* A */
daniele 2:d12a891f2eca 580 {
daniele 2:d12a891f2eca 581 source = pico_tree_findKey(&IGMPBlock, index->keyValue); /* B */
daniele 2:d12a891f2eca 582 if (source) {
daniele 2:d12a891f2eca 583 pico_tree_delete(&IGMPBlock, source);
daniele 2:d12a891f2eca 584 sources--;
daniele 2:d12a891f2eca 585 }
daniele 2:d12a891f2eca 586 }
daniele 2:d12a891f2eca 587 if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */
daniele 2:d12a891f2eca 588 break;
daniele 2:d12a891f2eca 589
daniele 2:d12a891f2eca 590 /* ALLOW (A-B) */
daniele 2:d12a891f2eca 591 record_type = IGMP_ALLOW_NEW_SOURCES;
daniele 2:d12a891f2eca 592 IGMPFilter = &IGMPAllow;
daniele 2:d12a891f2eca 593 pico_tree_foreach(index, &g->MCASTSources)
daniele 2:d12a891f2eca 594 {
daniele 2:d12a891f2eca 595 pico_tree_insert(&IGMPAllow, index->keyValue);
daniele 2:d12a891f2eca 596 sources++;
daniele 2:d12a891f2eca 597 }
daniele 2:d12a891f2eca 598 pico_tree_foreach(index, params->MCASTFilter) /* B */
daniele 2:d12a891f2eca 599 {
daniele 2:d12a891f2eca 600 source = pico_tree_findKey(&IGMPAllow, index->keyValue); /* A */
daniele 2:d12a891f2eca 601 if (source) {
daniele 2:d12a891f2eca 602 pico_tree_delete(&IGMPAllow, source);
daniele 2:d12a891f2eca 603 sources--;
daniele 2:d12a891f2eca 604 }
daniele 2:d12a891f2eca 605 }
daniele 2:d12a891f2eca 606 if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */
daniele 2:d12a891f2eca 607 break;
daniele 2:d12a891f2eca 608
daniele 2:d12a891f2eca 609 /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report (RFC 3376 $5.1) */
daniele 2:d12a891f2eca 610 params->f = NULL;
daniele 2:d12a891f2eca 611 return 0;
daniele 2:d12a891f2eca 612
daniele 2:d12a891f2eca 613 default:
daniele 2:d12a891f2eca 614 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 615 return -1;
daniele 2:d12a891f2eca 616 }
daniele 2:d12a891f2eca 617 break;
daniele 2:d12a891f2eca 618
daniele 2:d12a891f2eca 619 default:
daniele 2:d12a891f2eca 620 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 621 return -1;
daniele 2:d12a891f2eca 622 }
daniele 2:d12a891f2eca 623
daniele 2:d12a891f2eca 624 len = sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (sources * sizeof(struct pico_ip4));
daniele 2:d12a891f2eca 625 params->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + len);
daniele 2:d12a891f2eca 626 params->f->net_len += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 627 params->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 628 params->f->transport_len -= IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 629 params->f->dev = pico_ipv4_link_find(&params->mcast_link);
daniele 2:d12a891f2eca 630 /* params->f->len is correctly set by alloc */
daniele 2:d12a891f2eca 631
daniele 2:d12a891f2eca 632 report = (struct igmpv3_report *)params->f->transport_hdr;
daniele 2:d12a891f2eca 633 report->type = IGMP_TYPE_MEM_REPORT_V3;
daniele 2:d12a891f2eca 634 report->res0 = 0;
daniele 2:d12a891f2eca 635 report->crc = 0;
daniele 2:d12a891f2eca 636 report->res1 = 0;
daniele 2:d12a891f2eca 637 report->groups = short_be(1);
daniele 2:d12a891f2eca 638
daniele 2:d12a891f2eca 639 record = &report->record[0];
daniele 2:d12a891f2eca 640 record->type = record_type;
daniele 2:d12a891f2eca 641 record->aux = 0;
daniele 2:d12a891f2eca 642 record->sources = short_be(sources);
daniele 2:d12a891f2eca 643 record->mcast_group = params->mcast_group.addr;
daniele 2:d12a891f2eca 644 if (!pico_tree_empty(IGMPFilter)) {
daniele 2:d12a891f2eca 645 i = 0;
daniele 2:d12a891f2eca 646 pico_tree_foreach(index, IGMPFilter)
daniele 2:d12a891f2eca 647 {
daniele 2:d12a891f2eca 648 record->source_addr[i] = ((struct pico_ip4 *)index->keyValue)->addr;
daniele 2:d12a891f2eca 649 i++;
daniele 2:d12a891f2eca 650 }
daniele 2:d12a891f2eca 651 }
daniele 2:d12a891f2eca 652 report->crc = short_be(pico_checksum(report, len));
daniele 2:d12a891f2eca 653
daniele 2:d12a891f2eca 654 break;
daniele 2:d12a891f2eca 655 }
daniele 2:d12a891f2eca 656
daniele 2:d12a891f2eca 657 default:
daniele 2:d12a891f2eca 658 pico_err = PICO_ERR_EINVAL;
daniele 2:d12a891f2eca 659 return -1;
daniele 2:d12a891f2eca 660 }
daniele 2:d12a891f2eca 661 return 0;
daniele 2:d12a891f2eca 662 }
daniele 2:d12a891f2eca 663
daniele 2:d12a891f2eca 664 /* XXX TO BE DELETED */
daniele 2:d12a891f2eca 665 static int create_igmp_frame(struct igmp_parameters *params, struct pico_frame **f, struct pico_ip4 src, struct pico_ip4 *mcast_group, uint8_t type)
daniele 2:d12a891f2eca 666 {
daniele 2:d12a891f2eca 667 uint8_t ret = 0;
daniele 2:d12a891f2eca 668 struct igmpv2_message *igmp_hdr = NULL;
daniele 2:d12a891f2eca 669
daniele 2:d12a891f2eca 670 *f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + sizeof(struct igmpv2_message));
daniele 2:d12a891f2eca 671 (*f)->net_len += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 672 (*f)->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 673 (*f)->transport_len -= IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 674 (*f)->len += IP_OPTION_ROUTER_ALERT_LEN;
daniele 2:d12a891f2eca 675 (*f)->dev = pico_ipv4_link_find(&src);
daniele 2:d12a891f2eca 676
daniele 2:d12a891f2eca 677 igmp_hdr = (struct igmpv2_message *) (*f)->transport_hdr;
daniele 2:d12a891f2eca 678 igmp_hdr->type = type;
daniele 2:d12a891f2eca 679 igmp_hdr->max_resp_time = IGMP_DEFAULT_MAX_RESPONSE_TIME;
daniele 2:d12a891f2eca 680 igmp_hdr->mcast_group = mcast_group->addr;
daniele 2:d12a891f2eca 681
daniele 2:d12a891f2eca 682 ret |= pico_igmp_checksum(params);
daniele 2:d12a891f2eca 683 return ret;
daniele 2:d12a891f2eca 684 }
daniele 2:d12a891f2eca 685
daniele 2:d12a891f2eca 686 static void generate_event_timer_expired(long unsigned int empty, void *data)
daniele 2:d12a891f2eca 687 {
daniele 2:d12a891f2eca 688 struct timer_callback_info *info = (struct timer_callback_info *) data;
daniele 2:d12a891f2eca 689 struct igmp_parameters params = {0};
daniele 2:d12a891f2eca 690 struct pico_frame* f = (struct pico_frame*)info->f;
daniele 2:d12a891f2eca 691 struct igmpv2_message *igmp_hdr = (struct igmpv2_message *) f->transport_hdr;
daniele 2:d12a891f2eca 692
daniele 2:d12a891f2eca 693 params.event = IGMP_EVENT_TIMER_EXPIRED;
daniele 2:d12a891f2eca 694 params.mcast_group.addr = igmp_hdr->mcast_group;
daniele 2:d12a891f2eca 695 params.timer_start = info->timer_start;
daniele 2:d12a891f2eca 696 params.f = info->f;
daniele 2:d12a891f2eca 697
daniele 2:d12a891f2eca 698 pico_igmp_process_event(&params);
daniele 2:d12a891f2eca 699 pico_free(info);
daniele 2:d12a891f2eca 700 }
daniele 2:d12a891f2eca 701
daniele 2:d12a891f2eca 702 /* state callback prototypes */
daniele 2:d12a891f2eca 703 typedef int (*callback)(struct igmp_parameters *);
daniele 2:d12a891f2eca 704
daniele 2:d12a891f2eca 705 /* stop timer, send leave if flag set */
daniele 2:d12a891f2eca 706 static int stslifs(struct igmp_parameters *params)
daniele 2:d12a891f2eca 707 {
daniele 2:d12a891f2eca 708 struct igmp_parameters *rbtparams = NULL;
daniele 2:d12a891f2eca 709
daniele 2:d12a891f2eca 710 igmp_dbg("IGMP: event = leave group | action = stop timer, send leave if flag set\n");
daniele 2:d12a891f2eca 711
daniele 2:d12a891f2eca 712 rbtparams = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 713 if (!rbtparams)
daniele 2:d12a891f2eca 714 return -1;
daniele 2:d12a891f2eca 715
daniele 2:d12a891f2eca 716 if (stop_timer(&(rbtparams->mcast_group)) < 0)
daniele 2:d12a891f2eca 717 return -1;
daniele 2:d12a891f2eca 718
daniele 2:d12a891f2eca 719 /* always send leave, even if not last host */
daniele 2:d12a891f2eca 720 if (generate_igmp_report(rbtparams) < 0)
daniele 2:d12a891f2eca 721 return -1;
daniele 2:d12a891f2eca 722 if (!rbtparams->f)
daniele 2:d12a891f2eca 723 return 0;
daniele 2:d12a891f2eca 724 if (send_membership_report(rbtparams, rbtparams->f) < 0)
daniele 2:d12a891f2eca 725 return -1;
daniele 2:d12a891f2eca 726
daniele 2:d12a891f2eca 727 /* delete from tree */
daniele 2:d12a891f2eca 728 pico_igmp_delete_parameters(rbtparams);
daniele 2:d12a891f2eca 729 igmp_dbg("IGMP: new state = non-member\n");
daniele 2:d12a891f2eca 730 return 0;
daniele 2:d12a891f2eca 731 }
daniele 2:d12a891f2eca 732
daniele 2:d12a891f2eca 733 /* send report, set flag, start timer */
daniele 2:d12a891f2eca 734 static int srsfst(struct igmp_parameters *params)
daniele 2:d12a891f2eca 735 {
daniele 2:d12a891f2eca 736 struct igmp_parameters *rbtparams = NULL;
daniele 2:d12a891f2eca 737 struct pico_frame *copy_frame = NULL;
daniele 2:d12a891f2eca 738
daniele 2:d12a891f2eca 739 igmp_dbg("IGMP: event = join group | action = send report, set flag, start timer\n");
daniele 2:d12a891f2eca 740
daniele 2:d12a891f2eca 741 rbtparams = pico_zalloc(sizeof(struct igmp_parameters));
daniele 2:d12a891f2eca 742 if (!rbtparams) {
daniele 2:d12a891f2eca 743 pico_err = PICO_ERR_ENOMEM;
daniele 2:d12a891f2eca 744 return -1;
daniele 2:d12a891f2eca 745 }
daniele 2:d12a891f2eca 746 memcpy(rbtparams, params, sizeof(struct igmp_parameters));
daniele 2:d12a891f2eca 747 rbtparams->state = IGMP_STATE_NON_MEMBER;
daniele 2:d12a891f2eca 748 rbtparams->last_host = IGMP_HOST_LAST;
daniele 2:d12a891f2eca 749 rbtparams->timer_start = TIMER_NOT_ACTIVE;
daniele 2:d12a891f2eca 750 pico_tree_insert(&IGMPParameters, rbtparams);
daniele 2:d12a891f2eca 751
daniele 2:d12a891f2eca 752 if (generate_igmp_report(rbtparams) < 0)
daniele 2:d12a891f2eca 753 return -1;
daniele 2:d12a891f2eca 754 if (!rbtparams->f)
daniele 2:d12a891f2eca 755 return 0;
daniele 2:d12a891f2eca 756 copy_frame = pico_frame_copy(rbtparams->f);
daniele 2:d12a891f2eca 757 if (!copy_frame) {
daniele 2:d12a891f2eca 758 pico_err = PICO_ERR_ENOMEM;
daniele 2:d12a891f2eca 759 return -1;
daniele 2:d12a891f2eca 760 }
daniele 2:d12a891f2eca 761 if (send_membership_report(rbtparams, copy_frame) < 0)
daniele 2:d12a891f2eca 762 return -1;
daniele 2:d12a891f2eca 763
daniele 2:d12a891f2eca 764 rbtparams->delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 100));
daniele 2:d12a891f2eca 765 if (start_timer(rbtparams, rbtparams->delay) < 0) /* XXX: change to one parameter? */
daniele 2:d12a891f2eca 766 return -1;
daniele 2:d12a891f2eca 767 rbtparams->state = IGMP_STATE_DELAYING_MEMBER;
daniele 2:d12a891f2eca 768 igmp_dbg("IGMP: new state = delaying member\n");
daniele 2:d12a891f2eca 769 return 0;
daniele 2:d12a891f2eca 770 }
daniele 2:d12a891f2eca 771
daniele 2:d12a891f2eca 772 /* merge report, send report, reset timer (IGMPv3 only) */
daniele 2:d12a891f2eca 773 static int mrsrrt(struct igmp_parameters *params)
daniele 2:d12a891f2eca 774 {
daniele 2:d12a891f2eca 775 struct igmp_parameters *rbtparams = NULL;
daniele 2:d12a891f2eca 776 struct pico_frame *copy_frame = NULL;
daniele 2:d12a891f2eca 777
daniele 2:d12a891f2eca 778 igmp_dbg("IGMP: event = update group | action = merge report, send report, reset timer (IGMPv3 only)\n");
daniele 2:d12a891f2eca 779
daniele 2:d12a891f2eca 780 rbtparams = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 781 if (!rbtparams)
daniele 2:d12a891f2eca 782 return -1;
daniele 2:d12a891f2eca 783
daniele 2:d12a891f2eca 784 if (rbtparams->mcast_router_version != PICO_IGMPV3) {
daniele 2:d12a891f2eca 785 igmp_dbg("IGMP: no IGMPv3 compatible router on network\n");
daniele 2:d12a891f2eca 786 pico_err = PICO_ERR_ENOPROTOOPT;
daniele 2:d12a891f2eca 787 return -1;
daniele 2:d12a891f2eca 788 }
daniele 2:d12a891f2eca 789
daniele 2:d12a891f2eca 790 /* XXX: merge with pending report rfc 3376 p20 */
daniele 2:d12a891f2eca 791
daniele 2:d12a891f2eca 792 if (generate_igmp_report(rbtparams) < 0)
daniele 2:d12a891f2eca 793 return -1;
daniele 2:d12a891f2eca 794 if (!rbtparams->f)
daniele 2:d12a891f2eca 795 return 0;
daniele 2:d12a891f2eca 796 copy_frame = pico_frame_copy(rbtparams->f);
daniele 2:d12a891f2eca 797 if (!copy_frame) {
daniele 2:d12a891f2eca 798 pico_err = PICO_ERR_ENOMEM;
daniele 2:d12a891f2eca 799 return -1;
daniele 2:d12a891f2eca 800 }
daniele 2:d12a891f2eca 801 if (send_membership_report(rbtparams, copy_frame) < 0)
daniele 2:d12a891f2eca 802 return -1;
daniele 2:d12a891f2eca 803
daniele 2:d12a891f2eca 804 /* XXX: reset timer */
daniele 2:d12a891f2eca 805
daniele 2:d12a891f2eca 806 rbtparams->state = IGMP_STATE_DELAYING_MEMBER;
daniele 2:d12a891f2eca 807 igmp_dbg("IGMP: new state = delaying member\n");
daniele 2:d12a891f2eca 808 return 0;
daniele 2:d12a891f2eca 809 }
daniele 2:d12a891f2eca 810
daniele 2:d12a891f2eca 811 /* send report, start timer (IGMPv3 only) */
daniele 2:d12a891f2eca 812 static int srst(struct igmp_parameters *params)
daniele 2:d12a891f2eca 813 {
daniele 2:d12a891f2eca 814 struct igmp_parameters *rbtparams = NULL;
daniele 2:d12a891f2eca 815 struct pico_frame *copy_frame = NULL;
daniele 2:d12a891f2eca 816
daniele 2:d12a891f2eca 817 igmp_dbg("IGMP: event = update group | action = send report, start timer (IGMPv3 only)\n");
daniele 2:d12a891f2eca 818
daniele 2:d12a891f2eca 819 rbtparams = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 820 if (!rbtparams)
daniele 2:d12a891f2eca 821 return -1;
daniele 2:d12a891f2eca 822
daniele 2:d12a891f2eca 823 if (rbtparams->mcast_router_version != PICO_IGMPV3) {
daniele 2:d12a891f2eca 824 igmp_dbg("IGMP: no IGMPv3 compatible router on network\n");
daniele 2:d12a891f2eca 825 pico_err = PICO_ERR_ENOPROTOOPT;
daniele 2:d12a891f2eca 826 return -1;
daniele 2:d12a891f2eca 827 }
daniele 2:d12a891f2eca 828
daniele 2:d12a891f2eca 829 if (generate_igmp_report(rbtparams) < 0)
daniele 2:d12a891f2eca 830 return -1;
daniele 2:d12a891f2eca 831 if (!rbtparams->f)
daniele 2:d12a891f2eca 832 return 0;
daniele 2:d12a891f2eca 833 copy_frame = pico_frame_copy(rbtparams->f);
daniele 2:d12a891f2eca 834 if (!copy_frame) {
daniele 2:d12a891f2eca 835 pico_err = PICO_ERR_ENOMEM;
daniele 2:d12a891f2eca 836 return -1;
daniele 2:d12a891f2eca 837 }
daniele 2:d12a891f2eca 838 if (send_membership_report(rbtparams, copy_frame) < 0)
daniele 2:d12a891f2eca 839 return -1;
daniele 2:d12a891f2eca 840
daniele 2:d12a891f2eca 841 /* XXX: start timer */
daniele 2:d12a891f2eca 842
daniele 2:d12a891f2eca 843 rbtparams->state = IGMP_STATE_DELAYING_MEMBER;
daniele 2:d12a891f2eca 844 igmp_dbg("IGMP: new state = delaying member\n");
daniele 2:d12a891f2eca 845 return 0;
daniele 2:d12a891f2eca 846 }
daniele 2:d12a891f2eca 847
daniele 2:d12a891f2eca 848 /* send leave if flag set */
daniele 2:d12a891f2eca 849 static int slifs(struct igmp_parameters *params)
daniele 2:d12a891f2eca 850 {
daniele 2:d12a891f2eca 851 struct igmp_parameters *rbtparams = NULL;
daniele 2:d12a891f2eca 852
daniele 2:d12a891f2eca 853 igmp_dbg("IGMP: event = leave group | action = send leave if flag set\n");
daniele 2:d12a891f2eca 854
daniele 2:d12a891f2eca 855 rbtparams = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 856 if (!rbtparams)
daniele 2:d12a891f2eca 857 return -1;
daniele 2:d12a891f2eca 858
daniele 2:d12a891f2eca 859 /* always send leave, even if not last host */
daniele 2:d12a891f2eca 860 if (generate_igmp_report(rbtparams) < 0)
daniele 2:d12a891f2eca 861 return -1;
daniele 2:d12a891f2eca 862 if (!rbtparams->f)
daniele 2:d12a891f2eca 863 return 0;
daniele 2:d12a891f2eca 864 if (send_membership_report(rbtparams, rbtparams->f) < 0)
daniele 2:d12a891f2eca 865 return -1;
daniele 2:d12a891f2eca 866
daniele 2:d12a891f2eca 867 /* delete from tree */
daniele 2:d12a891f2eca 868 pico_igmp_delete_parameters(rbtparams);
daniele 2:d12a891f2eca 869 igmp_dbg("IGMP: new state = non-member\n");
daniele 2:d12a891f2eca 870 return 0;
daniele 2:d12a891f2eca 871 }
daniele 2:d12a891f2eca 872
daniele 2:d12a891f2eca 873 /* start timer */
daniele 2:d12a891f2eca 874 static int st(struct igmp_parameters *params)
daniele 2:d12a891f2eca 875 {
daniele 2:d12a891f2eca 876 uint8_t ret = 0;
daniele 2:d12a891f2eca 877 struct igmp_parameters *info = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 878
daniele 2:d12a891f2eca 879 igmp_dbg("IGMP: event = query received | action = start timer\n");
daniele 2:d12a891f2eca 880
daniele 2:d12a891f2eca 881 ret |= create_igmp_frame(params, &(params->f), info->mcast_link, &(params->mcast_group), IGMP_TYPE_MEM_REPORT_V2);
daniele 2:d12a891f2eca 882 info->delay = (pico_rand() % (params->max_resp_time*100));
daniele 2:d12a891f2eca 883 ret |= start_timer(params, info->delay);
daniele 2:d12a891f2eca 884
daniele 2:d12a891f2eca 885 if (0 == ret) {
daniele 2:d12a891f2eca 886 info->state = IGMP_STATE_DELAYING_MEMBER;
daniele 2:d12a891f2eca 887 igmp_dbg("IGMP: new state = delaying member\n");
daniele 2:d12a891f2eca 888 return 0;
daniele 2:d12a891f2eca 889 } else {
daniele 2:d12a891f2eca 890 pico_err = PICO_ERR_ENOENT;
daniele 2:d12a891f2eca 891 return -1;
daniele 2:d12a891f2eca 892 }
daniele 2:d12a891f2eca 893 }
daniele 2:d12a891f2eca 894
daniele 2:d12a891f2eca 895 /* stop timer, clear flag */
daniele 2:d12a891f2eca 896 static int stcl(struct igmp_parameters *params)
daniele 2:d12a891f2eca 897 {
daniele 2:d12a891f2eca 898 uint8_t ret = 0;
daniele 2:d12a891f2eca 899 struct igmp_parameters *info = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 900
daniele 2:d12a891f2eca 901 igmp_dbg("IGMP: event = report received | action = stop timer, clear flag\n");
daniele 2:d12a891f2eca 902
daniele 2:d12a891f2eca 903 ret |= stop_timer(&(params->mcast_group));
daniele 2:d12a891f2eca 904 info->last_host = IGMP_HOST_NOT_LAST;
daniele 2:d12a891f2eca 905
daniele 2:d12a891f2eca 906 if (0 == ret) {
daniele 2:d12a891f2eca 907 info->state = IGMP_STATE_IDLE_MEMBER;
daniele 2:d12a891f2eca 908 igmp_dbg("IGMP: new state = idle member\n");
daniele 2:d12a891f2eca 909 return 0;
daniele 2:d12a891f2eca 910 } else {
daniele 2:d12a891f2eca 911 pico_err = PICO_ERR_ENOENT;
daniele 2:d12a891f2eca 912 return -1;
daniele 2:d12a891f2eca 913 }
daniele 2:d12a891f2eca 914 }
daniele 2:d12a891f2eca 915
daniele 2:d12a891f2eca 916 /* send report, set flag */
daniele 2:d12a891f2eca 917 static int srsf(struct igmp_parameters *params)
daniele 2:d12a891f2eca 918 {
daniele 2:d12a891f2eca 919 uint8_t ret = 0;
daniele 2:d12a891f2eca 920 struct igmp_parameters *info = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 921
daniele 2:d12a891f2eca 922 igmp_dbg("IGMP: event = timer expired | action = send report, set flag\n");
daniele 2:d12a891f2eca 923
daniele 2:d12a891f2eca 924 /* start time of parameter == start time of expired timer? */
daniele 2:d12a891f2eca 925 if (info->timer_start == params->timer_start) {
daniele 2:d12a891f2eca 926 ret |= send_membership_report(params, params->f);
daniele 2:d12a891f2eca 927 } else {
daniele 2:d12a891f2eca 928 pico_frame_discard(params->f);
daniele 2:d12a891f2eca 929 }
daniele 2:d12a891f2eca 930
daniele 2:d12a891f2eca 931 if (0 == ret) {
daniele 2:d12a891f2eca 932 info->state = IGMP_STATE_IDLE_MEMBER;
daniele 2:d12a891f2eca 933 igmp_dbg("IGMP: new state = idle member\n");
daniele 2:d12a891f2eca 934 return 0;
daniele 2:d12a891f2eca 935 } else {
daniele 2:d12a891f2eca 936 pico_err = PICO_ERR_ENOENT;
daniele 2:d12a891f2eca 937 return -1;
daniele 2:d12a891f2eca 938 }
daniele 2:d12a891f2eca 939 }
daniele 2:d12a891f2eca 940
daniele 2:d12a891f2eca 941 /* reset timer if max response time < current timer */
daniele 2:d12a891f2eca 942 static int rtimrtct(struct igmp_parameters *params)
daniele 2:d12a891f2eca 943 {
daniele 2:d12a891f2eca 944 uint8_t ret = 0;
daniele 2:d12a891f2eca 945 struct igmp_parameters *info = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 946 unsigned long current_time_left = ((unsigned long)info->delay - (PICO_TIME_MS() - (unsigned long)info->timer_start));
daniele 2:d12a891f2eca 947
daniele 2:d12a891f2eca 948 igmp_dbg("IGMP: event = query received | action = reset timer if max response time < current timer\n");
daniele 2:d12a891f2eca 949
daniele 2:d12a891f2eca 950 if (((unsigned long)(params->max_resp_time * 100)) < current_time_left) {
daniele 2:d12a891f2eca 951 ret |= create_igmp_frame(params, &(params->f), params->mcast_link, &(params->mcast_group), IGMP_TYPE_MEM_REPORT_V2);
daniele 2:d12a891f2eca 952 ret |= reset_timer(params);
daniele 2:d12a891f2eca 953 }
daniele 2:d12a891f2eca 954
daniele 2:d12a891f2eca 955 if (0 == ret) {
daniele 2:d12a891f2eca 956 info->state = IGMP_STATE_DELAYING_MEMBER;
daniele 2:d12a891f2eca 957 igmp_dbg("IGMP: new state = delaying member\n");
daniele 2:d12a891f2eca 958 return 0;
daniele 2:d12a891f2eca 959 } else {
daniele 2:d12a891f2eca 960 pico_err = PICO_ERR_ENOENT;
daniele 2:d12a891f2eca 961 return -1;
daniele 2:d12a891f2eca 962 }
daniele 2:d12a891f2eca 963 }
daniele 2:d12a891f2eca 964
daniele 2:d12a891f2eca 965 static int discard(struct igmp_parameters *params){
daniele 2:d12a891f2eca 966 igmp_dbg("IGMP: ignore and discard frame\n");
daniele 2:d12a891f2eca 967 pico_frame_discard(params->f);
daniele 2:d12a891f2eca 968 return 0;
daniele 2:d12a891f2eca 969 }
daniele 2:d12a891f2eca 970
daniele 2:d12a891f2eca 971 static int err_non(struct igmp_parameters *params){
daniele 2:d12a891f2eca 972 igmp_dbg("IGMP ERROR: state = non-member, event = %u\n", params->event);
daniele 2:d12a891f2eca 973 pico_err = PICO_ERR_ENOENT;
daniele 2:d12a891f2eca 974 return -1;
daniele 2:d12a891f2eca 975 }
daniele 2:d12a891f2eca 976
daniele 2:d12a891f2eca 977 /* finite state machine table */
daniele 2:d12a891f2eca 978 const callback host_membership_diagram_table[3][6] =
daniele 2:d12a891f2eca 979 { /* event |Delete Group |Create Group |Update Group |Query Received |Report Received |Timer Expired */
daniele 2:d12a891f2eca 980 /* state Non-Member */ { err_non, srsfst, srsfst, discard, err_non, discard },
daniele 2:d12a891f2eca 981 /* state Delaying Member */ { stslifs, mrsrrt, mrsrrt, rtimrtct, stcl, srsf },
daniele 2:d12a891f2eca 982 /* state Idle Member */ { slifs, srst, srst, st, discard, discard }
daniele 2:d12a891f2eca 983 };
daniele 2:d12a891f2eca 984
daniele 2:d12a891f2eca 985 static int pico_igmp_process_event(struct igmp_parameters *params)
daniele 2:d12a891f2eca 986 {
daniele 2:d12a891f2eca 987 struct pico_tree_node *index;
daniele 2:d12a891f2eca 988 uint8_t ret = 0;
daniele 2:d12a891f2eca 989 struct igmp_parameters *info = pico_igmp_find_parameters(&(params->mcast_group));
daniele 2:d12a891f2eca 990
daniele 2:d12a891f2eca 991 igmp_dbg("IGMP: process event on group address %08X\n", params->mcast_group.addr);
daniele 2:d12a891f2eca 992 if (NULL == info) {
daniele 2:d12a891f2eca 993 if (params->event == IGMP_EVENT_QUERY_RECV) { /* general query (mcast_group field is zero) */
daniele 2:d12a891f2eca 994 pico_tree_foreach(index,&IGMPParameters) {
daniele 2:d12a891f2eca 995 info = index->keyValue;
daniele 2:d12a891f2eca 996 params->mcast_link.addr = info->mcast_link.addr;
daniele 2:d12a891f2eca 997 params->mcast_group.addr = info->mcast_group.addr;
daniele 2:d12a891f2eca 998 igmp_dbg("IGMP: for each mcast_group = %08X | state = %u\n", params->mcast_group.addr, info->state);
daniele 2:d12a891f2eca 999 ret |= host_membership_diagram_table[info->state][params->event](params);
daniele 2:d12a891f2eca 1000 }
daniele 2:d12a891f2eca 1001 } else { /* first time this group enters the state diagram */
daniele 2:d12a891f2eca 1002 igmp_dbg("IGMP: state = Non-Member\n");
daniele 2:d12a891f2eca 1003 ret |= host_membership_diagram_table[IGMP_STATE_NON_MEMBER][params->event](params);
daniele 2:d12a891f2eca 1004 }
daniele 2:d12a891f2eca 1005 } else {
daniele 2:d12a891f2eca 1006 igmp_dbg("IGMP: state = %u (0: non-member - 1: delaying member - 2: idle member)\n", info->state);
daniele 2:d12a891f2eca 1007 ret |= host_membership_diagram_table[info->state][params->event](params);
daniele 2:d12a891f2eca 1008 }
daniele 2:d12a891f2eca 1009
daniele 2:d12a891f2eca 1010 if( 0 == ret) {
daniele 2:d12a891f2eca 1011 return 0;
daniele 2:d12a891f2eca 1012 } else {
daniele 2:d12a891f2eca 1013 igmp_dbg("IGMP ERROR: pico_igmp_process_event failed!\n");
daniele 2:d12a891f2eca 1014 return -1;
daniele 2:d12a891f2eca 1015 }
daniele 2:d12a891f2eca 1016 }
daniele 2:d12a891f2eca 1017