igmp_host_misc.c
Go to the documentation of this file.
1 /**
2  * @file igmp_host_misc.c
3  * @brief Helper functions for IGMP host
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL IGMP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "ipv4/ipv4.h"
37 #include "igmp/igmp_host.h"
38 #include "igmp/igmp_host_misc.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (IPV4_SUPPORT == ENABLED && IGMP_HOST_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Send Membership Report message
47  * @param[in] interface Underlying network interface
48  * @param[in] ipAddr IPv4 address specifying the group address
49  * @return Error code
50  **/
51 
53 {
55  IgmpHostContext *context;
56 
57  //Point to the IGMP host context
58  context = &interface->igmpHostContext;
59 
60  //Make sure the specified address is a valid multicast address
62  return ERROR_INVALID_ADDRESS;
63 
64  //The all-systems group (224.0.0.1) is handled as a special case. The host
65  //never sends a report for that group
67  return ERROR_INVALID_ADDRESS;
68 
69  //The type of report is determined by the state of the interface
70  if(context->igmpv1RouterPresent)
71  {
73  }
74  else
75  {
77  }
78 
79  //Format the Membership Report message
80  message.maxRespTime = 0;
81  message.checksum = 0;
82  message.groupAddr = ipAddr;
83 
84  //Message checksum calculation
85  message.checksum = ipCalcChecksum(&message, sizeof(IgmpMessage));
86 
87  //The Membership Report message is sent to the group being reported
88  return igmpSendMessage(interface, ipAddr, &message, sizeof(IgmpMessage));
89 }
90 
91 
92 /**
93  * @brief Send Leave Group message
94  * @param[in] interface Underlying network interface
95  * @param[in] ipAddr IPv4 address specifying the group address being left
96  * @return Error code
97  **/
98 
100 {
102  IgmpHostContext *context;
103 
104  //Point to the IGMP host context
105  context = &interface->igmpHostContext;
106 
107  //Make sure the specified address is a valid multicast address
109  return ERROR_INVALID_ADDRESS;
110 
111  //The all-systems group (224.0.0.1) is handled as a special case. The host
112  //never sends a Leave Group message for that group
114  return ERROR_INVALID_ADDRESS;
115 
116  //If the interface state says the querier is running IGMPv1, this action
117  //should be skipped
118  if(context->igmpv1RouterPresent)
119  return NO_ERROR;
120 
121  //Format the Leave Group message
123  message.maxRespTime = 0;
124  message.checksum = 0;
125  message.groupAddr = ipAddr;
126 
127  //Message checksum calculation
128  message.checksum = ipCalcChecksum(&message, sizeof(IgmpMessage));
129 
130  //Leave Group messages are addressed to the all-routers group because other
131  //group members have no need to know that a host has left the group, but it
132  //does no harm to address the message to the group
133  return igmpSendMessage(interface, IGMP_ALL_ROUTERS_ADDR, &message,
134  sizeof(IgmpMessage));
135 }
136 
137 
138 /**
139  * @brief Process incoming IGMP message
140  * @param[in] interface Underlying network interface
141  * @param[in] message Pointer to the incoming IGMP message
142  * @param[in] length Length of the IGMP message, in bytes
143  **/
144 
146  const IgmpMessage *message, size_t length)
147 {
148  //Check IGMP message type
150  {
151  //Process Membership Query message
153  }
154  else if(message->type == IGMP_TYPE_MEMBERSHIP_REPORT_V1 ||
156  {
157  //Process Membership Report message
159  }
160  else
161  {
162  //Discard Leave Group messages
163  }
164 }
165 
166 
167 /**
168  * @brief Process incoming Membership Query message
169  * @param[in] interface Underlying network interface
170  * @param[in] message Pointer to the incoming IGMP message
171  * @param[in] length Length of the IGMP message, in bytes
172  **/
173 
175  const IgmpMessage *message, size_t length)
176 {
177  uint_t i;
178  systime_t time;
180  Ipv4FilterEntry *entry;
181  IgmpHostContext *context;
182 
183  //The group address in the IGMP header must either be zero or a valid
184  //multicast group address (refer to RFC 2236, section 6)
185  if(message->groupAddr != IPV4_UNSPECIFIED_ADDR &&
186  !ipv4IsMulticastAddr(message->groupAddr))
187  {
188  return;
189  }
190 
191  //Point to the IGMP host context
192  context = &interface->igmpHostContext;
193 
194  //Get current time
195  time = osGetSystemTime();
196 
197  //IGMPv1 or IGMPv2 Membership Query message?
198  if(message->maxRespTime == 0)
199  {
200  //The host has received a query with the Max Response Time field set to 0
201  context->igmpv1RouterPresent = TRUE;
202  //Restart IGMPv1 router present timer
204  //The maximum response time is 10 seconds by default
206  }
207  else
208  {
209  //The Max Resp Time field specifies the maximum time allowed before
210  //sending a responding report
211  maxRespTime = message->maxRespTime * 100;
212  }
213 
214  //Go through the multicast filter table
215  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
216  {
217  //Point to the current entry
218  entry = &interface->ipv4Context.multicastFilter[i];
219 
220  //Valid entry?
221  if(entry->refCount > 0)
222  {
223  //The all-systems group (224.0.0.1) is handled as a special case. The
224  //host starts in Idle Member state for that group on every interface
225  //and never transitions to another state
226  if(entry->addr != IGMP_ALL_SYSTEMS_ADDR)
227  {
228  //A General Query applies to all memberships on the interface from which
229  //the Query is received. A Group-Specific Query applies to membership
230  //in a single group on the interface from which the Query is received
231  if(message->groupAddr == IPV4_UNSPECIFIED_ADDR ||
232  message->groupAddr == entry->addr)
233  {
234  //Check group state
236  {
237  //The timer has not yet expired?
238  if(timeCompare(time, entry->timer) < 0)
239  {
240  //If a timer for the group is already running, it is reset to
241  //the random value only if the requested Max Response Time is
242  //less than the remaining value of the running timer
243  if(maxRespTime < (entry->timer - time))
244  {
245  //Restart delay timer
247  }
248  }
249  }
250  else if(entry->state == IGMP_HOST_GROUP_STATE_IDLE_MEMBER)
251  {
252  //Switch to the "Delaying Member" state
254  //Delay the response by a random amount of time
256  }
257  else
258  {
259  //Just for sanity
260  }
261  }
262  }
263  }
264  }
265 }
266 
267 
268 /**
269  * @brief Process incoming Membership Report message
270  * @param[in] interface Underlying network interface
271  * @param[in] message Pointer to the incoming IGMP message
272  * @param[in] length Length of the IGMP message, in bytes
273  **/
274 
276  const IgmpMessage *message, size_t length)
277 {
278  uint_t i;
279  Ipv4FilterEntry *entry;
280 
281  //The group address in the IGMP header must be a valid multicast group
282  //address
283  if(!ipv4IsMulticastAddr(message->groupAddr))
284  return;
285 
286  //Go through the multicast filter table
287  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
288  {
289  //Point to the current entry
290  entry = &interface->ipv4Context.multicastFilter[i];
291 
292  //Valid entry?
293  if(entry->refCount > 0)
294  {
295  //Report messages are ignored for memberships in the Non-Member or
296  //Idle Member state
298  {
299  //The Membership Report message matches the current entry?
300  if(message->groupAddr == entry->addr)
301  {
302  //Clear flag
303  entry->flag = FALSE;
304  //Switch to the "Idle Member" state
306  }
307  }
308  }
309  }
310 }
311 
312 #endif
uint8_t message[]
Definition: chap.h:154
unsigned int uint_t
Definition: compiler_port.h:50
Debugging facilities.
uint32_t time
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
@ NO_ERROR
Success.
Definition: error.h:44
error_t igmpSendMessage(NetInterface *interface, Ipv4Addr destAddr, const IgmpMessage *message, size_t length)
Send IGMP message.
Definition: igmp_common.c:141
IgmpMessage
Definition: igmp_common.h:172
#define IGMP_V1_MAX_RESPONSE_TIME
Definition: igmp_common.h:121
@ IGMP_TYPE_LEAVE_GROUP
Definition: igmp_common.h:149
@ IGMP_TYPE_MEMBERSHIP_REPORT_V2
Definition: igmp_common.h:148
@ IGMP_TYPE_MEMBERSHIP_REPORT_V1
Definition: igmp_common.h:147
@ IGMP_TYPE_MEMBERSHIP_QUERY
Definition: igmp_common.h:146
#define IGMP_V1_ROUTER_PRESENT_TIMEOUT
Definition: igmp_common.h:114
uint8_t maxRespTime
Definition: igmp_common.h:169
#define IGMP_ALL_SYSTEMS_ADDR
Definition: igmp_common.h:130
#define IGMP_ALL_ROUTERS_ADDR
Definition: igmp_common.h:132
IGMP host.
@ IGMP_HOST_GROUP_STATE_IDLE_MEMBER
Definition: igmp_host.h:59
@ IGMP_HOST_GROUP_STATE_DELAYING_MEMBER
Definition: igmp_host.h:58
void igmpHostProcessMessage(NetInterface *interface, const IgmpMessage *message, size_t length)
Process incoming IGMP message.
void igmpHostProcessMembershipReport(NetInterface *interface, const IgmpMessage *message, size_t length)
Process incoming Membership Report message.
void igmpHostProcessMembershipQuery(NetInterface *interface, const IgmpMessage *message, size_t length)
Process incoming Membership Query message.
error_t igmpHostSendMembershipReport(NetInterface *interface, Ipv4Addr ipAddr)
Send Membership Report message.
error_t igmpHostSendLeaveGroup(NetInterface *interface, Ipv4Addr ipAddr)
Send Leave Group message.
Helper functions for IGMP host.
uint16_t ipCalcChecksum(const void *data, size_t length)
IP checksum calculation.
Definition: ip.c:499
Ipv4Addr ipAddr
Definition: ipcp.h:105
IPv4 (Internet Protocol Version 4)
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:267
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:110
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:168
#define IPV4_MULTICAST_FILTER_SIZE
Definition: ipv4.h:83
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:763
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:914
#define timeCompare(t1, t2)
Definition: os_port.h:40
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t systime_t
System time.
IGMP host context.
Definition: igmp_host.h:68
bool_t igmpv1RouterPresent
An IGMPv1 query has been recently heard.
Definition: igmp_host.h:69
NetTimer timer
IGMPv1 router present timer.
Definition: igmp_host.h:70
IPv4 multicast filter entry.
Definition: ipv4.h:357
uint_t state
IGMP host state.
Definition: ipv4.h:360
bool_t flag
IGMP flag.
Definition: ipv4.h:361
systime_t timer
Delay timer.
Definition: ipv4.h:362
Ipv4Addr addr
Multicast address.
Definition: ipv4.h:358
uint_t refCount
Reference count for the current entry.
Definition: ipv4.h:359
uint8_t length
Definition: tcp.h:368