igmp_host_misc.c
Go to the documentation of this file.
1 /**
2  * @file igmp_host_misc.c
3  * @brief Helper functions for IGMP host
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.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_multicast.h"
38 #include "ipv4/ipv4_misc.h"
39 #include "igmp/igmp_host.h"
40 #include "igmp/igmp_host_misc.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (IPV4_SUPPORT == ENABLED && IGMP_HOST_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Change host compatibility mode
49  * @param[in] context Pointer to the IGMP host context
50  * @param[in] compatibilityMode New host compatibility mode
51  **/
52 
54  IgmpVersion compatibilityMode)
55 {
56  uint_t i;
57  IgmpHostGroup *group;
58 
59  //Debug message
60  TRACE_DEBUG("Changing host compatibility mode to IGMPv%u...\r\n",
61  (uint_t) compatibilityMode);
62 
63  //Switch compatibility mode immediately
64  context->compatibilityMode = compatibilityMode;
65 
66  //Whenever a host changes its compatibility mode, it cancels all its pending
67  //response and retransmission timers (refer to RFC 3376, section 7.2.1)
70 
71  //Loop through multicast groups
72  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
73  {
74  //Point to the current group
75  group = &context->groups[i];
76 
77  //Valid group?
79  {
80  //Reset retransmission counter
81  group->retransmitCount = 0;
82 
83 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
84  //Clear source lists
85  group->allow.numSources = 0;
86  group->block.numSources = 0;
87  group->queriedSources.numSources = 0;
88 #endif
89  //Cancel the pending response, if any
90  netStopTimer(&group->timer);
91 
92  //Switch to the Idle Member state
94  }
95  }
96 
97  //Delete groups in "non-existent" state
99 }
100 
101 
102 /**
103  * @brief Send Membership Report message
104  * @param[in] context Pointer to the IGMP host context
105  * @param[in] groupAddr IPv4 address specifying the group address
106  **/
107 
109 {
110  size_t offset;
111  NetBuffer *buffer;
113 
114  //Allocate a memory buffer to hold the IGMP message
115  buffer = ipAllocBuffer(sizeof(IgmpMessage), &offset);
116  //Failed to allocate memory?
117  if(buffer == NULL)
118  return;
119 
120  //Point to the beginning of the IGMP message
121  message = netBufferAt(buffer, offset, 0);
122 
123  //The type of report is determined by the state of the interface
124  if(context->compatibilityMode == IGMP_VERSION_1)
125  {
127  }
128  else
129  {
131  }
132 
133  //Format the Membership Report message
134  message->maxRespTime = 0;
135  message->checksum = 0;
136  message->groupAddr = groupAddr;
137 
138  //Message checksum calculation
139  message->checksum = ipCalcChecksum(message, sizeof(IgmpMessage));
140 
141  //The Membership Report message is sent to the group being reported
142  igmpSendMessage(context->interface, groupAddr, buffer, offset);
143 
144  //Free previously allocated memory
145  netBufferFree(buffer);
146 }
147 
148 
149 /**
150  * @brief Send Leave Group message
151  * @param[in] context Pointer to the IGMP host context
152  * @param[in] groupAddr IPv4 address specifying the group address being left
153  **/
154 
156 {
157  size_t offset;
158  NetBuffer *buffer;
160 
161  //If the interface state says the querier is running IGMPv1, this action
162  //should be skipped
163  if(context->compatibilityMode == IGMP_VERSION_1)
164  return;
165 
166  //Allocate a memory buffer to hold the IGMP message
167  buffer = ipAllocBuffer(sizeof(IgmpMessage), &offset);
168  //Failed to allocate memory?
169  if(buffer == NULL)
170  return;
171 
172  //Point to the beginning of the IGMP message
173  message = netBufferAt(buffer, offset, 0);
174 
175  //Format the Leave Group message
177  message->maxRespTime = 0;
178  message->checksum = 0;
179  message->groupAddr = groupAddr;
180 
181  //Message checksum calculation
182  message->checksum = ipCalcChecksum(message, sizeof(IgmpMessage));
183 
184  //Leave Group messages are addressed to the all-routers group because other
185  //group members have no need to know that a host has left the group, but it
186  //does no harm to address the message to the group
187  igmpSendMessage(context->interface, IGMP_ALL_ROUTERS_ADDR, buffer, offset);
188 
189  //Free previously allocated memory
190  netBufferFree(buffer);
191 }
192 
193 
194 /**
195  * @brief Send Current-State Report message
196  * @param[in] context Pointer to the IGMP host context
197  * @param[in] groupAddr IPv4 address specifying the group address
198  **/
199 
202 {
203  uint_t i;
204  size_t n;
205  size_t length;
206  size_t offset;
207  NetBuffer *buffer;
208  IgmpHostGroup *group;
210  IgmpGroupRecord *record;
211 
212  //Allocate a memory buffer to hold the IGMP message
213  buffer = ipAllocBuffer(IGMP_MAX_MSG_SIZE, &offset);
214  //Failed to allocate memory?
215  if(buffer == NULL)
216  return;
217 
218  //Point to the beginning of the IGMP message
219  message = netBufferAt(buffer, offset, 0);
220 
221  //Format the Version 3 Membership Report message
223  message->reserved1 = 0;
224  message->checksum = 0;
225  message->reserved2 = 0;
226  message->numOfGroupRecords = 0;
227 
228  //Total length of the message
229  length = sizeof(IgmpMembershipReportV3);
230 
231  //Loop through multicast groups
232  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
233  {
234  //Point to the current group
235  group = &context->groups[i];
236 
237  //Matching group?
238  if(igmpHostMatchGroup(group, groupAddr))
239  {
240 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
241  //Check whether the interface has reception state for that group
242  //address
243  if(group->filterMode == IP_FILTER_MODE_EXCLUDE ||
244  group->filter.numSources > 0)
245  {
246  uint_t j;
247 
248  //General Query or Group-Specific Query?
250  group->queriedSources.numSources == 0)
251  {
252  //Calculate the length of the group record
253  n = sizeof(IgmpGroupRecord) + group->filter.numSources *
254  sizeof(Ipv4Addr);
255 
256  //If the set of Group Records required in a Report does not fit
257  //within the size limit of a single Report message, the Group
258  //Records are sent in as many Report messages as needed to report
259  //the entire set (refer to RFC 3376, section 4.2.16)
260  if((length + n) > IGMP_MAX_MSG_SIZE)
261  {
262  //Send report message
263  igmpHostFlushReportRecords(context, buffer, offset, &length);
264  }
265 
266  //Point to the buffer where to format the record
267  record = (IgmpGroupRecord *) ((uint8_t *) message + length);
268 
269  //The Current-State Record carries the associated filter mode
270  //(MODE_IS_INCLUDE or MODE_IS_EXCLUDE)
271  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
272  {
273  record->recordType = IGMP_GROUP_RECORD_TYPE_IS_IN;
274  }
275  else
276  {
277  record->recordType = IGMP_GROUP_RECORD_TYPE_IS_EX;
278  }
279 
280  //Format group record
281  record->auxDataLen = 0;
282  record->numOfSources = htons(group->filter.numSources);
283  record->multicastAddr = group->addr;
284 
285  //Format the list of source addresses
286  for(j = 0; j < group->filter.numSources; j++)
287  {
288  record->srcAddr[j] = group->filter.sources[j];
289  }
290 
291  //Increment the number of group records
292  message->numOfGroupRecords++;
293  //Update the length of the message
294  length += n;
295  }
296  else
297  {
298  //If the list of recorded sources B for that group is non-empty,
299  //then the contents of the responding Current-State Record is
300  //determined from the interface state and the pending response
301  //record
302  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
303  {
304  //If the interface state is INCLUDE (A), then the contents of
305  //the responding Current-State Record is IS_IN (A*B)
306  for(j = 0; j < group->queriedSources.numSources; )
307  {
308  if(ipv4FindSrcAddr(&group->filter,
309  group->queriedSources.sources[j]) >= 0)
310  {
311  j++;
312  }
313  else
314  {
315  ipv4RemoveSrcAddr(&group->queriedSources,
316  group->queriedSources.sources[j]);
317  }
318  }
319  }
320  else
321  {
322  //If the interface state is EXCLUDE (A), then the contents of
323  //the responding Current-State Record is IS_IN (B-A)
324  for(j = 0; j < group->filter.numSources; j++)
325  {
326  ipv4RemoveSrcAddr(&group->queriedSources,
327  group->filter.sources[j]);
328  }
329  }
330 
331  //If the resulting Current-State Record has an empty set of
332  //source addresses, then no response is sent
333  if(group->queriedSources.numSources > 0)
334  {
335  //Calculate the length of the group record
336  n = sizeof(IgmpGroupRecord) +
337  group->queriedSources.numSources * sizeof(Ipv4Addr);
338 
339  //If the set of Group Records required in a Report does not
340  //fit within the size limit of a single Report message, the
341  //Group Records are sent in as many Report messages as needed
342  //to report the entire set (refer to RFC 3376, section 4.2.16)
343  if((length + n) > IGMP_MAX_MSG_SIZE)
344  {
345  //Send report message
346  igmpHostFlushReportRecords(context, buffer, offset, &length);
347  }
348 
349  //Point to the buffer where to format the record
350  record = (IgmpGroupRecord *) ((uint8_t *) message + length);
351 
352  //Format group record
353  record->recordType = IGMP_GROUP_RECORD_TYPE_IS_IN;
354  record->auxDataLen = 0;
355  record->numOfSources = htons(group->queriedSources.numSources);
356  record->multicastAddr = group->addr;
357 
358  //Format the list of source addresses
359  for(j = 0; j < group->queriedSources.numSources; j++)
360  {
361  record->srcAddr[j] = group->queriedSources.sources[j];
362  }
363 
364  //Increment the number of group records
365  message->numOfGroupRecords++;
366  //Update the length of the message
367  length += n;
368  }
369  }
370  }
371 
372  //Finally, after any required Report messages have been generated,
373  //the source lists associated with any reported groups are cleared
374  group->queriedSources.numSources = 0;
375 #else
376  //Check whether the interface has reception state for that group
377  //address
378  if(group->filterMode == IP_FILTER_MODE_EXCLUDE)
379  {
380  //Calculate the length of the group record
381  n = sizeof(IgmpGroupRecord);
382 
383  //If the set of Group Records required in a Report does not fit
384  //within the size limit of a single Report message, the Group
385  //Records are sent in as many Report messages as needed to report
386  //the entire set (refer to RFC 3376, section 4.2.16)
387  if((length + n) > IGMP_MAX_MSG_SIZE)
388  {
389  //Send report message
390  igmpHostFlushReportRecords(context, buffer, offset, &length);
391  }
392 
393  //Point to the buffer where to format the record
394  record = (IgmpGroupRecord *) ((uint8_t *) message + length);
395 
396  //The Current-State Record carries the associated filter mode
397  record->recordType = IGMP_GROUP_RECORD_TYPE_IS_EX;
398  record->auxDataLen = 0;
399  record->numOfSources = HTONS(0);
400  record->multicastAddr = group->addr;
401 
402  //Increment the number of group records
403  message->numOfGroupRecords++;
404  //Update the length of the message
405  length += n;
406  }
407 #endif
408  }
409  }
410 
411  //Version 3 Reports are sent with an IP destination address of 224.0.0.22,
412  //to which all IGMPv3-capable multicast routers listen (refer to RFC 3376,
413  //section 4.2.14)
414  igmpHostFlushReportRecords(context, buffer, offset, &length);
415 
416  //Free previously allocated memory
417  netBufferFree(buffer);
418 }
419 
420 
421 /**
422  * @brief Send State-Change Report message
423  * @param[in] context Pointer to the IGMP host context
424  **/
425 
427 {
428  uint_t i;
429  size_t n;
430  size_t length;
431  size_t offset;
432  NetBuffer *buffer;
433  IgmpHostGroup *group;
435  IgmpGroupRecord *record;
436 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
437  uint_t j;
438 #endif
439 
440  //Allocate a memory buffer to hold the IGMP message
441  buffer = ipAllocBuffer(IGMP_MAX_MSG_SIZE, &offset);
442  //Failed to allocate memory?
443  if(buffer == NULL)
444  return;
445 
446  //Point to the beginning of the IGMP message
447  message = netBufferAt(buffer, offset, 0);
448 
449  //Format the Version 3 Membership Report message
451  message->reserved1 = 0;
452  message->checksum = 0;
453  message->reserved2 = 0;
454  message->numOfGroupRecords = 0;
455 
456  //Total length of the message
457  length = sizeof(IgmpMembershipReportV3);
458 
459  //Loop through multicast groups
460  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
461  {
462  //Point to the current group
463  group = &context->groups[i];
464 
465  //Valid group?
467  {
468  //The report should contain a Filter Mode Change Record if the Filter
469  //Mode Retransmission Counter has a value higher than zero
470  if(group->retransmitCount > 0)
471  {
472  //Calculate the length of the group record
473  n = sizeof(IgmpGroupRecord) + group->filter.numSources *
474  sizeof(Ipv4Addr);
475 
476  //If the set of Group Records required in a Report does not fit
477  //within the size limit of a single Report message, the Group
478  //Records are sent in as many Report messages as needed to report
479  //the entire set (refer to RFC 3376, section 4.2.16)
480  if((length + n) > IGMP_MAX_MSG_SIZE)
481  {
482  //Send report message
483  igmpHostFlushReportRecords(context, buffer, offset, &length);
484  }
485 
486  //Point to the buffer where to format the record
487  record = (IgmpGroupRecord *) ((uint8_t *) message + length);
488 
489  //If the current filter-mode of the interface is INCLUDE, a TO_IN
490  //record is included in the report, otherwise a TO_EX record is
491  //included
492  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
493  {
494  record->recordType = IGMP_GROUP_RECORD_TYPE_TO_IN;
495  }
496  else
497  {
498  record->recordType = IGMP_GROUP_RECORD_TYPE_TO_EX;
499  }
500 
501  //Format group record
502  record->auxDataLen = 0;
503  record->numOfSources = htons(group->filter.numSources);
504  record->multicastAddr = group->addr;
505 
506 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
507  //Format the list of source addresses
508  for(j = 0; j < group->filter.numSources; j++)
509  {
510  record->srcAddr[j] = group->filter.sources[j];
511  }
512 #endif
513  //Increment the number of group records
514  message->numOfGroupRecords++;
515  //Update the length of the message
516  length += n;
517  }
518  else
519  {
520 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
521  //If the computed source list for a ALLOW record is empty, that
522  //record is omitted from the State-Change report
523  if(group->allow.numSources > 0)
524  {
525  //Calculate the length of the ALLOW record
526  n = sizeof(IgmpGroupRecord) + group->allow.numSources *
527  sizeof(Ipv4Addr);
528 
529  //If the set of Group Records required in a Report does not fit
530  //within the size limit of a single Report message, the Group
531  //Records are sent in as many Report messages as needed to report
532  //the entire set (refer to RFC 3376, section 4.2.16)
533  if((length + n) > IGMP_MAX_MSG_SIZE)
534  {
535  igmpHostFlushReportRecords(context, buffer, offset, &length);
536  }
537 
538  //Point to the buffer where to format the record
539  record = (IgmpGroupRecord *) ((uint8_t *) message + length);
540 
541  //The ALLOW record contains the list of the additional sources
542  //that the system wishes to hear from
543  record->recordType = IGMP_GROUP_RECORD_TYPE_ALLOW;
544  record->auxDataLen = 0;
545  record->numOfSources = htons(group->allow.numSources);
546  record->multicastAddr = group->addr;
547 
548  //Format the list of source addresses
549  for(j = 0; j < group->allow.numSources; j++)
550  {
551  record->srcAddr[j] = group->allow.sources[j].addr;
552  }
553 
554  //Increment the number of group records
555  message->numOfGroupRecords++;
556  //Update the length of the message
557  length += n;
558  }
559 
560  //If the computed source list for a BLOCK record is empty, that
561  //record is omitted from the State-Change report
562  if(group->block.numSources > 0)
563  {
564  //Calculate the length of the BLOCK record
565  n = sizeof(IgmpGroupRecord) + group->block.numSources *
566  sizeof(Ipv4Addr);
567 
568  //If the set of Group Records required in a Report does not fit
569  //within the size limit of a single Report message, the Group
570  //Records are sent in as many Report messages as needed to report
571  //the entire set (refer to RFC 3376, section 4.2.16)
572  if((length + n) > IGMP_MAX_MSG_SIZE)
573  {
574  igmpHostFlushReportRecords(context, buffer, offset, &length);
575  }
576 
577  //Point to the buffer where to format the record
578  record = (IgmpGroupRecord *) ((uint8_t *) message + length);
579 
580  //The BLOCK record contains the list of the sources that the
581  //system no longer wishes to hear from
582  record->recordType = IGMP_GROUP_RECORD_TYPE_BLOCK;
583  record->auxDataLen = 0;
584  record->numOfSources = htons(group->block.numSources);
585  record->multicastAddr = group->addr;
586 
587  //Format the list of source addresses
588  for(j = 0; j < group->block.numSources; j++)
589  {
590  record->srcAddr[j] = group->block.sources[j].addr;
591  }
592 
593  //Increment the number of group records
594  message->numOfGroupRecords++;
595  //Update the length of the message
596  length += n;
597  }
598 #endif
599  }
600 
601  //Retransmission state needs to be maintained until [Robustness
602  //Variable] State-Change reports have been sent by the host
604  }
605  }
606 
607  //Version 3 Reports are sent with an IP destination address of 224.0.0.22,
608  //to which all IGMPv3-capable multicast routers listen (refer to RFC 3376,
609  //section 4.2.14)
610  igmpHostFlushReportRecords(context, buffer, offset, &length);
611 
612  //Free previously allocated memory
613  netBufferFree(buffer);
614 }
615 
616 
617 /**
618  * @brief Flush report records
619  * @param[in] context Pointer to the IGMP host context
620  * @param[in] buffer Multi-part buffer containing the report message
621  * @param[in] offset Offset to the first byte of the report message
622  * @param[in,out] length Length of the report message, in bytes
623  **/
624 
626  size_t offset, size_t *length)
627 {
629 
630  //Any group records included in the message?
631  if(*length > 0)
632  {
633  //Point to the beginning of the report message
634  message = netBufferAt(buffer, offset, 0);
635 
636  //The Number of Group Records field specifies how many Group Records are
637  //present in this Report
638  message->numOfGroupRecords = htons(message->numOfGroupRecords);
639 
640  //Message checksum calculation
641  message->checksum = ipCalcChecksum(message, *length);
642 
643  //Adjust the length of the multi-part buffer
644  netBufferSetLength(buffer, offset + *length);
645 
646  //Version 3 Reports are sent with an IP destination address of 224.0.0.22,
647  //to which all IGMPv3-capable multicast routers listen (refer to RFC 3376,
648  //section 4.2.14)
650  offset);
651 
652  //Reset the Checksum field
653  message->checksum = 0;
654  //Reset the Number of Group Records field
655  message->numOfGroupRecords = 0;
656 
657  //Update the length of the message
658  *length = sizeof(IgmpMembershipReportV3);
659  }
660 }
661 
662 
663 /**
664  * @brief Process incoming IGMP message
665  * @param[in] context Pointer to the IGMP host context
666  * @param[in] pseudoHeader IPv4 pseudo header
667  * @param[in] message Pointer to the incoming IGMP message
668  * @param[in] length Length of the IGMP message, in bytes
669  **/
670 
672  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
673  size_t length)
674 {
675  //Check IGMP message type
677  {
678  //The IGMP version of a Membership Query message is determined as follows
679  if(length == sizeof(IgmpMessage))
680  {
681  //Process Membership Query message
682  igmpHostProcessMembershipQuery(context, pseudoHeader, message, length);
683  }
684  else if(length >= sizeof(IgmpMembershipQueryV3))
685  {
686  //Process Version 3 Membership Query message
687  igmpHostProcessMembershipQueryV3(context, pseudoHeader,
689  }
690  else
691  {
692  //Query messages that do not match any of the above conditions must be
693  //silently ignored (refer to RFC 3376, section 7.1)
694  }
695  }
696  else if(message->type == IGMP_TYPE_MEMBERSHIP_REPORT_V1 ||
698  {
699  //Process Membership Report message
700  igmpHostProcessMembershipReport(context, pseudoHeader, message, length);
701  }
702  else
703  {
704  //Discard other messages
705  }
706 }
707 
708 
709 /**
710  * @brief Process incoming Membership Query message
711  * @param[in] context Pointer to the IGMP host context
712  * @param[in] pseudoHeader IPv4 pseudo header
713  * @param[in] message Pointer to the incoming IGMP message
714  * @param[in] length Length of the IGMP message, in bytes
715  **/
716 
718  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
719  size_t length)
720 {
721  uint_t i;
722  systime_t delay;
724  IgmpHostGroup *group;
725 
726  //The group address in the IGMP header must either be zero or a valid
727  //multicast group address (refer to RFC 2236, section 6)
728  if(message->groupAddr != IPV4_UNSPECIFIED_ADDR &&
729  !ipv4IsMulticastAddr(message->groupAddr))
730  {
731  return;
732  }
733 
734  //Hosts should ignore v2 or v3 General Queries sent to a multicast address
735  //other than 224.0.0.1 (refer to RFC 3376, section 9.1)
736  if(message->groupAddr == IPV4_UNSPECIFIED_ADDR &&
737  pseudoHeader->destAddr != IGMP_ALL_SYSTEMS_ADDR)
738  {
739  return;
740  }
741 
742  //When in IGMPv1 mode, routers send Periodic Queries with a Max Response
743  //Time of 0
744  if(message->maxRespTime == 0)
745  {
746  //IGMPv1 Querier Present timer is set to Older Version Querier Present
747  //Timeout seconds whenever an IGMPv1 Membership Query is received
750 
751  //The Host Compatibility Mode of an interface changes whenever an older
752  //version query (than the current compatibility mode) is heard
753  if(context->compatibilityMode > IGMP_VERSION_1)
754  {
755  //The host should switch compatibility mode immediately
757  }
758 
759  //IGMPv1 routers send General Queries with the Max Response Time set to
760  //0. This must be interpreted as a value of 100 (10 seconds)
762  }
763  else
764  {
765  //IGMPv2 Querier Present timer is set to Older Version Querier Present
766  //Timeout seconds whenever an IGMPv2 Membership Query is received
769 
770  //The Host Compatibility Mode of an interface changes whenever an older
771  //version query (than the current compatibility mode) is heard
772  if(context->compatibilityMode > IGMP_VERSION_2)
773  {
774  //The host should switch compatibility mode immediately
776  }
777 
778  //The Max Resp Time field specifies the maximum time allowed before
779  //sending a responding report (in units of 1/10 second)
780  maxRespTime = message->maxRespTime * 100;
781  }
782 
783  //Loop through multicast groups
784  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
785  {
786  //Point to the current group
787  group = &context->groups[i];
788 
789  //Matching group?
790  if(igmpHostMatchGroup(group, message->groupAddr))
791  {
792  //Check group state
794  {
795  //If a timer for the group is already running, it is reset to
796  //the random value only if the requested Max Response Time is
797  //less than the remaining value of the running timer
798  if(maxRespTime < netGetRemainingTime(&group->timer))
799  {
800  //Select a random value in the range 0 - Max Response Time
802  //Restart delay timer
803  netStartTimer(&group->timer, delay);
804  }
805  }
806  else if(group->state == IGMP_HOST_GROUP_STATE_IDLE_MEMBER)
807  {
808  //Select a random value in the range 0 - Max Response Time
810  //Start delay timer
811  netStartTimer(&group->timer, delay);
812 
813  //Switch to the Delaying Member state
815  }
816  else
817  {
818  //Just for sanity
819  }
820  }
821  }
822 }
823 
824 
825 /**
826  * @brief Process incoming Version 3 Membership Query message
827  * @param[in] context Pointer to the IGMP host context
828  * @param[in] pseudoHeader IPv4 pseudo header
829  * @param[in] message Pointer to the incoming IGMP message
830  * @param[in] length Length of the IGMP message, in bytes
831  **/
832 
834  const Ipv4PseudoHeader *pseudoHeader, const IgmpMembershipQueryV3 *message,
835  size_t length)
836 {
837  uint_t i;
838  uint_t n;
839  systime_t delay;
841  IgmpHostGroup *group;
842 
843  //When Host Compatibility Mode is IGMPv2, a host acts in IGMPv2
844  //compatibility mode, using only the IGMPv2 protocol, on that interface
845  if(context->compatibilityMode < IGMP_VERSION_3)
846  return;
847 
848  //Check the length of the Version 3 Membership Query message
849  if(length < sizeof(IgmpMembershipQueryV3))
850  return;
851 
852  //The Group Address field is set to zero when sending a General Query,
853  //and set to the IP multicast address being queried when sending a
854  //Group-Specific Query or Group-and-Source-Specific Query (refer to
855  //RFC 3376, section 4.1.3)
856  if(message->groupAddr != IPV4_UNSPECIFIED_ADDR &&
857  !ipv4IsMulticastAddr(message->groupAddr))
858  {
859  return;
860  }
861 
862  //Hosts should ignore v3 General Queries sent to a multicast address other
863  //than 224.0.0.1 (refer to RFC 3376, section 9.1)
864  if(message->groupAddr == IPV4_UNSPECIFIED_ADDR &&
865  pseudoHeader->destAddr != IGMP_ALL_SYSTEMS_ADDR)
866  {
867  return;
868  }
869 
870  //The Number of Sources field specifies how many source addresses are
871  //present in the Query
872  n = ntohs(message->numOfSources);
873 
874  //Malformed message?
875  if(length < (sizeof(IgmpMembershipQueryV3) + n * sizeof(Ipv4Addr)))
876  return;
877 
878  //The Max Resp Code field specifies the maximum time allowed before sending
879  //a responding report
880  if(message->maxRespCode < 128)
881  {
882  //The time is represented in units of 1/10 second
883  maxRespTime = message->maxRespCode * 100;
884  }
885  else
886  {
887  //Max Resp Code represents a floating-point value
888  maxRespTime = igmpDecodeFloatingPointValue(message->maxRespCode) * 100;
889  }
890 
891  //When a new Query arrives on an interface, provided the system has state
892  //to report, a delay for a response is randomly selected in the range
893  //0 - Max Resp Time (refer to RFC 3376, section 5.2)
895 
896  //The following rules are then used to determine if a Report needs to be
897  //scheduled and the type of Report to schedule
898  if(netTimerRunning(&context->generalQueryTimer) &&
899  netGetRemainingTime(&context->generalQueryTimer) < delay)
900  {
901  //If there is a pending response to a previous General Query scheduled
902  //sooner than the selected delay, no additional response needs to be
903  //scheduled
904  }
905  else if(message->groupAddr == IPV4_UNSPECIFIED_ADDR)
906  {
907  //If the received Query is a General Query, the interface timer is used
908  //to schedule a response to the General Query after the selected delay.
909  //Any previously pending response to a General Query is canceled
910  netStartTimer(&context->generalQueryTimer, delay);
911  }
912  else
913  {
914  //Loop through multicast groups
915  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
916  {
917  //Point to the current group
918  group = &context->groups[i];
919 
920  //Matching group?
921  if(igmpHostMatchGroup(group, message->groupAddr))
922  {
923 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
924  error_t error;
925  uint_t j;
926 
927  //Initialize status code
928  error = NO_ERROR;
929 
930  //No pending response to a previous Query for this group?
931  if(!netTimerRunning(&group->timer))
932  {
933  //If the received Query is a Group-and-Source-Specific Query, the
934  //list of queried sources is recorded to be used when generating
935  //a response
936  group->queriedSources.numSources = 0;
937 
938  //Save the list of queried sources
939  for(j = 0; j < n; j++)
940  {
941  error = ipv4AddSrcAddr(&group->queriedSources,
942  message->srcAddr[j]);
943  }
944 
945  //The implementation limits the number of source addresses that
946  //can be recorded
947  if(error)
948  {
949  group->queriedSources.numSources = 0;
950  }
951 
952  //If the received Query is a Group-Specific Query or a Group-and-
953  //Source-Specific Query and there is no pending response to a
954  //previous Query for this group, then the group timer is used to
955  //schedule a report
956  netStartTimer(&group->timer, delay);
957  }
958  else
959  {
960  //Check whether the new Query is a Group-Specific Query or the
961  //recorded source-list associated with the group is empty
962  if(n == 0 || group->queriedSources.numSources == 0)
963  {
964  //If there already is a pending response to a previous Query
965  //scheduled for this group, and either the new Query is a
966  //Group-Specific Query or the recorded source-list associated
967  //with the group is empty, then the group source-list is
968  //cleared and a single response is scheduled using
969  //the group timer
970  group->queriedSources.numSources = 0;
971  }
972  else
973  {
974  //If the received Query is a Group-and-Source-Specific Query
975  //and there is a pending response for this group with a non-
976  //empty source-list, then the group source list is augmented
977  //to contain the list of sources in the new Query and a single
978  //response is scheduled using the group timer
979  for(j = 0; j < n; j++)
980  {
981  error = ipv4AddSrcAddr(&group->queriedSources,
982  message->srcAddr[j]);
983  }
984 
985  //The implementation limits the number of source addresses
986  //that can be recorded
987  if(error)
988  {
989  group->queriedSources.numSources = 0;
990  }
991  }
992 
993  //The new response is scheduled to be sent at the earliest of the
994  //remaining time for the pending report and the selected delay
995  if(delay < netGetRemainingTime(&group->timer))
996  {
997  netStartTimer(&group->timer, delay);
998  }
999  }
1000 #else
1001  //No pending response to a previous Query for this group?
1002  if(!netTimerRunning(&group->timer))
1003  {
1004  //The group timer is used to schedule a report
1005  netStartTimer(&group->timer, delay);
1006  }
1007  else
1008  {
1009  //The new response is scheduled to be sent at the earliest of the
1010  //remaining time for the pending report and the selected delay
1011  if(delay < netGetRemainingTime(&group->timer))
1012  {
1013  netStartTimer(&group->timer, delay);
1014  }
1015  }
1016 #endif
1017  }
1018  }
1019  }
1020 }
1021 
1022 
1023 /**
1024  * @brief Process incoming Membership Report message
1025  * @param[in] context Pointer to the IGMP host context
1026  * @param[in] pseudoHeader IPv4 pseudo header
1027  * @param[in] message Pointer to the incoming IGMP message
1028  * @param[in] length Length of the IGMP message, in bytes
1029  **/
1030 
1032  const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message,
1033  size_t length)
1034 {
1035  IgmpHostGroup *group;
1036 
1037  //When Host Compatibility Mode is IGMPv3, a host acts using the IGMPv3
1038  //protocol on that interface
1039  if(context->compatibilityMode > IGMP_VERSION_2)
1040  return;
1041 
1042  //The group address in the IGMP header must be a valid multicast group
1043  //address
1044  if(!ipv4IsMulticastAddr(message->groupAddr))
1045  return;
1046 
1047  //Search the list of groups for the specified multicast address
1048  group = igmpHostFindGroup(context, message->groupAddr);
1049 
1050  //Any matching group found?
1051  if(group != NULL)
1052  {
1053  //Report messages are ignored for memberships in the Non-Member or Idle
1054  //Member state
1056  {
1057  //Clear flag
1058  group->flag = FALSE;
1059  //Switch to the Idle Member state
1061  }
1062  }
1063 }
1064 
1065 
1066 /**
1067  * @brief Merge difference the report and the pending report
1068  * @param[in] group Pointer to the multicast group
1069  * @param[in] newFilterMode New filter mode for the affected group
1070  * @param[in] newFilter New interface state for the affected group
1071  **/
1072 
1074  IpFilterMode newFilterMode, const Ipv4SrcAddrList *newFilter)
1075 {
1076 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
1077  uint_t i;
1078 
1079  //The interface state for the affected group before and after the latest
1080  //change is compared
1081  if(newFilterMode == IP_FILTER_MODE_INCLUDE &&
1083  {
1084  //The interface has changed to INCLUDE filter mode for the specified
1085  //multicast address
1086  group->allow.numSources = 0;
1087  group->block.numSources = 0;
1088  }
1089  else if(newFilterMode == IP_FILTER_MODE_EXCLUDE &&
1091  {
1092  //The interface has changed to EXCLUDE filter mode for the specified
1093  //multicast address
1094  group->allow.numSources = 0;
1095  group->block.numSources = 0;
1096  }
1097  else if(newFilterMode == IP_FILTER_MODE_INCLUDE &&
1099  {
1100  //The ALLOW record contains the list of the additional sources that the
1101  //system wishes to hear from
1102  for(i = 0; i < newFilter->numSources; i++)
1103  {
1104  if(ipv4FindSrcAddr(&group->filter, newFilter->sources[i]) < 0)
1105  {
1106  igmpHostAddSrcAddr(&group->allow, newFilter->sources[i]);
1107  igmpHostRemoveSrcAddr(&group->block, newFilter->sources[i]);
1108  }
1109  }
1110 
1111  //The BLOCK record contains the list of the sources that the system no
1112  //longer wishes to hear from
1113  for(i = 0; i < group->filter.numSources; i++)
1114  {
1115  if(ipv4FindSrcAddr(newFilter, group->filter.sources[i]) < 0)
1116  {
1117  igmpHostAddSrcAddr(&group->block, group->filter.sources[i]);
1118  igmpHostRemoveSrcAddr(&group->allow, group->filter.sources[i]);
1119  }
1120  }
1121  }
1122  else if(newFilterMode == IP_FILTER_MODE_EXCLUDE &&
1124  {
1125  //The BLOCK record contains the list of the sources that the system no
1126  //longer wishes to hear from
1127  for(i = 0; i < newFilter->numSources; i++)
1128  {
1129  if(ipv4FindSrcAddr(&group->filter, newFilter->sources[i]) < 0)
1130  {
1131  igmpHostAddSrcAddr(&group->block, newFilter->sources[i]);
1132  igmpHostRemoveSrcAddr(&group->allow, newFilter->sources[i]);
1133  }
1134  }
1135 
1136  //The ALLOW record contains the list of the additional sources that the
1137  //system wishes to hear from
1138  for(i = 0; i < group->filter.numSources; i++)
1139  {
1140  if(ipv4FindSrcAddr(newFilter, group->filter.sources[i]) < 0)
1141  {
1142  igmpHostAddSrcAddr(&group->allow, group->filter.sources[i]);
1143  igmpHostRemoveSrcAddr(&group->block, group->filter.sources[i]);
1144  }
1145  }
1146  }
1147  else
1148  {
1149  //Just for sanity
1150  }
1151 #endif
1152 
1153  //When the filter mode changes, the Filter Mode Retransmission Counter is
1154  //set to [Robustness Variable]
1155  if(newFilterMode != group->filterMode)
1156  {
1158  }
1159 }
1160 
1161 
1162 /**
1163  * @brief Get the retransmission status of the State-Change report
1164  * @param[in] context Pointer to the IGMP host context
1165  * @return TRUE if additional retransmissions are needed, else FALSE
1166  **/
1167 
1169 {
1170  uint_t i;
1171  bool_t status;
1172  IgmpHostGroup *group;
1173 
1174  //Clear status flag
1175  status = FALSE;
1176 
1177  //Loop through multicast groups
1178  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1179  {
1180  //Point to the current group
1181  group = &context->groups[i];
1182 
1183  //Valid group?
1185  {
1186  //Retransmission in progress?
1188  {
1189  status = TRUE;
1190  break;
1191  }
1192  }
1193  }
1194 
1195  //Return TRUE if additional retransmissions are needed
1196  return status;
1197 }
1198 
1199 
1200 /**
1201  * @brief Get the retransmission status for a given group
1202  * @param[in] group Pointer to the multicast group
1203  * @return TRUE if additional retransmissions are needed, else FALSE
1204  **/
1205 
1207 {
1208  bool_t status;
1209 
1210  //Clear status flag
1211  status = FALSE;
1212 
1213 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
1214  //Retransmission in progress?
1215  if(group->retransmitCount > 0 || group->allow.numSources > 0 ||
1216  group->block.numSources > 0)
1217  {
1218  status = TRUE;
1219  }
1220 #else
1221  //Retransmission in progress?
1222  if(group->retransmitCount > 0)
1223  {
1224  status = TRUE;
1225  }
1226 #endif
1227 
1228  //Return TRUE if additional retransmissions are needed
1229  return status;
1230 }
1231 
1232 
1233 /**
1234  * @brief Decrement retransmission counters for a given group
1235  * @param[in] group Pointer to the multicast group
1236  **/
1237 
1239 {
1240  //Filter mode change?
1241  if(group->retransmitCount > 0)
1242  {
1243  //The Filter Mode Retransmission Counter is decremented by one unit after
1244  //the transmission of the report
1245  group->retransmitCount--;
1246  }
1247  else
1248  {
1249 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
1250  int_t i;
1251 
1252  //The ALLOW record contains the list of the additional sources that the
1253  //system wishes to hear from
1254  for(i = group->allow.numSources - 1; i >= 0; i--)
1255  {
1256  //For each included source, its Source Retransmission Counter is
1257  //decreased with one unit after the transmission of the report
1258  if(group->allow.sources[i].retransmitCount > 0)
1259  {
1260  group->allow.sources[i].retransmitCount--;
1261  }
1262 
1263  //If the counter reaches zero, the source is deleted from the list
1264  if(group->allow.sources[i].retransmitCount == 0)
1265  {
1266  igmpHostRemoveSrcAddr(&group->allow, group->allow.sources[i].addr);
1267  }
1268  }
1269 
1270  //The BLOCK record contains the list of the sources that the system no
1271  //longer wishes to hear from
1272  for(i = group->block.numSources - 1; i >= 0; i--)
1273  {
1274  //For each included source, its Source Retransmission Counter is
1275  //decreased with one unit after the transmission of the report
1276  if(group->block.sources[i].retransmitCount > 0)
1277  {
1278  group->block.sources[i].retransmitCount--;
1279  }
1280 
1281  //If the counter reaches zero, the source is deleted from the list
1282  if(group->block.sources[i].retransmitCount == 0)
1283  {
1284  igmpHostRemoveSrcAddr(&group->block, group->block.sources[i].addr);
1285  }
1286  }
1287 #endif
1288  }
1289 }
1290 
1291 
1292 /**
1293  * @brief Create a new multicast group
1294  * @param[in] context Pointer to the IGMP host context
1295  * @param[in] groupAddr Multicast group address
1296  * @return Pointer to the newly created multicast group
1297  **/
1298 
1301 {
1302  uint_t i;
1303  IgmpHostGroup *group;
1304 
1305  //Initialize pointer
1306  group = NULL;
1307 
1308  //Valid multicast address?
1310  {
1311  //Loop through multicast groups
1312  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1313  {
1314  //Check whether the entry is available
1315  if(context->groups[i].state == IGMP_HOST_GROUP_STATE_NON_MEMBER)
1316  {
1317  //Debug message
1318  TRACE_DEBUG("Creating IGMP group (%s)...\r\n",
1319  ipv4AddrToString(groupAddr, NULL));
1320 
1321  //Point to the current group
1322  group = &context->groups[i];
1323 
1324  //Initialize group
1325  osMemset(group, 0, sizeof(IgmpHostGroup));
1326 
1327  //Switch to the Init Member state
1329  //Save the multicast group address
1330  group->addr = groupAddr;
1331 
1332  //A per-group and interface timer is used for scheduling responses to
1333  //Group-Specific and Group-and-Source-Specific Queries
1334  netStopTimer(&group->timer);
1335 
1336  //The "non-existent" state is considered to have a filter mode of
1337  //INCLUDE and an empty source list
1339  group->filter.numSources = 0;
1340 
1341  //We are done
1342  break;
1343  }
1344  }
1345  }
1346 
1347  //Return a pointer to the newly created multicast group
1348  return group;
1349 }
1350 
1351 
1352 /**
1353  * @brief Search the list of multicast groups for a given group address
1354  * @param[in] context Pointer to the IGMP host context
1355  * @param[in] groupAddr Multicast group address
1356  * @return Pointer to the matching multicast group, if any
1357  **/
1358 
1360 {
1361  uint_t i;
1362  IgmpHostGroup *group;
1363 
1364  //Initialize pointer
1365  group = NULL;
1366 
1367  //Loop through multicast groups
1368  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1369  {
1370  //Matching group?
1371  if(context->groups[i].state != IGMP_HOST_GROUP_STATE_NON_MEMBER &&
1372  context->groups[i].addr == groupAddr)
1373  {
1374  //Point to the current group
1375  group = &context->groups[i];
1376  break;
1377  }
1378  }
1379 
1380  //Return a pointer to the matching multicast group
1381  return group;
1382 }
1383 
1384 
1385 /**
1386  * @brief Check whether a group matches a given multicast address
1387  * @param[in] group Pointer to the multicast group
1388  * @param[in] multicastAddr IPv4 multicast address
1389  * @return TRUE if the group matches the specified multicast address, else FALSE
1390  **/
1391 
1393 {
1394  bool_t match;
1395 
1396  //Initialize flag
1397  match = FALSE;
1398 
1399  //Valid group?
1401  {
1402  //Matching multicast address?
1404  multicastAddr == group->addr)
1405  {
1406  match = TRUE;
1407  }
1408  }
1409 
1410  //Return TRUE if the group matches the specified multicast address
1411  return match;
1412 }
1413 
1414 
1415 /**
1416  * @brief Delete a multicast group
1417  * @param[in] group Pointer to the multicast group
1418  **/
1419 
1421 {
1422  //Debug message
1423  TRACE_DEBUG("Deleting IGMP group (%s)...\r\n",
1424  ipv4AddrToString(group->addr, NULL));
1425 
1426  //Groups in Non-Member state require no storage in the host
1428 }
1429 
1430 
1431 /**
1432  * @brief Delete groups in "non-existent" state
1433  * @param[in] context Pointer to the IGMP host context
1434  **/
1435 
1437 {
1438  uint_t i;
1439  IgmpHostGroup *group;
1440 
1441  //Loop through multicast groups
1442  for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
1443  {
1444  //Point to the current group
1445  group = &context->groups[i];
1446 
1447  //Valid group?
1449  {
1450  //Retransmission state needs to be maintained until [Robustness
1451  //Variable] State-Change reports have been sent by the host
1453  {
1454  //The "non-existent" state is considered to have a filter mode of
1455  //INCLUDE and an empty source list
1456  if(group->filterMode == IP_FILTER_MODE_INCLUDE &&
1457  group->filter.numSources == 0)
1458  {
1459  //Delete the group
1460  igmpHostDeleteGroup(group);
1461  }
1462  }
1463  }
1464  }
1465 }
1466 
1467 
1468 /**
1469  * @brief Append a source address to a given list
1470  * @param[in] list Pointer to the list of source addresses
1471  * @param[in] srcAddr Source address to be added
1472  **/
1473 
1475 {
1476 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
1477  error_t error;
1478  size_t n;
1479 
1480  //Initialize status code
1481  error = NO_ERROR;
1482 
1483  //Make sure that the source address is not a duplicate
1484  if(igmpHostFindSrcAddr(list, srcAddr) < 0)
1485  {
1486  //Make sure there is enough room to add the source address
1488  {
1489  //Get the index of the new element
1490  n = list->numSources;
1491 
1492  //When a source is included in the list, its counter is set to
1493  //[Robustness Variable]
1494  list->sources[n].addr = srcAddr;
1495  list->sources[n].retransmitCount = IGMP_ROBUSTNESS_VARIABLE;
1496 
1497  //Adjust the number of elements
1498  list->numSources++;
1499  }
1500  else
1501  {
1502  //The implementation limits the number of source addresses
1503  error = ERROR_OUT_OF_RESOURCES;
1504  }
1505  }
1506 
1507  //Return status code
1508  return error;
1509 #else
1510  //Not implemented
1511  return ERROR_NOT_IMPLEMENTED;
1512 #endif
1513 }
1514 
1515 
1516 /**
1517  * @brief Remove a source address from a given list
1518  * @param[in] list Pointer to the list of source addresses
1519  * @param[in] srcAddr Source address to be removed
1520  **/
1521 
1523 {
1524 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
1525  uint_t i;
1526  uint_t j;
1527 
1528  //Loop through the list of source addresses
1529  for(i = 0; i < list->numSources; i++)
1530  {
1531  //Matching IP address?
1532  if(list->sources[i].addr == srcAddr)
1533  {
1534  //Remove the source address from the list
1535  for(j = i + 1; j < list->numSources; j++)
1536  {
1537  list->sources[j - 1] = list->sources[j];
1538  }
1539 
1540  //Update the length of the list
1541  list->numSources--;
1542 
1543  //We are done
1544  break;
1545  }
1546  }
1547 #endif
1548 }
1549 
1550 
1551 /**
1552  * @brief Search the list of sources for a given IP address
1553  * @param[in] list Pointer to the list of source addresses
1554  * @param[in] srcAddr Source IP address
1555  * @return Index of the matching IP address is returned. -1 is
1556  * returned if the specified IP address cannot be found
1557  **/
1558 
1560 {
1561 #if (IPV4_MAX_MULTICAST_SOURCES > 0)
1562  int_t i;
1563  int_t index;
1564 
1565  //Initialize index
1566  index = -1;
1567 
1568  //Loop through the list of source addresses
1569  for(i = 0; i < list->numSources; i++)
1570  {
1571  //Matching IP address?
1572  if(list->sources[i].addr == srcAddr)
1573  {
1574  index = i;
1575  break;
1576  }
1577  }
1578 
1579  //Return the index of the matching IP address, if any
1580  return index;
1581 #else
1582  //Not implemented
1583  return -1;
1584 #endif
1585 }
1586 
1587 #endif
IgmpMembershipReportV3
Definition: igmp_common.h:255
Multicast group.
Definition: igmp_host.h:93
systime_t igmpGetRandomDelay(systime_t maxDelay)
Generate a random delay.
Definition: igmp_common.c:373
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:175
IpFilterMode
Multicast filter mode.
Definition: ip.h:67
#define htons(value)
Definition: cpu_endian.h:413
void ipv4RemoveSrcAddr(Ipv4SrcAddrList *list, Ipv4Addr srcAddr)
Remove a source address from a given list.
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
Source address list.
Definition: ipv4.h:399
error_t ipv4AddSrcAddr(Ipv4SrcAddrList *list, Ipv4Addr srcAddr)
Append a source address to a given list.
uint8_t maxRespTime
Definition: igmp_common.h:212
bool_t netTimerRunning(NetTimer *timer)
Check whether the timer is running.
Definition: net_misc.c:793
systime_t netGetRemainingTime(NetTimer *timer)
Get the remaining value of the running timer.
Definition: net_misc.c:837
IgmpHostGroupState state
Multicast group state.
Definition: igmp_host.h:94
IgmpMessage
Definition: igmp_common.h:215
signed int int_t
Definition: compiler_port.h:49
IgmpVersion
IGMP versions.
Definition: igmp_common.h:161
bool_t igmpHostGetGroupRetransmitStatus(IgmpHostGroup *group)
Get the retransmission status for a given group.
NetInterface * interface
Underlying network interface.
Definition: igmp_host.h:115
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
int_t ipv4FindSrcAddr(const Ipv4SrcAddrList *list, Ipv4Addr srcAddr)
Search the list of sources for a given IP address.
uint8_t message[]
Definition: chap.h:154
#define IGMP_ALL_SYSTEMS_ADDR
Definition: igmp_common.h:144
#define TRUE
Definition: os_port.h:50
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
void igmpHostChangeCompatibilityMode(IgmpHostContext *context, IgmpVersion compatibilityMode)
Change host compatibility mode.
void igmpHostMergeReports(IgmpHostGroup *group, IpFilterMode newFilterMode, const Ipv4SrcAddrList *newFilter)
Merge difference the report and the pending report.
@ IP_FILTER_MODE_EXCLUDE
Definition: ip.h:68
bool_t igmpHostGetRetransmitStatus(IgmpHostContext *context)
Get the retransmission status of the State-Change report.
#define IPV4_MAX_MULTICAST_SOURCES
Definition: ipv4.h:90
IgmpHostGroup groups[IPV4_MULTICAST_FILTER_SIZE]
Multicast groups.
Definition: igmp_host.h:121
@ IGMP_TYPE_MEMBERSHIP_REPORT_V2
Definition: igmp_common.h:176
void igmpHostProcessMembershipQueryV3(IgmpHostContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMembershipQueryV3 *message, size_t length)
Process incoming Version 3 Membership Query message.
void igmpHostDecGroupRetransmitCounters(IgmpHostGroup *group)
Decrement retransmission counters for a given group.
void igmpHostRemoveSrcAddr(IgmpHostSrcAddrList *list, Ipv4Addr srcAddr)
Remove a source address from a given list.
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:297
Source address list.
Definition: igmp_host.h:80
NetTimer stateChangeReportTimer
Retransmission timer for state-change reports.
Definition: igmp_host.h:120
void igmpHostSendStateChangeReport(IgmpHostContext *context)
Send State-Change Report message.
IpFilterMode filterMode
Filter mode.
Definition: igmp_host.h:99
IGMP host context.
Definition: igmp_host.h:114
IPv4 multicast filtering.
int_t igmpHostFindSrcAddr(const IgmpHostSrcAddrList *list, Ipv4Addr srcAddr)
Search the list of sources for a given IP address.
Helper functions for IPv4.
#define FALSE
Definition: os_port.h:46
@ 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_HOST_GROUP_STATE_DELAYING_MEMBER
Definition: igmp_host.h:59
void netStopTimer(NetTimer *timer)
Stop timer.
Definition: net_misc.c:780
#define IGMP_ALL_ROUTERS_ADDR
Definition: igmp_common.h:146
#define IGMP_MAX_MSG_SIZE
Definition: igmp_common.h:135
@ IGMP_GROUP_RECORD_TYPE_BLOCK
Definition: igmp_common.h:193
IgmpHostGroup * igmpHostCreateGroup(IgmpHostContext *context, Ipv4Addr groupAddr)
Create a new multicast group.
void igmpHostSendCurrentStateReport(IgmpHostContext *context, Ipv4Addr groupAddr)
Send Current-State Report message.
uint_t numSources
Number of source addresses.
Definition: ipv4.h:400
Ipv4Addr addr
Multicast group address.
Definition: igmp_host.h:95
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
void igmpHostFlushUnusedGroups(IgmpHostContext *context)
Delete groups in "non-existent" state.
error_t igmpSendMessage(NetInterface *interface, Ipv4Addr destAddr, NetBuffer *buffer, size_t offset)
Send IGMP message.
Definition: igmp_common.c:157
@ IGMP_GROUP_RECORD_TYPE_ALLOW
Definition: igmp_common.h:192
@ IGMP_HOST_GROUP_STATE_NON_MEMBER
Definition: igmp_host.h:57
@ IGMP_TYPE_MEMBERSHIP_REPORT_V3
Definition: igmp_common.h:178
#define Ipv4PseudoHeader
Definition: ipv4.h:39
uint_t numSources
Number of source address.
Definition: igmp_host.h:81
IGMP host.
uint8_t length
Definition: tcp.h:368
bool_t igmpHostMatchGroup(IgmpHostGroup *group, Ipv4Addr multicastAddr)
Check whether a group matches a given multicast address.
#define IGMP_ROBUSTNESS_VARIABLE
Definition: igmp_common.h:46
#define IGMP_OLDER_VERSION_QUERIER_PRESENT_TIMEOUT
Definition: igmp_common.h:114
@ IGMP_GROUP_RECORD_TYPE_IS_EX
Definition: igmp_common.h:189
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
#define IGMP_V3_ALL_ROUTERS_ADDR
Definition: igmp_common.h:148
NetTimer generalQueryTimer
Timer for scheduling responses to general queries.
Definition: igmp_host.h:119
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
@ IGMP_VERSION_2
Definition: igmp_common.h:163
NetTimer igmpv2QuerierPresentTimer
IGMPv2 querier present timer.
Definition: igmp_host.h:118
#define HTONS(value)
Definition: cpu_endian.h:410
void igmpHostSendLeaveGroup(IgmpHostContext *context, Ipv4Addr groupAddr)
Send Leave Group message.
uint8_t n
bool_t flag
We are the last host to send a report for this group.
Definition: igmp_host.h:96
IgmpGroupRecord
Definition: igmp_common.h:269
Ipv4Addr groupAddr
Definition: igmp_common.h:214
@ IGMP_VERSION_3
Definition: igmp_common.h:164
void igmpHostDeleteGroup(IgmpHostGroup *group)
Delete a multicast group.
IgmpMembershipQueryV3
Definition: igmp_common.h:240
@ MLD_NODE_GROUP_STATE_NON_LISTENER
Definition: mld_node.h:57
void igmpHostProcessMessage(IgmpHostContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length)
Process incoming IGMP message.
@ IP_FILTER_MODE_INCLUDE
Definition: ip.h:69
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
Helper functions for IGMP host.
MacAddr srcAddr
Definition: ethernet.h:220
IgmpHostGroup * igmpHostFindGroup(IgmpHostContext *context, Ipv4Addr groupAddr)
Search the list of multicast groups for a given group address.
error_t igmpHostAddSrcAddr(IgmpHostSrcAddrList *list, Ipv4Addr srcAddr)
Append a source address to a given list.
void igmpHostProcessMembershipQuery(IgmpHostContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length)
Process incoming Membership Query message.
@ IGMP_VERSION_1
Definition: igmp_common.h:162
void igmpHostSendMembershipReport(IgmpHostContext *context, Ipv4Addr groupAddr)
Send Membership Report message.
NetTimer igmpv1QuerierPresentTimer
IGMPv1 querier present timer.
Definition: igmp_host.h:117
NetTimer timer
Report delay timer.
Definition: igmp_host.h:98
@ IGMP_GROUP_RECORD_TYPE_IS_IN
Definition: igmp_common.h:188
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
@ IGMP_GROUP_RECORD_TYPE_TO_IN
Definition: igmp_common.h:190
@ IGMP_HOST_GROUP_STATE_INIT_MEMBER
Definition: igmp_host.h:58
void igmpHostProcessMembershipReport(IgmpHostContext *context, const Ipv4PseudoHeader *pseudoHeader, const IgmpMessage *message, size_t length)
Process incoming Membership Report message.
IPv4 (Internet Protocol Version 4)
IgmpVersion compatibilityMode
Host compatibility mode.
Definition: igmp_host.h:116
#define IGMP_V1_MAX_RESPONSE_TIME
Definition: igmp_common.h:121
uint_t retransmitCount
Filter mode retransmission counter.
Definition: igmp_host.h:97
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
void igmpHostFlushReportRecords(IgmpHostContext *context, NetBuffer *buffer, size_t offset, size_t *length)
Flush report records.
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1457
@ NO_ERROR
Success.
Definition: error.h:44
Ipv4Addr multicastAddr
Definition: igmp_common.h:267
@ IGMP_HOST_GROUP_STATE_IDLE_MEMBER
Definition: igmp_host.h:60
@ IGMP_TYPE_LEAVE_GROUP
Definition: igmp_common.h:177
Debugging facilities.
Ipv4SrcAddrList filter
Current-state record.
Definition: igmp_host.h:100
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:117
uint16_t ipCalcChecksum(const void *data, size_t length)
IP checksum calculation.
Definition: ip.c:466
#define IPV4_MULTICAST_FILTER_SIZE
Definition: ipv4.h:83