mld_common.c
Go to the documentation of this file.
1 /**
2  * @file mld_common.c
3  * @brief Definitions common to MLD node, router and snooping switch
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * MLD is used by an IPv6 router to discover the presence of multicast
30  * listeners on its directly attached links, and to discover specifically
31  * which multicast addresses are of interest to those neighboring nodes.
32  * Refer to the following RFCs for complete details:
33  * - RFC 2710: Multicast Listener Discovery (MLD) for IPv6
34  * - RFC 3590: Source Address Selection for MLD Protocol
35  * - RFC 3810: Multicast Listener Discovery Version 2 (MLDv2) for IPv6
36  * - RFC 9777: Multicast Listener Discovery Version 2 (MLDv2) for IPv6
37  *
38  * @author Oryx Embedded SARL (www.oryx-embedded.com)
39  * @version 2.5.2
40  **/
41 
42 //Switch to the appropriate trace level
43 #define TRACE_LEVEL MLD_TRACE_LEVEL
44 
45 //Dependencies
46 #include "core/net.h"
47 #include "ipv6/ipv6_multicast.h"
48 #include "ipv6/icmpv6.h"
49 #include "mld/mld_node.h"
50 #include "mld/mld_node_misc.h"
51 #include "mld/mld_common.h"
52 #include "mld/mld_debug.h"
53 #include "mibs/ip_mib_module.h"
54 #include "debug.h"
55 
56 //Check TCP/IP stack configuration
57 #if (IPV6_SUPPORT == ENABLED && MLD_NODE_SUPPORT == ENABLED)
58 
59 //Link-local All-Routers IPv6 address
61  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0016);
62 
63 //Tick counter to handle periodic operations
65 
66 
67 /**
68  * @brief MLD initialization
69  * @param[in] interface Underlying network interface
70  * @return Error code
71  **/
72 
74 {
75  error_t error;
76 
77  //Join the All-Nodes multicast address
79  //Any error to report?
80  if(error)
81  return error;
82 
83 #if (MLD_NODE_SUPPORT == ENABLED)
84  //MLD node initialization
85  error = mldNodeInit(interface);
86  //Any error to report?
87  if(error)
88  return error;
89 #endif
90 
91  //Successful initialization
92  return NO_ERROR;
93 }
94 
95 
96 /**
97  * @brief MLD node timer handler
98  *
99  * This routine must be periodically called by the TCP/IP stack to
100  * handle MLD related timers
101  *
102  * @param[in] interface Underlying network interface
103  **/
104 
105 void mldTick(NetInterface *interface)
106 {
107 #if (MLD_NODE_SUPPORT == ENABLED)
108  //Manage MLD node timers
109  mldNodeTick(&interface->mldNodeContext);
110 #endif
111 }
112 
113 
114 /**
115  * @brief Callback function for link change event
116  * @param[in] interface Underlying network interface
117  **/
118 
120 {
121 #if (MLD_NODE_SUPPORT == ENABLED)
122  //Notify the MLD node of link state changes
123  mldNodeLinkChangeEvent(&interface->mldNodeContext);
124 #endif
125 }
126 
127 
128 /**
129  * @brief Send MLD message
130  * @param[in] interface Underlying network interface
131  * @param[in] destAddr Destination IP address
132  * @param[in] buffer Multi-part buffer containing the payload
133  * @param[in] offset Offset to the first byte of the payload
134  * @return Error code
135  **/
136 
138  NetBuffer *buffer, size_t offset)
139 {
140  size_t length;
142  Ipv6PseudoHeader pseudoHeader;
143  NetTxAncillary ancillary;
144 
145  //Retrieve the length of payload
146  length = netBufferGetLength(buffer) - offset;
147 
148  //Point to the beginning of the MLD message
149  message = netBufferAt(buffer, offset, length);
150  //Sanity check
151  if(message == NULL)
152  return ERROR_FAILURE;
153 
154  //Check if a valid link-local address is available on the interface
156  {
157  //The message is sent with a link-local address as the IPv6 source address
158  pseudoHeader.srcAddr = interface->ipv6Context.addrList[0].addr;
159  }
160  else
161  {
162  //Check MLD message type
164  {
165  //MLD Query messages must be sent with a valid link-local address as
166  //the IPv6 source address (refer to RFC 3590, section 4)
167  return ERROR_NO_ADDRESS;
168  }
169  else
170  {
171  //MLD Report and Done messages are sent with a link-local address as
172  //the IPv6 source address, if a valid address is available on the
173  //interface. If a valid link-local address is not available, the
174  //message is sent with the unspecified address as the IPv6 source
175  //address
176  pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
177  }
178  }
179 
180  //Format IPv6 pseudo header
181  pseudoHeader.destAddr = *destAddr;
182  pseudoHeader.length = htons(length);
183  pseudoHeader.reserved[0] = 0;
184  pseudoHeader.reserved[1] = 0;
185  pseudoHeader.reserved[2] = 0;
186  pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
187 
188  //Message checksum calculation
189  message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
190  sizeof(Ipv6PseudoHeader), buffer, offset, length);
191 
192  //Total number of ICMP messages which this entity attempted to send
193  IP_MIB_INC_COUNTER32(icmpv6Stats.icmpStatsOutMsgs, 1);
194  //Increment per-message type ICMP counter
195  IP_MIB_INC_COUNTER32(icmpv6MsgStatsTable.icmpMsgStatsOutPkts[message->type], 1);
196 
197  //Debug message
198  TRACE_INFO("Sending MLD message (%" PRIuSIZE " bytes)...\r\n", length);
199  //Dump message contents for debugging purpose
201 
202  //Additional options can be passed to the stack along with the packet
203  ancillary = NET_DEFAULT_TX_ANCILLARY;
204 
205  //All MLD messages must be sent with an IPv6 Hop Limit of 1, and an IPv6
206  //Router Alert option in a Hop-by-Hop Options header (refer to RFC 2710,
207  //section 3)
208  ancillary.ttl = MLD_HOP_LIMIT;
209  ancillary.routerAlert = TRUE;
210 
211  //Send the MLD message
212  return ipv6SendDatagram(interface, &pseudoHeader, buffer, offset,
213  &ancillary);
214 }
215 
216 
217 /**
218  * @brief Process incoming MLD message
219  * @param[in] interface Underlying network interface
220  * @param[in] pseudoHeader IPv6 pseudo header
221  * @param[in] buffer Multi-part buffer containing the incoming MLD message
222  * @param[in] offset Offset to the first byte of the MLD message
223  * @param[in] ancillary Additional options passed to the stack along with
224  * the packet
225  **/
226 
228  const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer,
229  size_t offset, const NetRxAncillary *ancillary)
230 {
231  size_t length;
232  const MldMessage *message;
233 
234  //Retrieve the length of the MLD message
235  length = netBufferGetLength(buffer) - offset;
236 
237  //To be valid, an MLD message must be at least 24 octets long
238  if(length < sizeof(MldMessage))
239  return;
240 
241  //Point to the beginning of the MLD message
242  message = netBufferAt(buffer, offset, length);
243  //Sanity check
244  if(message == NULL)
245  return;
246 
247  //Debug message
248  TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length);
249  //Dump message contents for debugging purpose
251 
252  //All MLD messages are sent with an IPv6 Hop Limit of 1
253  if(ancillary->ttl != MLD_HOP_LIMIT)
254  return;
255 
256 #if (MLD_NODE_SUPPORT == ENABLED)
257  //Pass the message to the MLD node
258  mldNodeProcessMessage(&interface->mldNodeContext, pseudoHeader, message,
259  length);
260 #endif
261 }
262 
263 
264 /**
265  * @brief Generate a random delay
266  * @param[in] maxDelay maximum delay
267  * @return Random amount of time
268  **/
269 
271 {
272  systime_t delay;
273 
274  //Generate a random delay in the specified range
275  if(maxDelay > MLD_TICK_INTERVAL)
276  {
277  delay = netGenerateRandRange(0, maxDelay - MLD_TICK_INTERVAL);
278  }
279  else
280  {
281  delay = 0;
282  }
283 
284  //Return the random value
285  return delay;
286 }
287 
288 
289 /**
290  * @brief Decode a floating-point value (8-bit code)
291  * @param[in] code Floating-point representation
292  * @return Decoded value
293  **/
294 
296 {
297  uint8_t exp;
298  uint8_t mant;
299 
300  //Retrieve the value of the exponent
301  exp = (code >> 4) & 0x07;
302  //Retrieve the value of the mantissa
303  mant = code & 0x0F;
304 
305  //The code represents a floating-point value
306  return (mant | 0x10) << (exp + 3);
307 }
308 
309 
310 /**
311  * @brief Decode a floating-point value (16-bit code)
312  * @param[in] code Floating-point representation
313  * @return Decoded value
314  **/
315 
317 {
318  uint16_t exp;
319  uint16_t mant;
320 
321  //Retrieve the value of the exponent
322  exp = (code >> 12) & 0x07;
323  //Retrieve the value of the mantissa
324  mant = code & 0x0FFF;
325 
326  //The code represents a floating-point value
327  return (mant | 0x1000) << (exp + 3);
328 }
329 
330 #endif
#define htons(value)
Definition: cpu_endian.h:413
@ ERROR_NO_ADDRESS
Definition: error.h:200
uint8_t code
Definition: coap_common.h:179
Ipv4Addr destAddr
Definition: ipv4.h:330
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:72
const Ipv6Addr MLD_V2_ALL_ROUTERS_ADDR
Definition: mld_common.c:60
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:118
uint32_t mldDecodeFloatingPointValue8(uint8_t code)
Decode a floating-point value (8-bit code)
Definition: mld_common.c:295
#define IP_MIB_INC_COUNTER32(name, value)
Definition: ip_mib_module.h:46
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
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:137
Ipv6Addr
Definition: ipv6.h:260
systime_t mldTickCounter
Definition: mld_common.c:64
@ IPV6_ICMPV6_HEADER
Definition: ipv6.h:193
error_t mldNodeInit(NetInterface *interface)
MLD node initialization.
Definition: mld_node.c:64
void mldTick(NetInterface *interface)
MLD node timer handler.
Definition: mld_common.c:105
@ ICMPV6_TYPE_MCAST_LISTENER_QUERY
Definition: icmpv6.h:59
void mldNodeTick(MldNodeContext *context)
MLD node timer handler.
Definition: mld_node.c:103
void mldLinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: mld_common.c:119
systime_t mldGetRandomDelay(systime_t maxDelay)
Generate a random delay.
Definition: mld_common.c:270
IPv6 multicast filtering.
ICMPv6 (Internet Control Message Protocol Version 6)
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:963
Data logging functions for debugging purpose (MLD)
error_t
Error codes.
Definition: error.h:43
error_t ipv6JoinMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
Join an IPv6 multicast group.
#define Ipv6PseudoHeader
Definition: ipv6.h:42
Definitions common to MLD node, router and snooping switch.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const Ipv6Addr IPV6_LINK_LOCAL_ALL_NODES_ADDR
Definition: ipv6.c:74
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
#define NetTxAncillary
Definition: net_misc.h:36
const Ipv6Addr IPV6_UNSPECIFIED_ADDR
Definition: ipv6.c:66
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MLD_HOP_LIMIT
Definition: mld_common.h:80
uint32_t systime_t
System time.
void mldNodeLinkChangeEvent(MldNodeContext *context)
Callback function for link change event.
Definition: mld_node.c:462
MLD node (Multicast Listener Discovery for IPv6)
uint16_t ipCalcUpperLayerChecksumEx(const void *pseudoHeader, size_t pseudoHeaderLen, const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP upper-layer checksum over a multi-part buffer.
Definition: ip.c:685
void mldNodeProcessMessage(MldNodeContext *context, const Ipv6PseudoHeader *pseudoHeader, const MldMessage *message, size_t length)
Process incoming MLD message.
error_t ipv6SendDatagram(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv6 datagram.
Definition: ipv6.c:1713
void mldProcessMessage(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Process incoming MLD message.
Definition: mld_common.c:227
IP MIB module.
Ipv6AddrState ipv6GetLinkLocalAddrState(NetInterface *interface)
Get the state of the link-local address.
Definition: ipv6.c:327
uint32_t mldDecodeFloatingPointValue16(uint16_t code)
Decode a floating-point value (16-bit code)
Definition: mld_common.c:316
#define MLD_TICK_INTERVAL
Definition: mld_common.h:39
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
@ IPV6_ADDR_STATE_PREFERRED
An address assigned to an interface whose use is unrestricted.
Definition: ipv6.h:175
error_t mldInit(NetInterface *interface)
MLD initialization.
Definition: mld_common.c:73
Helper functions for MLD node.
#define PRIuSIZE
TCP/IP stack core.
void mldDumpMessage(const MldMessage *message, size_t length)
Dump MLD message for debugging purpose.
Definition: mld_debug.c:70
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.