mld_node_misc.c
Go to the documentation of this file.
1 /**
2  * @file mld_node_misc.c
3  * @brief Helper functions for MLD node
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 MLD_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "ipv6/ipv6.h"
37 #include "ipv6/ipv6_multicast.h"
38 #include "ipv6/icmpv6.h"
39 #include "mld/mld_node.h"
40 #include "mld/mld_node_misc.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (IPV6_SUPPORT == ENABLED && MLD_NODE_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Change host compatibility mode
49  * @param[in] context Pointer to the MLD node context
50  * @param[in] compatibilityMode New host compatibility mode
51  **/
52 
54  MldVersion compatibilityMode)
55 {
56  uint_t i;
57  MldNodeGroup *group;
58 
59  //Debug message
60  TRACE_DEBUG("Changing host compatibility mode to MLDv%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 3810, section 8.2.1)
70 
71  //Loop through multicast groups
72  for(i = 0; i < IPV6_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 (IPV6_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 Listener state
94  }
95  }
96 
97  //Delete groups in "non-existent" state
98  mldNodeFlushUnusedGroups(context);
99 }
100 
101 
102 /**
103  * @brief Send an unsolicited Report message
104  * @param[in] context Pointer to the MLD node context
105  * @param[in] groupAddr IPv6 address specifying the multicast address
106  **/
107 
109  const Ipv6Addr *groupAddr)
110 {
111  MldNodeGroup *group;
112 
113  //Search the list of groups for the specified multicast address
114  group = mldNodeFindGroup(context, groupAddr);
115 
116  //Any matching group found?
117  if(group != NULL)
118  {
119  //Check group state
121  {
122  //Check host compatibility mode
123  if(context->compatibilityMode == MLD_VERSION_1)
124  {
125  //Send a Multicast Listener Report message
127  }
128  else
129  {
130  //Send a Version 2 Multicast Listener Report message
132  }
133  }
134  }
135 }
136 
137 
138 /**
139  * @brief Send Multicast Listener Report message
140  * @param[in] context Pointer to the MLD node context
141  * @param[in] groupAddr IPv6 address specifying the multicast address
142  **/
143 
145  const Ipv6Addr *groupAddr)
146 {
147  size_t offset;
148  NetBuffer *buffer;
150 
151  //Allocate a memory buffer to hold the MLD message
152  buffer = ipAllocBuffer(sizeof(MldMessage), &offset);
153  //Failed to allocate memory?
154  if(buffer == NULL)
155  return;
156 
157  //Point to the beginning of the MLD message
158  message = netBufferAt(buffer, offset, 0);
159 
160  //Format the Multicast Listener Report message
162  message->code = 0;
163  message->checksum = 0;
164  message->maxRespDelay = 0;
165  message->reserved = 0;
166  message->multicastAddr = *groupAddr;
167 
168  //The Multicast Listener Report message is sent to the multicast address
169  //being reported
170  mldSendMessage(context->interface, groupAddr, buffer, offset);
171 
172  //Free previously allocated memory
173  netBufferFree(buffer);
174 }
175 
176 
177 /**
178  * @brief Send Multicast Listener Done message
179  * @param[in] context Pointer to the MLD node context
180  * @param[in] groupAddr IPv6 address specifying the multicast address being left
181  **/
182 
184  const Ipv6Addr *groupAddr)
185 {
186  size_t offset;
187  NetBuffer *buffer;
189 
190  //Allocate a memory buffer to hold the MLD message
191  buffer = ipAllocBuffer(sizeof(MldMessage), &offset);
192  //Failed to allocate memory?
193  if(buffer == NULL)
194  return;
195 
196  //Point to the beginning of the MLD message
197  message = netBufferAt(buffer, offset, 0);
198 
199  //Format the Multicast Listener Done message
201  message->code = 0;
202  message->checksum = 0;
203  message->maxRespDelay = 0;
204  message->reserved = 0;
205  message->multicastAddr = *groupAddr;
206 
207  //The Multicast Listener Done message is sent to the all-routers multicast
208  //address
210  buffer, offset);
211 
212  //Free previously allocated memory
213  netBufferFree(buffer);
214 }
215 
216 
217 /**
218  * @brief Send Current-State Report message
219  * @param[in] context Pointer to the MLD node context
220  * @param[in] groupAddr IPv6 address specifying the group address
221  **/
222 
224  const Ipv6Addr *groupAddr)
225 {
226  uint_t i;
227  size_t n;
228  size_t length;
229  size_t offset;
230  NetBuffer *buffer;
231  MldNodeGroup *group;
233  MldMcastAddrRecord *record;
234 
235  //Allocate a memory buffer to hold the MLD message
236  buffer = ipAllocBuffer(MLD_MAX_MSG_SIZE, &offset);
237  //Failed to allocate memory?
238  if(buffer == NULL)
239  return;
240 
241  //Point to the beginning of the MLD message
242  message = netBufferAt(buffer, offset, 0);
243 
244  //Format the Version 2 Multicast Listener Report message
246  message->reserved1 = 0;
247  message->checksum = 0;
248  message->reserved2 = 0;
249  message->numOfMcastAddrRecords = 0;
250 
251  //Total length of the message
252  length = sizeof(MldListenerReportV2);
253 
254  //Loop through multicast groups
255  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
256  {
257  //Point to the current group
258  group = &context->groups[i];
259 
260  //Matching group?
261  if(mldNodeMatchGroup(group, groupAddr))
262  {
263 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
264  //Check whether the interface has reception state for that group
265  //address
266  if(group->filterMode == IP_FILTER_MODE_EXCLUDE ||
267  group->filter.numSources > 0)
268  {
269  uint_t j;
270 
271  //General Query or Group-Specific Query?
273  group->queriedSources.numSources == 0)
274  {
275  //Calculate the length of the multicast address record
276  n = sizeof(MldMcastAddrRecord) + group->filter.numSources *
277  sizeof(Ipv6Addr);
278 
279  //If the set of Multicast Address Records required in a Report
280  //does not fit within the size limit of a single Report message,
281  //the Multicast Address Records are sent in as many Report
282  //messages as needed to report the entire set (refer to RFC 3810,
283  //section 5.2.15)
284  if((length + n) > MLD_MAX_MSG_SIZE)
285  {
286  //Send report message
287  mldNodeFlushReportRecords(context, buffer, offset, &length);
288  }
289 
290  //Point to the buffer where to format the record
291  record = (MldMcastAddrRecord *) ((uint8_t *) message + length);
292 
293  //The Current-State Record carries the associated filter mode
294  //(MODE_IS_INCLUDE or MODE_IS_EXCLUDE)
295  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
296  {
297  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_IS_IN;
298  }
299  else
300  {
301  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_IS_EX;
302  }
303 
304  //Format multicast address record
305  record->auxDataLen = 0;
306  record->numOfSources = htons(group->filter.numSources);
307  record->multicastAddr = group->addr;
308 
309  //Format the list of source addresses
310  for(j = 0; j < group->filter.numSources; j++)
311  {
312  record->srcAddr[j] = group->filter.sources[j];
313  }
314 
315  //Increment the number of multicast address records
316  message->numOfMcastAddrRecords++;
317  //Update the length of the message
318  length += n;
319  }
320  else
321  {
322  //If the list of recorded sources B for that multicast address
323  //is non-empty, then the contents of the responding Current-State
324  //Record is determined from the interface state and the pending
325  //response record
326  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
327  {
328  //If the interface state is INCLUDE (A), then the contents of
329  //the responding Current-State Record is IS_IN (A*B)
330  for(j = 0; j < group->queriedSources.numSources; )
331  {
332  if(ipv6FindSrcAddr(&group->filter,
333  &group->queriedSources.sources[j]) >= 0)
334  {
335  j++;
336  }
337  else
338  {
339  ipv6RemoveSrcAddr(&group->queriedSources,
340  &group->queriedSources.sources[j]);
341  }
342  }
343  }
344  else
345  {
346  //If the interface state is EXCLUDE (A), then the contents of
347  //the responding Current-State Record is IS_IN (B-A)
348  for(j = 0; j < group->filter.numSources; j++)
349  {
350  ipv6RemoveSrcAddr(&group->queriedSources,
351  &group->filter.sources[j]);
352  }
353  }
354 
355  //If the resulting Current-State Record has an empty set of
356  //source addresses, then no response is sent
357  if(group->queriedSources.numSources > 0)
358  {
359  //Calculate the length of the multicast address record
360  n = sizeof(MldMcastAddrRecord) +
361  group->queriedSources.numSources * sizeof(Ipv6Addr);
362 
363  //If the set of Multicast Address Records required in a
364  //Report does not fit within the size limit of a single
365  //Report message, the Multicast Address Records are sent in
366  //as many Report messages as needed to report the entire set
367  //(refer to RFC 3810, section 5.2.15)
368  if((length + n) > MLD_MAX_MSG_SIZE)
369  {
370  //Send report message
371  mldNodeFlushReportRecords(context, buffer, offset, &length);
372  }
373 
374  //Point to the buffer where to format the record
375  record = (MldMcastAddrRecord *) ((uint8_t *) message + length);
376 
377  //Format multicast address record
378  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_IS_IN;
379  record->auxDataLen = 0;
380  record->numOfSources = htons(group->queriedSources.numSources);
381  record->multicastAddr = group->addr;
382 
383  //Format the list of source addresses
384  for(j = 0; j < group->queriedSources.numSources; j++)
385  {
386  record->srcAddr[j] = group->queriedSources.sources[j];
387  }
388 
389  //Increment the number of multicast address records
390  message->numOfMcastAddrRecords++;
391  //Update the length of the message
392  length += n;
393  }
394  }
395  }
396 
397  //Finally, after any required Report messages have been generated,
398  //the source lists associated with any reported groups are cleared
399  group->queriedSources.numSources = 0;
400 #else
401  //Check whether the interface has reception state for that group
402  //address
403  if(group->filterMode == IP_FILTER_MODE_EXCLUDE)
404  {
405  //Calculate the length of the multicast address record
406  n = sizeof(MldMcastAddrRecord);
407 
408  //If the set of Multicast Address Records required in a Report
409  //does not fit within the size limit of a single Report message,
410  //the Multicast Address Records are sent in as many Report
411  //messages as needed to report the entire set (refer to RFC 3810,
412  //section 5.2.15)
413  if((length + n) > MLD_MAX_MSG_SIZE)
414  {
415  //Send report message
416  mldNodeFlushReportRecords(context, buffer, offset, &length);
417  }
418 
419  //Point to the buffer where to format the record
420  record = (MldMcastAddrRecord *) ((uint8_t *) message + length);
421 
422  //The Current-State Record carries the associated filter mode
423  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_IS_EX;
424  record->auxDataLen = 0;
425  record->numOfSources = HTONS(0);
426  record->multicastAddr = group->addr;
427 
428  //Increment the number of multicast address records
429  message->numOfMcastAddrRecords++;
430  //Update the length of the message
431  length += n;
432  }
433 #endif
434  }
435  }
436 
437  //Version 2 Multicast Listener Reports are sent with an IP destination
438  //address of ff02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
439  //routers listen (refer to RFC 3810, section 5.2.14)
440  mldNodeFlushReportRecords(context, buffer, offset, &length);
441 
442  //Free previously allocated memory
443  netBufferFree(buffer);
444 }
445 
446 
447 /**
448  * @brief Send State-Change Report message
449  * @param[in] context Pointer to the MLD node context
450  * @param[in] groupAddr IPv6 address specifying the group address
451  **/
452 
454  const Ipv6Addr *groupAddr)
455 {
456  uint_t i;
457  size_t n;
458  size_t length;
459  size_t offset;
460  NetBuffer *buffer;
461  MldNodeGroup *group;
463  MldMcastAddrRecord *record;
464 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
465  uint_t j;
466 #endif
467 
468  //Allocate a memory buffer to hold the MLD message
469  buffer = ipAllocBuffer(MLD_MAX_MSG_SIZE, &offset);
470  //Failed to allocate memory?
471  if(buffer == NULL)
472  return;
473 
474  //Point to the beginning of the MLD message
475  message = netBufferAt(buffer, offset, 0);
476 
477  //Format the Version 2 Multicast Listener Report message
479  message->reserved1 = 0;
480  message->checksum = 0;
481  message->reserved2 = 0;
482  message->numOfMcastAddrRecords = 0;
483 
484  //Total length of the message
485  length = sizeof(MldListenerReportV2);
486 
487  //Loop through multicast groups
488  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
489  {
490  //Point to the current group
491  group = &context->groups[i];
492 
493  //Matching group?
494  if(mldNodeMatchGroup(group, groupAddr))
495  {
496  //The report should contain a Filter Mode Change Record if the Filter
497  //Mode Retransmission Counter has a value higher than zero
498  if(group->retransmitCount > 0)
499  {
500  //Calculate the length of the multicast address record
501  n = sizeof(MldMcastAddrRecord) + group->filter.numSources *
502  sizeof(Ipv6Addr);
503 
504  //If the set of Multicast Address Records required in a Report
505  //does not fit within the size limit of a single Report message,
506  //the Multicast Address Records are sent in as many Report
507  //messages as needed to report the entire set (refer to RFC 3810,
508  //section 5.2.15)
509  if((length + n) > MLD_MAX_MSG_SIZE)
510  {
511  //Send report message
512  mldNodeFlushReportRecords(context, buffer, offset, &length);
513  }
514 
515  //Point to the buffer where to format the record
516  record = (MldMcastAddrRecord *) ((uint8_t *) message + length);
517 
518  //If the current filter-mode of the interface is INCLUDE, a TO_IN
519  //record is included in the report, otherwise a TO_EX record is
520  //included
521  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
522  {
523  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_TO_IN;
524  }
525  else
526  {
527  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_TO_EX;
528  }
529 
530  //Format multicast address record
531  record->auxDataLen = 0;
532  record->numOfSources = htons(group->filter.numSources);
533  record->multicastAddr = group->addr;
534 
535 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
536  //Format the list of source addresses
537  for(j = 0; j < group->filter.numSources; j++)
538  {
539  record->srcAddr[j] = group->filter.sources[j];
540  }
541 #endif
542  //Increment the number of multicast address records
543  message->numOfMcastAddrRecords++;
544  //Update the length of the message
545  length += n;
546  }
547  else
548  {
549 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
550  //If the computed source list for a ALLOW record is empty, that
551  //record is omitted from the State-Change report
552  if(group->allow.numSources > 0)
553  {
554  //Calculate the length of the ALLOW record
555  n = sizeof(MldMcastAddrRecord) + group->allow.numSources *
556  sizeof(Ipv6Addr);
557 
558  //If the set of Multicast Address Records required in a Report
559  //does not fit within the size limit of a single Report message,
560  //the Multicast Address Records are sent in as many Report
561  //messages as needed to report the entire set (refer to RFC 3810,
562  //section 5.2.15)
563  if((length + n) > MLD_MAX_MSG_SIZE)
564  {
565  //Send report message
566  mldNodeFlushReportRecords(context, buffer, offset, &length);
567  }
568 
569  //Point to the buffer where to format the record
570  record = (MldMcastAddrRecord *) ((uint8_t *) message + length);
571 
572  //The ALLOW record contains the list of the additional sources
573  //that the system wishes to hear from
574  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_ALLOW;
575  record->auxDataLen = 0;
576  record->numOfSources = htons(group->allow.numSources);
577  record->multicastAddr = group->addr;
578 
579  //Format the list of source addresses
580  for(j = 0; j < group->allow.numSources; j++)
581  {
582  record->srcAddr[j] = group->allow.sources[j].addr;
583  }
584 
585  //Increment the number of multicast address records
586  message->numOfMcastAddrRecords++;
587  //Update the length of the message
588  length += n;
589  }
590 
591  //If the computed source list for a BLOCK record is empty, that
592  //record is omitted from the State-Change report
593  if(group->block.numSources > 0)
594  {
595  //Calculate the length of the BLOCK record
596  n = sizeof(MldMcastAddrRecord) + group->block.numSources *
597  sizeof(Ipv6Addr);
598 
599  //If the set of Multicast Address Records required in a Report
600  //does not fit within the size limit of a single Report message,
601  //the Multicast Address Records are sent in as many Report
602  //messages as needed to report the entire set (refer to RFC 3810,
603  //section 5.2.15)
604  if((length + n) > MLD_MAX_MSG_SIZE)
605  {
606  //Send report message
607  mldNodeFlushReportRecords(context, buffer, offset, &length);
608  }
609 
610  //Point to the buffer where to format the record
611  record = (MldMcastAddrRecord *) ((uint8_t *) message + length);
612 
613  //The BLOCK record contains the list of the sources that the
614  //system no longer wishes to hear from
615  record->recordType = MLD_MCAST_ADDR_RECORD_TYPE_BLOCK;
616  record->auxDataLen = 0;
617  record->numOfSources = htons(group->block.numSources);
618  record->multicastAddr = group->addr;
619 
620  //Format the list of source addresses
621  for(j = 0; j < group->block.numSources; j++)
622  {
623  record->srcAddr[j] = group->block.sources[j].addr;
624  }
625 
626  //Increment the number of multicast address records
627  message->numOfMcastAddrRecords++;
628  //Update the length of the message
629  length += n;
630  }
631 #endif
632  }
633 
634  //Retransmission state needs to be maintained until [Robustness
635  //Variable] State-Change reports have been sent by the host
637  }
638  }
639 
640  //Version 2 Multicast Listener Reports are sent with an IP destination
641  //address of ff02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
642  //routers listen (refer to RFC 3810, section 5.2.14)
643  mldNodeFlushReportRecords(context, buffer, offset, &length);
644 
645  //Free previously allocated memory
646  netBufferFree(buffer);
647 }
648 
649 
650 /**
651  * @brief Flush report records
652  * @param[in] context Pointer to the MLD node context
653  * @param[in] buffer Multi-part buffer containing the report message
654  * @param[in] offset Offset to the first byte of the report message
655  * @param[in,out] length Length of the report message, in bytes
656  **/
657 
659  size_t offset, size_t *length)
660 {
662 
663  //Any multicast address records included in the message?
664  if(*length > 0)
665  {
666  //Point to the beginning of the report message
667  message = netBufferAt(buffer, offset, 0);
668 
669  //The Nr of Mcast Address Records field specifies how many Multicast
670  //Address Records are present in this Report
671  message->numOfMcastAddrRecords = htons(message->numOfMcastAddrRecords);
672 
673  //Adjust the length of the multi-part buffer
674  netBufferSetLength(buffer, offset + *length);
675 
676  //Version 2 Multicast Listener Reports are sent with an IP destination
677  //address of ff02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
678  //routers listen (refer to RFC 3810, section 5.2.14)
680  offset);
681 
682  //Reset the Checksum field
683  message->checksum = 0;
684  //Reset the Nr of Mcast Address Records field
685  message->numOfMcastAddrRecords = 0;
686 
687  //Update the length of the message
688  *length = sizeof(MldListenerReportV2);
689  }
690 }
691 
692 
693 /**
694  * @brief Process incoming MLD message
695  * @param[in] context Pointer to the MLD node context
696  * @param[in] pseudoHeader IPv6 pseudo header
697  * @param[in] message Pointer to the incoming MLD message
698  * @param[in] length Length of the MLD message, in bytes
699  **/
700 
702  const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message,
703  size_t length)
704 {
705  //Check MLD message type
707  {
708  //The MLD version of a Multicast Listener Query message is determined as
709  //follows
710  if(length == sizeof(MldMessage))
711  {
712  //Process Multicast Listener Query message
713  mldNodeProcessListenerQuery(context, pseudoHeader, message, length);
714  }
715  else if(length >= sizeof(MldListenerQueryV2))
716  {
717  //Process Version 2 Multicast Listener Query message
718  mldNodeProcessListenerQueryV2(context, pseudoHeader,
720  }
721  else
722  {
723  //Query messages that do not match any of the above conditions must be
724  //silently ignored (refer to RFC 3810, section 8.1)
725  }
726  }
728  {
729  //Process Multicast Listener Report message
730  mldNodeProcessListenerReport(context, pseudoHeader, message, length);
731  }
732  else
733  {
734  //Discard other messages
735  }
736 }
737 
738 
739 /**
740  * @brief Process incoming Multicast Listener Query message
741  * @param[in] context Pointer to the MLD node context
742  * @param[in] pseudoHeader IPv6 pseudo header
743  * @param[in] message Pointer to the incoming MLD message
744  * @param[in] length Length of the MLD message, in bytes
745  **/
746 
748  const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message,
749  size_t length)
750 {
751  uint_t i;
752  systime_t delay;
754  MldNodeGroup *group;
755 
756  //MLD Query messages must be sent with a valid link-local address as the
757  //IPv6 source address. If a node receives a query message with an IPv6
758  //source address set to the unspecified address, it must silently discard
759  //the message (refer to RFC 3590, section 4)
760  if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
761  return;
762 
763  //A General Query is used to learn which multicast addresses have listeners
764  //on an attached link. A Multicast-Address-Specific Query is used to learn
765  //if a particular multicast address has any listeners on an attached link
766  if(!ipv6CompAddr(&message->multicastAddr, &IPV6_UNSPECIFIED_ADDR) &&
767  !ipv6IsMulticastAddr(&message->multicastAddr))
768  {
769  return;
770  }
771 
772  //The Older Version Querier Present timer for the interface is set to Older
773  //Version Querier Present Timeout seconds
776 
777  //The Host Compatibility Mode of an interface is set to MLDv1 whenever an
778  //MLDv1 Multicast Address Listener Query is received on that interface
779  if(context->compatibilityMode > MLD_VERSION_1)
780  {
781  //The host should switch compatibility mode immediately
783  }
784 
785  //The Maximum Response Delay field specifies the maximum allowed delay
786  //before sending a responding report, in units of milliseconds
787  maxRespDelay = ntohs(message->maxRespDelay);
788 
789  //Loop through multicast groups
790  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
791  {
792  //Point to the current group
793  group = &context->groups[i];
794 
795  //Matching group?
796  if(mldNodeMatchGroup(group, &message->multicastAddr))
797  {
798  //Check group state
800  {
801  //If a timer for the address is already running, it is reset to
802  //the new random value only if the requested Max Response Delay
803  //is less than the remaining value of the running timer
804  if(maxRespDelay < netGetRemainingTime(&group->timer))
805  {
806  //Select a random value in the range 0 - Max Response Delay
808  //Restart delay timer
809  netStartTimer(&group->timer, delay);
810  }
811  }
812  else if(group->state == MLD_NODE_GROUP_STATE_IDLE_LISTENER)
813  {
814  //Select a random value in the range 0 - Max Response Delay
816  //Start delay timer
817  netStartTimer(&group->timer, delay);
818 
819  //Switch to the Delaying Listener state
821  }
822  else
823  {
824  //Just for sanity
825  }
826  }
827  }
828 }
829 
830 
831 /**
832  * @brief Process incoming Version 2 Multicast Listener Query message
833  * @param[in] context Pointer to the MLD node context
834  * @param[in] pseudoHeader IPv6 pseudo header
835  * @param[in] message Pointer to the incoming MLD message
836  * @param[in] length Length of the MLD message, in bytes
837  **/
838 
840  const Ipv6PseudoHeader *pseudoHeader, const MldListenerQueryV2 *message,
841  size_t length)
842 {
843  uint_t i;
844  uint_t n;
845  systime_t delay;
847  uint16_t maxRespCode;
848  MldNodeGroup *group;
849 
850  //When Host Compatibility Mode is MLDv1, a host acts in MLDv1 compatibility
851  //mode, using only the MLDv1 protocol, on that interface
852  if(context->compatibilityMode < MLD_VERSION_2)
853  return;
854 
855  //Check the length of the Version 2 Membership Query message
856  if(length < sizeof(MldListenerQueryV2))
857  return;
858 
859  //For a General Query, the Multicast Address field is set to zero. For a
860  //Multicast Address Specific Query or Multicast Address and Source Specific
861  //Query, it is set to the multicast address being queried (refer to
862  //RFC 3810, section 5.1.5)
863  if(!ipv6CompAddr(&message->multicastAddr, &IPV6_UNSPECIFIED_ADDR) &&
864  !ipv6IsMulticastAddr(&message->multicastAddr))
865  {
866  return;
867  }
868 
869  //The Number of Sources field specifies how many source addresses are
870  //present in the Query
871  n = ntohs(message->numOfSources);
872 
873  //Malformed message?
874  if(length < (sizeof(MldListenerQueryV2) + n * sizeof(Ipv6Addr)))
875  return;
876 
877  //The Maximum Response Code field specifies the maximum time allowed before
878  //sending a responding report
879  maxRespCode = ntohs(message->maxRespCode);
880 
881  //The Maximum Response Delay is is derived from the Maximum Response Code as
882  //follows
883  if(maxRespCode < 32768)
884  {
885  //The time is represented in units of milliseconds
887  }
888  else
889  {
890  //Maximum Response Code represents a floating-point value
892  }
893 
894  //If the node has a per-interface listening state record that corresponds to
895  //the queried multicast address, a delay for a response is randomly selected
896  //in the range 0 - Maximum Response Delay (refer to RFC 3810, section 6.2)
898 
899  //The following rules are then used to determine if a Report needs to be
900  //scheduled and the type of Report to schedule
901  if(netTimerRunning(&context->generalQueryTimer) &&
902  netGetRemainingTime(&context->generalQueryTimer) < delay)
903  {
904  //If there is a pending response to a previous General Query scheduled
905  //sooner than the selected delay, no additional response needs to be
906  //scheduled
907  }
908  else if(ipv6CompAddr(&message->multicastAddr, &IPV6_UNSPECIFIED_ADDR))
909  {
910  //If the received Query is a General Query, the interface timer is used
911  //to schedule a response to the General Query after the selected delay.
912  //Any previously pending response to a General Query is canceled
913  netStartTimer(&context->generalQueryTimer, delay);
914  }
915  else
916  {
917  //Loop through multicast groups
918  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
919  {
920  //Point to the current group
921  group = &context->groups[i];
922 
923  //Matching group?
924  if(mldNodeMatchGroup(group, &message->multicastAddr))
925  {
926 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
927  error_t error;
928  uint_t j;
929 
930  //Initialize status code
931  error = NO_ERROR;
932 
933  //No pending response to a previous Query for this group?
934  if(!netTimerRunning(&group->timer))
935  {
936  //If the received Query is a Group-and-Source-Specific Query, the
937  //list of queried sources is recorded to be used when generating
938  //a response
939  group->queriedSources.numSources = 0;
940 
941  //Save the list of queried sources
942  for(j = 0; j < n; j++)
943  {
944  error = ipv6AddSrcAddr(&group->queriedSources,
945  &message->srcAddr[j]);
946  }
947 
948  //The implementation limits the number of source addresses that
949  //can be recorded
950  if(error)
951  {
952  group->queriedSources.numSources = 0;
953  }
954 
955  //If the received Query is a Group-Specific Query or a Group-and-
956  //Source-Specific Query and there is no pending response to a
957  //previous Query for this group, then the group timer is used to
958  //schedule a report
959  netStartTimer(&group->timer, delay);
960  }
961  else
962  {
963  //Check whether the new Query is a Group-Specific Query or the
964  //recorded source-list associated with the group is empty
965  if(n == 0 || group->queriedSources.numSources == 0)
966  {
967  //If there already is a pending response to a previous Query
968  //scheduled for this group, and either the new Query is a
969  //Group-Specific Query or the recorded source-list associated
970  //with the group is empty, then the group source-list is
971  //cleared and a single response is scheduled using
972  //the group timer
973  group->queriedSources.numSources = 0;
974  }
975  else
976  {
977  //If the received Query is a Group-and-Source-Specific Query
978  //and there is a pending response for this group with a non-
979  //empty source-list, then the group source list is augmented
980  //to contain the list of sources in the new Query and a single
981  //response is scheduled using the group timer
982  for(j = 0; j < n; j++)
983  {
984  error = ipv6AddSrcAddr(&group->queriedSources,
985  &message->srcAddr[j]);
986  }
987 
988  //The implementation limits the number of source addresses
989  //that can be recorded
990  if(error)
991  {
992  group->queriedSources.numSources = 0;
993  }
994  }
995 
996  //The new response is scheduled to be sent at the earliest of the
997  //remaining time for the pending report and the selected delay
998  if(delay < netGetRemainingTime(&group->timer))
999  {
1000  netStartTimer(&group->timer, delay);
1001  }
1002  }
1003 #else
1004  //No pending response to a previous Query for this group?
1005  if(!netTimerRunning(&group->timer))
1006  {
1007  //The group timer is used to schedule a report
1008  netStartTimer(&group->timer, delay);
1009  }
1010  else
1011  {
1012  //The new response is scheduled to be sent at the earliest of the
1013  //remaining time for the pending report and the selected delay
1014  if(delay < netGetRemainingTime(&group->timer))
1015  {
1016  netStartTimer(&group->timer, delay);
1017  }
1018  }
1019 #endif
1020  }
1021  }
1022  }
1023 }
1024 
1025 
1026 /**
1027  * @brief Process incoming Multicast Listener Report message
1028  * @param[in] context Pointer to the MLD node context
1029  * @param[in] pseudoHeader IPv6 pseudo header
1030  * @param[in] message Pointer to the incoming MLD message
1031  * @param[in] length Length of the MLD message, in bytes
1032  **/
1033 
1035  const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message,
1036  size_t length)
1037 {
1038  MldNodeGroup *group;
1039 
1040  //When Host Compatibility Mode is MLDv2, a host acts using the MLDv2
1041  //protocol on that interface
1042  if(context->compatibilityMode > MLD_VERSION_1)
1043  return;
1044 
1045  //In a Report message, the Multicast Address field holds a specific IPv6
1046  //multicast address to which the message sender is listening
1047  if(!ipv6IsMulticastAddr(&message->multicastAddr))
1048  return;
1049 
1050  //Search the list of groups for the specified multicast address
1051  group = mldNodeFindGroup(context, &message->multicastAddr);
1052 
1053  //Any matching group found?
1054  if(group != NULL)
1055  {
1056  //Report messages are ignored for multicast addresses in the Non-Listener
1057  //or Idle Listener state
1059  {
1060  //Clear flag
1061  group->flag = FALSE;
1062  //Switch to the Idle Listener state
1064  }
1065  }
1066 }
1067 
1068 
1069 /**
1070  * @brief Merge difference the report and the pending report
1071  * @param[in] group Pointer to the multicast group
1072  * @param[in] newFilterMode New filter mode for the affected group
1073  * @param[in] newFilter New interface state for the affected group
1074  **/
1075 
1077  IpFilterMode newFilterMode, const Ipv6SrcAddrList *newFilter)
1078 {
1079 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
1080  uint_t i;
1081 
1082  //The interface state for the affected group before and after the latest
1083  //change is compared
1084  if(newFilterMode == IP_FILTER_MODE_INCLUDE &&
1086  {
1087  //The interface has changed to INCLUDE filter mode for the specified
1088  //multicast address
1089  group->allow.numSources = 0;
1090  group->block.numSources = 0;
1091  }
1092  else if(newFilterMode == IP_FILTER_MODE_EXCLUDE &&
1094  {
1095  //The interface has changed to EXCLUDE filter mode for the specified
1096  //multicast address
1097  group->allow.numSources = 0;
1098  group->block.numSources = 0;
1099  }
1100  else if(newFilterMode == IP_FILTER_MODE_INCLUDE &&
1102  {
1103  //The ALLOW record contains the list of the additional sources that the
1104  //system wishes to hear from
1105  for(i = 0; i < newFilter->numSources; i++)
1106  {
1107  if(ipv6FindSrcAddr(&group->filter, &newFilter->sources[i]) < 0)
1108  {
1109  mldNodeAddSrcAddr(&group->allow, &newFilter->sources[i]);
1110  mldNodeRemoveSrcAddr(&group->block, &newFilter->sources[i]);
1111  }
1112  }
1113 
1114  //The BLOCK record contains the list of the sources that the system no
1115  //longer wishes to hear from
1116  for(i = 0; i < group->filter.numSources; i++)
1117  {
1118  if(ipv6FindSrcAddr(newFilter, &group->filter.sources[i]) < 0)
1119  {
1120  mldNodeAddSrcAddr(&group->block, &group->filter.sources[i]);
1121  mldNodeRemoveSrcAddr(&group->allow, &group->filter.sources[i]);
1122  }
1123  }
1124  }
1125  else if(newFilterMode == IP_FILTER_MODE_EXCLUDE &&
1127  {
1128  //The BLOCK record contains the list of the sources that the system no
1129  //longer wishes to hear from
1130  for(i = 0; i < newFilter->numSources; i++)
1131  {
1132  if(ipv6FindSrcAddr(&group->filter, &newFilter->sources[i]) < 0)
1133  {
1134  mldNodeAddSrcAddr(&group->block, &newFilter->sources[i]);
1135  mldNodeRemoveSrcAddr(&group->allow, &newFilter->sources[i]);
1136  }
1137  }
1138 
1139  //The ALLOW record contains the list of the additional sources that the
1140  //system wishes to hear from
1141  for(i = 0; i < group->filter.numSources; i++)
1142  {
1143  if(ipv6FindSrcAddr(newFilter, &group->filter.sources[i]) < 0)
1144  {
1145  mldNodeAddSrcAddr(&group->allow, &group->filter.sources[i]);
1146  mldNodeRemoveSrcAddr(&group->block, &group->filter.sources[i]);
1147  }
1148  }
1149  }
1150  else
1151  {
1152  //Just for sanity
1153  }
1154 #endif
1155 
1156  //When the filter mode changes, the Filter Mode Retransmission Counter is
1157  //set to [Robustness Variable]
1158  if(newFilterMode != group->filterMode)
1159  {
1161  }
1162 }
1163 
1164 
1165 /**
1166  * @brief Get the retransmission status of the State-Change report
1167  * @param[in] context Pointer to the MLD node context
1168  * @return TRUE if additional retransmissions are needed, else FALSE
1169  **/
1170 
1172 {
1173  uint_t i;
1174  bool_t status;
1175  MldNodeGroup *group;
1176 
1177  //Clear status flag
1178  status = FALSE;
1179 
1180  //Loop through multicast groups
1181  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
1182  {
1183  //Point to the current group
1184  group = &context->groups[i];
1185 
1186  //Valid group?
1188  {
1189  //Retransmission in progress?
1191  {
1192  status = TRUE;
1193  break;
1194  }
1195  }
1196  }
1197 
1198  //Return TRUE if additional retransmissions are needed
1199  return status;
1200 }
1201 
1202 
1203 /**
1204  * @brief Get the retransmission status for a given group
1205  * @param[in] group Pointer to the multicast group
1206  * @return TRUE if additional retransmissions are needed, else FALSE
1207  **/
1208 
1210 {
1211  bool_t status;
1212 
1213  //Clear status flag
1214  status = FALSE;
1215 
1216 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
1217  //Retransmission in progress?
1218  if(group->retransmitCount > 0 || group->allow.numSources > 0 ||
1219  group->block.numSources > 0)
1220  {
1221  status = TRUE;
1222  }
1223 #else
1224  //Retransmission in progress?
1225  if(group->retransmitCount > 0)
1226  {
1227  status = TRUE;
1228  }
1229 #endif
1230 
1231  //Return TRUE if additional retransmissions are needed
1232  return status;
1233 }
1234 
1235 
1236 /**
1237  * @brief Decrement retransmission counters for a given group
1238  * @param[in] group Pointer to the multicast group
1239  **/
1240 
1242 {
1243  //Filter mode change?
1244  if(group->retransmitCount > 0)
1245  {
1246  //The Filter Mode Retransmission Counter is decremented by one unit after
1247  //the transmission of the report
1248  group->retransmitCount--;
1249  }
1250  else
1251  {
1252 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
1253  int_t i;
1254 
1255  //The ALLOW record contains the list of the additional sources that the
1256  //system wishes to hear from
1257  for(i = group->allow.numSources - 1; i >= 0; i--)
1258  {
1259  //For each included source, its Source Retransmission Counter is
1260  //decreased with one unit after the transmission of the report
1261  if(group->allow.sources[i].retransmitCount > 0)
1262  {
1263  group->allow.sources[i].retransmitCount--;
1264  }
1265 
1266  //If the counter reaches zero, the source is deleted from the list
1267  if(group->allow.sources[i].retransmitCount == 0)
1268  {
1269  mldNodeRemoveSrcAddr(&group->allow, &group->allow.sources[i].addr);
1270  }
1271  }
1272 
1273  //The BLOCK record contains the list of the sources that the system no
1274  //longer wishes to hear from
1275  for(i = group->block.numSources - 1; i >= 0; i--)
1276  {
1277  //For each included source, its Source Retransmission Counter is
1278  //decreased with one unit after the transmission of the report
1279  if(group->block.sources[i].retransmitCount > 0)
1280  {
1281  group->block.sources[i].retransmitCount--;
1282  }
1283 
1284  //If the counter reaches zero, the source is deleted from the list
1285  if(group->block.sources[i].retransmitCount == 0)
1286  {
1287  mldNodeRemoveSrcAddr(&group->block, &group->block.sources[i].addr);
1288  }
1289  }
1290 #endif
1291  }
1292 }
1293 
1294 
1295 /**
1296  * @brief Create a new multicast group
1297  * @param[in] context Pointer to the MLD node context
1298  * @param[in] groupAddr Multicast group address
1299  * @return Pointer to the newly created multicast group
1300  **/
1301 
1303  const Ipv6Addr *groupAddr)
1304 {
1305  uint_t i;
1306  MldNodeGroup *group;
1307 
1308  //Initialize pointer
1309  group = NULL;
1310 
1311  //Valid multicast address?
1314  {
1315  //Loop through multicast groups
1316  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
1317  {
1318  //Check whether the entry is available
1320  {
1321  //Debug message
1322  TRACE_DEBUG("Creating MLD group (%s)...\r\n",
1323  ipv6AddrToString(groupAddr, NULL));
1324 
1325  //Point to the current group
1326  group = &context->groups[i];
1327 
1328  //Initialize group
1329  osMemset(group, 0, sizeof(MldNodeGroup));
1330 
1331  //Switch to the Init Listener state
1333  //Save the multicast group address
1334  group->addr = *groupAddr;
1335 
1336  //A per-group and interface timer is used for scheduling responses to
1337  //Group-Specific and Group-and-Source-Specific Queries
1338  netStopTimer(&group->timer);
1339 
1340  //The "non-existent" state is considered to have a filter mode of
1341  //INCLUDE and an empty source list
1343  group->filter.numSources = 0;
1344 
1345  //We are done
1346  break;
1347  }
1348  }
1349  }
1350 
1351  //Return a pointer to the newly created multicast group
1352  return group;
1353 }
1354 
1355 
1356 /**
1357  * @brief Search the list of multicast groups for a given group address
1358  * @param[in] context Pointer to the MLD node context
1359  * @param[in] groupAddr Multicast group address
1360  * @return Pointer to the matching multicast group, if any
1361  **/
1362 
1364  const Ipv6Addr *groupAddr)
1365 {
1366  uint_t i;
1367  MldNodeGroup *group;
1368 
1369  //Initialize pointer
1370  group = NULL;
1371 
1372  //Loop through multicast groups
1373  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
1374  {
1375  //Matching group?
1376  if(context->groups[i].state != MLD_NODE_GROUP_STATE_NON_LISTENER &&
1377  ipv6CompAddr(&context->groups[i].addr, groupAddr))
1378  {
1379  //Point to the current group
1380  group = &context->groups[i];
1381  break;
1382  }
1383  }
1384 
1385  //Return a pointer to the matching multicast group
1386  return group;
1387 }
1388 
1389 
1390 /**
1391  * @brief Check whether a group matches a given multicast address
1392  * @param[in] group Pointer to the multicast group
1393  * @param[in] multicastAddr IPv6 multicast address
1394  * @return TRUE if the group matches the specified multicast address, else FALSE
1395  **/
1396 
1398 {
1399  bool_t match;
1400 
1401  //Initialize flag
1402  match = FALSE;
1403 
1404  //Valid group?
1406  {
1407  //Matching multicast address?
1409  ipv6CompAddr(multicastAddr, &group->addr))
1410  {
1411  match = TRUE;
1412  }
1413  }
1414 
1415  //Return TRUE if the group matches the specified multicast address
1416  return match;
1417 }
1418 
1419 
1420 /**
1421  * @brief Delete a multicast group
1422  * @param[in] group Pointer to the multicast group
1423  **/
1424 
1426 {
1427  //Debug message
1428  TRACE_DEBUG("Deleting MLD group (%s)...\r\n",
1429  ipv6AddrToString(&group->addr, NULL));
1430 
1431  //Groups in Non-Listener state require no storage in the host
1433 }
1434 
1435 
1436 /**
1437  * @brief Delete groups in "non-existent" state
1438  * @param[in] context Pointer to the MLD node context
1439  **/
1440 
1442 {
1443  uint_t i;
1444  MldNodeGroup *group;
1445 
1446  //Loop through multicast groups
1447  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
1448  {
1449  //Point to the current group
1450  group = &context->groups[i];
1451 
1452  //Valid group?
1454  {
1455  //Retransmission state needs to be maintained until [Robustness
1456  //Variable] State-Change reports have been sent by the host
1458  {
1459  //The "non-existent" state is considered to have a filter mode of
1460  //INCLUDE and an empty source list
1461  if(group->filterMode == IP_FILTER_MODE_INCLUDE &&
1462  group->filter.numSources == 0)
1463  {
1464  //Delete the group
1465  mldNodeDeleteGroup(group);
1466  }
1467  }
1468  }
1469  }
1470 }
1471 
1472 
1473 /**
1474  * @brief Append a source address to a given list
1475  * @param[in] list Pointer to the list of source addresses
1476  * @param[in] srcAddr Source address to be added
1477  **/
1478 
1480 {
1481 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
1482  error_t error;
1483  size_t n;
1484 
1485  //Initialize status code
1486  error = NO_ERROR;
1487 
1488  //Make sure that the source address is not a duplicate
1489  if(mldNodeFindSrcAddr(list, srcAddr) < 0)
1490  {
1491  //Make sure there is enough room to add the source address
1493  {
1494  //Get the index of the new element
1495  n = list->numSources;
1496 
1497  //When a source is included in the list, its counter is set to
1498  //[Robustness Variable]
1499  list->sources[n].addr = *srcAddr;
1500  list->sources[n].retransmitCount = MLD_ROBUSTNESS_VARIABLE;
1501 
1502  //Adjust the number of elements
1503  list->numSources++;
1504  }
1505  else
1506  {
1507  //The implementation limits the number of source addresses
1508  error = ERROR_OUT_OF_RESOURCES;
1509  }
1510  }
1511 
1512  //Return status code
1513  return error;
1514 #else
1515  //Not implemented
1516  return ERROR_NOT_IMPLEMENTED;
1517 #endif
1518 }
1519 
1520 
1521 /**
1522  * @brief Remove a source address from a given list
1523  * @param[in] list Pointer to the list of source addresses
1524  * @param[in] srcAddr Source address to be removed
1525  **/
1526 
1528 {
1529 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
1530  uint_t i;
1531  uint_t j;
1532 
1533  //Loop through the list of source addresses
1534  for(i = 0; i < list->numSources; i++)
1535  {
1536  //Matching IP address?
1537  if(ipv6CompAddr(&list->sources[i].addr, srcAddr))
1538  {
1539  //Remove the source address from the list
1540  for(j = i + 1; j < list->numSources; j++)
1541  {
1542  list->sources[j - 1] = list->sources[j];
1543  }
1544 
1545  //Update the length of the list
1546  list->numSources--;
1547 
1548  //We are done
1549  break;
1550  }
1551  }
1552 #endif
1553 }
1554 
1555 
1556 /**
1557  * @brief Search the list of sources for a given IP address
1558  * @param[in] list Pointer to the list of source addresses
1559  * @param[in] srcAddr Source IP address
1560  * @return Index of the matching IP address is returned. -1 is
1561  * returned if the specified IP address cannot be found
1562  **/
1563 
1565  const Ipv6Addr *srcAddr)
1566 {
1567 #if (IPV6_MAX_MULTICAST_SOURCES > 0)
1568  int_t i;
1569  int_t index;
1570 
1571  //Initialize index
1572  index = -1;
1573 
1574  //Loop through the list of source addresses
1575  for(i = 0; i < list->numSources; i++)
1576  {
1577  //Matching IP address?
1578  if(ipv6CompAddr(&list->sources[i].addr, srcAddr))
1579  {
1580  index = i;
1581  break;
1582  }
1583  }
1584 
1585  //Return the index of the matching IP address, if any
1586  return index;
1587 #else
1588  //Not implemented
1589  return -1;
1590 #endif
1591 }
1592 
1593 #endif
uint_t numSources
Number of source address.
Definition: mld_node.h:81
IpFilterMode
Multicast filter mode.
Definition: ip.h:67
char_t * ipv6AddrToString(const Ipv6Addr *ipAddr, char_t *str)
Convert a binary IPv6 address to a string representation.
Definition: ipv6.c:2329
#define htons(value)
Definition: cpu_endian.h:413
IPv6 (Internet Protocol Version 6)
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:766
int_t mldNodeFindSrcAddr(const MldNodeSrcAddrList *list, const Ipv6Addr *srcAddr)
Search the list of sources for a given IP address.
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
void mldNodeChangeCompatibilityMode(MldNodeContext *context, MldVersion compatibilityMode)
Change host compatibility mode.
Definition: mld_node_misc.c:53
Source address list.
Definition: ipv6.h:469
const Ipv6Addr MLD_V2_ALL_ROUTERS_ADDR
Definition: mld_common.c:59
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
int_t ipv6FindSrcAddr(const Ipv6SrcAddrList *list, const Ipv6Addr *srcAddr)
Search the list of sources for a given IP address.
NetTimer stateChangeReportTimer
Retransmission timer for state-change reports.
Definition: mld_node.h:119
signed int int_t
Definition: compiler_port.h:49
#define MLD_MAX_MSG_SIZE
Definition: mld_common.h:74
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
Ipv6SrcAddrList filter
Current-state record.
Definition: mld_node.h:100
void mldNodeRemoveSrcAddr(MldNodeSrcAddrList *list, const Ipv6Addr *srcAddr)
Remove a source address from a given list.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t message[]
Definition: chap.h:154
bool_t flag
We are the last host to send a report for this group.
Definition: mld_node.h:96
#define TRUE
Definition: os_port.h:50
error_t ipv6AddSrcAddr(Ipv6SrcAddrList *list, const Ipv6Addr *srcAddr)
Append a source address to a given list.
MldMessage
Definition: mld_common.h:134
error_t mldSendMessage(NetInterface *interface, const Ipv6Addr *destAddr, NetBuffer *buffer, size_t offset)
Send MLD message.
Definition: mld_common.c:136
MldNodeGroup * mldNodeFindGroup(MldNodeContext *context, const Ipv6Addr *groupAddr)
Search the list of multicast groups for a given group address.
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
NetTimer timer
Report delay timer.
Definition: mld_node.h:98
void mldNodeProcessListenerQueryV2(MldNodeContext *context, const Ipv6PseudoHeader *pseudoHeader, const MldListenerQueryV2 *message, size_t length)
Process incoming Version 2 Multicast Listener Query message.
Ipv6Addr
Definition: ipv6.h:260
@ IP_FILTER_MODE_EXCLUDE
Definition: ip.h:68
@ MLD_MCAST_ADDR_RECORD_TYPE_IS_EX
Definition: mld_common.h:106
bool_t mldNodeMatchGroup(MldNodeGroup *group, const Ipv6Addr *multicastAddr)
Check whether a group matches a given multicast address.
@ MLD_NODE_GROUP_STATE_DELAYING_LISTENER
Definition: mld_node.h:59
void mldNodeMergeReports(MldNodeGroup *group, IpFilterMode newFilterMode, const Ipv6SrcAddrList *newFilter)
Merge difference the report and the pending report.
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:127
MLD node context.
Definition: mld_node.h:114
void mldNodeFlushReportRecords(MldNodeContext *context, NetBuffer *buffer, size_t offset, size_t *length)
Flush report records.
MldVersion compatibilityMode
Host compatibility mode.
Definition: mld_node.h:116
@ MLD_MCAST_ADDR_RECORD_TYPE_IS_IN
Definition: mld_common.h:105
void mldNodeSendListenerDone(MldNodeContext *context, const Ipv6Addr *groupAddr)
Send Multicast Listener Done message.
@ MLD_VERSION_1
Definition: mld_common.h:94
@ ICMPV6_TYPE_MCAST_LISTENER_QUERY
Definition: icmpv6.h:59
error_t mldNodeAddSrcAddr(MldNodeSrcAddrList *list, const Ipv6Addr *srcAddr)
Append a source address to a given list.
MldNodeGroup groups[IPV6_MULTICAST_FILTER_SIZE]
Multicast groups.
Definition: mld_node.h:120
#define MLD_ROBUSTNESS_VARIABLE
Definition: mld_common.h:46
MldMcastAddrRecord
Definition: mld_common.h:190
@ MLD_MCAST_ADDR_RECORD_TYPE_TO_IN
Definition: mld_common.h:107
systime_t mldGetRandomDelay(systime_t maxDelay)
Generate a random delay.
Definition: mld_common.c:269
#define ipv6IsMulticastAddr(ipAddr)
Definition: ipv6.h:139
IPv6 multicast filtering.
#define FALSE
Definition: os_port.h:46
ICMPv6 (Internet Control Message Protocol Version 6)
uint16_t maxRespDelay
Definition: mld_common.h:131
void mldNodeSendStateChangeReport(MldNodeContext *context, const Ipv6Addr *groupAddr)
Send State-Change Report message.
error_t
Error codes.
Definition: error.h:43
#define Ipv6PseudoHeader
Definition: ipv6.h:42
void netStopTimer(NetTimer *timer)
Stop timer.
Definition: net_misc.c:780
IpFilterMode filterMode
Filter mode.
Definition: mld_node.h:99
@ ICMPV6_TYPE_MCAST_LISTENER_REPORT_V1
Definition: icmpv6.h:60
MldNodeGroup * mldNodeCreateGroup(MldNodeContext *context, const Ipv6Addr *groupAddr)
Create a new multicast group.
void mldNodeDecGroupRetransmitCounters(MldNodeGroup *group)
Decrement retransmission counters for a given group.
const Ipv6Addr IPV6_LINK_LOCAL_ALL_NODES_ADDR
Definition: ipv6.c:74
#define IPV6_MAX_MULTICAST_SOURCES
Definition: ipv6.h:107
uint_t numSources
Number of source addresses.
Definition: ipv6.h:470
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
void mldNodeFlushUnusedGroups(MldNodeContext *context)
Delete groups in "non-existent" state.
@ MLD_NODE_GROUP_STATE_IDLE_LISTENER
Definition: mld_node.h:60
#define IPV6_MULTICAST_FILTER_SIZE
Definition: ipv6.h:100
const Ipv6Addr IPV6_UNSPECIFIED_ADDR
Definition: ipv6.c:66
NetTimer olderVersionQuerierPresentTimer
Older version querier present timer.
Definition: mld_node.h:117
uint8_t length
Definition: tcp.h:368
NetInterface * interface
Underlying network interface.
Definition: mld_node.h:115
MldListenerReportV2
Definition: mld_common.h:176
void mldNodeProcessListenerQuery(MldNodeContext *context, const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message, size_t length)
Process incoming Multicast Listener Query message.
#define ipv6IsLinkLocalUnicastAddr(ipAddr)
Definition: ipv6.h:131
Ipv6Addr addr
Multicast group address.
Definition: mld_node.h:95
uint_t retransmitCount
Filter mode retransmission counter.
Definition: mld_node.h:97
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
MLD node (Multicast Listener Discovery for IPv6)
void mldNodeSendCurrentStateReport(MldNodeContext *context, const Ipv6Addr *groupAddr)
Send Current-State Report message.
#define TRACE_DEBUG(...)
Definition: debug.h:107
bool_t mldNodeGetRetransmitStatus(MldNodeContext *context)
Get the retransmission status of the State-Change report.
void mldNodeProcessMessage(MldNodeContext *context, const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message, size_t length)
Process incoming MLD message.
void mldNodeProcessListenerReport(MldNodeContext *context, const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message, size_t length)
Process incoming Multicast Listener Report message.
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
const Ipv6Addr IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR
Definition: ipv6.c:78
@ MLD_MCAST_ADDR_RECORD_TYPE_TO_EX
Definition: mld_common.h:108
void mldNodeSendListenerReport(MldNodeContext *context, const Ipv6Addr *groupAddr)
Send Multicast Listener Report message.
Ipv4Addr groupAddr
Definition: igmp_common.h:214
MldVersion
MLD versions.
Definition: mld_common.h:93
void mldNodeSendUnsolicitedReport(MldNodeContext *context, const Ipv6Addr *groupAddr)
Send an unsolicited Report message.
uint32_t mldDecodeFloatingPointValue16(uint16_t code)
Decode a floating-point value (16-bit code)
Definition: mld_common.c:315
@ MLD_NODE_GROUP_STATE_NON_LISTENER
Definition: mld_node.h:57
@ 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
@ ICMPV6_TYPE_MCAST_LISTENER_DONE_V1
Definition: icmpv6.h:61
MacAddr srcAddr
Definition: ethernet.h:220
@ MLD_MCAST_ADDR_RECORD_TYPE_BLOCK
Definition: mld_common.h:110
void mldNodeDeleteGroup(MldNodeGroup *group)
Delete a multicast group.
bool_t mldNodeGetGroupRetransmitStatus(MldNodeGroup *group)
Get the retransmission status for a given group.
@ MLD_NODE_GROUP_STATE_INIT_LISTENER
Definition: mld_node.h:58
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
void ipv6RemoveSrcAddr(Ipv6SrcAddrList *list, const Ipv6Addr *srcAddr)
Remove a source address from a given list.
NetTimer generalQueryTimer
Timer for scheduling responses to general queries.
Definition: mld_node.h:118
Source address list.
Definition: mld_node.h:80
MldListenerQueryV2
Definition: mld_common.h:161
@ ICMPV6_TYPE_MCAST_LISTENER_REPORT_V2
Definition: icmpv6.h:67
Helper functions for MLD node.
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
@ MLD_VERSION_2
Definition: mld_common.h:95
@ MLD_MCAST_ADDR_RECORD_TYPE_ALLOW
Definition: mld_common.h:109
#define MLD_OLDER_VERSION_QUERIER_PRESENT_TIMEOUT
Definition: mld_common.h:60
Multicast group.
Definition: mld_node.h:93
uint8_t maxRespCode
Definition: igmp_common.h:225
@ NO_ERROR
Success.
Definition: error.h:44
Ipv4Addr multicastAddr
Definition: igmp_common.h:267
Debugging facilities.
MldNodeGroupState state
Multicast group state.
Definition: mld_node.h:94