2007-08-09 16:53:47 +00:00
/**
* @ file
* IGMP - Internet Group Management Protocol
2007-08-09 22:21:44 +00:00
*
2007-08-09 16:53:47 +00:00
*/
2007-03-11 19:45:32 +00:00
/*
* Copyright ( c ) 2002 CITEL Technologies Ltd .
* 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. Neither the name of CITEL Technologies Ltd nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ` ` 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 CITEL TECHNOLOGIES OR CONTRIBUTORS 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 .
*
* This file is a contribution to the lwIP TCP / IP stack .
* The Swedish Institute of Computer Science and Adam Dunkels
* are specifically granted permission to redistribute this
* source code .
*/
2007-08-30 09:14:28 +00:00
/*-------------------------------------------------------------
Note 1 )
2007-03-11 19:45:32 +00:00
Although the rfc requires V1 AND V2 capability
2007-08-30 09:14:28 +00:00
we will only support v2 since now V1 is very old ( August 1989 )
2007-03-11 19:45:32 +00:00
V1 can be added if required
a debug print and statistic have been implemented to
show this up .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-08-30 09:14:28 +00:00
Note 2 )
2007-03-11 19:45:32 +00:00
A query for a specific group address ( as opposed to ALLHOSTS )
has now been implemented as I am unsure if it is required
a debug print and statistic have been implemented to
show this up .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-08-30 09:14:28 +00:00
Note 3 )
2007-03-11 19:45:32 +00:00
The router alert rfc 2113 is implemented in outgoing packets
but not checked rigorously incoming
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Steve Reynolds
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-08-09 16:53:47 +00:00
/*-----------------------------------------------------------------------------
* RFC 988 - Host extensions for IP multicasting - V0
* RFC 1054 - Host extensions for IP multicasting -
* RFC 1112 - Host extensions for IP multicasting - V1
* RFC 2236 - Internet Group Management Protocol , Version 2 - V2 < - this code is based on this RFC ( it ' s the " de facto " standard )
* RFC 3376 - Internet Group Management Protocol , Version 3 - V3
* RFC 4604 - Using Internet Group Management Protocol Version 3. . . - V3 +
* RFC 2113 - IP Router Alert Option -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-03-11 19:45:32 +00:00
/*-----------------------------------------------------------------------------
* Includes
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# include "lwip/debug.h"
# include "lwip/def.h"
# include "lwip/mem.h"
# include "lwip/ip.h"
# include "lwip/inet.h"
# include "lwip/netif.h"
# include "lwip/icmp.h"
# include "lwip/udp.h"
# include "lwip/tcp.h"
# include "lwip/stats.h"
# include "lwip/igmp.h"
# include "arch/perf.h"
# include "string.h"
/* IGMP support available? */
# if defined(LWIP_IGMP) && (LWIP_IGMP > 0)
/*-----------------------------------------------------------------------------
* Globales
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-06-11 07:27:12 +00:00
static struct igmp_group * igmp_group_list ;
static struct ip_addr allsystems ;
static struct ip_addr allrouters ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
/**
2007-08-29 21:12:32 +00:00
* Initialize the IGMP module
2007-06-08 12:54:40 +00:00
*/
void
igmp_init ( void )
{
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_init: initializing \n " ) ) ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
IP4_ADDR ( & allsystems , 224 , 0 , 0 , 1 ) ;
IP4_ADDR ( & allrouters , 224 , 0 , 0 , 2 ) ;
2007-06-11 07:27:12 +00:00
igmp_group_list = NULL ;
2007-08-29 21:12:32 +00:00
}
/**
* Start IGMP processing on interface
*
* @ param netif network interface on which start IGMP processing
*/
err_t
igmp_start ( struct netif * netif )
{
struct igmp_group * group ;
2007-08-09 16:53:47 +00:00
2007-08-29 21:12:32 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_start: starting IGMP processing on if %x \n " , ( int ) netif ) ) ;
2007-06-08 12:54:40 +00:00
2007-08-29 21:12:32 +00:00
group = igmp_lookup_group ( netif , & allsystems ) ;
if ( group ! = NULL ) {
group - > group_state = IDLE_MEMBER ;
/* Allow the igmp messages at the MAC level */
if ( netif - > igmp_mac_filter ! = NULL ) {
netif - > igmp_mac_filter ( netif , & allsystems , IGMP_ADD_MAC_FILTER ) ;
2007-06-08 12:54:40 +00:00
}
2007-08-29 21:12:32 +00:00
return ERR_OK ;
2007-06-08 12:54:40 +00:00
}
2007-08-29 21:12:32 +00:00
return ERR_MEM ;
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
/**
2007-06-11 07:27:12 +00:00
* Search for a group in the global igmp_group_list
2007-06-08 12:54:40 +00:00
*
2007-08-09 16:53:47 +00:00
* @ param ifp the network interface for which to look
* @ param addr the group ip address to search for
2007-06-08 12:54:40 +00:00
* @ return a struct igmp_group * if the group has been found ,
* NULL if the group wasn ' t found .
*/
struct igmp_group *
2007-08-09 16:53:47 +00:00
igmp_lookfor_group ( struct netif * ifp , struct ip_addr * addr )
2007-06-08 12:54:40 +00:00
{
2007-06-11 07:27:12 +00:00
struct igmp_group * group = igmp_group_list ;
2007-06-08 12:54:40 +00:00
while ( group ) {
if ( ( group - > interface = = ifp ) & & ( ip_addr_cmp ( & ( group - > group_address ) , addr ) ) ) {
return group ;
}
group = group - > next ;
}
/* to be clearer, we return NULL here instead of
* ' group ' ( which is also NULL at this point ) .
*/
return NULL ;
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
/**
* Search for a specific igmp group and create a new one if not found -
*
2007-08-30 09:14:28 +00:00
* @ param ifp the network interface for which to look
2007-06-08 12:54:40 +00:00
* @ param addr the group ip address to search
* @ return a struct igmp_group * ,
* NULL on memory error .
*/
struct igmp_group *
2007-08-09 16:53:47 +00:00
igmp_lookup_group ( struct netif * ifp , struct ip_addr * addr )
2007-06-08 12:54:40 +00:00
{
2007-06-11 07:27:12 +00:00
struct igmp_group * group = igmp_group_list ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
/* Search if the group already exists */
2007-08-09 16:53:47 +00:00
group = igmp_lookfor_group ( ifp , addr ) ;
2007-06-08 12:54:40 +00:00
if ( group ! = NULL ) {
/* Group already exists. */
return group ;
}
/* Group doesn't exist yet, create a new one. */
group = mem_malloc ( sizeof ( struct igmp_group ) ) ;
2007-08-09 16:53:47 +00:00
if ( group ! = NULL ) {
2007-06-08 12:54:40 +00:00
group - > interface = ifp ;
ip_addr_set ( & ( group - > group_address ) , addr ) ;
group - > timer = 0 ; /* Not running */
group - > group_state = NON_MEMBER ;
group - > last_reporter_flag = 0 ;
2007-06-11 07:27:12 +00:00
group - > next = igmp_group_list ;
2007-06-08 12:54:40 +00:00
2007-06-11 07:27:12 +00:00
igmp_group_list = group ;
2007-06-08 12:54:40 +00:00
}
2007-08-30 14:20:54 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_lookup_group: %sallocated a new group with address " , ( group ? " " : " impossible to " ) ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , addr ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " on if %x \n " , ( int ) ifp ) ) ;
2007-03-11 19:45:32 +00:00
return group ;
}
2007-06-08 12:54:40 +00:00
/**
* Called from ip_input ( ) if a new IGMP packet is received .
*
* @ param p received igmp packet , p - > payload pointing to the ip header
* @ param inp network interface on which the packet was received
* @ param dest destination ip address of the igmp packet
*/
void
igmp_input ( struct pbuf * p , struct netif * inp , struct ip_addr * dest )
{
struct ip_hdr * iphdr ;
2007-08-09 20:21:59 +00:00
struct igmp_msg * igmp ;
2007-03-11 19:45:32 +00:00
struct igmp_group * group ;
struct igmp_group * groupref ;
2007-06-08 12:54:40 +00:00
2007-07-26 17:10:56 +00:00
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
iphdr = p - > payload ;
if ( pbuf_header ( p , - ( IPH_HL ( iphdr ) * 4 ) ) | | ( p - > len < IGMP_MINLEN ) ) {
2007-06-08 12:54:40 +00:00
pbuf_free ( p ) ;
2007-08-09 20:09:22 +00:00
IGMP_STATS_INC ( igmp . lenerr ) ;
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: length error \n " ) ) ;
2007-06-08 12:54:40 +00:00
return ;
}
2007-03-11 19:45:32 +00:00
2007-08-30 14:20:54 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: message from " ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , & ( iphdr - > src ) ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " to address " ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , & ( iphdr - > dest ) ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " on if %x \n " , ( int ) inp ) ) ;
2007-07-26 17:10:56 +00:00
2007-03-21 14:47:52 +00:00
/* Now calculate and check the checksum */
2007-08-09 20:21:59 +00:00
igmp = ( struct igmp_msg * ) p - > payload ;
2007-07-26 17:10:56 +00:00
if ( inet_chksum ( igmp , p - > len ) ) {
2007-06-08 12:54:40 +00:00
pbuf_free ( p ) ;
2007-08-09 20:09:22 +00:00
IGMP_STATS_INC ( igmp . chkerr ) ;
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: checksum error \n " ) ) ;
2007-06-08 12:54:40 +00:00
return ;
}
2007-03-11 19:45:32 +00:00
2007-08-09 16:53:47 +00:00
/* Packet is ok so find an existing group */
group = igmp_lookfor_group ( inp , dest ) ; /* use the incoming IP address! */
2007-03-11 19:45:32 +00:00
2007-03-21 14:47:52 +00:00
/* If group can be found or create... */
2007-06-08 12:54:40 +00:00
if ( ! group ) {
pbuf_free ( p ) ;
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: IGMP frame not for us \n " ) ) ;
2007-06-08 12:54:40 +00:00
return ;
}
2007-03-11 19:45:32 +00:00
2007-03-21 14:47:52 +00:00
/* NOW ACT ON THE INCOMING MESSAGE TYPE... */
2007-08-30 14:20:54 +00:00
switch ( igmp - > igmp_msgtype ) {
case IGMP_MEMB_QUERY : {
/* IGMP_MEMB_QUERY to the "all systems" address ? */
if ( ( ip_addr_cmp ( dest , & allsystems ) ) & & ( igmp - > igmp_group_address . addr = = 0 ) ) {
/* THIS IS THE GENERAL QUERY */
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 ) ) ) ;
if ( igmp - > igmp_maxresp = = 0 ) {
IGMP_STATS_INC ( igmp . v1_rxed ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2 \n " ) ) ;
igmp - > igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR ;
}
IGMP_STATS_INC ( igmp . group_query_rxed ) ;
groupref = igmp_group_list ;
while ( groupref ) {
/* Do not send messages on the all systems group address! */
if ( ( groupref - > interface = = inp ) & & ( ! ( ip_addr_cmp ( & ( groupref - > group_address ) , & allsystems ) ) ) ) {
igmp_delaying_member ( groupref , igmp - > igmp_maxresp ) ;
}
groupref = groupref - > next ;
}
} else {
/* IGMP_MEMB_QUERY to a specific group ? */
if ( group - > group_address . addr ! = 0 ) {
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: IGMP_MEMB_QUERY to a specific group " ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , & group - > group_address ) ;
if ( ip_addr_cmp ( dest , & allsystems ) ) {
LWIP_DEBUGF ( IGMP_DEBUG , ( " using \" ALL SYSTEMS \" address (224.0.0.1) [igmp_maxresp=%i] \n " , ( int ) ( igmp - > igmp_maxresp ) ) ) ;
/* we first need to re-lookfor the group since we used dest last time */
group = igmp_lookfor_group ( inp , & igmp - > igmp_group_address ) ;
} else {
LWIP_DEBUGF ( IGMP_DEBUG , ( " with the group address as destination [igmp_maxresp=%i] \n " , ( int ) ( igmp - > igmp_maxresp ) ) ) ;
}
if ( group ! = NULL ) {
IGMP_STATS_INC ( igmp . unicast_query ) ;
igmp_delaying_member ( group , igmp - > igmp_maxresp ) ;
}
}
}
break ;
}
case IGMP_V2_MEMB_REPORT : {
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: IGMP_V2_MEMB_REPORT \n " ) ) ;
IGMP_STATS_INC ( igmp . report_rxed ) ;
if ( group - > group_state = = DELAYING_MEMBER ) {
/* This is on a specific group we have already looked up */
group - > timer = 0 ; /* stopped */
group - > group_state = IDLE_MEMBER ;
group - > last_reporter_flag = 0 ;
}
break ;
}
default : {
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_input: unexpected msg %x in state %x on group %x on if %x \n " , ( int ) igmp - > igmp_msgtype , ( int ) group - > group_state , ( int ) & group , ( int ) group - > interface ) ) ;
break ;
}
2007-06-08 12:54:40 +00:00
}
2007-08-30 14:20:54 +00:00
2007-06-08 12:54:40 +00:00
pbuf_free ( p ) ;
2007-03-11 19:45:32 +00:00
return ;
}
2007-06-08 12:54:40 +00:00
/**
* Join a group on one network interface .
*
* @ param ifp the network interface which should join a new group
* @ param groupaddr the ip address of the group which to join
* @ return ERR_OK if group was joined , an err_t otherwise
*/
err_t
igmp_joingroup ( struct netif * ifp , struct ip_addr * groupaddr )
{
struct igmp_group * group ;
2007-03-11 19:45:32 +00:00
2007-09-03 09:56:38 +00:00
/* make sure netif is valid */
LWIP_ERROR ( " igmp_joingroup: attempt to join on NULL netif " , ( ifp ! = NULL ) , return ERR_VAL ; ) ;
2007-08-09 16:53:47 +00:00
/* make sure it is multicast address */
2007-08-30 15:48:14 +00:00
LWIP_ERROR ( " igmp_joingroup: attempt to join non-multicast address " , ip_addr_ismulticast ( groupaddr ) , return ERR_VAL ; ) ;
2007-08-09 16:53:47 +00:00
/* find group or create a new one if not found */
group = igmp_lookup_group ( ifp , groupaddr ) ;
2007-06-08 12:54:40 +00:00
2007-08-09 16:53:47 +00:00
if ( group ! = NULL ) {
2007-06-08 12:54:40 +00:00
/* This should create a new group, check the state to make sure */
if ( group - > group_state ! = NON_MEMBER ) {
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_joingroup: join to group not in state NON_MEMBER \n " ) ) ;
2007-06-08 12:54:40 +00:00
return ERR_OK ;
}
/* OK - it was new group */
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_joingroup: join to new group: " ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , groupaddr ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " \n " ) ) ;
2007-06-08 12:54:40 +00:00
if ( ifp - > igmp_mac_filter ! = NULL ) {
ifp - > igmp_mac_filter ( ifp , groupaddr , IGMP_ADD_MAC_FILTER ) ;
}
2007-08-09 20:09:22 +00:00
IGMP_STATS_INC ( igmp . join_sent ) ;
2007-06-08 12:54:40 +00:00
igmp_send ( group , IGMP_V2_MEMB_REPORT ) ;
2007-08-30 14:20:54 +00:00
igmp_start_timer ( group , IGMP_JOIN_DELAYING_MEMBER_TMR ) ;
2007-06-08 12:54:40 +00:00
/* Need to work out where this timer comes from */
group - > group_state = DELAYING_MEMBER ;
return ERR_OK ;
}
2007-03-11 19:45:32 +00:00
return ERR_MEM ;
}
2007-06-08 12:54:40 +00:00
/**
* Leave a group on one network interface .
*
* @ param ifp the network interface which should leave a group
* @ param groupaddr the ip address of the group which to leave
* @ return ERR_OK if group was left , an err_t otherwise
*/
err_t
igmp_leavegroup ( struct netif * ifp , struct ip_addr * groupaddr )
{
struct igmp_group * group ;
2007-09-03 09:56:38 +00:00
/* make sure netif is valid */
LWIP_ERROR ( " igmp_leavegroup: attempt to leave on NULL netif " , ( ifp ! = NULL ) , return ERR_VAL ; ) ;
2007-08-30 15:48:14 +00:00
/* make sure it is multicast address */
LWIP_ERROR ( " igmp_leavegroup: attempt to leave non-multicast address " , ip_addr_ismulticast ( groupaddr ) , return ERR_VAL ; ) ;
/* find group */
2007-08-09 16:53:47 +00:00
group = igmp_lookfor_group ( ifp , groupaddr ) ;
2007-06-08 12:54:40 +00:00
2007-08-09 16:53:47 +00:00
if ( group ! = NULL ) {
2007-06-08 12:54:40 +00:00
/* Only send a leave if the flag is set according to the state diagram */
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_leavegroup: Leaving group: " ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , groupaddr ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " \n " ) ) ;
2007-06-08 12:54:40 +00:00
if ( group - > last_reporter_flag ) {
2007-08-30 09:14:28 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_leavegroup: sending leaving group \n " ) ) ;
2007-08-09 20:09:22 +00:00
IGMP_STATS_INC ( igmp . leave_sent ) ;
2007-06-08 12:54:40 +00:00
igmp_send ( group , IGMP_LEAVE_GROUP ) ;
}
/* The block is not deleted since the group still exists and we may rejoin */
group - > last_reporter_flag = 0 ;
group - > group_state = NON_MEMBER ;
group - > timer = 0 ;
if ( ifp - > igmp_mac_filter ! = NULL ) {
ifp - > igmp_mac_filter ( ifp , groupaddr , IGMP_DEL_MAC_FILTER ) ;
}
return ERR_OK ;
}
2007-03-11 19:45:32 +00:00
2007-08-30 09:14:28 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_leavegroup: not member of group \n " ) ) ;
2007-08-09 16:53:47 +00:00
return ERR_VAL ;
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
/**
* The igmp timer function ( both for NO_SYS = 1 and = 0 )
* Should be called every IGMP_TMR_INTERVAL milliseconds ( 100 ms is default ) .
*/
void
2007-08-09 16:53:47 +00:00
igmp_tmr ( void )
2007-06-08 12:54:40 +00:00
{
2007-06-11 07:27:12 +00:00
struct igmp_group * group = igmp_group_list ;
2007-06-08 12:54:40 +00:00
2007-08-09 16:53:47 +00:00
while ( group ! = NULL ) {
2007-06-08 12:54:40 +00:00
if ( group - > timer ! = 0 ) {
group - > timer - = 1 ;
if ( group - > timer = = 0 ) {
igmp_timeout ( group ) ;
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
}
group = group - > next ;
}
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
/**
* Called if a timeout for one group is reached .
* Sends a report for this group .
*
* @ param group an igmp_group for which a timeout is reached
*/
void
igmp_timeout ( struct igmp_group * group )
{
/* If the state is DELAYING_MEMBER then we send a report for this group */
2007-08-09 16:53:47 +00:00
if ( group - > group_state = = DELAYING_MEMBER ) {
2007-08-30 14:20:54 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_timeout: report membership for group with address " ) ) ;
ip_addr_debug_print ( IGMP_DEBUG , & ( group - > group_address ) ) ;
LWIP_DEBUGF ( IGMP_DEBUG , ( " on if %x \n " , ( int ) group - > interface ) ) ;
2007-06-08 12:54:40 +00:00
igmp_send ( group , IGMP_V2_MEMB_REPORT ) ;
}
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
/**
* Start a timer for an igmp group
*
* @ param group the igmp_group for which to start a timer
* @ param max_time the time in multiples of IGMP_TMR_INTERVAL ( decrease with
* every call to igmp_tmr ( ) )
*/
void
igmp_start_timer ( struct igmp_group * group , u8_t max_time )
{
2007-08-30 14:20:54 +00:00
/**
* @ todo Important ! ! this should be random 0 - > max_time . Find out how to do this
2007-06-08 12:54:40 +00:00
*/
2007-03-11 19:45:32 +00:00
group - > timer = max_time ;
}
2007-06-08 12:54:40 +00:00
/**
* Stop a timer for an igmp_group
*
* @ param group the igmp_group for which to stop the timer
*/
void
igmp_stop_timer ( struct igmp_group * group )
{
group - > timer = 0 ;
2007-03-11 19:45:32 +00:00
}
2007-08-30 14:20:54 +00:00
/**
* Delaying membership report for a group if necessary
*
* @ param group the igmp_group for which " delaying " membership report
* @ param maxresp query delay
*/
void
igmp_delaying_member ( struct igmp_group * group , u8_t maxresp )
{
if ( ( group - > group_state = = IDLE_MEMBER ) | | ( ( group - > group_state = = DELAYING_MEMBER ) & & ( maxresp > group - > timer ) ) ) {
igmp_start_timer ( group , ( maxresp ) / 2 ) ;
group - > group_state = DELAYING_MEMBER ;
}
}
2007-06-08 12:54:40 +00:00
/**
2007-03-11 19:45:32 +00:00
* Sends an IP packet on a network interface . This function constructs the IP header
* and calculates the IP header checksum . If the source IP address is NULL ,
* the IP address of the outgoing network interface is filled in as source address .
2007-06-08 12:54:40 +00:00
*
* @ param p the packet to send ( p - > payload points to the data , e . g . next
protocol header ; if dest = = IP_HDRINCL , p already includes an IP
header and p - > payload points to that IP header )
* @ param src the source IP address to send from ( if src = = IP_ADDR_ANY , the
* IP address of the netif used to send is used as source address )
* @ param dest the destination IP address to send the packet to
* @ param ttl the TTL value to be set in the IP header
* @ param proto the PROTOCOL to be set in the IP header
* @ param netif the netif on which to send this packet
* @ return ERR_OK if the packet was sent OK
* ERR_BUF if p doesn ' t have enough space for IP / LINK headers
* returns errors returned by netif - > output
*/
err_t
igmp_ip_output_if ( struct pbuf * p , struct ip_addr * src , struct ip_addr * dest ,
u8_t ttl , u8_t proto , struct netif * netif )
{
2007-08-09 20:09:22 +00:00
static u16_t ip_id = 0 ;
struct ip_hdr * iphdr = NULL ;
u16_t * ra = NULL ;
2007-03-11 19:45:32 +00:00
2007-03-21 14:47:52 +00:00
/* First write in the "router alert" */
2007-06-08 12:54:40 +00:00
if ( pbuf_header ( p , ROUTER_ALERTLEN ) ) {
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_ip_output_if: not enough room for IP header in pbuf \n " ) ) ;
return ERR_BUF ;
}
2007-03-11 19:45:32 +00:00
2007-03-21 14:47:52 +00:00
/* This is the "router alert" option */
2007-03-11 19:45:32 +00:00
ra = p - > payload ;
ra [ 0 ] = htons ( 0x9404 ) ;
ra [ 1 ] = 0x0000 ;
2007-03-21 14:47:52 +00:00
/* now the normal ip header */
2007-06-08 12:54:40 +00:00
if ( pbuf_header ( p , IP_HLEN ) ) {
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_ip_output_if: not enough room for IP header in pbuf \n " ) ) ;
return ERR_BUF ;
}
2007-03-11 19:45:32 +00:00
iphdr = p - > payload ;
2007-06-08 12:54:40 +00:00
if ( dest ! = IP_HDRINCL ) {
iphdr - > _ttl_proto = ( proto < < 8 ) ;
iphdr - > _ttl_proto | = ttl ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
/* iphdr->dest = dest->addr; */
ip_addr_set ( & ( iphdr - > dest ) , dest ) ;
2007-03-11 19:45:32 +00:00
# ifdef HAVE_BITFIELDS
2007-06-08 12:54:40 +00:00
iphdr - > _v_hl_tos | = ( ( IP_HLEN + ROUTER_ALERTLEN ) / 4 ) < < 16 ;
iphdr - > _v_hl_tos | = 4 < < 24 ;
2007-03-11 19:45:32 +00:00
# else
2007-06-08 12:54:40 +00:00
iphdr - > _v_hl_tos = ( 4 < < 4 ) | ( ( IP_HLEN + ROUTER_ALERTLEN ) / 4 & 0xf ) ;
2007-03-11 19:45:32 +00:00
# endif /* HAVE_BITFIELDS */
2007-06-08 12:54:40 +00:00
iphdr - > _v_hl_tos | = 0 ;
iphdr - > _len = htons ( p - > tot_len ) ;
iphdr - > _offset = htons ( 0 ) ;
iphdr - > _id = htons ( ip_id + + ) ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
if ( ip_addr_isany ( src ) ) {
ip_addr_set ( & ( iphdr - > src ) , & ( netif - > ip_addr ) ) ;
} else {
ip_addr_set ( & ( iphdr - > src ) , src ) ;
}
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
iphdr - > _chksum = 0 ;
iphdr - > _chksum = inet_chksum ( iphdr , IP_HLEN + ROUTER_ALERTLEN ) ;
} else {
dest = & ( iphdr - > dest ) ;
}
2007-03-11 19:45:32 +00:00
# if IP_DEBUG
2007-06-08 12:54:40 +00:00
ip_debug_print ( p ) ;
2007-03-11 19:45:32 +00:00
# endif
2007-08-30 09:14:28 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_ip_output_if: sending to if %x \n " , ( int ) netif ) ) ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
return netif - > output ( netif , p , dest ) ;
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
/**
* Send an igmp packet to a specific group .
*
2007-08-09 22:21:44 +00:00
* @ param group the group to which to send the packet
2007-06-08 12:54:40 +00:00
* @ param type the type of igmp packet to send
*/
void
igmp_send ( struct igmp_group * group , u8_t type )
{
2007-08-09 20:21:59 +00:00
struct pbuf * p = NULL ;
struct igmp_msg * igmp = NULL ;
struct ip_addr src = { 0 } ;
struct ip_addr * dest = NULL ;
2007-03-11 19:45:32 +00:00
/* IP header + IGMP header */
2007-06-08 12:54:40 +00:00
p = pbuf_alloc ( PBUF_TRANSPORT , IGMP_MINLEN , PBUF_RAM ) ;
2007-03-11 19:45:32 +00:00
2007-06-08 12:54:40 +00:00
if ( p ) {
igmp = p - > payload ;
2007-08-09 20:21:59 +00:00
LWIP_ASSERT ( " igmp_send: check that first pbuf can hold struct igmp_msg " ,
( p - > len > = sizeof ( struct igmp_msg ) ) ) ;
2007-06-08 12:54:40 +00:00
ip_addr_set ( & src , & ( ( group - > interface ) - > ip_addr ) ) ;
2007-03-11 19:45:32 +00:00
2007-08-09 16:53:47 +00:00
if ( type = = IGMP_V2_MEMB_REPORT ) {
2007-06-08 12:54:40 +00:00
dest = & ( group - > group_address ) ;
2007-08-09 20:09:22 +00:00
IGMP_STATS_INC ( igmp . report_sent ) ;
2007-06-08 12:54:40 +00:00
ip_addr_set ( & ( igmp - > igmp_group_address ) , & ( group - > group_address ) ) ;
group - > last_reporter_flag = 1 ; /* Remember we were the last to report */
} else {
2007-08-09 16:53:47 +00:00
if ( type = = IGMP_LEAVE_GROUP ) {
2007-06-08 12:54:40 +00:00
dest = & allrouters ;
ip_addr_set ( & ( igmp - > igmp_group_address ) , & ( group - > group_address ) ) ;
2007-03-11 19:45:32 +00:00
}
2007-06-08 12:54:40 +00:00
}
2007-03-11 19:45:32 +00:00
2007-08-30 14:20:54 +00:00
if ( ( type = = IGMP_V2_MEMB_REPORT ) | | ( type = = IGMP_LEAVE_GROUP ) ) {
igmp - > igmp_msgtype = type ;
igmp - > igmp_maxresp = 0 ;
igmp - > igmp_checksum = 0 ;
igmp - > igmp_checksum = inet_chksum ( igmp , IGMP_MINLEN ) ;
2007-06-08 12:54:40 +00:00
2007-08-30 14:20:54 +00:00
igmp_ip_output_if ( p , & src , dest , IGMP_TTL , IP_PROTO_IGMP , group - > interface ) ;
}
pbuf_free ( p ) ;
2007-06-08 12:54:40 +00:00
} else {
2007-08-09 16:53:47 +00:00
LWIP_DEBUGF ( IGMP_DEBUG , ( " igmp_send: not enough memory for igmp_send \n " ) ) ;
2007-06-08 12:54:40 +00:00
}
2007-03-11 19:45:32 +00:00
}
# endif /* LWIP_IGMP */