Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
segundo 0:ac1725ba162c 1 #pragma diag_remark 177
segundo 0:ac1725ba162c 2 /**
segundo 0:ac1725ba162c 3 * @file
segundo 0:ac1725ba162c 4 * IGMP - Internet Group Management Protocol
segundo 0:ac1725ba162c 5 *
segundo 0:ac1725ba162c 6 */
segundo 0:ac1725ba162c 7
segundo 0:ac1725ba162c 8 /*
segundo 0:ac1725ba162c 9 * Copyright (c) 2002 CITEL Technologies Ltd.
segundo 0:ac1725ba162c 10 * All rights reserved.
segundo 0:ac1725ba162c 11 *
segundo 0:ac1725ba162c 12 * Redistribution and use in source and binary forms, with or without
segundo 0:ac1725ba162c 13 * modification, are permitted provided that the following conditions
segundo 0:ac1725ba162c 14 * are met:
segundo 0:ac1725ba162c 15 * 1. Redistributions of source code must retain the above copyright
segundo 0:ac1725ba162c 16 * notice, this list of conditions and the following disclaimer.
segundo 0:ac1725ba162c 17 * 2. Redistributions in binary form must reproduce the above copyright
segundo 0:ac1725ba162c 18 * notice, this list of conditions and the following disclaimer in the
segundo 0:ac1725ba162c 19 * documentation and/or other materials provided with the distribution.
segundo 0:ac1725ba162c 20 * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
segundo 0:ac1725ba162c 21 * may be used to endorse or promote products derived from this software
segundo 0:ac1725ba162c 22 * without specific prior written permission.
segundo 0:ac1725ba162c 23 *
segundo 0:ac1725ba162c 24 * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
segundo 0:ac1725ba162c 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
segundo 0:ac1725ba162c 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
segundo 0:ac1725ba162c 27 * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
segundo 0:ac1725ba162c 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
segundo 0:ac1725ba162c 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
segundo 0:ac1725ba162c 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
segundo 0:ac1725ba162c 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
segundo 0:ac1725ba162c 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
segundo 0:ac1725ba162c 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
segundo 0:ac1725ba162c 34 * SUCH DAMAGE.
segundo 0:ac1725ba162c 35 *
segundo 0:ac1725ba162c 36 * This file is a contribution to the lwIP TCP/IP stack.
segundo 0:ac1725ba162c 37 * The Swedish Institute of Computer Science and Adam Dunkels
segundo 0:ac1725ba162c 38 * are specifically granted permission to redistribute this
segundo 0:ac1725ba162c 39 * source code.
segundo 0:ac1725ba162c 40 */
segundo 0:ac1725ba162c 41
segundo 0:ac1725ba162c 42 /*-------------------------------------------------------------
segundo 0:ac1725ba162c 43 Note 1)
segundo 0:ac1725ba162c 44 Although the rfc requires V1 AND V2 capability
segundo 0:ac1725ba162c 45 we will only support v2 since now V1 is very old (August 1989)
segundo 0:ac1725ba162c 46 V1 can be added if required
segundo 0:ac1725ba162c 47
segundo 0:ac1725ba162c 48 a debug print and statistic have been implemented to
segundo 0:ac1725ba162c 49 show this up.
segundo 0:ac1725ba162c 50 -------------------------------------------------------------
segundo 0:ac1725ba162c 51 -------------------------------------------------------------
segundo 0:ac1725ba162c 52 Note 2)
segundo 0:ac1725ba162c 53 A query for a specific group address (as opposed to ALLHOSTS)
segundo 0:ac1725ba162c 54 has now been implemented as I am unsure if it is required
segundo 0:ac1725ba162c 55
segundo 0:ac1725ba162c 56 a debug print and statistic have been implemented to
segundo 0:ac1725ba162c 57 show this up.
segundo 0:ac1725ba162c 58 -------------------------------------------------------------
segundo 0:ac1725ba162c 59 -------------------------------------------------------------
segundo 0:ac1725ba162c 60 Note 3)
segundo 0:ac1725ba162c 61 The router alert rfc 2113 is implemented in outgoing packets
segundo 0:ac1725ba162c 62 but not checked rigorously incoming
segundo 0:ac1725ba162c 63 -------------------------------------------------------------
segundo 0:ac1725ba162c 64 Steve Reynolds
segundo 0:ac1725ba162c 65 ------------------------------------------------------------*/
segundo 0:ac1725ba162c 66
segundo 0:ac1725ba162c 67 /*-----------------------------------------------------------------------------
segundo 0:ac1725ba162c 68 * RFC 988 - Host extensions for IP multicasting - V0
segundo 0:ac1725ba162c 69 * RFC 1054 - Host extensions for IP multicasting -
segundo 0:ac1725ba162c 70 * RFC 1112 - Host extensions for IP multicasting - V1
segundo 0:ac1725ba162c 71 * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
segundo 0:ac1725ba162c 72 * RFC 3376 - Internet Group Management Protocol, Version 3 - V3
segundo 0:ac1725ba162c 73 * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
segundo 0:ac1725ba162c 74 * RFC 2113 - IP Router Alert Option -
segundo 0:ac1725ba162c 75 *----------------------------------------------------------------------------*/
segundo 0:ac1725ba162c 76
segundo 0:ac1725ba162c 77 /*-----------------------------------------------------------------------------
segundo 0:ac1725ba162c 78 * Includes
segundo 0:ac1725ba162c 79 *----------------------------------------------------------------------------*/
segundo 0:ac1725ba162c 80
segundo 0:ac1725ba162c 81 #include "lwip/opt.h"
segundo 0:ac1725ba162c 82
segundo 0:ac1725ba162c 83 #if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
segundo 0:ac1725ba162c 84
segundo 0:ac1725ba162c 85 #include "lwip/igmp.h"
segundo 0:ac1725ba162c 86 #include "lwip/debug.h"
segundo 0:ac1725ba162c 87 #include "lwip/def.h"
segundo 0:ac1725ba162c 88 #include "lwip/mem.h"
segundo 0:ac1725ba162c 89 #include "lwip/ip.h"
segundo 0:ac1725ba162c 90 #include "lwip/inet_chksum.h"
segundo 0:ac1725ba162c 91 #include "lwip/netif.h"
segundo 0:ac1725ba162c 92 #include "lwip/icmp.h"
segundo 0:ac1725ba162c 93 #include "lwip/udp.h"
segundo 0:ac1725ba162c 94 #include "lwip/tcp.h"
segundo 0:ac1725ba162c 95 #include "lwip/stats.h"
segundo 0:ac1725ba162c 96
segundo 0:ac1725ba162c 97 #include "string.h"
segundo 0:ac1725ba162c 98
segundo 0:ac1725ba162c 99 /*
segundo 0:ac1725ba162c 100 * IGMP constants
segundo 0:ac1725ba162c 101 */
segundo 0:ac1725ba162c 102 #define IGMP_TTL 1
segundo 0:ac1725ba162c 103 #define IGMP_MINLEN 8
segundo 0:ac1725ba162c 104 #define ROUTER_ALERT 0x9404
segundo 0:ac1725ba162c 105 #define ROUTER_ALERTLEN 4
segundo 0:ac1725ba162c 106
segundo 0:ac1725ba162c 107 /*
segundo 0:ac1725ba162c 108 * IGMP message types, including version number.
segundo 0:ac1725ba162c 109 */
segundo 0:ac1725ba162c 110 #define IGMP_MEMB_QUERY 0x11 /* Membership query */
segundo 0:ac1725ba162c 111 #define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
segundo 0:ac1725ba162c 112 #define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
segundo 0:ac1725ba162c 113 #define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
segundo 0:ac1725ba162c 114
segundo 0:ac1725ba162c 115 /* Group membership states */
segundo 0:ac1725ba162c 116 #define IGMP_GROUP_NON_MEMBER 0
segundo 0:ac1725ba162c 117 #define IGMP_GROUP_DELAYING_MEMBER 1
segundo 0:ac1725ba162c 118 #define IGMP_GROUP_IDLE_MEMBER 2
segundo 0:ac1725ba162c 119
segundo 0:ac1725ba162c 120 /**
segundo 0:ac1725ba162c 121 * IGMP packet format.
segundo 0:ac1725ba162c 122 */
segundo 0:ac1725ba162c 123 #ifdef PACK_STRUCT_USE_INCLUDES
segundo 0:ac1725ba162c 124 # include "arch/bpstruct.h"
segundo 0:ac1725ba162c 125 #endif
segundo 0:ac1725ba162c 126 PACK_STRUCT_BEGIN
segundo 0:ac1725ba162c 127 struct igmp_msg {
segundo 0:ac1725ba162c 128 PACK_STRUCT_FIELD(u8_t igmp_msgtype);
segundo 0:ac1725ba162c 129 PACK_STRUCT_FIELD(u8_t igmp_maxresp);
segundo 0:ac1725ba162c 130 PACK_STRUCT_FIELD(u16_t igmp_checksum);
segundo 0:ac1725ba162c 131 PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
segundo 0:ac1725ba162c 132 } PACK_STRUCT_STRUCT;
segundo 0:ac1725ba162c 133 PACK_STRUCT_END
segundo 0:ac1725ba162c 134 #ifdef PACK_STRUCT_USE_INCLUDES
segundo 0:ac1725ba162c 135 # include "arch/epstruct.h"
segundo 0:ac1725ba162c 136 #endif
segundo 0:ac1725ba162c 137
segundo 0:ac1725ba162c 138
segundo 0:ac1725ba162c 139 static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
segundo 0:ac1725ba162c 140 static err_t igmp_remove_group(struct igmp_group *group);
segundo 0:ac1725ba162c 141 static void igmp_timeout( struct igmp_group *group);
segundo 0:ac1725ba162c 142 static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
segundo 0:ac1725ba162c 143 static void igmp_stop_timer(struct igmp_group *group);
segundo 0:ac1725ba162c 144 static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
segundo 0:ac1725ba162c 145 static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
segundo 0:ac1725ba162c 146 static void igmp_send(struct igmp_group *group, u8_t type);
segundo 0:ac1725ba162c 147
segundo 0:ac1725ba162c 148
segundo 0:ac1725ba162c 149 static struct igmp_group* igmp_group_list;
segundo 0:ac1725ba162c 150 static ip_addr_t allsystems;
segundo 0:ac1725ba162c 151 static ip_addr_t allrouters;
segundo 0:ac1725ba162c 152
segundo 0:ac1725ba162c 153
segundo 0:ac1725ba162c 154 /**
segundo 0:ac1725ba162c 155 * Initialize the IGMP module
segundo 0:ac1725ba162c 156 */
segundo 0:ac1725ba162c 157 void
segundo 0:ac1725ba162c 158 igmp_init(void)
segundo 0:ac1725ba162c 159 {
segundo 0:ac1725ba162c 160 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
segundo 0:ac1725ba162c 161
segundo 0:ac1725ba162c 162 IP4_ADDR(&allsystems, 224, 0, 0, 1);
segundo 0:ac1725ba162c 163 IP4_ADDR(&allrouters, 224, 0, 0, 2);
segundo 0:ac1725ba162c 164 }
segundo 0:ac1725ba162c 165
segundo 0:ac1725ba162c 166 #ifdef LWIP_DEBUG
segundo 0:ac1725ba162c 167 /**
segundo 0:ac1725ba162c 168 * Dump global IGMP groups list
segundo 0:ac1725ba162c 169 */
segundo 0:ac1725ba162c 170 void
segundo 0:ac1725ba162c 171 igmp_dump_group_list()
segundo 0:ac1725ba162c 172 {
segundo 0:ac1725ba162c 173 struct igmp_group *group = igmp_group_list;
segundo 0:ac1725ba162c 174
segundo 0:ac1725ba162c 175 while (group != NULL) {
segundo 0:ac1725ba162c 176 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
segundo 0:ac1725ba162c 177 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
segundo 0:ac1725ba162c 178 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
segundo 0:ac1725ba162c 179 group = group->next;
segundo 0:ac1725ba162c 180 }
segundo 0:ac1725ba162c 181 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
segundo 0:ac1725ba162c 182 }
segundo 0:ac1725ba162c 183 #else
segundo 0:ac1725ba162c 184 #define igmp_dump_group_list()
segundo 0:ac1725ba162c 185 #endif /* LWIP_DEBUG */
segundo 0:ac1725ba162c 186
segundo 0:ac1725ba162c 187 /**
segundo 0:ac1725ba162c 188 * Start IGMP processing on interface
segundo 0:ac1725ba162c 189 *
segundo 0:ac1725ba162c 190 * @param netif network interface on which start IGMP processing
segundo 0:ac1725ba162c 191 */
segundo 0:ac1725ba162c 192 err_t
segundo 0:ac1725ba162c 193 igmp_start(struct netif *netif)
segundo 0:ac1725ba162c 194 {
segundo 0:ac1725ba162c 195 struct igmp_group* group;
segundo 0:ac1725ba162c 196
segundo 0:ac1725ba162c 197 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
segundo 0:ac1725ba162c 198
segundo 0:ac1725ba162c 199 group = igmp_lookup_group(netif, &allsystems);
segundo 0:ac1725ba162c 200
segundo 0:ac1725ba162c 201 if (group != NULL) {
segundo 0:ac1725ba162c 202 group->group_state = IGMP_GROUP_IDLE_MEMBER;
segundo 0:ac1725ba162c 203 group->use++;
segundo 0:ac1725ba162c 204
segundo 0:ac1725ba162c 205 /* Allow the igmp messages at the MAC level */
segundo 0:ac1725ba162c 206 if (netif->igmp_mac_filter != NULL) {
segundo 0:ac1725ba162c 207 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
segundo 0:ac1725ba162c 208 ip_addr_debug_print(IGMP_DEBUG, &allsystems);
segundo 0:ac1725ba162c 209 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
segundo 0:ac1725ba162c 210 netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
segundo 0:ac1725ba162c 211 }
segundo 0:ac1725ba162c 212
segundo 0:ac1725ba162c 213 return ERR_OK;
segundo 0:ac1725ba162c 214 }
segundo 0:ac1725ba162c 215
segundo 0:ac1725ba162c 216 return ERR_MEM;
segundo 0:ac1725ba162c 217 }
segundo 0:ac1725ba162c 218
segundo 0:ac1725ba162c 219 /**
segundo 0:ac1725ba162c 220 * Stop IGMP processing on interface
segundo 0:ac1725ba162c 221 *
segundo 0:ac1725ba162c 222 * @param netif network interface on which stop IGMP processing
segundo 0:ac1725ba162c 223 */
segundo 0:ac1725ba162c 224 err_t
segundo 0:ac1725ba162c 225 igmp_stop(struct netif *netif)
segundo 0:ac1725ba162c 226 {
segundo 0:ac1725ba162c 227 struct igmp_group *group = igmp_group_list;
segundo 0:ac1725ba162c 228 struct igmp_group *prev = NULL;
segundo 0:ac1725ba162c 229 struct igmp_group *next;
segundo 0:ac1725ba162c 230
segundo 0:ac1725ba162c 231 /* look for groups joined on this interface further down the list */
segundo 0:ac1725ba162c 232 while (group != NULL) {
segundo 0:ac1725ba162c 233 next = group->next;
segundo 0:ac1725ba162c 234 /* is it a group joined on this interface? */
segundo 0:ac1725ba162c 235 if (group->netif == netif) {
segundo 0:ac1725ba162c 236 /* is it the first group of the list? */
segundo 0:ac1725ba162c 237 if (group == igmp_group_list) {
segundo 0:ac1725ba162c 238 igmp_group_list = next;
segundo 0:ac1725ba162c 239 }
segundo 0:ac1725ba162c 240 /* is there a "previous" group defined? */
segundo 0:ac1725ba162c 241 if (prev != NULL) {
segundo 0:ac1725ba162c 242 prev->next = next;
segundo 0:ac1725ba162c 243 }
segundo 0:ac1725ba162c 244 /* disable the group at the MAC level */
segundo 0:ac1725ba162c 245 if (netif->igmp_mac_filter != NULL) {
segundo 0:ac1725ba162c 246 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
segundo 0:ac1725ba162c 247 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
segundo 0:ac1725ba162c 248 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
segundo 0:ac1725ba162c 249 netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
segundo 0:ac1725ba162c 250 }
segundo 0:ac1725ba162c 251 /* free group */
segundo 0:ac1725ba162c 252 memp_free(MEMP_IGMP_GROUP, group);
segundo 0:ac1725ba162c 253 } else {
segundo 0:ac1725ba162c 254 /* change the "previous" */
segundo 0:ac1725ba162c 255 prev = group;
segundo 0:ac1725ba162c 256 }
segundo 0:ac1725ba162c 257 /* move to "next" */
segundo 0:ac1725ba162c 258 group = next;
segundo 0:ac1725ba162c 259 }
segundo 0:ac1725ba162c 260 return ERR_OK;
segundo 0:ac1725ba162c 261 }
segundo 0:ac1725ba162c 262
segundo 0:ac1725ba162c 263 /**
segundo 0:ac1725ba162c 264 * Report IGMP memberships for this interface
segundo 0:ac1725ba162c 265 *
segundo 0:ac1725ba162c 266 * @param netif network interface on which report IGMP memberships
segundo 0:ac1725ba162c 267 */
segundo 0:ac1725ba162c 268 void
segundo 0:ac1725ba162c 269 igmp_report_groups(struct netif *netif)
segundo 0:ac1725ba162c 270 {
segundo 0:ac1725ba162c 271 struct igmp_group *group = igmp_group_list;
segundo 0:ac1725ba162c 272
segundo 0:ac1725ba162c 273 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
segundo 0:ac1725ba162c 274
segundo 0:ac1725ba162c 275 while (group != NULL) {
segundo 0:ac1725ba162c 276 if (group->netif == netif) {
segundo 0:ac1725ba162c 277 igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
segundo 0:ac1725ba162c 278 }
segundo 0:ac1725ba162c 279 group = group->next;
segundo 0:ac1725ba162c 280 }
segundo 0:ac1725ba162c 281 }
segundo 0:ac1725ba162c 282
segundo 0:ac1725ba162c 283 /**
segundo 0:ac1725ba162c 284 * Search for a group in the global igmp_group_list
segundo 0:ac1725ba162c 285 *
segundo 0:ac1725ba162c 286 * @param ifp the network interface for which to look
segundo 0:ac1725ba162c 287 * @param addr the group ip address to search for
segundo 0:ac1725ba162c 288 * @return a struct igmp_group* if the group has been found,
segundo 0:ac1725ba162c 289 * NULL if the group wasn't found.
segundo 0:ac1725ba162c 290 */
segundo 0:ac1725ba162c 291 struct igmp_group *
segundo 0:ac1725ba162c 292 igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
segundo 0:ac1725ba162c 293 {
segundo 0:ac1725ba162c 294 struct igmp_group *group = igmp_group_list;
segundo 0:ac1725ba162c 295
segundo 0:ac1725ba162c 296 while (group != NULL) {
segundo 0:ac1725ba162c 297 if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
segundo 0:ac1725ba162c 298 return group;
segundo 0:ac1725ba162c 299 }
segundo 0:ac1725ba162c 300 group = group->next;
segundo 0:ac1725ba162c 301 }
segundo 0:ac1725ba162c 302
segundo 0:ac1725ba162c 303 /* to be clearer, we return NULL here instead of
segundo 0:ac1725ba162c 304 * 'group' (which is also NULL at this point).
segundo 0:ac1725ba162c 305 */
segundo 0:ac1725ba162c 306 return NULL;
segundo 0:ac1725ba162c 307 }
segundo 0:ac1725ba162c 308
segundo 0:ac1725ba162c 309 /**
segundo 0:ac1725ba162c 310 * Search for a specific igmp group and create a new one if not found-
segundo 0:ac1725ba162c 311 *
segundo 0:ac1725ba162c 312 * @param ifp the network interface for which to look
segundo 0:ac1725ba162c 313 * @param addr the group ip address to search
segundo 0:ac1725ba162c 314 * @return a struct igmp_group*,
segundo 0:ac1725ba162c 315 * NULL on memory error.
segundo 0:ac1725ba162c 316 */
segundo 0:ac1725ba162c 317 struct igmp_group *
segundo 0:ac1725ba162c 318 igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
segundo 0:ac1725ba162c 319 {
segundo 0:ac1725ba162c 320 struct igmp_group *group = igmp_group_list;
segundo 0:ac1725ba162c 321
segundo 0:ac1725ba162c 322 /* Search if the group already exists */
segundo 0:ac1725ba162c 323 group = igmp_lookfor_group(ifp, addr);
segundo 0:ac1725ba162c 324 if (group != NULL) {
segundo 0:ac1725ba162c 325 /* Group already exists. */
segundo 0:ac1725ba162c 326 return group;
segundo 0:ac1725ba162c 327 }
segundo 0:ac1725ba162c 328
segundo 0:ac1725ba162c 329 /* Group doesn't exist yet, create a new one */
segundo 0:ac1725ba162c 330 group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
segundo 0:ac1725ba162c 331 if (group != NULL) {
segundo 0:ac1725ba162c 332 group->netif = ifp;
segundo 0:ac1725ba162c 333 ip_addr_set(&(group->group_address), addr);
segundo 0:ac1725ba162c 334 group->timer = 0; /* Not running */
segundo 0:ac1725ba162c 335 group->group_state = IGMP_GROUP_NON_MEMBER;
segundo 0:ac1725ba162c 336 group->last_reporter_flag = 0;
segundo 0:ac1725ba162c 337 group->use = 0;
segundo 0:ac1725ba162c 338 group->next = igmp_group_list;
segundo 0:ac1725ba162c 339
segundo 0:ac1725ba162c 340 igmp_group_list = group;
segundo 0:ac1725ba162c 341 }
segundo 0:ac1725ba162c 342
segundo 0:ac1725ba162c 343 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
segundo 0:ac1725ba162c 344 ip_addr_debug_print(IGMP_DEBUG, addr);
segundo 0:ac1725ba162c 345 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
segundo 0:ac1725ba162c 346
segundo 0:ac1725ba162c 347 return group;
segundo 0:ac1725ba162c 348 }
segundo 0:ac1725ba162c 349
segundo 0:ac1725ba162c 350 /**
segundo 0:ac1725ba162c 351 * Remove a group in the global igmp_group_list
segundo 0:ac1725ba162c 352 *
segundo 0:ac1725ba162c 353 * @param group the group to remove from the global igmp_group_list
segundo 0:ac1725ba162c 354 * @return ERR_OK if group was removed from the list, an err_t otherwise
segundo 0:ac1725ba162c 355 */
segundo 0:ac1725ba162c 356 static err_t
segundo 0:ac1725ba162c 357 igmp_remove_group(struct igmp_group *group)
segundo 0:ac1725ba162c 358 {
segundo 0:ac1725ba162c 359 err_t err = ERR_OK;
segundo 0:ac1725ba162c 360
segundo 0:ac1725ba162c 361 /* Is it the first group? */
segundo 0:ac1725ba162c 362 if (igmp_group_list == group) {
segundo 0:ac1725ba162c 363 igmp_group_list = group->next;
segundo 0:ac1725ba162c 364 } else {
segundo 0:ac1725ba162c 365 /* look for group further down the list */
segundo 0:ac1725ba162c 366 struct igmp_group *tmpGroup;
segundo 0:ac1725ba162c 367 for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
segundo 0:ac1725ba162c 368 if (tmpGroup->next == group) {
segundo 0:ac1725ba162c 369 tmpGroup->next = group->next;
segundo 0:ac1725ba162c 370 break;
segundo 0:ac1725ba162c 371 }
segundo 0:ac1725ba162c 372 }
segundo 0:ac1725ba162c 373 /* Group not found in the global igmp_group_list */
segundo 0:ac1725ba162c 374 if (tmpGroup == NULL)
segundo 0:ac1725ba162c 375 err = ERR_ARG;
segundo 0:ac1725ba162c 376 }
segundo 0:ac1725ba162c 377 /* free group */
segundo 0:ac1725ba162c 378 memp_free(MEMP_IGMP_GROUP, group);
segundo 0:ac1725ba162c 379
segundo 0:ac1725ba162c 380 return err;
segundo 0:ac1725ba162c 381 }
segundo 0:ac1725ba162c 382
segundo 0:ac1725ba162c 383 /**
segundo 0:ac1725ba162c 384 * Called from ip_input() if a new IGMP packet is received.
segundo 0:ac1725ba162c 385 *
segundo 0:ac1725ba162c 386 * @param p received igmp packet, p->payload pointing to the ip header
segundo 0:ac1725ba162c 387 * @param inp network interface on which the packet was received
segundo 0:ac1725ba162c 388 * @param dest destination ip address of the igmp packet
segundo 0:ac1725ba162c 389 */
segundo 0:ac1725ba162c 390 void
segundo 0:ac1725ba162c 391 igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
segundo 0:ac1725ba162c 392 {
segundo 0:ac1725ba162c 393 struct ip_hdr * iphdr;
segundo 0:ac1725ba162c 394 struct igmp_msg* igmp;
segundo 0:ac1725ba162c 395 struct igmp_group* group;
segundo 0:ac1725ba162c 396 struct igmp_group* groupref;
segundo 0:ac1725ba162c 397
segundo 0:ac1725ba162c 398 IGMP_STATS_INC(igmp.recv);
segundo 0:ac1725ba162c 399
segundo 0:ac1725ba162c 400 /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
segundo 0:ac1725ba162c 401 iphdr = (struct ip_hdr *)p->payload;
segundo 0:ac1725ba162c 402 if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
segundo 0:ac1725ba162c 403 pbuf_free(p);
segundo 0:ac1725ba162c 404 IGMP_STATS_INC(igmp.lenerr);
segundo 0:ac1725ba162c 405 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
segundo 0:ac1725ba162c 406 return;
segundo 0:ac1725ba162c 407 }
segundo 0:ac1725ba162c 408
segundo 0:ac1725ba162c 409 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
segundo 0:ac1725ba162c 410 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
segundo 0:ac1725ba162c 411 LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
segundo 0:ac1725ba162c 412 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
segundo 0:ac1725ba162c 413 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
segundo 0:ac1725ba162c 414
segundo 0:ac1725ba162c 415 /* Now calculate and check the checksum */
segundo 0:ac1725ba162c 416 igmp = (struct igmp_msg *)p->payload;
segundo 0:ac1725ba162c 417 if (inet_chksum(igmp, p->len)) {
segundo 0:ac1725ba162c 418 pbuf_free(p);
segundo 0:ac1725ba162c 419 IGMP_STATS_INC(igmp.chkerr);
segundo 0:ac1725ba162c 420 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
segundo 0:ac1725ba162c 421 return;
segundo 0:ac1725ba162c 422 }
segundo 0:ac1725ba162c 423
segundo 0:ac1725ba162c 424 /* Packet is ok so find an existing group */
segundo 0:ac1725ba162c 425 group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
segundo 0:ac1725ba162c 426
segundo 0:ac1725ba162c 427 /* If group can be found or create... */
segundo 0:ac1725ba162c 428 if (!group) {
segundo 0:ac1725ba162c 429 pbuf_free(p);
segundo 0:ac1725ba162c 430 IGMP_STATS_INC(igmp.drop);
segundo 0:ac1725ba162c 431 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
segundo 0:ac1725ba162c 432 return;
segundo 0:ac1725ba162c 433 }
segundo 0:ac1725ba162c 434
segundo 0:ac1725ba162c 435 /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
segundo 0:ac1725ba162c 436 switch (igmp->igmp_msgtype) {
segundo 0:ac1725ba162c 437 case IGMP_MEMB_QUERY: {
segundo 0:ac1725ba162c 438 /* IGMP_MEMB_QUERY to the "all systems" address ? */
segundo 0:ac1725ba162c 439 if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
segundo 0:ac1725ba162c 440 /* THIS IS THE GENERAL QUERY */
segundo 0:ac1725ba162c 441 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
segundo 0:ac1725ba162c 442
segundo 0:ac1725ba162c 443 if (igmp->igmp_maxresp == 0) {
segundo 0:ac1725ba162c 444 IGMP_STATS_INC(igmp.rx_v1);
segundo 0:ac1725ba162c 445 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
segundo 0:ac1725ba162c 446 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
segundo 0:ac1725ba162c 447 } else {
segundo 0:ac1725ba162c 448 IGMP_STATS_INC(igmp.rx_general);
segundo 0:ac1725ba162c 449 }
segundo 0:ac1725ba162c 450
segundo 0:ac1725ba162c 451 groupref = igmp_group_list;
segundo 0:ac1725ba162c 452 while (groupref) {
segundo 0:ac1725ba162c 453 /* Do not send messages on the all systems group address! */
segundo 0:ac1725ba162c 454 if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
segundo 0:ac1725ba162c 455 igmp_delaying_member(groupref, igmp->igmp_maxresp);
segundo 0:ac1725ba162c 456 }
segundo 0:ac1725ba162c 457 groupref = groupref->next;
segundo 0:ac1725ba162c 458 }
segundo 0:ac1725ba162c 459 } else {
segundo 0:ac1725ba162c 460 /* IGMP_MEMB_QUERY to a specific group ? */
segundo 0:ac1725ba162c 461 if (!ip_addr_isany(&igmp->igmp_group_address)) {
segundo 0:ac1725ba162c 462 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
segundo 0:ac1725ba162c 463 ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
segundo 0:ac1725ba162c 464 if (ip_addr_cmp(dest, &allsystems)) {
segundo 0:ac1725ba162c 465 ip_addr_t groupaddr;
segundo 0:ac1725ba162c 466 LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
segundo 0:ac1725ba162c 467 /* we first need to re-look for the group since we used dest last time */
segundo 0:ac1725ba162c 468 ip_addr_copy(groupaddr, igmp->igmp_group_address);
segundo 0:ac1725ba162c 469 group = igmp_lookfor_group(inp, &groupaddr);
segundo 0:ac1725ba162c 470 } else {
segundo 0:ac1725ba162c 471 LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
segundo 0:ac1725ba162c 472 }
segundo 0:ac1725ba162c 473
segundo 0:ac1725ba162c 474 if (group != NULL) {
segundo 0:ac1725ba162c 475 IGMP_STATS_INC(igmp.rx_group);
segundo 0:ac1725ba162c 476 igmp_delaying_member(group, igmp->igmp_maxresp);
segundo 0:ac1725ba162c 477 } else {
segundo 0:ac1725ba162c 478 IGMP_STATS_INC(igmp.drop);
segundo 0:ac1725ba162c 479 }
segundo 0:ac1725ba162c 480 } else {
segundo 0:ac1725ba162c 481 IGMP_STATS_INC(igmp.proterr);
segundo 0:ac1725ba162c 482 }
segundo 0:ac1725ba162c 483 }
segundo 0:ac1725ba162c 484 break;
segundo 0:ac1725ba162c 485 }
segundo 0:ac1725ba162c 486 case IGMP_V2_MEMB_REPORT: {
segundo 0:ac1725ba162c 487 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
segundo 0:ac1725ba162c 488 IGMP_STATS_INC(igmp.rx_report);
segundo 0:ac1725ba162c 489 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
segundo 0:ac1725ba162c 490 /* This is on a specific group we have already looked up */
segundo 0:ac1725ba162c 491 group->timer = 0; /* stopped */
segundo 0:ac1725ba162c 492 group->group_state = IGMP_GROUP_IDLE_MEMBER;
segundo 0:ac1725ba162c 493 group->last_reporter_flag = 0;
segundo 0:ac1725ba162c 494 }
segundo 0:ac1725ba162c 495 break;
segundo 0:ac1725ba162c 496 }
segundo 0:ac1725ba162c 497 default: {
segundo 0:ac1725ba162c 498 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
segundo 0:ac1725ba162c 499 igmp->igmp_msgtype, group->group_state, &group, group->netif));
segundo 0:ac1725ba162c 500 IGMP_STATS_INC(igmp.proterr);
segundo 0:ac1725ba162c 501 break;
segundo 0:ac1725ba162c 502 }
segundo 0:ac1725ba162c 503 }
segundo 0:ac1725ba162c 504
segundo 0:ac1725ba162c 505 pbuf_free(p);
segundo 0:ac1725ba162c 506 return;
segundo 0:ac1725ba162c 507 }
segundo 0:ac1725ba162c 508
segundo 0:ac1725ba162c 509 /**
segundo 0:ac1725ba162c 510 * Join a group on one network interface.
segundo 0:ac1725ba162c 511 *
segundo 0:ac1725ba162c 512 * @param ifaddr ip address of the network interface which should join a new group
segundo 0:ac1725ba162c 513 * @param groupaddr the ip address of the group which to join
segundo 0:ac1725ba162c 514 * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
segundo 0:ac1725ba162c 515 */
segundo 0:ac1725ba162c 516 err_t
segundo 0:ac1725ba162c 517 igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
segundo 0:ac1725ba162c 518 {
segundo 0:ac1725ba162c 519 err_t err = ERR_VAL; /* no matching interface */
segundo 0:ac1725ba162c 520 struct igmp_group *group;
segundo 0:ac1725ba162c 521 struct netif *netif;
segundo 0:ac1725ba162c 522
segundo 0:ac1725ba162c 523 /* make sure it is multicast address */
segundo 0:ac1725ba162c 524 LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
segundo 0:ac1725ba162c 525 LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
segundo 0:ac1725ba162c 526
segundo 0:ac1725ba162c 527 /* loop through netif's */
segundo 0:ac1725ba162c 528 netif = netif_list;
segundo 0:ac1725ba162c 529 while (netif != NULL) {
segundo 0:ac1725ba162c 530 /* Should we join this interface ? */
segundo 0:ac1725ba162c 531 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
segundo 0:ac1725ba162c 532 /* find group or create a new one if not found */
segundo 0:ac1725ba162c 533 group = igmp_lookup_group(netif, groupaddr);
segundo 0:ac1725ba162c 534
segundo 0:ac1725ba162c 535 if (group != NULL) {
segundo 0:ac1725ba162c 536 /* This should create a new group, check the state to make sure */
segundo 0:ac1725ba162c 537 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
segundo 0:ac1725ba162c 538 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
segundo 0:ac1725ba162c 539 } else {
segundo 0:ac1725ba162c 540 /* OK - it was new group */
segundo 0:ac1725ba162c 541 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
segundo 0:ac1725ba162c 542 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
segundo 0:ac1725ba162c 543 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
segundo 0:ac1725ba162c 544
segundo 0:ac1725ba162c 545 /* If first use of the group, allow the group at the MAC level */
segundo 0:ac1725ba162c 546 if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
segundo 0:ac1725ba162c 547 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
segundo 0:ac1725ba162c 548 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
segundo 0:ac1725ba162c 549 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
segundo 0:ac1725ba162c 550 netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
segundo 0:ac1725ba162c 551 }
segundo 0:ac1725ba162c 552
segundo 0:ac1725ba162c 553 IGMP_STATS_INC(igmp.tx_join);
segundo 0:ac1725ba162c 554 igmp_send(group, IGMP_V2_MEMB_REPORT);
segundo 0:ac1725ba162c 555
segundo 0:ac1725ba162c 556 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
segundo 0:ac1725ba162c 557
segundo 0:ac1725ba162c 558 /* Need to work out where this timer comes from */
segundo 0:ac1725ba162c 559 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
segundo 0:ac1725ba162c 560 }
segundo 0:ac1725ba162c 561 /* Increment group use */
segundo 0:ac1725ba162c 562 group->use++;
segundo 0:ac1725ba162c 563 /* Join on this interface */
segundo 0:ac1725ba162c 564 err = ERR_OK;
segundo 0:ac1725ba162c 565 } else {
segundo 0:ac1725ba162c 566 /* Return an error even if some network interfaces are joined */
segundo 0:ac1725ba162c 567 /** @todo undo any other netif already joined */
segundo 0:ac1725ba162c 568 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
segundo 0:ac1725ba162c 569 return ERR_MEM;
segundo 0:ac1725ba162c 570 }
segundo 0:ac1725ba162c 571 }
segundo 0:ac1725ba162c 572 /* proceed to next network interface */
segundo 0:ac1725ba162c 573 netif = netif->next;
segundo 0:ac1725ba162c 574 }
segundo 0:ac1725ba162c 575
segundo 0:ac1725ba162c 576 return err;
segundo 0:ac1725ba162c 577 }
segundo 0:ac1725ba162c 578
segundo 0:ac1725ba162c 579 /**
segundo 0:ac1725ba162c 580 * Leave a group on one network interface.
segundo 0:ac1725ba162c 581 *
segundo 0:ac1725ba162c 582 * @param ifaddr ip address of the network interface which should leave a group
segundo 0:ac1725ba162c 583 * @param groupaddr the ip address of the group which to leave
segundo 0:ac1725ba162c 584 * @return ERR_OK if group was left on the netif(s), an err_t otherwise
segundo 0:ac1725ba162c 585 */
segundo 0:ac1725ba162c 586 err_t
segundo 0:ac1725ba162c 587 igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
segundo 0:ac1725ba162c 588 {
segundo 0:ac1725ba162c 589 err_t err = ERR_VAL; /* no matching interface */
segundo 0:ac1725ba162c 590 struct igmp_group *group;
segundo 0:ac1725ba162c 591 struct netif *netif;
segundo 0:ac1725ba162c 592
segundo 0:ac1725ba162c 593 /* make sure it is multicast address */
segundo 0:ac1725ba162c 594 LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
segundo 0:ac1725ba162c 595 LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
segundo 0:ac1725ba162c 596
segundo 0:ac1725ba162c 597 /* loop through netif's */
segundo 0:ac1725ba162c 598 netif = netif_list;
segundo 0:ac1725ba162c 599 while (netif != NULL) {
segundo 0:ac1725ba162c 600 /* Should we leave this interface ? */
segundo 0:ac1725ba162c 601 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
segundo 0:ac1725ba162c 602 /* find group */
segundo 0:ac1725ba162c 603 group = igmp_lookfor_group(netif, groupaddr);
segundo 0:ac1725ba162c 604
segundo 0:ac1725ba162c 605 if (group != NULL) {
segundo 0:ac1725ba162c 606 /* Only send a leave if the flag is set according to the state diagram */
segundo 0:ac1725ba162c 607 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
segundo 0:ac1725ba162c 608 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
segundo 0:ac1725ba162c 609 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
segundo 0:ac1725ba162c 610
segundo 0:ac1725ba162c 611 /* If there is no other use of the group */
segundo 0:ac1725ba162c 612 if (group->use <= 1) {
segundo 0:ac1725ba162c 613 /* If we are the last reporter for this group */
segundo 0:ac1725ba162c 614 if (group->last_reporter_flag) {
segundo 0:ac1725ba162c 615 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
segundo 0:ac1725ba162c 616 IGMP_STATS_INC(igmp.tx_leave);
segundo 0:ac1725ba162c 617 igmp_send(group, IGMP_LEAVE_GROUP);
segundo 0:ac1725ba162c 618 }
segundo 0:ac1725ba162c 619
segundo 0:ac1725ba162c 620 /* Disable the group at the MAC level */
segundo 0:ac1725ba162c 621 if (netif->igmp_mac_filter != NULL) {
segundo 0:ac1725ba162c 622 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
segundo 0:ac1725ba162c 623 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
segundo 0:ac1725ba162c 624 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
segundo 0:ac1725ba162c 625 netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
segundo 0:ac1725ba162c 626 }
segundo 0:ac1725ba162c 627
segundo 0:ac1725ba162c 628 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
segundo 0:ac1725ba162c 629 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
segundo 0:ac1725ba162c 630 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
segundo 0:ac1725ba162c 631
segundo 0:ac1725ba162c 632 /* Free the group */
segundo 0:ac1725ba162c 633 igmp_remove_group(group);
segundo 0:ac1725ba162c 634 } else {
segundo 0:ac1725ba162c 635 /* Decrement group use */
segundo 0:ac1725ba162c 636 group->use--;
segundo 0:ac1725ba162c 637 }
segundo 0:ac1725ba162c 638 /* Leave on this interface */
segundo 0:ac1725ba162c 639 err = ERR_OK;
segundo 0:ac1725ba162c 640 } else {
segundo 0:ac1725ba162c 641 /* It's not a fatal error on "leavegroup" */
segundo 0:ac1725ba162c 642 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
segundo 0:ac1725ba162c 643 }
segundo 0:ac1725ba162c 644 }
segundo 0:ac1725ba162c 645 /* proceed to next network interface */
segundo 0:ac1725ba162c 646 netif = netif->next;
segundo 0:ac1725ba162c 647 }
segundo 0:ac1725ba162c 648
segundo 0:ac1725ba162c 649 return err;
segundo 0:ac1725ba162c 650 }
segundo 0:ac1725ba162c 651
segundo 0:ac1725ba162c 652 /**
segundo 0:ac1725ba162c 653 * The igmp timer function (both for NO_SYS=1 and =0)
segundo 0:ac1725ba162c 654 * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
segundo 0:ac1725ba162c 655 */
segundo 0:ac1725ba162c 656 void
segundo 0:ac1725ba162c 657 igmp_tmr(void)
segundo 0:ac1725ba162c 658 {
segundo 0:ac1725ba162c 659 struct igmp_group *group = igmp_group_list;
segundo 0:ac1725ba162c 660
segundo 0:ac1725ba162c 661 while (group != NULL) {
segundo 0:ac1725ba162c 662 if (group->timer > 0) {
segundo 0:ac1725ba162c 663 group->timer--;
segundo 0:ac1725ba162c 664 if (group->timer == 0) {
segundo 0:ac1725ba162c 665 igmp_timeout(group);
segundo 0:ac1725ba162c 666 }
segundo 0:ac1725ba162c 667 }
segundo 0:ac1725ba162c 668 group = group->next;
segundo 0:ac1725ba162c 669 }
segundo 0:ac1725ba162c 670 }
segundo 0:ac1725ba162c 671
segundo 0:ac1725ba162c 672 /**
segundo 0:ac1725ba162c 673 * Called if a timeout for one group is reached.
segundo 0:ac1725ba162c 674 * Sends a report for this group.
segundo 0:ac1725ba162c 675 *
segundo 0:ac1725ba162c 676 * @param group an igmp_group for which a timeout is reached
segundo 0:ac1725ba162c 677 */
segundo 0:ac1725ba162c 678 static void
segundo 0:ac1725ba162c 679 igmp_timeout(struct igmp_group *group)
segundo 0:ac1725ba162c 680 {
segundo 0:ac1725ba162c 681 /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
segundo 0:ac1725ba162c 682 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
segundo 0:ac1725ba162c 683 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
segundo 0:ac1725ba162c 684 ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
segundo 0:ac1725ba162c 685 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
segundo 0:ac1725ba162c 686
segundo 0:ac1725ba162c 687 IGMP_STATS_INC(igmp.tx_report);
segundo 0:ac1725ba162c 688 igmp_send(group, IGMP_V2_MEMB_REPORT);
segundo 0:ac1725ba162c 689 }
segundo 0:ac1725ba162c 690 }
segundo 0:ac1725ba162c 691
segundo 0:ac1725ba162c 692 /**
segundo 0:ac1725ba162c 693 * Start a timer for an igmp group
segundo 0:ac1725ba162c 694 *
segundo 0:ac1725ba162c 695 * @param group the igmp_group for which to start a timer
segundo 0:ac1725ba162c 696 * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
segundo 0:ac1725ba162c 697 * every call to igmp_tmr())
segundo 0:ac1725ba162c 698 */
segundo 0:ac1725ba162c 699 static void
segundo 0:ac1725ba162c 700 igmp_start_timer(struct igmp_group *group, u8_t max_time)
segundo 0:ac1725ba162c 701 {
segundo 0:ac1725ba162c 702 /* ensure the input value is > 0 */
segundo 0:ac1725ba162c 703 if (max_time == 0) {
segundo 0:ac1725ba162c 704 max_time = 1;
segundo 0:ac1725ba162c 705 }
segundo 0:ac1725ba162c 706 /* ensure the random value is > 0 */
segundo 0:ac1725ba162c 707 group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
segundo 0:ac1725ba162c 708 }
segundo 0:ac1725ba162c 709
segundo 0:ac1725ba162c 710 /**
segundo 0:ac1725ba162c 711 * Stop a timer for an igmp_group
segundo 0:ac1725ba162c 712 *
segundo 0:ac1725ba162c 713 * @param group the igmp_group for which to stop the timer
segundo 0:ac1725ba162c 714 */
segundo 0:ac1725ba162c 715 static void
segundo 0:ac1725ba162c 716 igmp_stop_timer(struct igmp_group *group)
segundo 0:ac1725ba162c 717 {
segundo 0:ac1725ba162c 718 group->timer = 0;
segundo 0:ac1725ba162c 719 }
segundo 0:ac1725ba162c 720
segundo 0:ac1725ba162c 721 /**
segundo 0:ac1725ba162c 722 * Delaying membership report for a group if necessary
segundo 0:ac1725ba162c 723 *
segundo 0:ac1725ba162c 724 * @param group the igmp_group for which "delaying" membership report
segundo 0:ac1725ba162c 725 * @param maxresp query delay
segundo 0:ac1725ba162c 726 */
segundo 0:ac1725ba162c 727 static void
segundo 0:ac1725ba162c 728 igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
segundo 0:ac1725ba162c 729 {
segundo 0:ac1725ba162c 730 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
segundo 0:ac1725ba162c 731 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
segundo 0:ac1725ba162c 732 ((group->timer == 0) || (maxresp < group->timer)))) {
segundo 0:ac1725ba162c 733 igmp_start_timer(group, maxresp);
segundo 0:ac1725ba162c 734 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
segundo 0:ac1725ba162c 735 }
segundo 0:ac1725ba162c 736 }
segundo 0:ac1725ba162c 737
segundo 0:ac1725ba162c 738
segundo 0:ac1725ba162c 739 /**
segundo 0:ac1725ba162c 740 * Sends an IP packet on a network interface. This function constructs the IP header
segundo 0:ac1725ba162c 741 * and calculates the IP header checksum. If the source IP address is NULL,
segundo 0:ac1725ba162c 742 * the IP address of the outgoing network interface is filled in as source address.
segundo 0:ac1725ba162c 743 *
segundo 0:ac1725ba162c 744 * @param p the packet to send (p->payload points to the data, e.g. next
segundo 0:ac1725ba162c 745 protocol header; if dest == IP_HDRINCL, p already includes an IP
segundo 0:ac1725ba162c 746 header and p->payload points to that IP header)
segundo 0:ac1725ba162c 747 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
segundo 0:ac1725ba162c 748 * IP address of the netif used to send is used as source address)
segundo 0:ac1725ba162c 749 * @param dest the destination IP address to send the packet to
segundo 0:ac1725ba162c 750 * @param ttl the TTL value to be set in the IP header
segundo 0:ac1725ba162c 751 * @param proto the PROTOCOL to be set in the IP header
segundo 0:ac1725ba162c 752 * @param netif the netif on which to send this packet
segundo 0:ac1725ba162c 753 * @return ERR_OK if the packet was sent OK
segundo 0:ac1725ba162c 754 * ERR_BUF if p doesn't have enough space for IP/LINK headers
segundo 0:ac1725ba162c 755 * returns errors returned by netif->output
segundo 0:ac1725ba162c 756 */
segundo 0:ac1725ba162c 757 static err_t
segundo 0:ac1725ba162c 758 igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
segundo 0:ac1725ba162c 759 {
segundo 0:ac1725ba162c 760 /* This is the "router alert" option */
segundo 0:ac1725ba162c 761 u16_t ra[2];
segundo 0:ac1725ba162c 762 ra[0] = PP_HTONS(ROUTER_ALERT);
segundo 0:ac1725ba162c 763 ra[1] = 0x0000; /* Router shall examine packet */
segundo 0:ac1725ba162c 764 IGMP_STATS_INC(igmp.xmit);
segundo 0:ac1725ba162c 765 return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
segundo 0:ac1725ba162c 766 }
segundo 0:ac1725ba162c 767
segundo 0:ac1725ba162c 768 /**
segundo 0:ac1725ba162c 769 * Send an igmp packet to a specific group.
segundo 0:ac1725ba162c 770 *
segundo 0:ac1725ba162c 771 * @param group the group to which to send the packet
segundo 0:ac1725ba162c 772 * @param type the type of igmp packet to send
segundo 0:ac1725ba162c 773 */
segundo 0:ac1725ba162c 774 static void
segundo 0:ac1725ba162c 775 igmp_send(struct igmp_group *group, u8_t type)
segundo 0:ac1725ba162c 776 {
segundo 0:ac1725ba162c 777 struct pbuf* p = NULL;
segundo 0:ac1725ba162c 778 struct igmp_msg* igmp = NULL;
segundo 0:ac1725ba162c 779 ip_addr_t src = *IP_ADDR_ANY;
segundo 0:ac1725ba162c 780 ip_addr_t* dest = NULL;
segundo 0:ac1725ba162c 781
segundo 0:ac1725ba162c 782 /* IP header + "router alert" option + IGMP header */
segundo 0:ac1725ba162c 783 p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
segundo 0:ac1725ba162c 784
segundo 0:ac1725ba162c 785 if (p) {
segundo 0:ac1725ba162c 786 igmp = (struct igmp_msg *)p->payload;
segundo 0:ac1725ba162c 787 LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
segundo 0:ac1725ba162c 788 (p->len >= sizeof(struct igmp_msg)));
segundo 0:ac1725ba162c 789 ip_addr_copy(src, group->netif->ip_addr);
segundo 0:ac1725ba162c 790
segundo 0:ac1725ba162c 791 if (type == IGMP_V2_MEMB_REPORT) {
segundo 0:ac1725ba162c 792 dest = &(group->group_address);
segundo 0:ac1725ba162c 793 ip_addr_copy(igmp->igmp_group_address, group->group_address);
segundo 0:ac1725ba162c 794 group->last_reporter_flag = 1; /* Remember we were the last to report */
segundo 0:ac1725ba162c 795 } else {
segundo 0:ac1725ba162c 796 if (type == IGMP_LEAVE_GROUP) {
segundo 0:ac1725ba162c 797 dest = &allrouters;
segundo 0:ac1725ba162c 798 ip_addr_copy(igmp->igmp_group_address, group->group_address);
segundo 0:ac1725ba162c 799 }
segundo 0:ac1725ba162c 800 }
segundo 0:ac1725ba162c 801
segundo 0:ac1725ba162c 802 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
segundo 0:ac1725ba162c 803 igmp->igmp_msgtype = type;
segundo 0:ac1725ba162c 804 igmp->igmp_maxresp = 0;
segundo 0:ac1725ba162c 805 igmp->igmp_checksum = 0;
segundo 0:ac1725ba162c 806 igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
segundo 0:ac1725ba162c 807
segundo 0:ac1725ba162c 808 igmp_ip_output_if(p, &src, dest, group->netif);
segundo 0:ac1725ba162c 809 }
segundo 0:ac1725ba162c 810
segundo 0:ac1725ba162c 811 pbuf_free(p);
segundo 0:ac1725ba162c 812 } else {
segundo 0:ac1725ba162c 813 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
segundo 0:ac1725ba162c 814 IGMP_STATS_INC(igmp.memerr);
segundo 0:ac1725ba162c 815 }
segundo 0:ac1725ba162c 816 }
segundo 0:ac1725ba162c 817
segundo 0:ac1725ba162c 818 #endif /* LWIP_IGMP */