igmp_snooping_misc.c
Go to the documentation of this file.
1 /**
2  * @file igmp_snooping_misc.c
3  * @brief Helper functions for IGMP snooping switch
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.2
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 "ipv4/ipv4_multicast.h"
38 #include "igmp/igmp_snooping.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (IPV4_SUPPORT == ENABLED && IGMP_SNOOPING_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Process incoming IGMP message
48  * @param[in] context Pointer to the IGMP snooping switch context
49  * @param[in] pseudoHeader IPv4 pseudo header
50  * @param[in] message Pointer to the incoming IGMP message
51  * @param[in] length Length of the IGMP message, in bytes
52  * @param[in] ancillary Additional options passed to the stack along with
53  * the packet
54  **/
55 
57  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
58  size_t length, const NetRxAncillary *ancillary)
59 {
60  //Check the ingress port the IGMP message was received on
61  if(ancillary->port == 0)
62  {
63  return;
64  }
65  else if(ancillary->port == SWITCH_CPU_PORT)
66  {
67  }
68  else if(ancillary->port > context->numPorts)
69  {
70  return;
71  }
72 
73  //Check IGMP message type
75  {
76  //Process Membership Query message
77  igmpSnoopingProcessMembershipQuery(context, pseudoHeader, message,
78  length, ancillary);
79  }
80  else if(message->type == IGMP_TYPE_MEMBERSHIP_REPORT_V1 ||
82  {
83  //Process Membership Report message
84  igmpSnoopingProcessMembershipReport(context, pseudoHeader, message,
85  length, ancillary);
86  }
87  else if(message->type == IGMP_TYPE_MEMBERSHIP_REPORT_V3)
88  {
89  //Process Version 3 Membership Report message
90  igmpSnoopingProcessMembershipReportV3(context, pseudoHeader,
91  (IgmpMembershipReportV3 *) message, length, ancillary);
92  }
93  else if(message->type == IGMP_TYPE_LEAVE_GROUP)
94  {
95  //Process Leave Group message
96  igmpSnoopingProcessLeaveGroup(context, pseudoHeader, message,
97  length, ancillary);
98  }
99  else
100  {
101  //Process unrecognized IGMP messages
102  igmpSnoopingProcessUnknownMessage(context, pseudoHeader, message,
103  length, ancillary);
104  }
105 }
106 
107 
108 /**
109  * @brief Process incoming Membership Query message
110  * @param[in] context Pointer to the IGMP snooping switch context
111  * @param[in] pseudoHeader IPv4 pseudo header
112  * @param[in] message Pointer to the incoming IGMP message
113  * @param[in] length Length of the IGMP message, in bytes
114  * @param[in] ancillary Additional options passed to the stack along with
115  * the packet
116  **/
117 
119  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
120  size_t length, const NetRxAncillary *ancillary)
121 {
122  uint_t i;
123  uint32_t portMap;
126  IgmpSnoopingGroup *group;
127 
128  //The group address in the IGMP header must either be zero or a valid
129  //multicast group address (refer to RFC 2236, section 6)
130  if(message->groupAddr != IPV4_UNSPECIFIED_ADDR &&
131  !ipv4IsMulticastAddr(message->groupAddr))
132  {
133  return;
134  }
135 
136  //Point to snooping switch port
137  port = &context->ports[ancillary->port - 1];
138 
139  //The IGMP version of a Membership Query message is determined as follows
140  if(length == sizeof(IgmpMessage) && message->maxRespTime == 0)
141  {
142  //The maximum response time is 10 seconds by default
144  }
145  else if(length == sizeof(IgmpMessage) && message->maxRespTime != 0)
146  {
147  //The Max Resp Time field specifies the maximum time allowed before
148  //sending a responding report (in units of 1/10 second)
149  maxRespTime = message->maxRespTime * 100;
150  }
151  else if(length >= sizeof(IgmpMembershipQueryV3))
152  {
153  //The Max Resp Code field specifies the maximum time allowed before
154  //sending a responding report
155  if(message->maxRespTime < 128)
156  {
157  //The time is represented in units of 1/10 second
158  maxRespTime = message->maxRespTime * 100;
159  }
160  else
161  {
162  //Max Resp Code represents a floating-point value
163  maxRespTime = igmpDecodeFloatingPointValue(message->maxRespTime) * 100;
164  }
165  }
166  else
167  {
168  //Query messages that do not match any of the above conditions must be
169  //silently ignored (refer to RFC 3376, section 7.1)
170  return;
171  }
172 
173  //A switch supporting IGMP snooping must maintain a list of multicast
174  //routers and the ports on which they are attached. This list can be
175  //constructed by checking the arrival port for IGMP Queries (sent by
176  //multicast routers) where the source address is not 0.0.0.0
177  if(pseudoHeader->srcAddr != IPV4_UNSPECIFIED_ADDR)
178  {
179  //Check whether a new router has been detected
180  if(!port->routerPresent)
181  {
182  //Update the list of router ports
183  port->routerPresent = TRUE;
184 
185  //The snooping switch must update its forwarding table when the list
186  //of router ports has changed
187  for(i = 0; i < context->numGroups; i++)
188  {
189  //Point to the current group
190  group = &context->groups[i];
191 
192  //Check whether there are hosts on the network which have sent
193  //reports for this multicast group
195  {
196  //Update the corresponding entry in forwarding table
197  igmpSnoopingUpdateStaticFdbEntry(context, group->addr);
198  }
199  }
200 
201  //Check whether unregistered packets should be forwarded to router
202  //ports only
203  if(!context->floodUnknownMulticastPackets)
204  {
205  //Retrieve the port map identifying router ports
206  portMap = igmpSnoopingGetRouterPorts(context);
207 
208  //Forward unknown multicast packets on all ports to which
209  //an IGMP router is attached
210  igmpSnoopingSetUnknownMcastFwdPorts(context, TRUE, portMap);
211  }
212  }
213 
214  //Start timer
216  }
217 
218  //Group-Specific Query received?
219  if(ipv4IsMulticastAddr(message->groupAddr))
220  {
221  //Group-Specific Queries are used to learn if a particular group has any
222  //members on an attached network
223  for(i = 0; i < context->numGroups; i++)
224  {
225  //Point to the current group
226  group = &context->groups[i];
227 
228  //"Members Present" state?
230  group->addr == message->groupAddr)
231  {
232  //Set the timer to [Max Response Time] * [Last Member Query Count]
233  netStartTimer(&group->timer, maxRespTime *
235 
236  //Switch to the "Checking Membership" state
238  }
239  }
240  }
241 
242  //Flood all ports except the port the message was received on
243  portMap = ((1 << context->numPorts) - 1) & ~(1 << (ancillary->port - 1));
244 
245  //Forward the IGMP message
246  if(portMap != 0)
247  {
248  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
249  pseudoHeader, message, length);
250  }
251 }
252 
253 
254 /**
255  * @brief Process incoming Membership Report message
256  * @param[in] context Pointer to the IGMP snooping switch context
257  * @param[in] pseudoHeader IPv4 pseudo header
258  * @param[in] message Pointer to the incoming IGMP message
259  * @param[in] length Length of the IGMP message, in bytes
260  * @param[in] ancillary Additional options passed to the stack along with
261  * the packet
262  **/
263 
265  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
266  size_t length, const NetRxAncillary *ancillary)
267 {
268  uint32_t portMap;
269  IgmpSnoopingGroup *group;
270 
271  //The group address in the IGMP header must be a valid multicast group
272  //address
273  if(!ipv4IsMulticastAddr(message->groupAddr))
274  return;
275 
276  //In a Membership Report, the group address field holds the IP multicast
277  //group address of the group being reported (refer to RFC 2236, section 2.4)
278  group = igmpSnoopingFindGroup(context, message->groupAddr, ancillary->port);
279 
280  //First report received for this multicast group?
281  if(group == NULL)
282  {
283  //Create a new multicast group
284  group = igmpSnoopingCreateGroup(context, message->groupAddr,
285  ancillary->port);
286  }
287 
288  //Valid multicast group?
289  if(group != NULL)
290  {
291  //Start timer
293  //Switch to the "Members Present" state
295  }
296 
297  //A snooping switch should forward IGMP Membership Reports only to ports
298  //where multicast routers are attached (refer to RFC 4541, section 2.1.1)
299  portMap = igmpSnoopingGetRouterPorts(context);
300 
301  //An administrative control may be provided to override this restriction,
302  //allowing the report messages to be flooded to other ports
303  if(context->floodReports)
304  {
305  portMap = ((1 << context->numPorts) - 1);
306  }
307 
308  //Prevent the message from being forwarded back to the port on which it was
309  //originally received
310  portMap &= ~(1 << (ancillary->port - 1));
311 
312  //Forward the IGMP message
313  if(portMap != 0)
314  {
315  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
316  pseudoHeader, message, length);
317  }
318 }
319 
320 
321 /**
322  * @brief Process incoming Version 3 Membership Report message
323  * @param[in] context Pointer to the IGMP snooping switch context
324  * @param[in] pseudoHeader IPv4 pseudo header
325  * @param[in] message Pointer to the incoming IGMP message
326  * @param[in] length Length of the IGMP message, in bytes
327  * @param[in] ancillary Additional options passed to the stack along with
328  * the packet
329  **/
330 
332  const Ipv4PseudoHeader *pseudoHeader, const IgmpMembershipReportV3 *message,
333  size_t length, const NetRxAncillary *ancillary)
334 {
335  size_t i;
336  size_t n;
337  size_t recordLen;
338  uint_t k;
339  uint_t numRecords;
340  uint32_t portMap;
341  IgmpSnoopingGroup *group;
342  const IgmpGroupRecord *record;
343 
344  //Malformed Membership Report message?
345  if(length < sizeof(IgmpMembershipReportV3))
346  return;
347 
348  //Get the length occupied by the group records
349  n = length - sizeof(IgmpMembershipReportV3);
350 
351  //The Number of Group Records field specifies how many Group Records are
352  //present in this Report
353  numRecords = ntohs(message->numOfGroupRecords);
354 
355  //It is encouraged that snooping switches at least recognize and process
356  //IGMPv3 Join Reports, even if this processing is limited to the behavior
357  //for IGMPv2 Joins (refer to RFC 4541, section 2.1.2)
358  for(i = 0, k = 0; i < n && k < numRecords; i += recordLen, k++)
359  {
360  //Malformed Membership Report message?
361  if((i + sizeof(IgmpGroupRecord)) > n)
362  break;
363 
364  //Point to the current group record
365  record = (IgmpGroupRecord *) (message->groupRecords + i);
366 
367  //Determine the length of the group record
368  recordLen = sizeof(IgmpGroupRecord) + record->auxDataLen +
369  ntohs(record->numOfSources) * sizeof(Ipv4Addr);
370 
371  //Malformed Membership Report message?
372  if((i + recordLen) > n)
373  break;
374 
375  //The Multicast Address field contains the IP multicast address to which
376  //this Group Record pertains
377  group = igmpSnoopingFindGroup(context, record->multicastAddr,
378  ancillary->port);
379 
380  //Check group record type
381  if(record->recordType == IGMP_GROUP_RECORD_TYPE_TO_IN &&
382  record->numOfSources == 0)
383  {
384  //Valid multicast group?
385  if(group != NULL)
386  {
387  //Ignore Leave Group messages for which there are no group members
389  {
390  //The Last Member Query Time represents the "leave latency", or
391  //the difference between the transmission of a membership change
392  //and the change in the information given to the routing protocol
393  netStartTimer(&group->timer, context->lastMemberQueryTime);
394 
395  //Switch to the "Checking Membership" state
397  }
398  }
399  }
400  else if(record->recordType == IGMP_GROUP_RECORD_TYPE_IS_IN ||
401  record->recordType == IGMP_GROUP_RECORD_TYPE_IS_EX ||
402  record->recordType == IGMP_GROUP_RECORD_TYPE_TO_IN ||
403  record->recordType == IGMP_GROUP_RECORD_TYPE_TO_EX ||
404  record->recordType == IGMP_GROUP_RECORD_TYPE_ALLOW)
405  {
406  //First report received for this multicast group?
407  if(group == NULL)
408  {
409  //Create a new multicast group
410  group = igmpSnoopingCreateGroup(context, record->multicastAddr,
411  ancillary->port);
412  }
413 
414  //Valid multicast group?
415  if(group != NULL)
416  {
417  //Start timer
419  //Switch to the "Members Present" state
421  }
422  }
423  else
424  {
425  //Just for sanity
426  }
427  }
428 
429  //A snooping switch should forward IGMP Membership Reports only to ports
430  //where multicast routers are attached (refer to RFC 4541, section 2.1.1)
431  portMap = igmpSnoopingGetRouterPorts(context);
432 
433  //An administrative control may be provided to override this restriction,
434  //allowing the report messages to be flooded to other ports
435  if(context->floodReports)
436  {
437  portMap = ((1 << context->numPorts) - 1);
438  }
439 
440  //Prevent the message from being forwarded back to the port on which it was
441  //originally received
442  portMap &= ~(1 << (ancillary->port - 1));
443 
444  //Forward the IGMP message
445  if(portMap != 0)
446  {
447  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
448  pseudoHeader, (IgmpMessage *) message, length);
449  }
450 }
451 
452 
453 /**
454  * @brief Process incoming Leave Group message
455  * @param[in] context Pointer to the IGMP snooping switch context
456  * @param[in] pseudoHeader IPv4 pseudo header
457  * @param[in] message Pointer to the incoming IGMP message
458  * @param[in] length Length of the IGMP message, in bytes
459  * @param[in] ancillary Additional options passed to the stack along with
460  * the packet
461  **/
462 
464  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
465  size_t length, const NetRxAncillary *ancillary)
466 {
467  uint32_t portMap;
468  IgmpSnoopingGroup *group;
469 
470  //The group address in the IGMP header must be a valid multicast group
471  //address
472  if(!ipv4IsMulticastAddr(message->groupAddr))
473  return;
474 
475  //In a Leave Group message, the group address field holds the IP multicast
476  //group address of the group being left (refer to RFC 2236, section 2.4)
477  group = igmpSnoopingFindGroup(context, message->groupAddr, ancillary->port);
478 
479  //Valid multicast group?
480  if(group != NULL)
481  {
482  //Ignore Leave Group messages for which there are no group members
484  {
485  //The Last Member Query Time represents the "leave latency", or the
486  //difference between the transmission of a membership change and the
487  //change in the information given to the routing protocol
488  netStartTimer(&group->timer, context->lastMemberQueryTime);
489 
490  //Switch to the "Checking Membership" state
492  }
493  }
494 
495  //Flood all ports except the port the message was received on
496  portMap = ((1 << context->numPorts) - 1) & ~(1 << (ancillary->port - 1));
497 
498  //Forward the IGMP message
499  if(portMap != 0)
500  {
501  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
502  pseudoHeader, message, length);
503  }
504 }
505 
506 
507 /**
508  * @brief Process unrecognized IGMP messages
509  * @param[in] context Pointer to the IGMP snooping switch context
510  * @param[in] pseudoHeader IPv4 pseudo header
511  * @param[in] message Pointer to the incoming IGMP message
512  * @param[in] length Length of the IGMP message, in bytes
513  * @param[in] ancillary Additional options passed to the stack along with
514  * the packet
515  **/
516 
518  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
519  size_t length, const NetRxAncillary *ancillary)
520 {
521  uint32_t portMap;
522 
523  //A switch that supports IGMP snooping must flood all unrecognized IGMP
524  //messages to all other ports and must not attempt to make use of any
525  //information beyond the end of the network layer header
526  portMap = ((1 << context->numPorts) - 1) & ~(1 << (ancillary->port - 1));
527 
528  //Forward the IGMP message
529  if(portMap != 0)
530  {
531  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
532  pseudoHeader, message, length);
533  }
534 }
535 
536 
537 /**
538  * @brief Forward an IGMP message to the desired ports
539  * @param[in] context Pointer to the IGMP snooping switch context
540  * @param[in] forwardPorts Port map
541  * @param[in] destMacAddr Destination MAC address
542  * @param[in] pseudoHeader IPv4 pseudo header
543  * @param[in] message Pointer to the IGMP message
544  * @param[in] length Length of the IGMP message, in bytes
545  **/
546 
548  uint32_t forwardPorts, const MacAddr *destMacAddr,
549  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
550  size_t length)
551 {
552  error_t error;
553  size_t offset;
554  NetBuffer *buffer;
555  NetTxAncillary ancillary;
556 
557  //Debug message
558  TRACE_INFO("Forwarding IGMP message (%" PRIuSIZE " bytes)...\r\n", length);
559  //Dump port map
560  TRACE_INFO(" Switch Port Map = 0x%02" PRIX8 "\r\n", forwardPorts);
561 
562  //Allocate a memory buffer to hold an IGMP message
563  buffer = ipAllocBuffer(0, &offset);
564 
565  //Successful memory allocation?
566  if(buffer != NULL)
567  {
568  //Copy the IGMP message
569  error = netBufferAppend(buffer, message, length);
570 
571  //Check status code
572  if(!error)
573  {
574  //Additional options can be passed to the stack along with the packet
575  ancillary = NET_DEFAULT_TX_ANCILLARY;
576 
577  //All IGMP messages are sent with an IP TTL of 1 and contain an IP
578  //Router Alert option in their IP header (refer to RFC 2236, section 2)
579  ancillary.ttl = IGMP_TTL;
580  ancillary.routerAlert = TRUE;
581 
582  //Specify egress ports
583  ancillary.ports = forwardPorts;
584 
585  //Override port state if necessary
586  if(!context->floodUnknownMulticastPackets)
587  {
588  ancillary.override = TRUE;
589  }
590 
591  //Forward the IGMP message
592  error = ipv4SendDatagram(context->interface, pseudoHeader, buffer,
593  offset, &ancillary);
594  }
595 
596  //Free previously allocated memory
597  netBufferFree(buffer);
598  }
599  else
600  {
601  //Failed to allocate memory
602  error = ERROR_OUT_OF_MEMORY;
603  }
604 
605  //Return status code
606  return error;
607 }
608 
609 
610 /**
611  * @brief Create a new multicast group
612  * @param[in] context Pointer to the IGMP snooping switch context
613  * @param[in] groupAddr Multicast group address
614  * @param[in] port Port number associated with the multicast group
615  * @return Pointer to the newly created multicast group
616  **/
617 
619  Ipv4Addr groupAddr, uint8_t port)
620 {
621  uint_t i;
622  IgmpSnoopingGroup *group;
623 
624  //Initialize pointer
625  group = NULL;
626 
627  //Loop through multicast groups
628  for(i = 0; i < context->numGroups; i++)
629  {
630  //Check whether the entry is available
632  {
633  //Point to the current group
634  group = &context->groups[i];
635 
636  //Switch to the "Members Present" state
638  //Save the multicast group address
639  group->addr = groupAddr;
640  //Save port number
641  group->port = port;
642 
643  //Update the corresponding entry in forwarding table
645 
646  //We are done
647  break;
648  }
649  }
650 
651  //Return a pointer to the newly created multicast group
652  return group;
653 }
654 
655 
656 /**
657  * @brief Search the list of multicast groups for a given group address
658  * @param[in] context Pointer to the IGMP snooping switch context
659  * @param[in] groupAddr Multicast group address
660  * @param[in] port Port number
661  * @return Pointer to the matching multicast group, if any
662  **/
663 
665  Ipv4Addr groupAddr, uint8_t port)
666 {
667  uint_t i;
668  IgmpSnoopingGroup *group;
669 
670  //Initialize pointer
671  group = NULL;
672 
673  //Loop through multicast groups
674  for(i = 0; i < context->numGroups; i++)
675  {
676  //Check whether there are hosts on this port which have sent reports for
677  //this multicast group
679  context->groups[i].addr == groupAddr &&
680  context->groups[i].port == port)
681  {
682  //Point to the current group
683  group = &context->groups[i];
684  break;
685  }
686  }
687 
688  //Return a pointer to the matching multicast group
689  return group;
690 }
691 
692 
693 /**
694  * @brief Delete a multicast group
695  * @param[in] context Pointer to the IGMP snooping switch context
696  * @param[in] group Multicast group
697  **/
698 
700  IgmpSnoopingGroup *group)
701 {
702  //Switch to the "No Members Present" state
704 
705  //Update the corresponding entry in forwarding table
706  igmpSnoopingUpdateStaticFdbEntry(context, group->addr);
707 }
708 
709 
710 /**
711  * @brief Enable IGMP monitoring
712  * @param[in] context Pointer to the IGMP snooping switch context
713  * @param[in] enable Enable or disable IGMP monitoring
714  **/
715 
717 {
718  NetInterface *interface;
719 
720  //Point to the underlying network interface
721  interface = context->interface;
722 
723  //Valid switch driver?
724  if(interface->switchDriver != NULL &&
725  interface->switchDriver->enableIgmpSnooping != NULL)
726  {
727  //Enable IGMP snooping
728  interface->switchDriver->enableIgmpSnooping(interface, enable);
729  }
730 }
731 
732 
733 /**
734  * @brief Update a entry of the static MAC table
735  * @param[in] context Pointer to the IGMP snooping switch context
736  * @param[in] groupAddr Multicast group address to be updated
737  **/
738 
741 {
742  uint_t i;
743  uint32_t forwardPorts;
744  SwitchFdbEntry entry;
745  NetInterface *interface;
746  IgmpSnoopingGroup *group;
747 
748  //Clear port map
749  forwardPorts = 0;
750 
751  //Point to the underlying network interface
752  interface = context->interface;
753 
754  //Packets should be forwarded according to group-based port membership
755  //tables (refer to RFC 4541, section 2.1.2)
756  for(i = 0; i < context->numGroups; i++)
757  {
758  //Point to the current group
759  group = &context->groups[i];
760 
761  //Check whether there are hosts on this port which have sent reports for
762  //this multicast group
764  group->addr == groupAddr)
765  {
766  //Valid port number?
767  if(group->port > 0 && group->port <= context->numPorts)
768  {
769  forwardPorts |= (1 << (group->port - 1));
770  }
771  else
772  {
773  forwardPorts |= SWITCH_CPU_PORT_MASK;
774  }
775  }
776  }
777 
778  //Check whether this multicast group has any members
779  if(forwardPorts != 0)
780  {
781  //Packets must also be forwarded on router ports
782  forwardPorts |= igmpSnoopingGetRouterPorts(context);
783 
784  //Valid switch driver?
785  if(interface->switchDriver != NULL &&
786  interface->switchDriver->addStaticFdbEntry != NULL)
787  {
788  //Format forwarding database entry
790  entry.srcPort = 0;
791  entry.destPorts = forwardPorts;
792  entry.override = FALSE;
793 
794  //Debug message
795  TRACE_DEBUG("IGMP Snooping: Adding FDB entry...\r\n");
796  TRACE_DEBUG(" MAC Address: %s\r\n", macAddrToString(&entry.macAddr, NULL));
797  TRACE_DEBUG(" Forward Ports: 0x%08X\r\n", entry.destPorts);
798 
799  //Update the static MAC table of the switch
800  interface->switchDriver->addStaticFdbEntry(context->interface, &entry);
801  }
802  }
803  else
804  {
805  //Valid switch driver?
806  if(interface->switchDriver != NULL &&
807  interface->switchDriver->deleteStaticFdbEntry != NULL)
808  {
809  //Format forwarding database entry
811  entry.srcPort = 0;
812  entry.destPorts = 0;
813  entry.override = FALSE;
814 
815  //Debug message
816  TRACE_DEBUG("IGMP Snooping: Deleting FDB entry...\r\n");
817  TRACE_DEBUG(" MAC Address: %s\r\n", macAddrToString(&entry.macAddr, NULL));
818 
819  //Update the static MAC table of the switch
820  interface->switchDriver->deleteStaticFdbEntry(context->interface,
821  &entry);
822  }
823  }
824 }
825 
826 
827 /**
828  * @brief Set forward ports for unknown multicast packets
829  * @param[in] context Pointer to the IGMP snooping switch context
830  * @param[in] enable Enable or disable forwarding of unknown multicast packets
831  * @param[in] forwardPorts Port map
832  **/
833 
835  bool_t enable, uint32_t forwardPorts)
836 {
837  NetInterface *interface;
838 
839  //Point to the underlying network interface
840  interface = context->interface;
841 
842  //Valid switch driver?
843  if(interface->switchDriver != NULL &&
844  interface->switchDriver->setUnknownMcastFwdPorts != NULL)
845  {
846  interface->switchDriver->setUnknownMcastFwdPorts(context->interface,
847  enable, forwardPorts);
848  }
849 }
850 
851 
852 /*
853  * @brief Retrieve the port map identifying router ports
854  * @param[in] context Pointer to the IGMP snooping switch context
855  * @return Port map identifying router ports
856  **/
857 
859 {
860  uint_t i;
861  uint32_t routerPorts;
862 
863  //Clear port map
864  routerPorts = 0;
865 
866  //Loop through the list of multicast routers
867  for(i = 0; i < context->numPorts; i++)
868  {
869  //Check whether any IGMP router is attached to this port
870  if(context->ports[i].routerPresent)
871  {
872  routerPorts |= (1 << i);
873  }
874  }
875 
876  //Return the port map that identifies router ports
877  return routerPorts;
878 }
879 
880 #endif
IgmpMembershipReportV3
Definition: igmp_common.h:255
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:186
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:798
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:716
int bool_t
Definition: compiler_port.h:63
uint32_t destPorts
Definition: nic.h:152
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:70
uint8_t maxRespTime
Definition: igmp_common.h:212
IgmpMessage
Definition: igmp_common.h:215
#define SWITCH_CPU_PORT
Definition: nic.h:59
#define IGMP_GROUP_MEMBERSHIP_INTERVAL
Definition: igmp_common.h:66
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t message[]
Definition: chap.h:154
void igmpSnoopingSetUnknownMcastFwdPorts(IgmpSnoopingContext *context, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
#define TRUE
Definition: os_port.h:50
uint32_t igmpSnoopingGetRouterPorts(IgmpSnoopingContext *context)
#define IGMP_LAST_MEMBER_QUERY_COUNT
Definition: igmp_common.h:96
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
IGMP snooping switch.
#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL
Definition: igmp_common.h:70
@ IGMP_TYPE_MEMBERSHIP_REPORT_V2
Definition: igmp_common.h:176
void igmpSnoopingUpdateStaticFdbEntry(IgmpSnoopingContext *context, Ipv4Addr groupAddr)
Update a entry of the static MAC table.
IgmpSnoopingGroupState state
Multicast group state.
Definition: igmp_snooping.h:80
void igmpSnoopingDeleteGroup(IgmpSnoopingContext *context, IgmpSnoopingGroup *group)
Delete a multicast group.
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:323
void igmpSnoopingProcessMembershipReport(IgmpSnoopingContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length, const NetRxAncillary *ancillary)
Process incoming Membership Report message.
systime_t lastMemberQueryTime
Leave latency.
IPv4 multicast filtering.
IgmpSnoopingGroup * igmpSnoopingCreateGroup(IgmpSnoopingContext *context, Ipv4Addr groupAddr, uint8_t port)
Create a new multicast group.
uint_t numPorts
Number of ports.
#define FALSE
Definition: os_port.h:46
@ IGMP_SNOOPING_GROUP_STATE_MEMBERS_PRESENT
Definition: igmp_snooping.h:58
@ IGMP_TYPE_MEMBERSHIP_REPORT_V1
Definition: igmp_common.h:175
@ IGMP_TYPE_MEMBERSHIP_QUERY
Definition: igmp_common.h:174
error_t
Error codes.
Definition: error.h:43
@ IGMP_SNOOPING_GROUP_STATE_NO_MEMBERS_PRESENT
Definition: igmp_snooping.h:57
NetInterface * interface
The primary interface on an attached network.
@ IGMP_SNOOPING_GROUP_STATE_CHECKING_MEMBERSHIP
Definition: igmp_snooping.h:59
bool_t floodUnknownMulticastPackets
Flood unregistered multicast traffic to all ports.
char_t * macAddrToString(const MacAddr *macAddr, char_t *str)
Convert a MAC address to a dash delimited string.
Definition: ethernet.c:926
IgmpSnoopingGroup * groups
Multicast groups.
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
@ IGMP_GROUP_RECORD_TYPE_ALLOW
Definition: igmp_common.h:192
#define NetTxAncillary
Definition: net_misc.h:36
@ IGMP_TYPE_MEMBERSHIP_REPORT_V3
Definition: igmp_common.h:178
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:105
Ipv4Addr addr
Multicast group address.
Definition: igmp_snooping.h:81
uint8_t length
Definition: tcp.h:375
void igmpSnoopingProcessMessage(IgmpSnoopingContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length, const NetRxAncillary *ancillary)
Process incoming IGMP message.
Snooping switch port.
Definition: igmp_snooping.h:68
void igmpSnoopingEnableMonitoring(IgmpSnoopingContext *context, bool_t enable)
Enable IGMP monitoring.
uint_t numGroups
Maximum number of multicast groups.
#define IGMP_TTL
Definition: igmp_common.h:141
void igmpSnoopingProcessUnknownMessage(IgmpSnoopingContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length, const NetRxAncillary *ancillary)
Process unrecognized IGMP messages.
MacAddr
Definition: ethernet.h:197
@ IGMP_GROUP_RECORD_TYPE_IS_EX
Definition: igmp_common.h:189
uint32_t systime_t
System time.
uint16_t port
Definition: dns_common.h:270
#define ntohs(value)
Definition: cpu_endian.h:421
IgmpSnoopingGroup * igmpSnoopingFindGroup(IgmpSnoopingContext *context, Ipv4Addr groupAddr, uint8_t port)
Search the list of multicast groups for a given group address.
uint32_t igmpDecodeFloatingPointValue(uint8_t code)
Decode a floating-point value.
Definition: igmp_common.c:398
#define TRACE_DEBUG(...)
Definition: debug.h:119
@ IGMP_GROUP_RECORD_TYPE_TO_EX
Definition: igmp_common.h:191
error_t ipv4SendDatagram(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv4 datagram.
Definition: ipv4.c:1021
uint8_t n
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
bool_t floodReports
Flood IGMP report messages to all ports (not only to router ports)
IgmpGroupRecord
Definition: igmp_common.h:269
Ipv4Addr groupAddr
Definition: igmp_common.h:214
void igmpSnoopingProcessMembershipReportV3(IgmpSnoopingContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMembershipReportV3 *message, size_t length, const NetRxAncillary *ancillary)
Process incoming Version 3 Membership Report message.
MacAddr macAddr
Definition: nic.h:150
IgmpMembershipQueryV3
Definition: igmp_common.h:240
uint8_t srcPort
Definition: nic.h:151
void igmpSnoopingProcessLeaveGroup(IgmpSnoopingContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length, const NetRxAncillary *ancillary)
Process incoming Leave Group message.
@ IGMP_GROUP_RECORD_TYPE_IS_IN
Definition: igmp_common.h:188
@ IGMP_GROUP_RECORD_TYPE_TO_IN
Definition: igmp_common.h:190
IgmpSnoopingPort * ports
Ports.
error_t igmpSnoopingForwardMessage(IgmpSnoopingContext *context, uint32_t forwardPorts, const MacAddr *destMacAddr, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length)
Forward an IGMP message to the desired ports.
IPv4 (Internet Protocol Version 4)
Helper functions for IGMP snooping switch.
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
#define IGMP_V1_MAX_RESPONSE_TIME
Definition: igmp_common.h:121
Multicast group.
Definition: igmp_snooping.h:79
IGMP snooping switch context.
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
void igmpSnoopingProcessMembershipQuery(IgmpSnoopingContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length, const NetRxAncillary *ancillary)
Process incoming Membership Query message.
error_t ipv4MapMulticastAddrToMac(Ipv4Addr ipAddr, MacAddr *macAddr)
Map an host group address to a MAC-layer multicast address.
bool_t override
Definition: nic.h:153
@ IGMP_TYPE_LEAVE_GROUP
Definition: igmp_common.h:177
Debugging facilities.
Forwarding database entry.
Definition: nic.h:149
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:128