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-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  * @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.4.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  //Initialize IGMP router context
115  context->interface = settings->interface;
116  context->version = settings->version;
117  context->numGroups = settings->numGroups;
118  context->groups = settings->groups;
119  context->addMcastRouteCallback = settings->addMcastRouteCallback;
120  context->deleteMcastRouteCallback = settings->deleteMcastRouteCallback;
121 
122  //A router should start in the Initial state on all attached networks, and
123  //immediately move to Querier state
124  context->state = IGMP_ROUTER_STATE_INIT;
125 
126  //Loop through multicast groups
127  for(i = 0; i < context->numGroups; i++)
128  {
129  //The "No Members Present" state, when there are no hosts on the network
130  //which have sent reports for this multicast group is the initial state
131  //for all groups on the router
132  context->groups[i].state = IGMP_ROUTER_GROUP_STATE_NO_MEMBERS_PRESENT;
133  }
134 
135  //Attach the IGMP router context to the network interface
136  interface->igmpRouterContext = context;
137 
138  //Successful initialization
139  return NO_ERROR;
140 }
141 
142 
143 /**
144  * @brief Start IGMP router
145  * @param[in] context Pointer to the IGMP router context
146  * @return Error code
147  **/
148 
150 {
151  //Make sure the IGMP router context is valid
152  if(context == NULL)
154 
155  //Debug message
156  TRACE_INFO("Starting IGMP router...\r\n");
157 
158  //Get exclusive access
160 
161  //Accept all frames with a multicast destination address
162  context->interface->acceptAllMulticast = TRUE;
163  //Update the MAC filter table
164  nicUpdateMacAddrFilter(context->interface);
165 
166  //The IGMP router is now running
167  context->running = TRUE;
168 
169  //Release exclusive access
171 
172  //Successful processing
173  return NO_ERROR;
174 }
175 
176 
177 /**
178  * @brief Stop IGMP router
179  * @param[in] context Pointer to the IGMP router context
180  * @return Error code
181  **/
182 
184 {
185  //Make sure the IGMP router context is valid
186  if(context == NULL)
188 
189  //Debug message
190  TRACE_INFO("Stopping IGMP router...\r\n");
191 
192  //Get exclusive access
194 
195  //Revert to default configuration
196  context->interface->acceptAllMulticast = FALSE;
197  //Update the MAC filter table
198  nicUpdateMacAddrFilter(context->interface);
199 
200  //The IGMP router is not running anymore
201  context->running = FALSE;
202 
203  //Release exclusive access
205 
206  //Successful processing
207  return NO_ERROR;
208 }
209 
210 
211 /**
212  * @brief IGMP router timer handler
213  *
214  * This routine must be periodically called by the TCP/IP stack to update
215  * IGMP router state machines
216  *
217  * @param[in] context Pointer to the IGMP router context
218  **/
219 
221 {
222  uint_t i;
223 
224  //Check whether the IGMP router is running
225  if(context->running)
226  {
227  //IGMP router state machine
228  igmpRouterFsm(context);
229 
230  //Loop through multicast groups
231  for(i = 0; i < context->numGroups; i++)
232  {
233  //IGMP group state machine
234  igmpRouterGroupFsm(context, &context->groups[i]);
235  }
236  }
237 }
238 
239 
240 /**
241  * @brief IGMP router state machine
242  * @param[in] context Pointer to the IGMP router context
243  **/
244 
246 {
247  //Check router state
248  if(context->state == IGMP_ROUTER_STATE_INIT)
249  {
250  //Send a General Query message
252 
253  //Number of General Queries left to sent out on startup
254  context->startupQueryCount = IGMP_STARTUP_QUERY_COUNT - 1;
255 
256  //Start General Query timer
257  netStartTimer(&context->generalQueryTimer, IGMP_STARTUP_QUERY_INTERVAL);
258 
259  //A router should start in the Initial state on all attached networks,
260  //and immediately move to Querier state (refer to RFC 2236, section 7)
261  context->state = IGMP_ROUTER_STATE_QUERIER;
262  }
263  else if(context->state == IGMP_ROUTER_STATE_QUERIER)
264  {
265  //This router is designated to transmit IGMP Membership Queries on this
266  //network
267  if(netTimerExpired(&context->generalQueryTimer))
268  {
269  //Send a General Query message
271 
272  //On startup, a router should send General Queries spaced closely
273  //together in order to quickly and reliably determine membership
274  //information (refer to RFC 2236, section 3)
275  if(context->startupQueryCount > 1)
276  {
277  //Number of General Queries left to sent out on startup
278  context->startupQueryCount--;
279 
280  //The Startup Query Interval is the interval between General Queries
281  //sent by a Querier on startup (refer to RFC 2236, section 8.6)
282  netStartTimer(&context->generalQueryTimer, IGMP_STARTUP_QUERY_INTERVAL);
283  }
284  else
285  {
286  //The Query Interval is the interval between General Queries sent by
287  //the Querier (refer to RFC 2236, section 8.2)
288  netStartTimer(&context->generalQueryTimer, IGMP_QUERY_INTERVAL);
289  }
290  }
291  }
292  else if(context->state == IGMP_ROUTER_STATE_NON_QUERIER)
293  {
294  //There is another router designated to transmit IGMP membership Queries
295  //on this network
296  if(netTimerExpired(&context->otherQuerierPresentTimer))
297  {
298  //Switch to the "Querier" state
299  context->state = IGMP_ROUTER_STATE_QUERIER;
300  }
301  }
302  else
303  {
304  //Invalid state
305  context->state = IGMP_ROUTER_STATE_INIT;
306  }
307 }
308 
309 
310 /**
311  * @brief IGMP group state machine
312  * @param[in] context Pointer to the IGMP router context
313  * @param[in] group Multicast group
314  **/
315 
317 {
318  //A router may be in one of four possible states with respect to any single
319  //IP multicast group on any single attached network
321  {
322  //The "No Members Present" state is the initial state for all groups on
323  //the router; it requires no storage in the router
324  }
326  {
327  //Check whether the timer set for a group membership has expired
328  if(netTimerExpired(&group->timer))
329  {
330  //There are no longer any members of this group on the network
331  igmpRouterDeleteGroup(context, group);
332  }
333  }
335  {
336  //Check whether the timer set for a group membership has expired
337  if(netTimerExpired(&group->timer))
338  {
339  //There are no longer any members of this group on the network
340  igmpRouterDeleteGroup(context, group);
341  }
342  else if(netTimerExpired(&group->v1HostTimer))
343  {
344  //Switch to the "Members Present" state
346  }
347  else
348  {
349  //Just for sanity
350  }
351  }
353  {
354  //Any Querier to non-Querier transition is ignored during this time; the
355  //same router keeps sending the Group-Specific Queries
356  if(group->lastMemberQueryCount > 0)
357  {
358  //Check whether the retransmit timer has expired
359  if(netTimerExpired(&group->retransmitTimer))
360  {
361  //Send a Group-Specific Query message
362  igmpRouterSendGroupSpecificQuery(context, group->addr);
363 
364  //Number of Group-Specific Queries left to sent before the router
365  //assumes there are no local members
366  group->lastMemberQueryCount--;
367 
368  //Start retransmit timer for the group membership
370  }
371  }
372  else
373  {
374  //Check whether the timer set for a group membership has expired
375  if(netTimerExpired(&group->timer))
376  {
377  //If no reports are received after the response time of the last query
378  //expires, the routers assume that the group has no local members
379  igmpRouterDeleteGroup(context, group);
380  }
381  }
382  }
383  else
384  {
385  //Invalid state
387  }
388 }
389 
390 #endif
unsigned int uint_t
Definition: compiler_port.h:50
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define IGMP_STARTUP_QUERY_COUNT
Definition: igmp_common.h:82
#define IGMP_QUERY_INTERVAL
Definition: igmp_common.h:53
#define IGMP_STARTUP_QUERY_INTERVAL
Definition: igmp_common.h:75
#define IGMP_LAST_MEMBER_QUERY_INTERVAL
Definition: igmp_common.h:89
void igmpRouterGetDefaultSettings(IgmpRouterSettings *settings)
Initialize settings with default values.
Definition: igmp_router.c:58
error_t igmpRouterStart(IgmpRouterContext *context)
Start IGMP router.
Definition: igmp_router.c:149
error_t igmpRouterStop(IgmpRouterContext *context)
Stop IGMP router.
Definition: igmp_router.c:183
error_t igmpRouterInit(IgmpRouterContext *context, const IgmpRouterSettings *settings)
IGMP router initialization.
Definition: igmp_router.c:87
void igmpRouterFsm(IgmpRouterContext *context)
IGMP router state machine.
Definition: igmp_router.c:245
void igmpRouterTick(IgmpRouterContext *context)
IGMP router timer handler.
Definition: igmp_router.c:220
void igmpRouterGroupFsm(IgmpRouterContext *context, IgmpRouterGroup *group)
IGMP group state machine.
Definition: igmp_router.c:316
IGMP router.
@ IGMP_ROUTER_GROUP_STATE_V1_MEMBERS_PRESENT
Definition: igmp_router.h:87
@ IGMP_ROUTER_GROUP_STATE_CHECKING_MEMBERSHIP
Definition: igmp_router.h:88
@ IGMP_ROUTER_GROUP_STATE_MEMBERS_PRESENT
Definition: igmp_router.h:86
@ IGMP_ROUTER_GROUP_STATE_NO_MEMBERS_PRESENT
Definition: igmp_router.h:85
#define IgmpRouterContext
Definition: igmp_router.h:47
@ IGMP_ROUTER_STATE_QUERIER
Definition: igmp_router.h:74
@ IGMP_ROUTER_STATE_INIT
Definition: igmp_router.h:73
@ IGMP_ROUTER_STATE_NON_QUERIER
Definition: igmp_router.h:75
@ IGMP_VERSION_2
Definition: igmp_router.h:62
void igmpRouterDeleteGroup(IgmpRouterContext *context, IgmpRouterGroup *group)
Delete a multicast group.
error_t igmpRouterSendGroupSpecificQuery(IgmpRouterContext *context, Ipv4Addr groupAddr)
Send Group-Specific Query message.
error_t igmpRouterSendGeneralQuery(IgmpRouterContext *context)
Send General Query message.
Helper functions fore IGMP router.
IPv4 (Internet Protocol Version 4)
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netMutex
Definition: net_legacy.h:195
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:763
bool_t netTimerExpired(NetTimer *timer)
Check whether the timer has expired.
Definition: net_misc.c:803
error_t nicUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Definition: nic.c:352
#define osMemset(p, value, length)
Definition: os_port.h:135
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Multicast group.
Definition: igmp_router.h:113
uint_t lastMemberQueryCount
Number of Group-Specific Queries to be sent.
Definition: igmp_router.h:116
IgmpRouterGroupState state
Multicast group state.
Definition: igmp_router.h:114
NetTimer v1HostTimer
IGMPv1 Host timer.
Definition: igmp_router.h:118
NetTimer timer
Timer for the group membership.
Definition: igmp_router.h:117
NetTimer retransmitTimer
Retransmit timer for the group membership.
Definition: igmp_router.h:119
Ipv4Addr addr
Multicast group address.
Definition: igmp_router.h:115
IGMP router settings.
Definition: igmp_router.h:128
IgmpRouterGroup * groups
Multicast groups.
Definition: igmp_router.h:132
uint_t numGroups
Maximum number of multicast groups.
Definition: igmp_router.h:131
IgmpVersion version
IGMP version.
Definition: igmp_router.h:130
IgmpRouterAddMcastRouteCallback addMcastRouteCallback
Add multicast route callback.
Definition: igmp_router.h:133
NetInterface * interface
Underlying network interface.
Definition: igmp_router.h:129
IgmpRouterDeleteMcastRouteCallback deleteMcastRouteCallback
Delete multicast route callback.
Definition: igmp_router.h:134