176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @file 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IGMP - Internet Group Management Protocol 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2002 CITEL Technologies Ltd. 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * All rights reserved. 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Redistribution and use in source and binary forms, with or without 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modification, are permitted provided that the following conditions 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are met: 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1. Redistributions of source code must retain the above copyright 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * notice, this list of conditions and the following disclaimer. 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2. Redistributions in binary form must reproduce the above copyright 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * notice, this list of conditions and the following disclaimer in the 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * documentation and/or other materials provided with the distribution. 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * may be used to endorse or promote products derived from this software 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * without specific prior written permission. 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * SUCH DAMAGE. 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This file is a contribution to the lwIP TCP/IP stack. 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The Swedish Institute of Computer Science and Adam Dunkels 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are specifically granted permission to redistribute this 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * source code. 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman*/ 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*------------------------------------------------------------- 4276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanNote 1) 4376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanAlthough the rfc requires V1 AND V2 capability 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanwe will only support v2 since now V1 is very old (August 1989) 4576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanV1 can be added if required 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana debug print and statistic have been implemented to 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanshow this up. 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman------------------------------------------------------------- 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman------------------------------------------------------------- 5176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanNote 2) 5276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanA query for a specific group address (as opposed to ALLHOSTS) 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanhas now been implemented as I am unsure if it is required 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana debug print and statistic have been implemented to 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanshow this up. 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman------------------------------------------------------------- 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman------------------------------------------------------------- 5976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanNote 3) 6076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanThe router alert rfc 2113 is implemented in outgoing packets 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbut not checked rigorously incoming 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman------------------------------------------------------------- 6376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanSteve Reynolds 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman------------------------------------------------------------*/ 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*----------------------------------------------------------------------------- 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 988 - Host extensions for IP multicasting - V0 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 1054 - Host extensions for IP multicasting - 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 1112 - Host extensions for IP multicasting - V1 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RFC 2113 - IP Router Alert Option - 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *----------------------------------------------------------------------------*/ 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*----------------------------------------------------------------------------- 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Includes 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *----------------------------------------------------------------------------*/ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/opt.h" 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/igmp.h" 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/debug.h" 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/def.h" 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/mem.h" 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/ip.h" 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/inet_chksum.h" 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/netif.h" 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/icmp.h" 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/udp.h" 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/tcp.h" 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/stats.h" 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "string.h" 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IGMP constants 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_TTL 1 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_MINLEN 8 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ROUTER_ALERT 0x9404U 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ROUTER_ALERTLEN 4 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IGMP message types, including version number. 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_MEMB_QUERY 0x11 /* Membership query */ 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Group membership states */ 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_GROUP_NON_MEMBER 0 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_GROUP_DELAYING_MEMBER 1 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IGMP_GROUP_IDLE_MEMBER 2 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IGMP packet format. 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef PACK_STRUCT_USE_INCLUDES 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman# include "arch/bpstruct.h" 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 12576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPACK_STRUCT_BEGIN 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct igmp_msg { 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PACK_STRUCT_FIELD(u8_t igmp_msgtype); 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PACK_STRUCT_FIELD(u8_t igmp_maxresp); 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PACK_STRUCT_FIELD(u16_t igmp_checksum); 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address); 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACK_STRUCT_STRUCT; 13276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPACK_STRUCT_END 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef PACK_STRUCT_USE_INCLUDES 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman# include "arch/epstruct.h" 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr); 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t igmp_remove_group(struct igmp_group *group); 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void igmp_timeout( struct igmp_group *group); 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void igmp_start_timer(struct igmp_group *group, u8_t max_time); 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void igmp_stop_timer(struct igmp_group *group); 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void igmp_send(struct igmp_group *group, u8_t type); 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct igmp_group* igmp_group_list; 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic ip_addr_t allsystems; 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic ip_addr_t allrouters; 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize the IGMP module 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_init(void) 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IP4_ADDR(&allsystems, 224, 0, 0, 1); 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IP4_ADDR(&allrouters, 224, 0, 0, 2); 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef LWIP_DEBUG 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Dump global IGMP groups list 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_dump_group_list() 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group = igmp_group_list; 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (group != NULL) { 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &group->group_address); 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = group->next; 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("\n")); 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define igmp_dump_group_list() 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_DEBUG */ 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Start IGMP processing on interface 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif network interface on which start IGMP processing 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_start(struct netif *netif) 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group* group; 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = igmp_lookup_group(netif, &allsystems); 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group != NULL) { 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->group_state = IGMP_GROUP_IDLE_MEMBER; 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->use++; 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Allow the igmp messages at the MAC level */ 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (netif->igmp_mac_filter != NULL) { 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &allsystems); 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ERR_OK; 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ERR_MEM; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Stop IGMP processing on interface 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif network interface on which stop IGMP processing 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_stop(struct netif *netif) 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group = igmp_group_list; 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *prev = NULL; 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *next; 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* look for groups joined on this interface further down the list */ 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (group != NULL) { 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman next = group->next; 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* is it a group joined on this interface? */ 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->netif == netif) { 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* is it the first group of the list? */ 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group == igmp_group_list) { 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_group_list = next; 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* is there a "previous" group defined? */ 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (prev != NULL) { 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman prev->next = next; 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable the group at the MAC level */ 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (netif->igmp_mac_filter != NULL) { 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &group->group_address); 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* free group */ 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memp_free(MEMP_IGMP_GROUP, group); 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* change the "previous" */ 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman prev = group; 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* move to "next" */ 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = next; 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ERR_OK; 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Report IGMP memberships for this interface 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif network interface on which report IGMP memberships 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_report_groups(struct netif *netif) 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group = igmp_group_list; 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (group != NULL) { 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->netif == netif) { 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = group->next; 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Search for a group in the global igmp_group_list 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ifp the network interface for which to look 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param addr the group ip address to search for 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return a struct igmp_group* if the group has been found, 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * NULL if the group wasn't found. 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct igmp_group * 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group = igmp_group_list; 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (group != NULL) { 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return group; 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = group->next; 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* to be clearer, we return NULL here instead of 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 'group' (which is also NULL at this point). 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Search for a specific igmp group and create a new one if not found- 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ifp the network interface for which to look 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param addr the group ip address to search 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return a struct igmp_group*, 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * NULL on memory error. 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct igmp_group * 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_lookup_group(struct netif *ifp, ip_addr_t *addr) 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group = igmp_group_list; 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Search if the group already exists */ 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = igmp_lookfor_group(ifp, addr); 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group != NULL) { 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Group already exists. */ 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return group; 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Group doesn't exist yet, create a new one */ 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group != NULL) { 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->netif = ifp; 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_set(&(group->group_address), addr); 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->timer = 0; /* Not running */ 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->group_state = IGMP_GROUP_NON_MEMBER; 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->last_reporter_flag = 0; 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->use = 0; 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->next = igmp_group_list; 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_group_list = group; 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, addr); 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return group; 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove a group in the global igmp_group_list 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param group the group to remove from the global igmp_group_list 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if group was removed from the list, an err_t otherwise 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_remove_group(struct igmp_group *group) 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_t err = ERR_OK; 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Is it the first group? */ 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (igmp_group_list == group) { 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_group_list = group->next; 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* look for group further down the list */ 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *tmpGroup; 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (tmpGroup->next == group) { 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tmpGroup->next = group->next; 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Group not found in the global igmp_group_list */ 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (tmpGroup == NULL) 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ERR_ARG; 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* free group */ 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memp_free(MEMP_IGMP_GROUP, group); 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called from ip_input() if a new IGMP packet is received. 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param p received igmp packet, p->payload pointing to the ip header 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param inp network interface on which the packet was received 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param dest destination ip address of the igmp packet 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ip_hdr * iphdr; 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_msg* igmp; 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group* group; 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group* groupref; 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.recv); 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iphdr = (struct ip_hdr *)p->payload; 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pbuf_free(p); 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.lenerr); 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Now calculate and check the checksum */ 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp = (struct igmp_msg *)p->payload; 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (inet_chksum(igmp, p->len)) { 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pbuf_free(p); 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.chkerr); 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Packet is ok so find an existing group */ 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If group can be found or create... */ 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!group) { 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pbuf_free(p); 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.drop); 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (igmp->igmp_msgtype) { 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case IGMP_MEMB_QUERY: { 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* IGMP_MEMB_QUERY to the "all systems" address ? */ 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* THIS IS THE GENERAL QUERY */ 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 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))); 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (igmp->igmp_maxresp == 0) { 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.rx_v1); 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.rx_general); 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman groupref = igmp_group_list; 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (groupref) { 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Do not send messages on the all systems group address! */ 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_delaying_member(groupref, igmp->igmp_maxresp); 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman groupref = groupref->next; 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* IGMP_MEMB_QUERY to a specific group ? */ 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!ip_addr_isany(&igmp->igmp_group_address)) { 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ip_addr_cmp(dest, &allsystems)) { 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_t groupaddr; 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* we first need to re-look for the group since we used dest last time */ 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_copy(groupaddr, igmp->igmp_group_address); 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = igmp_lookfor_group(inp, &groupaddr); 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group != NULL) { 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.rx_group); 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_delaying_member(group, igmp->igmp_maxresp); 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.drop); 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.proterr); 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case IGMP_V2_MEMB_REPORT: { 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.rx_report); 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* This is on a specific group we have already looked up */ 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->timer = 0; /* stopped */ 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->group_state = IGMP_GROUP_IDLE_MEMBER; 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->last_reporter_flag = 0; 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: { 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp->igmp_msgtype, group->group_state, &group, group->netif)); 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.proterr); 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pbuf_free(p); 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Join a group on one network interface. 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ifaddr ip address of the network interface which should join a new group 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param groupaddr the ip address of the group which to join 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if group was joined on the netif(s), an err_t otherwise 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_t err = ERR_VAL; /* no matching interface */ 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group; 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct netif *netif; 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* make sure it is multicast address */ 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* loop through netif's */ 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif = netif_list; 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (netif != NULL) { 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Should we join this interface ? */ 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* find group or create a new one if not found */ 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = igmp_lookup_group(netif, groupaddr); 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group != NULL) { 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* This should create a new group, check the state to make sure */ 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->group_state != IGMP_GROUP_NON_MEMBER) { 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* OK - it was new group */ 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, groupaddr); 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("\n")); 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If first use of the group, allow the group at the MAC level */ 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, groupaddr); 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.tx_join); 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_send(group, IGMP_V2_MEMB_REPORT); 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Need to work out where this timer comes from */ 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->group_state = IGMP_GROUP_DELAYING_MEMBER; 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Increment group use */ 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->use++; 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Join on this interface */ 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ERR_OK; 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Return an error even if some network interfaces are joined */ 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** @todo undo any other netif already joined */ 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ERR_MEM; 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* proceed to next network interface */ 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif = netif->next; 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Leave a group on one network interface. 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ifaddr ip address of the network interface which should leave a group 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param groupaddr the ip address of the group which to leave 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if group was left on the netif(s), an err_t otherwise 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_t err = ERR_VAL; /* no matching interface */ 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group; 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct netif *netif; 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* make sure it is multicast address */ 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* loop through netif's */ 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif = netif_list; 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (netif != NULL) { 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Should we leave this interface ? */ 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* find group */ 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = igmp_lookfor_group(netif, groupaddr); 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group != NULL) { 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Only send a leave if the flag is set according to the state diagram */ 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: ")); 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, groupaddr); 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("\n")); 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If there is no other use of the group */ 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->use <= 1) { 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If we are the last reporter for this group */ 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->last_reporter_flag) { 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.tx_leave); 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_send(group, IGMP_LEAVE_GROUP); 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Disable the group at the MAC level */ 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (netif->igmp_mac_filter != NULL) { 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, groupaddr); 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, groupaddr); 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("\n")); 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Free the group */ 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_remove_group(group); 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Decrement group use */ 63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->use--; 63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Leave on this interface */ 63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ERR_OK; 63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* It's not a fatal error on "leavegroup" */ 64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); 64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* proceed to next network interface */ 64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netif = netif->next; 64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The igmp timer function (both for NO_SYS=1 and =0) 65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). 65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid 65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_tmr(void) 65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_group *group = igmp_group_list; 65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (group != NULL) { 66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->timer > 0) { 66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->timer--; 66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->timer == 0) { 66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_timeout(group); 66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group = group->next; 66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called if a timeout for one group is reached. 67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Sends a report for this group. 67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param group an igmp_group for which a timeout is reached 67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_timeout(struct igmp_group *group) 67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ 68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { 68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); 68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); 68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); 68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.tx_report); 68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_send(group, IGMP_V2_MEMB_REPORT); 68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Start a timer for an igmp group 69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param group the igmp_group for which to start a timer 69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with 69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * every call to igmp_tmr()) 69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_start_timer(struct igmp_group *group, u8_t max_time) 70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* ensure the input value is > 0 */ 70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (max_time == 0) { 70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_time = 1; 70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* ensure the random value is > 0 */ 70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->timer = (LWIP_RAND() % (max_time - 1)) + 1; 70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Stop a timer for an igmp_group 71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param group the igmp_group for which to stop the timer 71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_stop_timer(struct igmp_group *group) 71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->timer = 0; 71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Delaying membership report for a group if necessary 72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param group the igmp_group for which "delaying" membership report 72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param maxresp query delay 72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_delaying_member(struct igmp_group *group, u8_t maxresp) 72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || 73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && 73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((group->timer == 0) || (maxresp < group->timer)))) { 73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_start_timer(group, maxresp); 73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->group_state = IGMP_GROUP_DELAYING_MEMBER; 73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Sends an IP packet on a network interface. This function constructs the IP header 74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and calculates the IP header checksum. If the source IP address is NULL, 74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the IP address of the outgoing network interface is filled in as source address. 74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param p the packet to send (p->payload points to the data, e.g. next 74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman protocol header; if dest == IP_HDRINCL, p already includes an IP 74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman header and p->payload points to that IP header) 74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param src the source IP address to send from (if src == IP_ADDR_ANY, the 74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IP address of the netif used to send is used as source address) 74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param dest the destination IP address to send the packet to 74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ttl the TTL value to be set in the IP header 75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param proto the PROTOCOL to be set in the IP header 75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif the netif on which to send this packet 75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if the packet was sent OK 75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ERR_BUF if p doesn't have enough space for IP/LINK headers 75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * returns errors returned by netif->output 75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t 75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif) 75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* This is the "router alert" option */ 76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16_t ra[2]; 76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ra[0] = PP_HTONS(ROUTER_ALERT); 76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ra[1] = 0x0000; /* Router shall examine packet */ 76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.xmit); 76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); 76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send an igmp packet to a specific group. 76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param group the group to which to send the packet 77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param type the type of igmp packet to send 77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void 77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanigmp_send(struct igmp_group *group, u8_t type) 77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct pbuf* p = NULL; 77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct igmp_msg* igmp = NULL; 77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_t src = *IP_ADDR_ANY; 77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_t* dest = NULL; 78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* IP header + "router alert" option + IGMP header */ 78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); 78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (p) { 78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp = (struct igmp_msg *)p->payload; 78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", 78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (p->len >= sizeof(struct igmp_msg))); 78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_copy(src, group->netif->ip_addr); 78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (type == IGMP_V2_MEMB_REPORT) { 79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dest = &(group->group_address); 79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_copy(igmp->igmp_group_address, group->group_address); 79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman group->last_reporter_flag = 1; /* Remember we were the last to report */ 79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (type == IGMP_LEAVE_GROUP) { 79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dest = &allrouters; 79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ip_addr_copy(igmp->igmp_group_address, group->group_address); 79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { 80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp->igmp_msgtype = type; 80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp->igmp_maxresp = 0; 80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp->igmp_checksum = 0; 80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); 80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman igmp_ip_output_if(p, &src, dest, group->netif); 80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pbuf_free(p); 81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); 81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman IGMP_STATS_INC(igmp.memerr); 81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_IGMP */ 818