ProjetoBB

Dependencies:   F7_Ethernet WebSocketClient mbed mcp3008

Fork of Nucleo_F746ZG_Ethernet by Dieter Graef

Committer:
DieterGraef
Date:
Sat Jun 18 10:49:12 2016 +0000
Revision:
0:f9b6112278fe
Ethernet for the NUCLEO STM32F746 Board Testprogram uses DHCP and NTP to set the clock

Who changed what in which revision?

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