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:
Mon Mar 14 16:15:36 2016 +0000
Revision:
20:08f08bfc3f3d
Parent:
8:f9d0ac9dd036
Synchronized with git revision fec574a5ed6db26aca1b13992ff271bf527d4a0d

Full URL: https://github.com/mbedmicro/mbed/commit/fec574a5ed6db26aca1b13992ff271bf527d4a0d/

Increased allocated netbufs to handle DTLS handshakes

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_delaying_member(struct igmp_group *group, u8_t maxresp);
mbed_official 0:51ac1d130fd4 143 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 144 static void igmp_send(struct igmp_group *group, u8_t type);
mbed_official 0:51ac1d130fd4 145
mbed_official 0:51ac1d130fd4 146
mbed_official 0:51ac1d130fd4 147 static struct igmp_group* igmp_group_list;
mbed_official 0:51ac1d130fd4 148 static ip_addr_t allsystems;
mbed_official 0:51ac1d130fd4 149 static ip_addr_t allrouters;
mbed_official 0:51ac1d130fd4 150
mbed_official 0:51ac1d130fd4 151
mbed_official 0:51ac1d130fd4 152 /**
mbed_official 0:51ac1d130fd4 153 * Initialize the IGMP module
mbed_official 0:51ac1d130fd4 154 */
mbed_official 0:51ac1d130fd4 155 void
mbed_official 0:51ac1d130fd4 156 igmp_init(void)
mbed_official 0:51ac1d130fd4 157 {
mbed_official 0:51ac1d130fd4 158 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
mbed_official 0:51ac1d130fd4 159
mbed_official 0:51ac1d130fd4 160 IP4_ADDR(&allsystems, 224, 0, 0, 1);
mbed_official 0:51ac1d130fd4 161 IP4_ADDR(&allrouters, 224, 0, 0, 2);
mbed_official 0:51ac1d130fd4 162 }
mbed_official 0:51ac1d130fd4 163
mbed_official 0:51ac1d130fd4 164 #ifdef LWIP_DEBUG
mbed_official 0:51ac1d130fd4 165 /**
mbed_official 0:51ac1d130fd4 166 * Dump global IGMP groups list
mbed_official 0:51ac1d130fd4 167 */
mbed_official 0:51ac1d130fd4 168 void
mbed_official 0:51ac1d130fd4 169 igmp_dump_group_list()
mbed_official 0:51ac1d130fd4 170 {
mbed_official 0:51ac1d130fd4 171 struct igmp_group *group = igmp_group_list;
mbed_official 0:51ac1d130fd4 172
mbed_official 0:51ac1d130fd4 173 while (group != NULL) {
mbed_official 0:51ac1d130fd4 174 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
mbed_official 0:51ac1d130fd4 175 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
mbed_official 0:51ac1d130fd4 176 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
mbed_official 0:51ac1d130fd4 177 group = group->next;
mbed_official 0:51ac1d130fd4 178 }
mbed_official 0:51ac1d130fd4 179 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
mbed_official 0:51ac1d130fd4 180 }
mbed_official 0:51ac1d130fd4 181 #else
mbed_official 0:51ac1d130fd4 182 #define igmp_dump_group_list()
mbed_official 0:51ac1d130fd4 183 #endif /* LWIP_DEBUG */
mbed_official 0:51ac1d130fd4 184
mbed_official 0:51ac1d130fd4 185 /**
mbed_official 0:51ac1d130fd4 186 * Start IGMP processing on interface
mbed_official 0:51ac1d130fd4 187 *
mbed_official 0:51ac1d130fd4 188 * @param netif network interface on which start IGMP processing
mbed_official 0:51ac1d130fd4 189 */
mbed_official 0:51ac1d130fd4 190 err_t
mbed_official 0:51ac1d130fd4 191 igmp_start(struct netif *netif)
mbed_official 0:51ac1d130fd4 192 {
mbed_official 0:51ac1d130fd4 193 struct igmp_group* group;
mbed_official 0:51ac1d130fd4 194
mbed_official 0:51ac1d130fd4 195 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
mbed_official 0:51ac1d130fd4 196
mbed_official 0:51ac1d130fd4 197 group = igmp_lookup_group(netif, &allsystems);
mbed_official 0:51ac1d130fd4 198
mbed_official 0:51ac1d130fd4 199 if (group != NULL) {
mbed_official 0:51ac1d130fd4 200 group->group_state = IGMP_GROUP_IDLE_MEMBER;
mbed_official 0:51ac1d130fd4 201 group->use++;
mbed_official 0:51ac1d130fd4 202
mbed_official 0:51ac1d130fd4 203 /* Allow the igmp messages at the MAC level */
mbed_official 0:51ac1d130fd4 204 if (netif->igmp_mac_filter != NULL) {
mbed_official 0:51ac1d130fd4 205 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
mbed_official 0:51ac1d130fd4 206 ip_addr_debug_print(IGMP_DEBUG, &allsystems);
mbed_official 0:51ac1d130fd4 207 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
mbed_official 0:51ac1d130fd4 208 netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
mbed_official 0:51ac1d130fd4 209 }
mbed_official 0:51ac1d130fd4 210
mbed_official 0:51ac1d130fd4 211 return ERR_OK;
mbed_official 0:51ac1d130fd4 212 }
mbed_official 0:51ac1d130fd4 213
mbed_official 0:51ac1d130fd4 214 return ERR_MEM;
mbed_official 0:51ac1d130fd4 215 }
mbed_official 0:51ac1d130fd4 216
mbed_official 0:51ac1d130fd4 217 /**
mbed_official 0:51ac1d130fd4 218 * Stop IGMP processing on interface
mbed_official 0:51ac1d130fd4 219 *
mbed_official 0:51ac1d130fd4 220 * @param netif network interface on which stop IGMP processing
mbed_official 0:51ac1d130fd4 221 */
mbed_official 0:51ac1d130fd4 222 err_t
mbed_official 0:51ac1d130fd4 223 igmp_stop(struct netif *netif)
mbed_official 0:51ac1d130fd4 224 {
mbed_official 0:51ac1d130fd4 225 struct igmp_group *group = igmp_group_list;
mbed_official 0:51ac1d130fd4 226 struct igmp_group *prev = NULL;
mbed_official 0:51ac1d130fd4 227 struct igmp_group *next;
mbed_official 0:51ac1d130fd4 228
mbed_official 0:51ac1d130fd4 229 /* look for groups joined on this interface further down the list */
mbed_official 0:51ac1d130fd4 230 while (group != NULL) {
mbed_official 0:51ac1d130fd4 231 next = group->next;
mbed_official 0:51ac1d130fd4 232 /* is it a group joined on this interface? */
mbed_official 0:51ac1d130fd4 233 if (group->netif == netif) {
mbed_official 0:51ac1d130fd4 234 /* is it the first group of the list? */
mbed_official 0:51ac1d130fd4 235 if (group == igmp_group_list) {
mbed_official 0:51ac1d130fd4 236 igmp_group_list = next;
mbed_official 0:51ac1d130fd4 237 }
mbed_official 0:51ac1d130fd4 238 /* is there a "previous" group defined? */
mbed_official 0:51ac1d130fd4 239 if (prev != NULL) {
mbed_official 0:51ac1d130fd4 240 prev->next = next;
mbed_official 0:51ac1d130fd4 241 }
mbed_official 0:51ac1d130fd4 242 /* disable the group at the MAC level */
mbed_official 0:51ac1d130fd4 243 if (netif->igmp_mac_filter != NULL) {
mbed_official 0:51ac1d130fd4 244 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
mbed_official 0:51ac1d130fd4 245 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
mbed_official 0:51ac1d130fd4 246 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
mbed_official 0:51ac1d130fd4 247 netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
mbed_official 0:51ac1d130fd4 248 }
mbed_official 0:51ac1d130fd4 249 /* free group */
mbed_official 0:51ac1d130fd4 250 memp_free(MEMP_IGMP_GROUP, group);
mbed_official 0:51ac1d130fd4 251 } else {
mbed_official 0:51ac1d130fd4 252 /* change the "previous" */
mbed_official 0:51ac1d130fd4 253 prev = group;
mbed_official 0:51ac1d130fd4 254 }
mbed_official 0:51ac1d130fd4 255 /* move to "next" */
mbed_official 0:51ac1d130fd4 256 group = next;
mbed_official 0:51ac1d130fd4 257 }
mbed_official 0:51ac1d130fd4 258 return ERR_OK;
mbed_official 0:51ac1d130fd4 259 }
mbed_official 0:51ac1d130fd4 260
mbed_official 0:51ac1d130fd4 261 /**
mbed_official 0:51ac1d130fd4 262 * Report IGMP memberships for this interface
mbed_official 0:51ac1d130fd4 263 *
mbed_official 0:51ac1d130fd4 264 * @param netif network interface on which report IGMP memberships
mbed_official 0:51ac1d130fd4 265 */
mbed_official 0:51ac1d130fd4 266 void
mbed_official 0:51ac1d130fd4 267 igmp_report_groups(struct netif *netif)
mbed_official 0:51ac1d130fd4 268 {
mbed_official 0:51ac1d130fd4 269 struct igmp_group *group = igmp_group_list;
mbed_official 0:51ac1d130fd4 270
mbed_official 0:51ac1d130fd4 271 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
mbed_official 0:51ac1d130fd4 272
mbed_official 0:51ac1d130fd4 273 while (group != NULL) {
mbed_official 0:51ac1d130fd4 274 if (group->netif == netif) {
mbed_official 0:51ac1d130fd4 275 igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
mbed_official 0:51ac1d130fd4 276 }
mbed_official 0:51ac1d130fd4 277 group = group->next;
mbed_official 0:51ac1d130fd4 278 }
mbed_official 0:51ac1d130fd4 279 }
mbed_official 0:51ac1d130fd4 280
mbed_official 0:51ac1d130fd4 281 /**
mbed_official 0:51ac1d130fd4 282 * Search for a group in the global igmp_group_list
mbed_official 0:51ac1d130fd4 283 *
mbed_official 0:51ac1d130fd4 284 * @param ifp the network interface for which to look
mbed_official 0:51ac1d130fd4 285 * @param addr the group ip address to search for
mbed_official 0:51ac1d130fd4 286 * @return a struct igmp_group* if the group has been found,
mbed_official 0:51ac1d130fd4 287 * NULL if the group wasn't found.
mbed_official 0:51ac1d130fd4 288 */
mbed_official 0:51ac1d130fd4 289 struct igmp_group *
mbed_official 0:51ac1d130fd4 290 igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
mbed_official 0:51ac1d130fd4 291 {
mbed_official 0:51ac1d130fd4 292 struct igmp_group *group = igmp_group_list;
mbed_official 0:51ac1d130fd4 293
mbed_official 0:51ac1d130fd4 294 while (group != NULL) {
mbed_official 0:51ac1d130fd4 295 if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
mbed_official 0:51ac1d130fd4 296 return group;
mbed_official 0:51ac1d130fd4 297 }
mbed_official 0:51ac1d130fd4 298 group = group->next;
mbed_official 0:51ac1d130fd4 299 }
mbed_official 0:51ac1d130fd4 300
mbed_official 0:51ac1d130fd4 301 /* to be clearer, we return NULL here instead of
mbed_official 0:51ac1d130fd4 302 * 'group' (which is also NULL at this point).
mbed_official 0:51ac1d130fd4 303 */
mbed_official 0:51ac1d130fd4 304 return NULL;
mbed_official 0:51ac1d130fd4 305 }
mbed_official 0:51ac1d130fd4 306
mbed_official 0:51ac1d130fd4 307 /**
mbed_official 0:51ac1d130fd4 308 * Search for a specific igmp group and create a new one if not found-
mbed_official 0:51ac1d130fd4 309 *
mbed_official 0:51ac1d130fd4 310 * @param ifp the network interface for which to look
mbed_official 0:51ac1d130fd4 311 * @param addr the group ip address to search
mbed_official 0:51ac1d130fd4 312 * @return a struct igmp_group*,
mbed_official 0:51ac1d130fd4 313 * NULL on memory error.
mbed_official 0:51ac1d130fd4 314 */
mbed_official 0:51ac1d130fd4 315 struct igmp_group *
mbed_official 0:51ac1d130fd4 316 igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
mbed_official 0:51ac1d130fd4 317 {
mbed_official 0:51ac1d130fd4 318 struct igmp_group *group = igmp_group_list;
mbed_official 0:51ac1d130fd4 319
mbed_official 0:51ac1d130fd4 320 /* Search if the group already exists */
mbed_official 0:51ac1d130fd4 321 group = igmp_lookfor_group(ifp, addr);
mbed_official 0:51ac1d130fd4 322 if (group != NULL) {
mbed_official 0:51ac1d130fd4 323 /* Group already exists. */
mbed_official 0:51ac1d130fd4 324 return group;
mbed_official 0:51ac1d130fd4 325 }
mbed_official 0:51ac1d130fd4 326
mbed_official 0:51ac1d130fd4 327 /* Group doesn't exist yet, create a new one */
mbed_official 0:51ac1d130fd4 328 group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
mbed_official 0:51ac1d130fd4 329 if (group != NULL) {
mbed_official 0:51ac1d130fd4 330 group->netif = ifp;
mbed_official 0:51ac1d130fd4 331 ip_addr_set(&(group->group_address), addr);
mbed_official 0:51ac1d130fd4 332 group->timer = 0; /* Not running */
mbed_official 0:51ac1d130fd4 333 group->group_state = IGMP_GROUP_NON_MEMBER;
mbed_official 0:51ac1d130fd4 334 group->last_reporter_flag = 0;
mbed_official 0:51ac1d130fd4 335 group->use = 0;
mbed_official 0:51ac1d130fd4 336 group->next = igmp_group_list;
mbed_official 0:51ac1d130fd4 337
mbed_official 0:51ac1d130fd4 338 igmp_group_list = group;
mbed_official 0:51ac1d130fd4 339 }
mbed_official 0:51ac1d130fd4 340
mbed_official 0:51ac1d130fd4 341 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
mbed_official 0:51ac1d130fd4 342 ip_addr_debug_print(IGMP_DEBUG, addr);
mbed_official 0:51ac1d130fd4 343 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
mbed_official 0:51ac1d130fd4 344
mbed_official 0:51ac1d130fd4 345 return group;
mbed_official 0:51ac1d130fd4 346 }
mbed_official 0:51ac1d130fd4 347
mbed_official 0:51ac1d130fd4 348 /**
mbed_official 0:51ac1d130fd4 349 * Remove a group in the global igmp_group_list
mbed_official 0:51ac1d130fd4 350 *
mbed_official 0:51ac1d130fd4 351 * @param group the group to remove from the global igmp_group_list
mbed_official 0:51ac1d130fd4 352 * @return ERR_OK if group was removed from the list, an err_t otherwise
mbed_official 0:51ac1d130fd4 353 */
mbed_official 0:51ac1d130fd4 354 static err_t
mbed_official 0:51ac1d130fd4 355 igmp_remove_group(struct igmp_group *group)
mbed_official 0:51ac1d130fd4 356 {
mbed_official 0:51ac1d130fd4 357 err_t err = ERR_OK;
mbed_official 0:51ac1d130fd4 358
mbed_official 0:51ac1d130fd4 359 /* Is it the first group? */
mbed_official 0:51ac1d130fd4 360 if (igmp_group_list == group) {
mbed_official 0:51ac1d130fd4 361 igmp_group_list = group->next;
mbed_official 0:51ac1d130fd4 362 } else {
mbed_official 0:51ac1d130fd4 363 /* look for group further down the list */
mbed_official 0:51ac1d130fd4 364 struct igmp_group *tmpGroup;
mbed_official 0:51ac1d130fd4 365 for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
mbed_official 0:51ac1d130fd4 366 if (tmpGroup->next == group) {
mbed_official 0:51ac1d130fd4 367 tmpGroup->next = group->next;
mbed_official 0:51ac1d130fd4 368 break;
mbed_official 0:51ac1d130fd4 369 }
mbed_official 0:51ac1d130fd4 370 }
mbed_official 0:51ac1d130fd4 371 /* Group not found in the global igmp_group_list */
mbed_official 0:51ac1d130fd4 372 if (tmpGroup == NULL)
mbed_official 0:51ac1d130fd4 373 err = ERR_ARG;
mbed_official 0:51ac1d130fd4 374 }
mbed_official 0:51ac1d130fd4 375 /* free group */
mbed_official 0:51ac1d130fd4 376 memp_free(MEMP_IGMP_GROUP, group);
mbed_official 0:51ac1d130fd4 377
mbed_official 0:51ac1d130fd4 378 return err;
mbed_official 0:51ac1d130fd4 379 }
mbed_official 0:51ac1d130fd4 380
mbed_official 0:51ac1d130fd4 381 /**
mbed_official 0:51ac1d130fd4 382 * Called from ip_input() if a new IGMP packet is received.
mbed_official 0:51ac1d130fd4 383 *
mbed_official 0:51ac1d130fd4 384 * @param p received igmp packet, p->payload pointing to the ip header
mbed_official 0:51ac1d130fd4 385 * @param inp network interface on which the packet was received
mbed_official 0:51ac1d130fd4 386 * @param dest destination ip address of the igmp packet
mbed_official 0:51ac1d130fd4 387 */
mbed_official 0:51ac1d130fd4 388 void
mbed_official 0:51ac1d130fd4 389 igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
mbed_official 0:51ac1d130fd4 390 {
mbed_official 0:51ac1d130fd4 391 struct ip_hdr * iphdr;
mbed_official 0:51ac1d130fd4 392 struct igmp_msg* igmp;
mbed_official 0:51ac1d130fd4 393 struct igmp_group* group;
mbed_official 0:51ac1d130fd4 394 struct igmp_group* groupref;
mbed_official 0:51ac1d130fd4 395
mbed_official 0:51ac1d130fd4 396 IGMP_STATS_INC(igmp.recv);
mbed_official 0:51ac1d130fd4 397
mbed_official 0:51ac1d130fd4 398 /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
mbed_official 0:51ac1d130fd4 399 iphdr = (struct ip_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 400 if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
mbed_official 0:51ac1d130fd4 401 pbuf_free(p);
mbed_official 0:51ac1d130fd4 402 IGMP_STATS_INC(igmp.lenerr);
mbed_official 0:51ac1d130fd4 403 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
mbed_official 0:51ac1d130fd4 404 return;
mbed_official 0:51ac1d130fd4 405 }
mbed_official 0:51ac1d130fd4 406
mbed_official 0:51ac1d130fd4 407 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
mbed_official 0:51ac1d130fd4 408 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
mbed_official 0:51ac1d130fd4 409 LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
mbed_official 0:51ac1d130fd4 410 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
mbed_official 0:51ac1d130fd4 411 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
mbed_official 0:51ac1d130fd4 412
mbed_official 0:51ac1d130fd4 413 /* Now calculate and check the checksum */
mbed_official 0:51ac1d130fd4 414 igmp = (struct igmp_msg *)p->payload;
mbed_official 0:51ac1d130fd4 415 if (inet_chksum(igmp, p->len)) {
mbed_official 0:51ac1d130fd4 416 pbuf_free(p);
mbed_official 0:51ac1d130fd4 417 IGMP_STATS_INC(igmp.chkerr);
mbed_official 0:51ac1d130fd4 418 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
mbed_official 0:51ac1d130fd4 419 return;
mbed_official 0:51ac1d130fd4 420 }
mbed_official 0:51ac1d130fd4 421
mbed_official 0:51ac1d130fd4 422 /* Packet is ok so find an existing group */
mbed_official 0:51ac1d130fd4 423 group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
mbed_official 0:51ac1d130fd4 424
mbed_official 0:51ac1d130fd4 425 /* If group can be found or create... */
mbed_official 0:51ac1d130fd4 426 if (!group) {
mbed_official 0:51ac1d130fd4 427 pbuf_free(p);
mbed_official 0:51ac1d130fd4 428 IGMP_STATS_INC(igmp.drop);
mbed_official 0:51ac1d130fd4 429 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
mbed_official 0:51ac1d130fd4 430 return;
mbed_official 0:51ac1d130fd4 431 }
mbed_official 0:51ac1d130fd4 432
mbed_official 0:51ac1d130fd4 433 /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
mbed_official 0:51ac1d130fd4 434 switch (igmp->igmp_msgtype) {
mbed_official 0:51ac1d130fd4 435 case IGMP_MEMB_QUERY: {
mbed_official 0:51ac1d130fd4 436 /* IGMP_MEMB_QUERY to the "all systems" address ? */
mbed_official 0:51ac1d130fd4 437 if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
mbed_official 0:51ac1d130fd4 438 /* THIS IS THE GENERAL QUERY */
mbed_official 0:51ac1d130fd4 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)));
mbed_official 0:51ac1d130fd4 440
mbed_official 0:51ac1d130fd4 441 if (igmp->igmp_maxresp == 0) {
mbed_official 0:51ac1d130fd4 442 IGMP_STATS_INC(igmp.rx_v1);
mbed_official 0:51ac1d130fd4 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"));
mbed_official 0:51ac1d130fd4 444 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
mbed_official 0:51ac1d130fd4 445 } else {
mbed_official 0:51ac1d130fd4 446 IGMP_STATS_INC(igmp.rx_general);
mbed_official 0:51ac1d130fd4 447 }
mbed_official 0:51ac1d130fd4 448
mbed_official 0:51ac1d130fd4 449 groupref = igmp_group_list;
mbed_official 0:51ac1d130fd4 450 while (groupref) {
mbed_official 0:51ac1d130fd4 451 /* Do not send messages on the all systems group address! */
mbed_official 0:51ac1d130fd4 452 if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
mbed_official 0:51ac1d130fd4 453 igmp_delaying_member(groupref, igmp->igmp_maxresp);
mbed_official 0:51ac1d130fd4 454 }
mbed_official 0:51ac1d130fd4 455 groupref = groupref->next;
mbed_official 0:51ac1d130fd4 456 }
mbed_official 0:51ac1d130fd4 457 } else {
mbed_official 0:51ac1d130fd4 458 /* IGMP_MEMB_QUERY to a specific group ? */
mbed_official 0:51ac1d130fd4 459 if (!ip_addr_isany(&igmp->igmp_group_address)) {
mbed_official 0:51ac1d130fd4 460 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
mbed_official 0:51ac1d130fd4 461 ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
mbed_official 0:51ac1d130fd4 462 if (ip_addr_cmp(dest, &allsystems)) {
mbed_official 0:51ac1d130fd4 463 ip_addr_t groupaddr;
mbed_official 0:51ac1d130fd4 464 LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
mbed_official 0:51ac1d130fd4 465 /* we first need to re-look for the group since we used dest last time */
mbed_official 0:51ac1d130fd4 466 ip_addr_copy(groupaddr, igmp->igmp_group_address);
mbed_official 0:51ac1d130fd4 467 group = igmp_lookfor_group(inp, &groupaddr);
mbed_official 0:51ac1d130fd4 468 } else {
mbed_official 0:51ac1d130fd4 469 LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
mbed_official 0:51ac1d130fd4 470 }
mbed_official 0:51ac1d130fd4 471
mbed_official 0:51ac1d130fd4 472 if (group != NULL) {
mbed_official 0:51ac1d130fd4 473 IGMP_STATS_INC(igmp.rx_group);
mbed_official 0:51ac1d130fd4 474 igmp_delaying_member(group, igmp->igmp_maxresp);
mbed_official 0:51ac1d130fd4 475 } else {
mbed_official 0:51ac1d130fd4 476 IGMP_STATS_INC(igmp.drop);
mbed_official 0:51ac1d130fd4 477 }
mbed_official 0:51ac1d130fd4 478 } else {
mbed_official 0:51ac1d130fd4 479 IGMP_STATS_INC(igmp.proterr);
mbed_official 0:51ac1d130fd4 480 }
mbed_official 0:51ac1d130fd4 481 }
mbed_official 0:51ac1d130fd4 482 break;
mbed_official 0:51ac1d130fd4 483 }
mbed_official 0:51ac1d130fd4 484 case IGMP_V2_MEMB_REPORT: {
mbed_official 0:51ac1d130fd4 485 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
mbed_official 0:51ac1d130fd4 486 IGMP_STATS_INC(igmp.rx_report);
mbed_official 0:51ac1d130fd4 487 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
mbed_official 0:51ac1d130fd4 488 /* This is on a specific group we have already looked up */
mbed_official 0:51ac1d130fd4 489 group->timer = 0; /* stopped */
mbed_official 0:51ac1d130fd4 490 group->group_state = IGMP_GROUP_IDLE_MEMBER;
mbed_official 0:51ac1d130fd4 491 group->last_reporter_flag = 0;
mbed_official 0:51ac1d130fd4 492 }
mbed_official 0:51ac1d130fd4 493 break;
mbed_official 0:51ac1d130fd4 494 }
mbed_official 0:51ac1d130fd4 495 default: {
mbed_official 0:51ac1d130fd4 496 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
mbed_official 0:51ac1d130fd4 497 igmp->igmp_msgtype, group->group_state, &group, group->netif));
mbed_official 0:51ac1d130fd4 498 IGMP_STATS_INC(igmp.proterr);
mbed_official 0:51ac1d130fd4 499 break;
mbed_official 0:51ac1d130fd4 500 }
mbed_official 0:51ac1d130fd4 501 }
mbed_official 0:51ac1d130fd4 502
mbed_official 0:51ac1d130fd4 503 pbuf_free(p);
mbed_official 0:51ac1d130fd4 504 return;
mbed_official 0:51ac1d130fd4 505 }
mbed_official 0:51ac1d130fd4 506
mbed_official 0:51ac1d130fd4 507 /**
mbed_official 0:51ac1d130fd4 508 * Join a group on one network interface.
mbed_official 0:51ac1d130fd4 509 *
mbed_official 0:51ac1d130fd4 510 * @param ifaddr ip address of the network interface which should join a new group
mbed_official 0:51ac1d130fd4 511 * @param groupaddr the ip address of the group which to join
mbed_official 0:51ac1d130fd4 512 * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
mbed_official 0:51ac1d130fd4 513 */
mbed_official 0:51ac1d130fd4 514 err_t
mbed_official 0:51ac1d130fd4 515 igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
mbed_official 0:51ac1d130fd4 516 {
mbed_official 0:51ac1d130fd4 517 err_t err = ERR_VAL; /* no matching interface */
mbed_official 0:51ac1d130fd4 518 struct igmp_group *group;
mbed_official 0:51ac1d130fd4 519 struct netif *netif;
mbed_official 0:51ac1d130fd4 520
mbed_official 0:51ac1d130fd4 521 /* make sure it is multicast address */
mbed_official 0:51ac1d130fd4 522 LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
mbed_official 0:51ac1d130fd4 523 LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
mbed_official 0:51ac1d130fd4 524
mbed_official 0:51ac1d130fd4 525 /* loop through netif's */
mbed_official 0:51ac1d130fd4 526 netif = netif_list;
mbed_official 0:51ac1d130fd4 527 while (netif != NULL) {
mbed_official 0:51ac1d130fd4 528 /* Should we join this interface ? */
mbed_official 0:51ac1d130fd4 529 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
mbed_official 0:51ac1d130fd4 530 /* find group or create a new one if not found */
mbed_official 0:51ac1d130fd4 531 group = igmp_lookup_group(netif, groupaddr);
mbed_official 0:51ac1d130fd4 532
mbed_official 0:51ac1d130fd4 533 if (group != NULL) {
mbed_official 0:51ac1d130fd4 534 /* This should create a new group, check the state to make sure */
mbed_official 0:51ac1d130fd4 535 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
mbed_official 0:51ac1d130fd4 536 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
mbed_official 0:51ac1d130fd4 537 } else {
mbed_official 0:51ac1d130fd4 538 /* OK - it was new group */
mbed_official 0:51ac1d130fd4 539 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
mbed_official 0:51ac1d130fd4 540 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
mbed_official 0:51ac1d130fd4 541 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
mbed_official 0:51ac1d130fd4 542
mbed_official 0:51ac1d130fd4 543 /* If first use of the group, allow the group at the MAC level */
mbed_official 0:51ac1d130fd4 544 if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
mbed_official 0:51ac1d130fd4 545 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
mbed_official 0:51ac1d130fd4 546 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
mbed_official 0:51ac1d130fd4 547 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
mbed_official 0:51ac1d130fd4 548 netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
mbed_official 0:51ac1d130fd4 549 }
mbed_official 0:51ac1d130fd4 550
mbed_official 0:51ac1d130fd4 551 IGMP_STATS_INC(igmp.tx_join);
mbed_official 0:51ac1d130fd4 552 igmp_send(group, IGMP_V2_MEMB_REPORT);
mbed_official 0:51ac1d130fd4 553
mbed_official 0:51ac1d130fd4 554 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
mbed_official 0:51ac1d130fd4 555
mbed_official 0:51ac1d130fd4 556 /* Need to work out where this timer comes from */
mbed_official 0:51ac1d130fd4 557 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
mbed_official 0:51ac1d130fd4 558 }
mbed_official 0:51ac1d130fd4 559 /* Increment group use */
mbed_official 0:51ac1d130fd4 560 group->use++;
mbed_official 0:51ac1d130fd4 561 /* Join on this interface */
mbed_official 0:51ac1d130fd4 562 err = ERR_OK;
mbed_official 0:51ac1d130fd4 563 } else {
mbed_official 0:51ac1d130fd4 564 /* Return an error even if some network interfaces are joined */
mbed_official 0:51ac1d130fd4 565 /** @todo undo any other netif already joined */
mbed_official 0:51ac1d130fd4 566 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
mbed_official 0:51ac1d130fd4 567 return ERR_MEM;
mbed_official 0:51ac1d130fd4 568 }
mbed_official 0:51ac1d130fd4 569 }
mbed_official 0:51ac1d130fd4 570 /* proceed to next network interface */
mbed_official 0:51ac1d130fd4 571 netif = netif->next;
mbed_official 0:51ac1d130fd4 572 }
mbed_official 0:51ac1d130fd4 573
mbed_official 0:51ac1d130fd4 574 return err;
mbed_official 0:51ac1d130fd4 575 }
mbed_official 0:51ac1d130fd4 576
mbed_official 0:51ac1d130fd4 577 /**
mbed_official 0:51ac1d130fd4 578 * Leave a group on one network interface.
mbed_official 0:51ac1d130fd4 579 *
mbed_official 0:51ac1d130fd4 580 * @param ifaddr ip address of the network interface which should leave a group
mbed_official 0:51ac1d130fd4 581 * @param groupaddr the ip address of the group which to leave
mbed_official 0:51ac1d130fd4 582 * @return ERR_OK if group was left on the netif(s), an err_t otherwise
mbed_official 0:51ac1d130fd4 583 */
mbed_official 0:51ac1d130fd4 584 err_t
mbed_official 0:51ac1d130fd4 585 igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
mbed_official 0:51ac1d130fd4 586 {
mbed_official 0:51ac1d130fd4 587 err_t err = ERR_VAL; /* no matching interface */
mbed_official 0:51ac1d130fd4 588 struct igmp_group *group;
mbed_official 0:51ac1d130fd4 589 struct netif *netif;
mbed_official 0:51ac1d130fd4 590
mbed_official 0:51ac1d130fd4 591 /* make sure it is multicast address */
mbed_official 0:51ac1d130fd4 592 LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
mbed_official 0:51ac1d130fd4 593 LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
mbed_official 0:51ac1d130fd4 594
mbed_official 0:51ac1d130fd4 595 /* loop through netif's */
mbed_official 0:51ac1d130fd4 596 netif = netif_list;
mbed_official 0:51ac1d130fd4 597 while (netif != NULL) {
mbed_official 0:51ac1d130fd4 598 /* Should we leave this interface ? */
mbed_official 0:51ac1d130fd4 599 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
mbed_official 0:51ac1d130fd4 600 /* find group */
mbed_official 0:51ac1d130fd4 601 group = igmp_lookfor_group(netif, groupaddr);
mbed_official 0:51ac1d130fd4 602
mbed_official 0:51ac1d130fd4 603 if (group != NULL) {
mbed_official 0:51ac1d130fd4 604 /* Only send a leave if the flag is set according to the state diagram */
mbed_official 0:51ac1d130fd4 605 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
mbed_official 0:51ac1d130fd4 606 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
mbed_official 0:51ac1d130fd4 607 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
mbed_official 0:51ac1d130fd4 608
mbed_official 0:51ac1d130fd4 609 /* If there is no other use of the group */
mbed_official 0:51ac1d130fd4 610 if (group->use <= 1) {
mbed_official 0:51ac1d130fd4 611 /* If we are the last reporter for this group */
mbed_official 0:51ac1d130fd4 612 if (group->last_reporter_flag) {
mbed_official 0:51ac1d130fd4 613 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
mbed_official 0:51ac1d130fd4 614 IGMP_STATS_INC(igmp.tx_leave);
mbed_official 0:51ac1d130fd4 615 igmp_send(group, IGMP_LEAVE_GROUP);
mbed_official 0:51ac1d130fd4 616 }
mbed_official 0:51ac1d130fd4 617
mbed_official 0:51ac1d130fd4 618 /* Disable the group at the MAC level */
mbed_official 0:51ac1d130fd4 619 if (netif->igmp_mac_filter != NULL) {
mbed_official 0:51ac1d130fd4 620 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
mbed_official 0:51ac1d130fd4 621 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
mbed_official 0:51ac1d130fd4 622 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
mbed_official 0:51ac1d130fd4 623 netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
mbed_official 0:51ac1d130fd4 624 }
mbed_official 0:51ac1d130fd4 625
mbed_official 0:51ac1d130fd4 626 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
mbed_official 0:51ac1d130fd4 627 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
mbed_official 0:51ac1d130fd4 628 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
mbed_official 0:51ac1d130fd4 629
mbed_official 0:51ac1d130fd4 630 /* Free the group */
mbed_official 0:51ac1d130fd4 631 igmp_remove_group(group);
mbed_official 0:51ac1d130fd4 632 } else {
mbed_official 0:51ac1d130fd4 633 /* Decrement group use */
mbed_official 0:51ac1d130fd4 634 group->use--;
mbed_official 0:51ac1d130fd4 635 }
mbed_official 0:51ac1d130fd4 636 /* Leave on this interface */
mbed_official 0:51ac1d130fd4 637 err = ERR_OK;
mbed_official 0:51ac1d130fd4 638 } else {
mbed_official 0:51ac1d130fd4 639 /* It's not a fatal error on "leavegroup" */
mbed_official 0:51ac1d130fd4 640 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
mbed_official 0:51ac1d130fd4 641 }
mbed_official 0:51ac1d130fd4 642 }
mbed_official 0:51ac1d130fd4 643 /* proceed to next network interface */
mbed_official 0:51ac1d130fd4 644 netif = netif->next;
mbed_official 0:51ac1d130fd4 645 }
mbed_official 0:51ac1d130fd4 646
mbed_official 0:51ac1d130fd4 647 return err;
mbed_official 0:51ac1d130fd4 648 }
mbed_official 0:51ac1d130fd4 649
mbed_official 0:51ac1d130fd4 650 /**
mbed_official 0:51ac1d130fd4 651 * The igmp timer function (both for NO_SYS=1 and =0)
mbed_official 0:51ac1d130fd4 652 * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
mbed_official 0:51ac1d130fd4 653 */
mbed_official 0:51ac1d130fd4 654 void
mbed_official 0:51ac1d130fd4 655 igmp_tmr(void)
mbed_official 0:51ac1d130fd4 656 {
mbed_official 0:51ac1d130fd4 657 struct igmp_group *group = igmp_group_list;
mbed_official 0:51ac1d130fd4 658
mbed_official 0:51ac1d130fd4 659 while (group != NULL) {
mbed_official 0:51ac1d130fd4 660 if (group->timer > 0) {
mbed_official 0:51ac1d130fd4 661 group->timer--;
mbed_official 0:51ac1d130fd4 662 if (group->timer == 0) {
mbed_official 0:51ac1d130fd4 663 igmp_timeout(group);
mbed_official 0:51ac1d130fd4 664 }
mbed_official 0:51ac1d130fd4 665 }
mbed_official 0:51ac1d130fd4 666 group = group->next;
mbed_official 0:51ac1d130fd4 667 }
mbed_official 0:51ac1d130fd4 668 }
mbed_official 0:51ac1d130fd4 669
mbed_official 0:51ac1d130fd4 670 /**
mbed_official 0:51ac1d130fd4 671 * Called if a timeout for one group is reached.
mbed_official 0:51ac1d130fd4 672 * Sends a report for this group.
mbed_official 0:51ac1d130fd4 673 *
mbed_official 0:51ac1d130fd4 674 * @param group an igmp_group for which a timeout is reached
mbed_official 0:51ac1d130fd4 675 */
mbed_official 0:51ac1d130fd4 676 static void
mbed_official 0:51ac1d130fd4 677 igmp_timeout(struct igmp_group *group)
mbed_official 0:51ac1d130fd4 678 {
mbed_official 0:51ac1d130fd4 679 /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
mbed_official 0:51ac1d130fd4 680 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
mbed_official 0:51ac1d130fd4 681 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
mbed_official 0:51ac1d130fd4 682 ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
mbed_official 0:51ac1d130fd4 683 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
mbed_official 0:51ac1d130fd4 684
mbed_official 0:51ac1d130fd4 685 IGMP_STATS_INC(igmp.tx_report);
mbed_official 0:51ac1d130fd4 686 igmp_send(group, IGMP_V2_MEMB_REPORT);
mbed_official 0:51ac1d130fd4 687 }
mbed_official 0:51ac1d130fd4 688 }
mbed_official 0:51ac1d130fd4 689
mbed_official 0:51ac1d130fd4 690 /**
mbed_official 0:51ac1d130fd4 691 * Start a timer for an igmp group
mbed_official 0:51ac1d130fd4 692 *
mbed_official 0:51ac1d130fd4 693 * @param group the igmp_group for which to start a timer
mbed_official 0:51ac1d130fd4 694 * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
mbed_official 0:51ac1d130fd4 695 * every call to igmp_tmr())
mbed_official 0:51ac1d130fd4 696 */
mbed_official 0:51ac1d130fd4 697 static void
mbed_official 0:51ac1d130fd4 698 igmp_start_timer(struct igmp_group *group, u8_t max_time)
mbed_official 0:51ac1d130fd4 699 {
mbed_official 0:51ac1d130fd4 700 /* ensure the input value is > 0 */
mbed_official 0:51ac1d130fd4 701 if (max_time == 0) {
mbed_official 0:51ac1d130fd4 702 max_time = 1;
mbed_official 0:51ac1d130fd4 703 }
mbed_official 0:51ac1d130fd4 704 /* ensure the random value is > 0 */
mbed_official 0:51ac1d130fd4 705 group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
mbed_official 0:51ac1d130fd4 706 }
mbed_official 0:51ac1d130fd4 707
mbed_official 0:51ac1d130fd4 708 /**
mbed_official 0:51ac1d130fd4 709 * Delaying membership report for a group if necessary
mbed_official 0:51ac1d130fd4 710 *
mbed_official 0:51ac1d130fd4 711 * @param group the igmp_group for which "delaying" membership report
mbed_official 0:51ac1d130fd4 712 * @param maxresp query delay
mbed_official 0:51ac1d130fd4 713 */
mbed_official 0:51ac1d130fd4 714 static void
mbed_official 0:51ac1d130fd4 715 igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
mbed_official 0:51ac1d130fd4 716 {
mbed_official 0:51ac1d130fd4 717 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
mbed_official 0:51ac1d130fd4 718 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
mbed_official 0:51ac1d130fd4 719 ((group->timer == 0) || (maxresp < group->timer)))) {
mbed_official 0:51ac1d130fd4 720 igmp_start_timer(group, maxresp);
mbed_official 0:51ac1d130fd4 721 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
mbed_official 0:51ac1d130fd4 722 }
mbed_official 0:51ac1d130fd4 723 }
mbed_official 0:51ac1d130fd4 724
mbed_official 0:51ac1d130fd4 725
mbed_official 0:51ac1d130fd4 726 /**
mbed_official 0:51ac1d130fd4 727 * Sends an IP packet on a network interface. This function constructs the IP header
mbed_official 0:51ac1d130fd4 728 * and calculates the IP header checksum. If the source IP address is NULL,
mbed_official 0:51ac1d130fd4 729 * the IP address of the outgoing network interface is filled in as source address.
mbed_official 0:51ac1d130fd4 730 *
mbed_official 0:51ac1d130fd4 731 * @param p the packet to send (p->payload points to the data, e.g. next
mbed_official 0:51ac1d130fd4 732 protocol header; if dest == IP_HDRINCL, p already includes an IP
mbed_official 0:51ac1d130fd4 733 header and p->payload points to that IP header)
mbed_official 0:51ac1d130fd4 734 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
mbed_official 0:51ac1d130fd4 735 * IP address of the netif used to send is used as source address)
mbed_official 0:51ac1d130fd4 736 * @param dest the destination IP address to send the packet to
mbed_official 0:51ac1d130fd4 737 * @param ttl the TTL value to be set in the IP header
mbed_official 0:51ac1d130fd4 738 * @param proto the PROTOCOL to be set in the IP header
mbed_official 0:51ac1d130fd4 739 * @param netif the netif on which to send this packet
mbed_official 0:51ac1d130fd4 740 * @return ERR_OK if the packet was sent OK
mbed_official 0:51ac1d130fd4 741 * ERR_BUF if p doesn't have enough space for IP/LINK headers
mbed_official 0:51ac1d130fd4 742 * returns errors returned by netif->output
mbed_official 0:51ac1d130fd4 743 */
mbed_official 0:51ac1d130fd4 744 static err_t
mbed_official 0:51ac1d130fd4 745 igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
mbed_official 0:51ac1d130fd4 746 {
mbed_official 0:51ac1d130fd4 747 /* This is the "router alert" option */
mbed_official 0:51ac1d130fd4 748 u16_t ra[2];
mbed_official 0:51ac1d130fd4 749 ra[0] = PP_HTONS(ROUTER_ALERT);
mbed_official 0:51ac1d130fd4 750 ra[1] = 0x0000; /* Router shall examine packet */
mbed_official 0:51ac1d130fd4 751 IGMP_STATS_INC(igmp.xmit);
mbed_official 0:51ac1d130fd4 752 return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
mbed_official 0:51ac1d130fd4 753 }
mbed_official 0:51ac1d130fd4 754
mbed_official 0:51ac1d130fd4 755 /**
mbed_official 0:51ac1d130fd4 756 * Send an igmp packet to a specific group.
mbed_official 0:51ac1d130fd4 757 *
mbed_official 0:51ac1d130fd4 758 * @param group the group to which to send the packet
mbed_official 0:51ac1d130fd4 759 * @param type the type of igmp packet to send
mbed_official 0:51ac1d130fd4 760 */
mbed_official 0:51ac1d130fd4 761 static void
mbed_official 0:51ac1d130fd4 762 igmp_send(struct igmp_group *group, u8_t type)
mbed_official 0:51ac1d130fd4 763 {
mbed_official 0:51ac1d130fd4 764 struct pbuf* p = NULL;
mbed_official 0:51ac1d130fd4 765 struct igmp_msg* igmp = NULL;
mbed_official 0:51ac1d130fd4 766 ip_addr_t src = *IP_ADDR_ANY;
mbed_official 0:51ac1d130fd4 767 ip_addr_t* dest = NULL;
mbed_official 0:51ac1d130fd4 768
mbed_official 0:51ac1d130fd4 769 /* IP header + "router alert" option + IGMP header */
mbed_official 0:51ac1d130fd4 770 p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
mbed_official 0:51ac1d130fd4 771
mbed_official 0:51ac1d130fd4 772 if (p) {
mbed_official 0:51ac1d130fd4 773 igmp = (struct igmp_msg *)p->payload;
mbed_official 0:51ac1d130fd4 774 LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
mbed_official 0:51ac1d130fd4 775 (p->len >= sizeof(struct igmp_msg)));
mbed_official 0:51ac1d130fd4 776 ip_addr_copy(src, group->netif->ip_addr);
mbed_official 0:51ac1d130fd4 777
mbed_official 0:51ac1d130fd4 778 if (type == IGMP_V2_MEMB_REPORT) {
mbed_official 0:51ac1d130fd4 779 dest = &(group->group_address);
mbed_official 0:51ac1d130fd4 780 ip_addr_copy(igmp->igmp_group_address, group->group_address);
mbed_official 0:51ac1d130fd4 781 group->last_reporter_flag = 1; /* Remember we were the last to report */
mbed_official 0:51ac1d130fd4 782 } else {
mbed_official 0:51ac1d130fd4 783 if (type == IGMP_LEAVE_GROUP) {
mbed_official 0:51ac1d130fd4 784 dest = &allrouters;
mbed_official 0:51ac1d130fd4 785 ip_addr_copy(igmp->igmp_group_address, group->group_address);
mbed_official 0:51ac1d130fd4 786 }
mbed_official 0:51ac1d130fd4 787 }
mbed_official 0:51ac1d130fd4 788
mbed_official 0:51ac1d130fd4 789 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
mbed_official 0:51ac1d130fd4 790 igmp->igmp_msgtype = type;
mbed_official 0:51ac1d130fd4 791 igmp->igmp_maxresp = 0;
mbed_official 0:51ac1d130fd4 792 igmp->igmp_checksum = 0;
mbed_official 0:51ac1d130fd4 793 igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
mbed_official 0:51ac1d130fd4 794
mbed_official 0:51ac1d130fd4 795 igmp_ip_output_if(p, &src, dest, group->netif);
mbed_official 0:51ac1d130fd4 796 }
mbed_official 0:51ac1d130fd4 797
mbed_official 0:51ac1d130fd4 798 pbuf_free(p);
mbed_official 0:51ac1d130fd4 799 } else {
mbed_official 0:51ac1d130fd4 800 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
mbed_official 0:51ac1d130fd4 801 IGMP_STATS_INC(igmp.memerr);
mbed_official 0:51ac1d130fd4 802 }
mbed_official 0:51ac1d130fd4 803 }
mbed_official 0:51ac1d130fd4 804
mbed_official 0:51ac1d130fd4 805 #endif /* LWIP_IGMP */