igmp_router.c
Go to the documentation of this file.
1 /**
2  * @file igmp_router.c
3  * @brief IGMP router
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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  * @section Description
28  *
29  * IGMP is used by IP hosts to report their multicast group memberships
30  * to routers. Refer to the following RFCs for complete details:
31  * - RFC 1112: Host Extensions for IP Multicasting
32  * - RFC 2236: Internet Group Management Protocol, Version 2
33  * - RFC 3376: Internet Group Management Protocol, Version 3
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 2.6.0
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL IGMP_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/net.h"
44 #include "ipv4/ipv4.h"
45 #include "igmp/igmp_router.h"
46 #include "igmp/igmp_router_misc.h"
47 #include "debug.h"
48 
49 //Check TCP/IP stack configuration
50 #if (IPV4_SUPPORT == ENABLED && IGMP_ROUTER_SUPPORT == ENABLED)
51 
52 
53 /**
54  * @brief Initialize settings with default values
55  * @param[out] settings Structure that contains IGMP router settings
56  **/
57 
59 {
60  //Primary interface on an attached network
61  settings->interface = NULL;
62 
63  //Implementations may provide a way for system administrators to enable the
64  //use of IGMPv1 on their routers; in the absence of explicit configuration,
65  //the configuration must default to IGMPv2 (refer to RFC 2236, section 4)
66  settings->version = IGMP_VERSION_2;
67 
68  //Maximum number of multicast groups
69  settings->numGroups = 0;
70  //Multicast groups
71  settings->groups = NULL;
72 
73  //Add multicast route callback
74  settings->addMcastRouteCallback = NULL;
75  //Delete multicast route callback
76  settings->deleteMcastRouteCallback = NULL;
77 }
78 
79 
80 /**
81  * @brief IGMP router initialization
82  * @param[in] context Pointer to the IGMP router context
83  * @param[in] settings IGMP router specific settings
84  * @return Error code
85  **/
86 
88  const IgmpRouterSettings *settings)
89 {
90  uint_t i;
91  NetInterface *interface;
92 
93  //Debug message
94  TRACE_INFO("Initializing IGMP router...\r\n");
95 
96  //Ensure the parameters are valid
97  if(context == NULL || settings == NULL)
99 
100  //The IGMP router must be bound to a valid interface
101  if(settings->interface == NULL)
103 
104  //Sanity check
105  if(settings->numGroups < 1 || settings->groups == NULL)
107 
108  //Point to the underlying network interface
109  interface = settings->interface;
110 
111  //Clear the IGMP router context
112  osMemset(context, 0, sizeof(IgmpRouterContext));
113 
114  //Attach TCP/IP stack context
115  context->netContext = settings->interface->netContext;
116 
117  //Save user settings
118  context->interface = settings->interface;
119  context->version = settings->version;
120  context->numGroups = settings->numGroups;
121  context->groups = settings->groups;
122  context->addMcastRouteCallback = settings->addMcastRouteCallback;
123  context->deleteMcastRouteCallback = settings->deleteMcastRouteCallback;
124 
125  //A router should start in the Initial state on all attached networks, and
126  //immediately move to Querier state
127  context->state = IGMP_ROUTER_STATE_INIT;
128 
129  //Loop through multicast groups
130  for(i = 0; i < context->numGroups; i++)
131  {
132  //The "No Members Present" state, when there are no hosts on the network
133  //which have sent reports for this multicast group is the initial state
134  //for all groups on the router
135  context->groups[i].state = IGMP_ROUTER_GROUP_STATE_NO_MEMBERS_PRESENT;
136  }
137 
138  //Get exclusive access
139  netLock(context->netContext);
140  //Attach the IGMP router context to the network interface
141  interface->igmpRouterContext = context;
142  //Release exclusive access
143  netUnlock(context->netContext);
144 
145  //Successful initialization
146  return NO_ERROR;
147 }
148 
149 
150 /**
151  * @brief Start IGMP router
152  * @param[in] context Pointer to the IGMP router context
153  * @return Error code
154  **/
155 
157 {
158  //Make sure the IGMP router context is valid
159  if(context == NULL)
161 
162  //Debug message
163  TRACE_INFO("Starting IGMP router...\r\n");
164 
165  //Get exclusive access
166  netLock(context->netContext);
167 
168  //Accept all frames with a multicast destination address
169  context->interface->acceptAllMulticast = TRUE;
170  //Update the MAC filter table
171  nicUpdateMacAddrFilter(context->interface);
172 
173  //The IGMP router is now running
174  context->running = TRUE;
175 
176  //Release exclusive access
177  netUnlock(context->netContext);
178 
179  //Successful processing
180  return NO_ERROR;
181 }
182 
183 
184 /**
185  * @brief Stop IGMP router
186  * @param[in] context Pointer to the IGMP router context
187  * @return Error code
188  **/
189 
191 {
192  //Make sure the IGMP router context is valid
193  if(context == NULL)
195 
196  //Debug message
197  TRACE_INFO("Stopping IGMP router...\r\n");
198 
199  //Get exclusive access
200  netLock(context->netContext);
201 
202  //Revert to default configuration
203  context->interface->acceptAllMulticast = FALSE;
204  //Update the MAC filter table
205  nicUpdateMacAddrFilter(context->interface);
206 
207  //The IGMP router is not running anymore
208  context->running = FALSE;
209 
210  //Release exclusive access
211  netUnlock(context->netContext);
212 
213  //Successful processing
214  return NO_ERROR;
215 }
216 
217 
218 /**
219  * @brief IGMP router timer handler
220  *
221  * This routine must be periodically called by the TCP/IP stack to update
222  * IGMP router state machines
223  *
224  * @param[in] context Pointer to the IGMP router context
225  **/
226 
228 {
229  uint_t i;
230 
231  //Check whether the IGMP router is running
232  if(context->running)
233  {
234  //IGMP router state machine
235  igmpRouterFsm(context);
236 
237  //Loop through multicast groups
238  for(i = 0; i < context->numGroups; i++)
239  {
240  //IGMP group state machine
241  igmpRouterGroupFsm(context, &context->groups[i]);
242  }
243  }
244 }
245 
246 
247 /**
248  * @brief IGMP router state machine
249  * @param[in] context Pointer to the IGMP router context
250  **/
251 
253 {
254  //Check router state
255  if(context->state == IGMP_ROUTER_STATE_INIT)
256  {
257  //Send a General Query message
259 
260  //Number of General Queries left to sent out on startup
261  context->startupQueryCount = IGMP_STARTUP_QUERY_COUNT - 1;
262 
263  //Start General Query timer
264  netStartTimer(&context->generalQueryTimer, IGMP_STARTUP_QUERY_INTERVAL);
265 
266  //A router should start in the Initial state on all attached networks,
267  //and immediately move to Querier state (refer to RFC 2236, section 7)
268  context->state = IGMP_ROUTER_STATE_QUERIER;
269  }
270  else if(context->state == IGMP_ROUTER_STATE_QUERIER)
271  {
272  //This router is designated to transmit IGMP Membership Queries on this
273  //network
274  if(netTimerExpired(&context->generalQueryTimer))
275  {
276  //Send a General Query message
278 
279  //On startup, a router should send General Queries spaced closely
280  //together in order to quickly and reliably determine membership
281  //information (refer to RFC 2236, section 3)
282  if(context->startupQueryCount > 1)
283  {
284  //Number of General Queries left to sent out on startup
285  context->startupQueryCount--;
286 
287  //The Startup Query Interval is the interval between General Queries
288  //sent by a Querier on startup (refer to RFC 2236, section 8.6)
289  netStartTimer(&context->generalQueryTimer, IGMP_STARTUP_QUERY_INTERVAL);
290  }
291  else
292  {
293  //The Query Interval is the interval between General Queries sent by
294  //the Querier (refer to RFC 2236, section 8.2)
295  netStartTimer(&context->generalQueryTimer, IGMP_QUERY_INTERVAL);
296  }
297  }
298  }
299  else if(context->state == IGMP_ROUTER_STATE_NON_QUERIER)
300  {
301  //There is another router designated to transmit IGMP membership Queries
302  //on this network
303  if(netTimerExpired(&context->otherQuerierPresentTimer))
304  {
305  //Switch to the "Querier" state
306  context->state = IGMP_ROUTER_STATE_QUERIER;
307  }
308  }
309  else
310  {
311  //Invalid state
312  context->state = IGMP_ROUTER_STATE_INIT;
313  }
314 }
315 
316 
317 /**
318  * @brief IGMP group state machine
319  * @param[in] context Pointer to the IGMP router context
320  * @param[in] group Multicast group
321  **/
322 
324 {
325  //A router may be in one of four possible states with respect to any single
326  //IP multicast group on any single attached network
328  {
329  //The "No Members Present" state is the initial state for all groups on
330  //the router; it requires no storage in the router
331  }
333  {
334  //Check whether the timer set for a group membership has expired
335  if(netTimerExpired(&group->timer))
336  {
337  //There are no longer any members of this group on the network
338  igmpRouterDeleteGroup(context, group);
339  }
340  }
342  {
343  //Check whether the timer set for a group membership has expired
344  if(netTimerExpired(&group->timer))
345  {
346  //There are no longer any members of this group on the network
347  igmpRouterDeleteGroup(context, group);
348  }
349  else if(netTimerExpired(&group->v1HostTimer))
350  {
351  //Switch to the "Members Present" state
353  }
354  else
355  {
356  //Just for sanity
357  }
358  }
360  {
361  //Any Querier to non-Querier transition is ignored during this time; the
362  //same router keeps sending the Group-Specific Queries
363  if(group->lastMemberQueryCount > 0)
364  {
365  //Check whether the retransmit timer has expired
366  if(netTimerExpired(&group->retransmitTimer))
367  {
368  //Send a Group-Specific Query message
369  igmpRouterSendGroupSpecificQuery(context, group->addr);
370 
371  //Number of Group-Specific Queries left to sent before the router
372  //assumes there are no local members
373  group->lastMemberQueryCount--;
374 
375  //Start retransmit timer for the group membership
377  }
378  }
379  else
380  {
381  //Check whether the timer set for a group membership has expired
382  if(netTimerExpired(&group->timer))
383  {
384  //If no reports are received after the response time of the last query
385  //expires, the routers assume that the group has no local members
386  igmpRouterDeleteGroup(context, group);
387  }
388  }
389  }
390  else
391  {
392  //Invalid state
394  }
395 }
396 
397 
398 /**
399  * @brief Release IGMP router context
400  * @param[in] context Pointer to the IGMP router context
401  **/
402 
404 {
405  NetInterface *interface;
406 
407  //Make sure the IGMP router context is valid
408  if(context != NULL)
409  {
410  //Get exclusive access
411  netLock(context->netContext);
412 
413  //Point to the underlying network interface
414  interface = context->interface;
415  //Detach the IGMP router context from the network interface
416  interface->igmpRouterContext = NULL;
417 
418  //Release exclusive access
419  netUnlock(context->netContext);
420 
421  //Clear IGMP router context
422  osMemset(context, 0, sizeof(IgmpRouterContext));
423  }
424 }
425 
426 #endif
IgmpVersion version
IGMP version.
Definition: igmp_router.h:118
@ IGMP_ROUTER_GROUP_STATE_NO_MEMBERS_PRESENT
Definition: igmp_router.h:73
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:798
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
void igmpRouterFsm(IgmpRouterContext *context)
IGMP router state machine.
Definition: igmp_router.c:252
Helper functions fore IGMP router.
Ipv4Addr addr
Multicast group address.
Definition: igmp_router.h:103
#define TRUE
Definition: os_port.h:50
void igmpRouterGroupFsm(IgmpRouterContext *context, IgmpRouterGroup *group)
IGMP group state machine.
Definition: igmp_router.c:323
error_t igmpRouterStart(IgmpRouterContext *context)
Start IGMP router.
Definition: igmp_router.c:156
error_t igmpRouterInit(IgmpRouterContext *context, const IgmpRouterSettings *settings)
IGMP router initialization.
Definition: igmp_router.c:87
IGMP router settings.
Definition: igmp_router.h:116
uint_t lastMemberQueryCount
Number of Group-Specific Queries to be sent.
Definition: igmp_router.h:104
@ IGMP_ROUTER_GROUP_STATE_MEMBERS_PRESENT
Definition: igmp_router.h:74
@ IGMP_ROUTER_GROUP_STATE_CHECKING_MEMBERSHIP
Definition: igmp_router.h:76
uint_t numGroups
Maximum number of multicast groups.
Definition: igmp_router.h:119
@ IGMP_ROUTER_GROUP_STATE_V1_MEMBERS_PRESENT
Definition: igmp_router.h:75
IgmpRouterDeleteMcastRouteCallback deleteMcastRouteCallback
Delete multicast route callback.
Definition: igmp_router.h:122
IGMP router.
void igmpRouterDeleteGroup(IgmpRouterContext *context, IgmpRouterGroup *group)
Delete a multicast group.
#define IGMP_STARTUP_QUERY_INTERVAL
Definition: igmp_common.h:75
#define FALSE
Definition: os_port.h:46
@ IGMP_ROUTER_STATE_QUERIER
Definition: igmp_router.h:62
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void igmpRouterDeinit(IgmpRouterContext *context)
Release IGMP router context.
Definition: igmp_router.c:403
error_t
Error codes.
Definition: error.h:43
NetTimer retransmitTimer
Retransmit timer for the group membership.
Definition: igmp_router.h:107
NetInterface * interface
Underlying network interface.
Definition: igmp_router.h:117
void igmpRouterGetDefaultSettings(IgmpRouterSettings *settings)
Initialize settings with default values.
Definition: igmp_router.c:58
error_t igmpRouterSendGeneralQuery(IgmpRouterContext *context)
Send General Query message.
#define NetInterface
Definition: net.h:40
@ IGMP_ROUTER_STATE_INIT
Definition: igmp_router.h:61
IgmpRouterGroupState state
Multicast group state.
Definition: igmp_router.h:102
IgmpRouterGroup * groups
Multicast groups.
Definition: igmp_router.h:120
#define TRACE_INFO(...)
Definition: debug.h:105
NetTimer v1HostTimer
IGMPv1 Host timer.
Definition: igmp_router.h:106
NetTimer timer
Timer for the group membership.
Definition: igmp_router.h:105
@ IGMP_ROUTER_STATE_NON_QUERIER
Definition: igmp_router.h:63
error_t igmpRouterSendGroupSpecificQuery(IgmpRouterContext *context, Ipv4Addr groupAddr)
Send Group-Specific Query message.
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:379
#define IGMP_LAST_MEMBER_QUERY_INTERVAL
Definition: igmp_common.h:89
@ IGMP_VERSION_2
Definition: igmp_common.h:163
#define IGMP_QUERY_INTERVAL
Definition: igmp_common.h:53
void igmpRouterTick(IgmpRouterContext *context)
IGMP router timer handler.
Definition: igmp_router.c:227
#define IgmpRouterContext
Definition: igmp_router.h:47
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
IgmpRouterAddMcastRouteCallback addMcastRouteCallback
Add multicast route callback.
Definition: igmp_router.h:121
IPv4 (Internet Protocol Version 4)
#define IGMP_STARTUP_QUERY_COUNT
Definition: igmp_common.h:82
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
Multicast group.
Definition: igmp_router.h:101
error_t igmpRouterStop(IgmpRouterContext *context)
Stop IGMP router.
Definition: igmp_router.c:190
bool_t netTimerExpired(NetTimer *timer)
Check whether the timer has expired.
Definition: net_misc.c:838
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.