Official mbed lwIP library (version 1.4.0)

Dependents:   LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more

Legacy Networking Libraries

This is an mbed 2 networking library. For mbed OS 5, lwip has been integrated with built-in networking interfaces. The networking libraries have been revised to better support additional network stacks and thread safety here.

This library is based on the code of lwIP v1.4.0

Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
All rights reserved. 

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
mbed_official
Date:
Fri Jun 22 09:25:39 2012 +0000
Revision:
0:51ac1d130fd4
Child:
8:f9d0ac9dd036
Initial import from lwip-1.4.0: http://download.savannah.gnu.org/releases/lwip/lwip-1.4.0.zip

Who changed what in which revision?

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