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-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.4
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_misc.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  //Ignore Leave Group messages for which there are no group members
386  {
387  //The Last Member Query Time represents the "leave latency", or the
388  //difference between the transmission of a membership change and the
389  //change in the information given to the routing protocol
390  netStartTimer(&group->timer, context->lastMemberQueryTime);
391 
392  //Switch to the "Checking Membership" state
394  }
395  }
396  else if(record->recordType == IGMP_GROUP_RECORD_TYPE_IS_IN ||
397  record->recordType == IGMP_GROUP_RECORD_TYPE_IS_EX ||
398  record->recordType == IGMP_GROUP_RECORD_TYPE_TO_IN ||
399  record->recordType == IGMP_GROUP_RECORD_TYPE_TO_EX ||
400  record->recordType == IGMP_GROUP_RECORD_TYPE_ALLOW)
401  {
402  //First report received for this multicast group?
403  if(group == NULL)
404  {
405  //Create a new multicast group
406  group = igmpSnoopingCreateGroup(context, record->multicastAddr,
407  ancillary->port);
408  }
409 
410  //Valid multicast group?
411  if(group != NULL)
412  {
413  //Start timer
415  //Switch to the "Members Present" state
417  }
418  }
419  else
420  {
421  //Just for sanity
422  }
423  }
424 
425  //A snooping switch should forward IGMP Membership Reports only to ports
426  //where multicast routers are attached (refer to RFC 4541, section 2.1.1)
427  portMap = igmpSnoopingGetRouterPorts(context);
428 
429  //An administrative control may be provided to override this restriction,
430  //allowing the report messages to be flooded to other ports
431  if(context->floodReports)
432  {
433  portMap = ((1 << context->numPorts) - 1);
434  }
435 
436  //Prevent the message from being forwarded back to the port on which it was
437  //originally received
438  portMap &= ~(1 << (ancillary->port - 1));
439 
440  //Forward the IGMP message
441  if(portMap != 0)
442  {
443  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
444  pseudoHeader, (IgmpMessage *) message, length);
445  }
446 }
447 
448 
449 /**
450  * @brief Process incoming Leave Group message
451  * @param[in] context Pointer to the IGMP snooping switch context
452  * @param[in] pseudoHeader IPv4 pseudo header
453  * @param[in] message Pointer to the incoming IGMP message
454  * @param[in] length Length of the IGMP message, in bytes
455  * @param[in] ancillary Additional options passed to the stack along with
456  * the packet
457  **/
458 
460  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
461  size_t length, const NetRxAncillary *ancillary)
462 {
463  uint32_t portMap;
464  IgmpSnoopingGroup *group;
465 
466  //The group address in the IGMP header must be a valid multicast group
467  //address
468  if(!ipv4IsMulticastAddr(message->groupAddr))
469  return;
470 
471  //In a Leave Group message, the group address field holds the IP multicast
472  //group address of the group being left (refer to RFC 2236, section 2.4)
473  group = igmpSnoopingFindGroup(context, message->groupAddr, ancillary->port);
474 
475  //Valid multicast group?
476  if(group != NULL)
477  {
478  //Ignore Leave Group messages for which there are no group members
480  {
481  //The Last Member Query Time represents the "leave latency", or the
482  //difference between the transmission of a membership change and the
483  //change in the information given to the routing protocol
484  netStartTimer(&group->timer, context->lastMemberQueryTime);
485 
486  //Switch to the "Checking Membership" state
488  }
489  }
490 
491  //Flood all ports except the port the message was received on
492  portMap = ((1 << context->numPorts) - 1) & ~(1 << (ancillary->port - 1));
493 
494  //Forward the IGMP message
495  if(portMap != 0)
496  {
497  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
498  pseudoHeader, message, length);
499  }
500 }
501 
502 
503 /**
504  * @brief Process unrecognized IGMP messages
505  * @param[in] context Pointer to the IGMP snooping switch context
506  * @param[in] pseudoHeader IPv4 pseudo header
507  * @param[in] message Pointer to the incoming IGMP message
508  * @param[in] length Length of the IGMP message, in bytes
509  * @param[in] ancillary Additional options passed to the stack along with
510  * the packet
511  **/
512 
514  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
515  size_t length, const NetRxAncillary *ancillary)
516 {
517  uint32_t portMap;
518 
519  //A switch that supports IGMP snooping must flood all unrecognized IGMP
520  //messages to all other ports and must not attempt to make use of any
521  //information beyond the end of the network layer header
522  portMap = ((1 << context->numPorts) - 1) & ~(1 << (ancillary->port - 1));
523 
524  //Forward the IGMP message
525  if(portMap != 0)
526  {
527  igmpSnoopingForwardMessage(context, portMap, &ancillary->destMacAddr,
528  pseudoHeader, message, length);
529  }
530 }
531 
532 
533 /**
534  * @brief Forward an IGMP message to the desired ports
535  * @param[in] context Pointer to the IGMP snooping switch context
536  * @param[in] forwardPorts Port map
537  * @param[in] destMacAddr Destination MAC address
538  * @param[in] pseudoHeader IPv4 pseudo header
539  * @param[in] message Pointer to the IGMP message
540  * @param[in] length Length of the IGMP message, in bytes
541  **/
542 
544  uint32_t forwardPorts, const MacAddr *destMacAddr,
545  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
546  size_t length)
547 {
548  error_t error;
549  size_t offset;
550  NetBuffer *buffer;
551  NetTxAncillary ancillary;
552 
553  //Debug message
554  TRACE_INFO("Forwarding IGMP message (%" PRIuSIZE " bytes)...\r\n", length);
555  //Dump port map
556  TRACE_INFO(" Switch Port Map = 0x%02" PRIX8 "\r\n", forwardPorts);
557 
558  //Allocate a memory buffer to hold an IGMP message
559  buffer = ipAllocBuffer(0, &offset);
560 
561  //Successful memory allocation?
562  if(buffer != NULL)
563  {
564  //Copy the IGMP message
565  error = netBufferAppend(buffer, message, length);
566 
567  //Check status code
568  if(!error)
569  {
570  //Additional options can be passed to the stack along with the packet
571  ancillary = NET_DEFAULT_TX_ANCILLARY;
572 
573  //All IGMP messages are sent with an IP TTL of 1 and contain an IP
574  //Router Alert option in their IP header (refer to RFC 2236, section 2)
575  ancillary.ttl = IGMP_TTL;
576  ancillary.routerAlert = TRUE;
577 
578  //Specify egress ports
579  ancillary.ports = forwardPorts;
580 
581  //Override port state if necessary
582  if(!context->floodUnknownMulticastPackets)
583  {
584  ancillary.override = TRUE;
585  }
586 
587  //Forward the IGMP message
588  error = ipv4SendDatagram(context->interface, pseudoHeader, buffer,
589  offset, &ancillary);
590  }
591 
592  //Free previously allocated memory
593  netBufferFree(buffer);
594  }
595  else
596  {
597  //Failed to allocate memory
598  error = ERROR_OUT_OF_MEMORY;
599  }
600 
601  //Return status code
602  return error;
603 }
604 
605 
606 /**
607  * @brief Create a new multicast group
608  * @param[in] context Pointer to the IGMP snooping switch context
609  * @param[in] groupAddr Multicast group address
610  * @param[in] port Port number associated with the multicast group
611  * @return Pointer to the newly created multicast group
612  **/
613 
615  Ipv4Addr groupAddr, uint8_t port)
616 {
617  uint_t i;
618  IgmpSnoopingGroup *group;
619 
620  //Initialize pointer
621  group = NULL;
622 
623  //Loop through multicast groups
624  for(i = 0; i < context->numGroups; i++)
625  {
626  //Check whether the entry is available
628  {
629  //Point to the current group
630  group = &context->groups[i];
631 
632  //Switch to the "Members Present" state
634  //Save the multicast group address
635  group->addr = groupAddr;
636  //Save port number
637  group->port = port;
638 
639  //Update the corresponding entry in forwarding table
641 
642  //We are done
643  break;
644  }
645  }
646 
647  //Return a pointer to the newly created multicast group
648  return group;
649 }
650 
651 
652 /**
653  * @brief Search the list of multicast groups for a given group address
654  * @param[in] context Pointer to the IGMP snooping switch context
655  * @param[in] groupAddr Multicast group address
656  * @param[in] port Port number
657  * @return Pointer to the matching multicast group, if any
658  **/
659 
661  Ipv4Addr groupAddr, uint8_t port)
662 {
663  uint_t i;
664  IgmpSnoopingGroup *group;
665 
666  //Initialize pointer
667  group = NULL;
668 
669  //Loop through multicast groups
670  for(i = 0; i < context->numGroups; i++)
671  {
672  //Check whether there are hosts on this port which have sent reports for
673  //this multicast group
675  context->groups[i].addr == groupAddr &&
676  context->groups[i].port == port)
677  {
678  //Point to the current group
679  group = &context->groups[i];
680  break;
681  }
682  }
683 
684  //Return a pointer to the matching multicast group
685  return group;
686 }
687 
688 
689 /**
690  * @brief Delete a multicast group
691  * @param[in] context Pointer to the IGMP snooping switch context
692  * @param[in] group Multicast group
693  **/
694 
696  IgmpSnoopingGroup *group)
697 {
698  //Switch to the "No Members Present" state
700 
701  //Update the corresponding entry in forwarding table
702  igmpSnoopingUpdateStaticFdbEntry(context, group->addr);
703 }
704 
705 
706 /**
707  * @brief Enable IGMP monitoring
708  * @param[in] context Pointer to the IGMP snooping switch context
709  * @param[in] enable Enable or disable MLD monitoring
710  **/
711 
713 {
714  NetInterface *interface;
715 
716  //Point to the underlying network interface
717  interface = context->interface;
718 
719  //Valid switch driver?
720  if(interface->switchDriver != NULL &&
721  interface->switchDriver->enableIgmpSnooping != NULL)
722  {
723  //Enable IGMP snooping
724  interface->switchDriver->enableIgmpSnooping(interface, enable);
725  }
726 }
727 
728 
729 /**
730  * @brief Update a entry of the static MAC table
731  * @param[in] context Pointer to the IGMP snooping switch context
732  * @param[in] groupAddr Multicast group address to be updated
733  **/
734 
737 {
738  uint_t i;
739  uint32_t forwardPorts;
740  SwitchFdbEntry entry;
741  NetInterface *interface;
742  IgmpSnoopingGroup *group;
743 
744  //Clear port map
745  forwardPorts = 0;
746 
747  //Point to the underlying network interface
748  interface = context->interface;
749 
750  //Packets should be forwarded according to group-based port membership
751  //tables (refer to RFC 4541, section 2.1.2)
752  for(i = 0; i < context->numGroups; i++)
753  {
754  //Point to the current group
755  group = &context->groups[i];
756 
757  //Check whether there are hosts on this port which have sent reports for
758  //this multicast group
760  group->addr == groupAddr)
761  {
762  //Valid port number?
763  if(group->port > 0 && group->port <= context->numPorts)
764  {
765  forwardPorts |= (1 << (group->port - 1));
766  }
767  else
768  {
769  forwardPorts |= SWITCH_CPU_PORT_MASK;
770  }
771  }
772  }
773 
774  //Check whether this multicast group has any members
775  if(forwardPorts != 0)
776  {
777  //Packets must also be forwarded on router ports
778  forwardPorts |= igmpSnoopingGetRouterPorts(context);
779 
780  //Valid switch driver?
781  if(interface->switchDriver != NULL &&
782  interface->switchDriver->addStaticFdbEntry != NULL)
783  {
784  //Format forwarding database entry
786  entry.srcPort = 0;
787  entry.destPorts = forwardPorts;
788  entry.override = FALSE;
789 
790  //Debug message
791  TRACE_DEBUG("IGMP Snooping: Adding FDB entry...\r\n");
792  TRACE_DEBUG(" MAC Address: %s\r\n", macAddrToString(&entry.macAddr, NULL));
793  TRACE_DEBUG(" Forward Ports: 0x%08X\r\n", entry.destPorts);
794 
795  //Update the static MAC table of the switch
796  interface->switchDriver->addStaticFdbEntry(context->interface, &entry);
797  }
798  }
799  else
800  {
801  //Valid switch driver?
802  if(interface->switchDriver != NULL &&
803  interface->switchDriver->deleteStaticFdbEntry != NULL)
804  {
805  //Format forwarding database entry
807  entry.srcPort = 0;
808  entry.destPorts = 0;
809  entry.override = FALSE;
810 
811  //Debug message
812  TRACE_DEBUG("IGMP Snooping: Deleting FDB entry...\r\n");
813  TRACE_DEBUG(" MAC Address: %s\r\n", macAddrToString(&entry.macAddr, NULL));
814 
815  //Update the static MAC table of the switch
816  interface->switchDriver->deleteStaticFdbEntry(context->interface,
817  &entry);
818  }
819  }
820 }
821 
822 
823 /**
824  * @brief Set forward ports for unknown multicast packets
825  * @param[in] context Pointer to the IGMP snooping switch context
826  * @param[in] enable Enable or disable forwarding of unknown multicast packets
827  * @param[in] forwardPorts Port map
828  **/
829 
831  bool_t enable, uint32_t forwardPorts)
832 {
833  NetInterface *interface;
834 
835  //Point to the underlying network interface
836  interface = context->interface;
837 
838  //Valid switch driver?
839  if(interface->switchDriver != NULL &&
840  interface->switchDriver->setUnknownMcastFwdPorts != NULL)
841  {
842  interface->switchDriver->setUnknownMcastFwdPorts(context->interface,
843  enable, forwardPorts);
844  }
845 }
846 
847 
848 /*
849  * @brief Retrieve the port map identifying router ports
850  * @param[in] context Pointer to the IGMP snooping switch context
851  * @return Port map identifying router ports
852  **/
853 
855 {
856  uint_t i;
857  uint32_t routerPorts;
858 
859  //Clear port map
860  routerPorts = 0;
861 
862  //Loop through the list of multicast routers
863  for(i = 0; i < context->numPorts; i++)
864  {
865  //Check whether any IGMP router is attached to this port
866  if(context->ports[i].routerPresent)
867  {
868  routerPorts |= (1 << i);
869  }
870  }
871 
872  //Return the port map that identifies router ports
873  return routerPorts;
874 }
875 
876 #endif
IgmpMembershipReportV3
Definition: igmp_common.h:255
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:175
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:766
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:711
int bool_t
Definition: compiler_port.h:53
uint32_t destPorts
Definition: nic.h:152
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
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:297
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.
IgmpSnoopingGroup * igmpSnoopingCreateGroup(IgmpSnoopingContext *context, Ipv4Addr groupAddr, uint8_t port)
Create a new multicast group.
uint_t numPorts
Number of ports.
Helper functions for IPv4.
#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:919
IgmpSnoopingGroup * groups
Multicast groups.
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
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:95
Ipv4Addr addr
Multicast group address.
Definition: igmp_snooping.h:81
uint8_t length
Definition: tcp.h:368
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:195
@ IGMP_GROUP_RECORD_TYPE_IS_EX
Definition: igmp_common.h:189
uint32_t systime_t
System time.
uint16_t port
Definition: dns_common.h:267
#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:107
@ 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:1010
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:50
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:117