Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file mld.c
Sergunb 0:8918a71cdbe9 3 * @brief MLD (Multicast Listener Discovery for IPv6)
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneTCP Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @section Description
Sergunb 0:8918a71cdbe9 26 *
Sergunb 0:8918a71cdbe9 27 * MLD is used by an IPv6 router to discover the presence of multicast
Sergunb 0:8918a71cdbe9 28 * listeners on its directly attached links, and to discover specifically
Sergunb 0:8918a71cdbe9 29 * which multicast addresses are of interest to those neighboring nodes.
Sergunb 0:8918a71cdbe9 30 * Refer to the following RFCs for complete details:
Sergunb 0:8918a71cdbe9 31 * - RFC 2710: Multicast Listener Discovery (MLD) for IPv6
Sergunb 0:8918a71cdbe9 32 * - RFC 3810: Multicast Listener Discovery Version 2 (MLDv2) for IPv6
Sergunb 0:8918a71cdbe9 33 *
Sergunb 0:8918a71cdbe9 34 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 35 * @version 1.7.6
Sergunb 0:8918a71cdbe9 36 **/
Sergunb 0:8918a71cdbe9 37
Sergunb 0:8918a71cdbe9 38 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 39 #define TRACE_LEVEL MLD_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 40
Sergunb 0:8918a71cdbe9 41 //Dependencies
Sergunb 0:8918a71cdbe9 42 #include "core/net.h"
Sergunb 0:8918a71cdbe9 43 #include "core/ip.h"
Sergunb 0:8918a71cdbe9 44 #include "ipv6/ipv6.h"
Sergunb 0:8918a71cdbe9 45 #include "ipv6/icmpv6.h"
Sergunb 0:8918a71cdbe9 46 #include "ipv6/mld.h"
Sergunb 0:8918a71cdbe9 47 #include "debug.h"
Sergunb 0:8918a71cdbe9 48
Sergunb 0:8918a71cdbe9 49 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 50 #if (IPV6_SUPPORT == ENABLED && MLD_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 51
Sergunb 0:8918a71cdbe9 52 //Tick counter to handle periodic operations
Sergunb 0:8918a71cdbe9 53 systime_t mldTickCounter;
Sergunb 0:8918a71cdbe9 54
Sergunb 0:8918a71cdbe9 55
Sergunb 0:8918a71cdbe9 56 /**
Sergunb 0:8918a71cdbe9 57 * @brief MLD initialization
Sergunb 0:8918a71cdbe9 58 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 59 * @return Error code
Sergunb 0:8918a71cdbe9 60 **/
Sergunb 0:8918a71cdbe9 61
Sergunb 0:8918a71cdbe9 62 error_t mldInit(NetInterface *interface)
Sergunb 0:8918a71cdbe9 63 {
Sergunb 0:8918a71cdbe9 64 //Successful initialization
Sergunb 0:8918a71cdbe9 65 return NO_ERROR;
Sergunb 0:8918a71cdbe9 66 }
Sergunb 0:8918a71cdbe9 67
Sergunb 0:8918a71cdbe9 68
Sergunb 0:8918a71cdbe9 69 /**
Sergunb 0:8918a71cdbe9 70 * @brief Start listening to the address on the interface
Sergunb 0:8918a71cdbe9 71 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 72 * @param[in] entry IPv6 filter entry identifying the address to listen to
Sergunb 0:8918a71cdbe9 73 * @return Error code
Sergunb 0:8918a71cdbe9 74 **/
Sergunb 0:8918a71cdbe9 75
Sergunb 0:8918a71cdbe9 76 error_t mldStartListening(NetInterface *interface, Ipv6FilterEntry *entry)
Sergunb 0:8918a71cdbe9 77 {
Sergunb 0:8918a71cdbe9 78 //The link-scope all-nodes address (FF02::1) is handled as a special
Sergunb 0:8918a71cdbe9 79 //case. The host starts in Idle Listener state for that address on
Sergunb 0:8918a71cdbe9 80 //every interface and never transitions to another state
Sergunb 0:8918a71cdbe9 81 if(ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
Sergunb 0:8918a71cdbe9 82 {
Sergunb 0:8918a71cdbe9 83 //Clear flag
Sergunb 0:8918a71cdbe9 84 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 85 //Enter the Idle Listener state
Sergunb 0:8918a71cdbe9 86 entry->state = MLD_STATE_IDLE_LISTENER;
Sergunb 0:8918a71cdbe9 87 }
Sergunb 0:8918a71cdbe9 88 else
Sergunb 0:8918a71cdbe9 89 {
Sergunb 0:8918a71cdbe9 90 //Link is up?
Sergunb 0:8918a71cdbe9 91 if(interface->linkState)
Sergunb 0:8918a71cdbe9 92 {
Sergunb 0:8918a71cdbe9 93 //Send a Multicast Listener Report message for the group on the interface
Sergunb 0:8918a71cdbe9 94 mldSendListenerReport(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 95
Sergunb 0:8918a71cdbe9 96 //Set flag
Sergunb 0:8918a71cdbe9 97 entry->flag = TRUE;
Sergunb 0:8918a71cdbe9 98 //Start timer
Sergunb 0:8918a71cdbe9 99 entry->timer = osGetSystemTime() + MLD_UNSOLICITED_REPORT_INTERVAL;
Sergunb 0:8918a71cdbe9 100 //Enter the Delaying Listener state
Sergunb 0:8918a71cdbe9 101 entry->state = MLD_STATE_DELAYING_LISTENER;
Sergunb 0:8918a71cdbe9 102 }
Sergunb 0:8918a71cdbe9 103 //Link is down?
Sergunb 0:8918a71cdbe9 104 else
Sergunb 0:8918a71cdbe9 105 {
Sergunb 0:8918a71cdbe9 106 //Clear flag
Sergunb 0:8918a71cdbe9 107 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 108 //Enter the Idle Listener state
Sergunb 0:8918a71cdbe9 109 entry->state = MLD_STATE_IDLE_LISTENER;
Sergunb 0:8918a71cdbe9 110 }
Sergunb 0:8918a71cdbe9 111 }
Sergunb 0:8918a71cdbe9 112
Sergunb 0:8918a71cdbe9 113 //Successful processing
Sergunb 0:8918a71cdbe9 114 return NO_ERROR;
Sergunb 0:8918a71cdbe9 115 }
Sergunb 0:8918a71cdbe9 116
Sergunb 0:8918a71cdbe9 117
Sergunb 0:8918a71cdbe9 118 /**
Sergunb 0:8918a71cdbe9 119 * @brief Stop listening to the address on the interface
Sergunb 0:8918a71cdbe9 120 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 121 * @param[in] entry IPv6 filter entry identifying the multicast address to leave
Sergunb 0:8918a71cdbe9 122 * @return Error code
Sergunb 0:8918a71cdbe9 123 **/
Sergunb 0:8918a71cdbe9 124
Sergunb 0:8918a71cdbe9 125 error_t mldStopListening(NetInterface *interface, Ipv6FilterEntry *entry)
Sergunb 0:8918a71cdbe9 126 {
Sergunb 0:8918a71cdbe9 127 //Check link state
Sergunb 0:8918a71cdbe9 128 if(interface->linkState)
Sergunb 0:8918a71cdbe9 129 {
Sergunb 0:8918a71cdbe9 130 //Send a Multicast Listener Done message if the flag is set
Sergunb 0:8918a71cdbe9 131 if(entry->flag)
Sergunb 0:8918a71cdbe9 132 mldSendListenerDone(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 133 }
Sergunb 0:8918a71cdbe9 134
Sergunb 0:8918a71cdbe9 135 //Switch to the Non-Listener state
Sergunb 0:8918a71cdbe9 136 entry->state = MLD_STATE_NON_LISTENER;
Sergunb 0:8918a71cdbe9 137
Sergunb 0:8918a71cdbe9 138 //Successful processing
Sergunb 0:8918a71cdbe9 139 return NO_ERROR;
Sergunb 0:8918a71cdbe9 140 }
Sergunb 0:8918a71cdbe9 141
Sergunb 0:8918a71cdbe9 142
Sergunb 0:8918a71cdbe9 143 /**
Sergunb 0:8918a71cdbe9 144 * @brief MLD timer handler
Sergunb 0:8918a71cdbe9 145 *
Sergunb 0:8918a71cdbe9 146 * This routine must be periodically called by the TCP/IP stack to
Sergunb 0:8918a71cdbe9 147 * handle MLD related timers
Sergunb 0:8918a71cdbe9 148 *
Sergunb 0:8918a71cdbe9 149 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 150 **/
Sergunb 0:8918a71cdbe9 151
Sergunb 0:8918a71cdbe9 152 void mldTick(NetInterface *interface)
Sergunb 0:8918a71cdbe9 153 {
Sergunb 0:8918a71cdbe9 154 uint_t i;
Sergunb 0:8918a71cdbe9 155 systime_t time;
Sergunb 0:8918a71cdbe9 156 Ipv6FilterEntry *entry;
Sergunb 0:8918a71cdbe9 157
Sergunb 0:8918a71cdbe9 158 //Get current time
Sergunb 0:8918a71cdbe9 159 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 160
Sergunb 0:8918a71cdbe9 161 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 162 for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 163 {
Sergunb 0:8918a71cdbe9 164 //Point to the current entry
Sergunb 0:8918a71cdbe9 165 entry = &interface->ipv6Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 166
Sergunb 0:8918a71cdbe9 167 //Valid entry?
Sergunb 0:8918a71cdbe9 168 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 169 {
Sergunb 0:8918a71cdbe9 170 //Delaying Listener state?
Sergunb 0:8918a71cdbe9 171 if(entry->state == MLD_STATE_DELAYING_LISTENER)
Sergunb 0:8918a71cdbe9 172 {
Sergunb 0:8918a71cdbe9 173 //Timer expired?
Sergunb 0:8918a71cdbe9 174 if(timeCompare(time, entry->timer) >= 0)
Sergunb 0:8918a71cdbe9 175 {
Sergunb 0:8918a71cdbe9 176 //Send a Multicast Listener Report message
Sergunb 0:8918a71cdbe9 177 mldSendListenerReport(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 178
Sergunb 0:8918a71cdbe9 179 //Set flag
Sergunb 0:8918a71cdbe9 180 entry->flag = TRUE;
Sergunb 0:8918a71cdbe9 181 //Switch to the Idle Listener state
Sergunb 0:8918a71cdbe9 182 entry->state = MLD_STATE_IDLE_LISTENER;
Sergunb 0:8918a71cdbe9 183 }
Sergunb 0:8918a71cdbe9 184 }
Sergunb 0:8918a71cdbe9 185 }
Sergunb 0:8918a71cdbe9 186 }
Sergunb 0:8918a71cdbe9 187 }
Sergunb 0:8918a71cdbe9 188
Sergunb 0:8918a71cdbe9 189
Sergunb 0:8918a71cdbe9 190 /**
Sergunb 0:8918a71cdbe9 191 * @brief Callback function for link change event
Sergunb 0:8918a71cdbe9 192 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 193 **/
Sergunb 0:8918a71cdbe9 194
Sergunb 0:8918a71cdbe9 195 void mldLinkChangeEvent(NetInterface *interface)
Sergunb 0:8918a71cdbe9 196 {
Sergunb 0:8918a71cdbe9 197 uint_t i;
Sergunb 0:8918a71cdbe9 198 systime_t time;
Sergunb 0:8918a71cdbe9 199 Ipv6FilterEntry *entry;
Sergunb 0:8918a71cdbe9 200
Sergunb 0:8918a71cdbe9 201 //Get current time
Sergunb 0:8918a71cdbe9 202 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 203
Sergunb 0:8918a71cdbe9 204 //Link up event?
Sergunb 0:8918a71cdbe9 205 if(interface->linkState)
Sergunb 0:8918a71cdbe9 206 {
Sergunb 0:8918a71cdbe9 207 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 208 for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 209 {
Sergunb 0:8918a71cdbe9 210 //Point to the current entry
Sergunb 0:8918a71cdbe9 211 entry = &interface->ipv6Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 212
Sergunb 0:8918a71cdbe9 213 //Valid entry?
Sergunb 0:8918a71cdbe9 214 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 215 {
Sergunb 0:8918a71cdbe9 216 //The link-scope all-nodes address (FF02::1) is handled as a special
Sergunb 0:8918a71cdbe9 217 //case. The host starts in Idle Listener state for that address on
Sergunb 0:8918a71cdbe9 218 //every interface and never transitions to another state
Sergunb 0:8918a71cdbe9 219 if(!ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
Sergunb 0:8918a71cdbe9 220 {
Sergunb 0:8918a71cdbe9 221 //Send an unsolicited Multicast Listener Report message for that group
Sergunb 0:8918a71cdbe9 222 mldSendListenerReport(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 223
Sergunb 0:8918a71cdbe9 224 //Set flag
Sergunb 0:8918a71cdbe9 225 entry->flag = TRUE;
Sergunb 0:8918a71cdbe9 226 //Start timer
Sergunb 0:8918a71cdbe9 227 entry->timer = time + MLD_UNSOLICITED_REPORT_INTERVAL;
Sergunb 0:8918a71cdbe9 228 //Enter the Delaying Listener state
Sergunb 0:8918a71cdbe9 229 entry->state = MLD_STATE_DELAYING_LISTENER;
Sergunb 0:8918a71cdbe9 230 }
Sergunb 0:8918a71cdbe9 231 }
Sergunb 0:8918a71cdbe9 232 }
Sergunb 0:8918a71cdbe9 233 }
Sergunb 0:8918a71cdbe9 234 //Link down event?
Sergunb 0:8918a71cdbe9 235 else
Sergunb 0:8918a71cdbe9 236 {
Sergunb 0:8918a71cdbe9 237 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 238 for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 239 {
Sergunb 0:8918a71cdbe9 240 //Point to the current entry
Sergunb 0:8918a71cdbe9 241 entry = &interface->ipv6Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 242
Sergunb 0:8918a71cdbe9 243 //Valid entry?
Sergunb 0:8918a71cdbe9 244 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 245 {
Sergunb 0:8918a71cdbe9 246 //Clear flag
Sergunb 0:8918a71cdbe9 247 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 248 //Enter the Idle Listener state
Sergunb 0:8918a71cdbe9 249 entry->state = MLD_STATE_IDLE_LISTENER;
Sergunb 0:8918a71cdbe9 250 }
Sergunb 0:8918a71cdbe9 251 }
Sergunb 0:8918a71cdbe9 252 }
Sergunb 0:8918a71cdbe9 253 }
Sergunb 0:8918a71cdbe9 254
Sergunb 0:8918a71cdbe9 255
Sergunb 0:8918a71cdbe9 256 /**
Sergunb 0:8918a71cdbe9 257 * @brief Process incoming Multicast Listener Query message
Sergunb 0:8918a71cdbe9 258 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 259 * @param[in] pseudoHeader IPv6 pseudo header
Sergunb 0:8918a71cdbe9 260 * @param[in] buffer Multi-part buffer containing the incoming MLD message
Sergunb 0:8918a71cdbe9 261 * @param[in] offset Offset to the first byte of the MLD message
Sergunb 0:8918a71cdbe9 262 * @param[in] hopLimit Hop Limit field from IPv6 header
Sergunb 0:8918a71cdbe9 263 **/
Sergunb 0:8918a71cdbe9 264
Sergunb 0:8918a71cdbe9 265 void mldProcessListenerQuery(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
Sergunb 0:8918a71cdbe9 266 const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Sergunb 0:8918a71cdbe9 267 {
Sergunb 0:8918a71cdbe9 268 uint_t i;
Sergunb 0:8918a71cdbe9 269 size_t length;
Sergunb 0:8918a71cdbe9 270 systime_t time;
Sergunb 0:8918a71cdbe9 271 systime_t maxRespDelay;
Sergunb 0:8918a71cdbe9 272 MldMessage *message;
Sergunb 0:8918a71cdbe9 273 Ipv6FilterEntry *entry;
Sergunb 0:8918a71cdbe9 274
Sergunb 0:8918a71cdbe9 275 //Retrieve the length of the MLD message
Sergunb 0:8918a71cdbe9 276 length = netBufferGetLength(buffer) - offset;
Sergunb 0:8918a71cdbe9 277
Sergunb 0:8918a71cdbe9 278 //The message must be at least 24 octets long
Sergunb 0:8918a71cdbe9 279 if(length < sizeof(MldMessage))
Sergunb 0:8918a71cdbe9 280 return;
Sergunb 0:8918a71cdbe9 281
Sergunb 0:8918a71cdbe9 282 //Point to the beginning of the MLD message
Sergunb 0:8918a71cdbe9 283 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 284 //Sanity check
Sergunb 0:8918a71cdbe9 285 if(message == NULL)
Sergunb 0:8918a71cdbe9 286 return;
Sergunb 0:8918a71cdbe9 287
Sergunb 0:8918a71cdbe9 288 //Debug message
Sergunb 0:8918a71cdbe9 289 TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length);
Sergunb 0:8918a71cdbe9 290 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 291 mldDumpMessage(message);
Sergunb 0:8918a71cdbe9 292
Sergunb 0:8918a71cdbe9 293 //Make sure the source address of the message is a valid link-local address
Sergunb 0:8918a71cdbe9 294 if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
Sergunb 0:8918a71cdbe9 295 return;
Sergunb 0:8918a71cdbe9 296
Sergunb 0:8918a71cdbe9 297 //Check the Hop Limit field
Sergunb 0:8918a71cdbe9 298 if(hopLimit != MLD_HOP_LIMIT)
Sergunb 0:8918a71cdbe9 299 return;
Sergunb 0:8918a71cdbe9 300
Sergunb 0:8918a71cdbe9 301 //Get current time
Sergunb 0:8918a71cdbe9 302 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 303
Sergunb 0:8918a71cdbe9 304 //The Max Resp Delay field specifies the maximum time allowed
Sergunb 0:8918a71cdbe9 305 //before sending a responding report
Sergunb 0:8918a71cdbe9 306 maxRespDelay = message->maxRespDelay * 10;
Sergunb 0:8918a71cdbe9 307
Sergunb 0:8918a71cdbe9 308 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 309 for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 310 {
Sergunb 0:8918a71cdbe9 311 //Point to the current entry
Sergunb 0:8918a71cdbe9 312 entry = &interface->ipv6Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 313
Sergunb 0:8918a71cdbe9 314 //Valid entry?
Sergunb 0:8918a71cdbe9 315 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 316 {
Sergunb 0:8918a71cdbe9 317 //The link-scope all-nodes address (FF02::1) is handled as a special
Sergunb 0:8918a71cdbe9 318 //case. The host starts in Idle Listener state for that address on
Sergunb 0:8918a71cdbe9 319 //every interface and never transitions to another state
Sergunb 0:8918a71cdbe9 320 if(!ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
Sergunb 0:8918a71cdbe9 321 {
Sergunb 0:8918a71cdbe9 322 //A General Query is used to learn which multicast addresses have listeners
Sergunb 0:8918a71cdbe9 323 //on an attached link. A Multicast-Address-Specific Query is used to learn
Sergunb 0:8918a71cdbe9 324 //if a particular multicast address has any listeners on an attached link
Sergunb 0:8918a71cdbe9 325 if(ipv6CompAddr(&message->multicastAddr, &IPV6_UNSPECIFIED_ADDR) ||
Sergunb 0:8918a71cdbe9 326 ipv6CompAddr(&message->multicastAddr, &entry->addr))
Sergunb 0:8918a71cdbe9 327 {
Sergunb 0:8918a71cdbe9 328 //Delaying Listener state?
Sergunb 0:8918a71cdbe9 329 if(entry->state == MLD_STATE_DELAYING_LISTENER)
Sergunb 0:8918a71cdbe9 330 {
Sergunb 0:8918a71cdbe9 331 //The timer has not yet expired?
Sergunb 0:8918a71cdbe9 332 if(timeCompare(time, entry->timer) < 0)
Sergunb 0:8918a71cdbe9 333 {
Sergunb 0:8918a71cdbe9 334 //If a timer for the address is already running, it is reset to
Sergunb 0:8918a71cdbe9 335 //the new random value only if the requested Max Response Delay
Sergunb 0:8918a71cdbe9 336 //is less than the remaining value of the running timer
Sergunb 0:8918a71cdbe9 337 if(maxRespDelay < (entry->timer - time))
Sergunb 0:8918a71cdbe9 338 {
Sergunb 0:8918a71cdbe9 339 //Restart delay timer
Sergunb 0:8918a71cdbe9 340 entry->timer = time + mldRand(maxRespDelay);
Sergunb 0:8918a71cdbe9 341 }
Sergunb 0:8918a71cdbe9 342 }
Sergunb 0:8918a71cdbe9 343 }
Sergunb 0:8918a71cdbe9 344 //Idle Listener state?
Sergunb 0:8918a71cdbe9 345 else if(entry->state == MLD_STATE_IDLE_LISTENER)
Sergunb 0:8918a71cdbe9 346 {
Sergunb 0:8918a71cdbe9 347 //Switch to the Delaying Listener state
Sergunb 0:8918a71cdbe9 348 entry->state = MLD_STATE_DELAYING_LISTENER;
Sergunb 0:8918a71cdbe9 349 //Delay the response by a random amount of time
Sergunb 0:8918a71cdbe9 350 entry->timer = time + mldRand(maxRespDelay);
Sergunb 0:8918a71cdbe9 351 }
Sergunb 0:8918a71cdbe9 352 }
Sergunb 0:8918a71cdbe9 353 }
Sergunb 0:8918a71cdbe9 354 }
Sergunb 0:8918a71cdbe9 355 }
Sergunb 0:8918a71cdbe9 356 }
Sergunb 0:8918a71cdbe9 357
Sergunb 0:8918a71cdbe9 358
Sergunb 0:8918a71cdbe9 359 /**
Sergunb 0:8918a71cdbe9 360 * @brief Process incoming Multicast Listener Report message
Sergunb 0:8918a71cdbe9 361 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 362 * @param[in] pseudoHeader IPv6 pseudo header
Sergunb 0:8918a71cdbe9 363 * @param[in] buffer Multi-part buffer containing the incoming MLD message
Sergunb 0:8918a71cdbe9 364 * @param[in] offset Offset to the first byte of the MLD message
Sergunb 0:8918a71cdbe9 365 * @param[in] hopLimit Hop Limit field from IPv6 header
Sergunb 0:8918a71cdbe9 366 **/
Sergunb 0:8918a71cdbe9 367
Sergunb 0:8918a71cdbe9 368 void mldProcessListenerReport(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
Sergunb 0:8918a71cdbe9 369 const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Sergunb 0:8918a71cdbe9 370 {
Sergunb 0:8918a71cdbe9 371 uint_t i;
Sergunb 0:8918a71cdbe9 372 size_t length;
Sergunb 0:8918a71cdbe9 373 MldMessage *message;
Sergunb 0:8918a71cdbe9 374 Ipv6FilterEntry *entry;
Sergunb 0:8918a71cdbe9 375
Sergunb 0:8918a71cdbe9 376 //Retrieve the length of the MLD message
Sergunb 0:8918a71cdbe9 377 length = netBufferGetLength(buffer) - offset;
Sergunb 0:8918a71cdbe9 378
Sergunb 0:8918a71cdbe9 379 //The message must be at least 24 octets long
Sergunb 0:8918a71cdbe9 380 if(length < sizeof(MldMessage))
Sergunb 0:8918a71cdbe9 381 return;
Sergunb 0:8918a71cdbe9 382
Sergunb 0:8918a71cdbe9 383 //Point to the beginning of the MLD message
Sergunb 0:8918a71cdbe9 384 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 385 //Sanity check
Sergunb 0:8918a71cdbe9 386 if(message == NULL)
Sergunb 0:8918a71cdbe9 387 return;
Sergunb 0:8918a71cdbe9 388
Sergunb 0:8918a71cdbe9 389 //Debug message
Sergunb 0:8918a71cdbe9 390 TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length);
Sergunb 0:8918a71cdbe9 391 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 392 mldDumpMessage(message);
Sergunb 0:8918a71cdbe9 393
Sergunb 0:8918a71cdbe9 394 //Make sure the source address of the message is a valid link-local address
Sergunb 0:8918a71cdbe9 395 if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
Sergunb 0:8918a71cdbe9 396 return;
Sergunb 0:8918a71cdbe9 397 //Check the Hop Limit field
Sergunb 0:8918a71cdbe9 398 if(hopLimit != MLD_HOP_LIMIT)
Sergunb 0:8918a71cdbe9 399 return;
Sergunb 0:8918a71cdbe9 400
Sergunb 0:8918a71cdbe9 401 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 402 for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 403 {
Sergunb 0:8918a71cdbe9 404 //Point to the current entry
Sergunb 0:8918a71cdbe9 405 entry = &interface->ipv6Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 406
Sergunb 0:8918a71cdbe9 407 //Valid entry?
Sergunb 0:8918a71cdbe9 408 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 409 {
Sergunb 0:8918a71cdbe9 410 //Report messages are ignored for multicast addresses
Sergunb 0:8918a71cdbe9 411 //in the Non-Listener or Idle Listener state
Sergunb 0:8918a71cdbe9 412 if(entry->state == MLD_STATE_DELAYING_LISTENER)
Sergunb 0:8918a71cdbe9 413 {
Sergunb 0:8918a71cdbe9 414 //The Multicast Listener Report message matches the current entry?
Sergunb 0:8918a71cdbe9 415 if(ipv6CompAddr(&message->multicastAddr, &entry->addr))
Sergunb 0:8918a71cdbe9 416 {
Sergunb 0:8918a71cdbe9 417 //Clear flag
Sergunb 0:8918a71cdbe9 418 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 419 //Switch to the Idle Listener state
Sergunb 0:8918a71cdbe9 420 entry->state = MLD_STATE_IDLE_LISTENER;
Sergunb 0:8918a71cdbe9 421 }
Sergunb 0:8918a71cdbe9 422 }
Sergunb 0:8918a71cdbe9 423 }
Sergunb 0:8918a71cdbe9 424 }
Sergunb 0:8918a71cdbe9 425 }
Sergunb 0:8918a71cdbe9 426
Sergunb 0:8918a71cdbe9 427
Sergunb 0:8918a71cdbe9 428 /**
Sergunb 0:8918a71cdbe9 429 * @brief Send Multicast Listener Report message
Sergunb 0:8918a71cdbe9 430 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 431 * @param[in] ipAddr IPv6 address specifying the multicast address
Sergunb 0:8918a71cdbe9 432 * @return Error code
Sergunb 0:8918a71cdbe9 433 **/
Sergunb 0:8918a71cdbe9 434
Sergunb 0:8918a71cdbe9 435 error_t mldSendListenerReport(NetInterface *interface, Ipv6Addr *ipAddr)
Sergunb 0:8918a71cdbe9 436 {
Sergunb 0:8918a71cdbe9 437 error_t error;
Sergunb 0:8918a71cdbe9 438 size_t offset;
Sergunb 0:8918a71cdbe9 439 MldMessage *message;
Sergunb 0:8918a71cdbe9 440 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 441 Ipv6PseudoHeader pseudoHeader;
Sergunb 0:8918a71cdbe9 442
Sergunb 0:8918a71cdbe9 443 //Make sure the specified address is a valid multicast address
Sergunb 0:8918a71cdbe9 444 if(!ipv6IsMulticastAddr(ipAddr))
Sergunb 0:8918a71cdbe9 445 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 446
Sergunb 0:8918a71cdbe9 447 //The link-scope all-nodes address (FF02::1) is handled as a special
Sergunb 0:8918a71cdbe9 448 //case. The host never sends a report for that address
Sergunb 0:8918a71cdbe9 449 if(ipv6CompAddr(ipAddr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
Sergunb 0:8918a71cdbe9 450 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 451
Sergunb 0:8918a71cdbe9 452 //Allocate a memory buffer to hold a MLD message
Sergunb 0:8918a71cdbe9 453 buffer = ipAllocBuffer(sizeof(MldMessage), &offset);
Sergunb 0:8918a71cdbe9 454 //Failed to allocate memory?
Sergunb 0:8918a71cdbe9 455 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 456 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 457
Sergunb 0:8918a71cdbe9 458 //Point to the beginning of the MLD message
Sergunb 0:8918a71cdbe9 459 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 460
Sergunb 0:8918a71cdbe9 461 //Format the Multicast Listener Report message
Sergunb 0:8918a71cdbe9 462 message->type = ICMPV6_TYPE_MULTICAST_LISTENER_REPORT_V1;
Sergunb 0:8918a71cdbe9 463 message->code = 0;
Sergunb 0:8918a71cdbe9 464 message->checksum = 0;
Sergunb 0:8918a71cdbe9 465 message->maxRespDelay = 0;
Sergunb 0:8918a71cdbe9 466 message->reserved = 0;
Sergunb 0:8918a71cdbe9 467 message->multicastAddr = *ipAddr;
Sergunb 0:8918a71cdbe9 468
Sergunb 0:8918a71cdbe9 469 //Format IPv6 pseudo header
Sergunb 0:8918a71cdbe9 470 pseudoHeader.srcAddr = interface->ipv6Context.addrList[0].addr;
Sergunb 0:8918a71cdbe9 471 pseudoHeader.destAddr = *ipAddr;
Sergunb 0:8918a71cdbe9 472 pseudoHeader.length = HTONS(sizeof(MldMessage));
Sergunb 0:8918a71cdbe9 473 pseudoHeader.reserved = 0;
Sergunb 0:8918a71cdbe9 474 pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
Sergunb 0:8918a71cdbe9 475
Sergunb 0:8918a71cdbe9 476 //Message checksum calculation
Sergunb 0:8918a71cdbe9 477 message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
Sergunb 0:8918a71cdbe9 478 sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(MldMessage));
Sergunb 0:8918a71cdbe9 479
Sergunb 0:8918a71cdbe9 480 //Debug message
Sergunb 0:8918a71cdbe9 481 TRACE_INFO("Sending MLD message (%" PRIuSIZE " bytes)...\r\n", sizeof(MldMessage));
Sergunb 0:8918a71cdbe9 482 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 483 mldDumpMessage(message);
Sergunb 0:8918a71cdbe9 484
Sergunb 0:8918a71cdbe9 485 //The Multicast Listener Report message is sent to the multicast address being reported
Sergunb 0:8918a71cdbe9 486 error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, MLD_HOP_LIMIT);
Sergunb 0:8918a71cdbe9 487
Sergunb 0:8918a71cdbe9 488 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 489 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 490 //Return status code
Sergunb 0:8918a71cdbe9 491 return error;
Sergunb 0:8918a71cdbe9 492 }
Sergunb 0:8918a71cdbe9 493
Sergunb 0:8918a71cdbe9 494
Sergunb 0:8918a71cdbe9 495 /**
Sergunb 0:8918a71cdbe9 496 * @brief Send Multicast Listener Done message
Sergunb 0:8918a71cdbe9 497 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 498 * @param[in] ipAddr IPv6 address specifying the multicast address being left
Sergunb 0:8918a71cdbe9 499 * @return Error code
Sergunb 0:8918a71cdbe9 500 **/
Sergunb 0:8918a71cdbe9 501
Sergunb 0:8918a71cdbe9 502 error_t mldSendListenerDone(NetInterface *interface, Ipv6Addr *ipAddr)
Sergunb 0:8918a71cdbe9 503 {
Sergunb 0:8918a71cdbe9 504 error_t error;
Sergunb 0:8918a71cdbe9 505 size_t offset;
Sergunb 0:8918a71cdbe9 506 MldMessage *message;
Sergunb 0:8918a71cdbe9 507 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 508 Ipv6PseudoHeader pseudoHeader;
Sergunb 0:8918a71cdbe9 509
Sergunb 0:8918a71cdbe9 510 //Make sure the specified address is a valid multicast address
Sergunb 0:8918a71cdbe9 511 if(!ipv6IsMulticastAddr(ipAddr))
Sergunb 0:8918a71cdbe9 512 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 513
Sergunb 0:8918a71cdbe9 514 //The link-scope all-nodes address (FF02::1) is handled as a special
Sergunb 0:8918a71cdbe9 515 //case. The host never sends a report for that address
Sergunb 0:8918a71cdbe9 516 if(ipv6CompAddr(ipAddr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
Sergunb 0:8918a71cdbe9 517 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 518
Sergunb 0:8918a71cdbe9 519 //Allocate a memory buffer to hold a MLD message
Sergunb 0:8918a71cdbe9 520 buffer = ipAllocBuffer(sizeof(MldMessage), &offset);
Sergunb 0:8918a71cdbe9 521 //Failed to allocate memory?
Sergunb 0:8918a71cdbe9 522 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 523 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 524
Sergunb 0:8918a71cdbe9 525 //Point to the beginning of the MLD message
Sergunb 0:8918a71cdbe9 526 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 527
Sergunb 0:8918a71cdbe9 528 //Format the Multicast Listener Done message
Sergunb 0:8918a71cdbe9 529 message->type = ICMPV6_TYPE_MULTICAST_LISTENER_DONE_V1;
Sergunb 0:8918a71cdbe9 530 message->code = 0;
Sergunb 0:8918a71cdbe9 531 message->checksum = 0;
Sergunb 0:8918a71cdbe9 532 message->maxRespDelay = 0;
Sergunb 0:8918a71cdbe9 533 message->reserved = 0;
Sergunb 0:8918a71cdbe9 534 message->multicastAddr = *ipAddr;
Sergunb 0:8918a71cdbe9 535
Sergunb 0:8918a71cdbe9 536 //Format IPv6 pseudo header
Sergunb 0:8918a71cdbe9 537 pseudoHeader.srcAddr = interface->ipv6Context.addrList[0].addr;
Sergunb 0:8918a71cdbe9 538 pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR;
Sergunb 0:8918a71cdbe9 539 pseudoHeader.length = HTONS(sizeof(MldMessage));
Sergunb 0:8918a71cdbe9 540 pseudoHeader.reserved = 0;
Sergunb 0:8918a71cdbe9 541 pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
Sergunb 0:8918a71cdbe9 542
Sergunb 0:8918a71cdbe9 543 //Message checksum calculation
Sergunb 0:8918a71cdbe9 544 message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
Sergunb 0:8918a71cdbe9 545 sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(MldMessage));
Sergunb 0:8918a71cdbe9 546
Sergunb 0:8918a71cdbe9 547 //Debug message
Sergunb 0:8918a71cdbe9 548 TRACE_INFO("Sending MLD message (%" PRIuSIZE " bytes)...\r\n", sizeof(MldMessage));
Sergunb 0:8918a71cdbe9 549 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 550 mldDumpMessage(message);
Sergunb 0:8918a71cdbe9 551
Sergunb 0:8918a71cdbe9 552 //The Multicast Listener Done message is sent to the all-routers multicast address
Sergunb 0:8918a71cdbe9 553 error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, MLD_HOP_LIMIT);
Sergunb 0:8918a71cdbe9 554
Sergunb 0:8918a71cdbe9 555 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 556 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 557 //Return status code
Sergunb 0:8918a71cdbe9 558 return error;
Sergunb 0:8918a71cdbe9 559 }
Sergunb 0:8918a71cdbe9 560
Sergunb 0:8918a71cdbe9 561
Sergunb 0:8918a71cdbe9 562 /**
Sergunb 0:8918a71cdbe9 563 * @brief Get a random value in the specified range
Sergunb 0:8918a71cdbe9 564 * @param[in] max Upper bound
Sergunb 0:8918a71cdbe9 565 * @return Random value in the specified range
Sergunb 0:8918a71cdbe9 566 **/
Sergunb 0:8918a71cdbe9 567
Sergunb 0:8918a71cdbe9 568 uint32_t mldRand(uint32_t max)
Sergunb 0:8918a71cdbe9 569 {
Sergunb 0:8918a71cdbe9 570 //Return a random value in the given range
Sergunb 0:8918a71cdbe9 571 return netGetRand() % (max + 1);
Sergunb 0:8918a71cdbe9 572 }
Sergunb 0:8918a71cdbe9 573
Sergunb 0:8918a71cdbe9 574
Sergunb 0:8918a71cdbe9 575 /**
Sergunb 0:8918a71cdbe9 576 * @brief Dump MLD message for debugging purpose
Sergunb 0:8918a71cdbe9 577 * @param[in] message Pointer to the MLD message
Sergunb 0:8918a71cdbe9 578 **/
Sergunb 0:8918a71cdbe9 579
Sergunb 0:8918a71cdbe9 580 void mldDumpMessage(const MldMessage *message)
Sergunb 0:8918a71cdbe9 581 {
Sergunb 0:8918a71cdbe9 582 //Dump MLD message
Sergunb 0:8918a71cdbe9 583 TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type);
Sergunb 0:8918a71cdbe9 584 TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code);
Sergunb 0:8918a71cdbe9 585 TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
Sergunb 0:8918a71cdbe9 586 TRACE_DEBUG(" Max Resp Delay = %" PRIu16 "\r\n", message->maxRespDelay);
Sergunb 0:8918a71cdbe9 587 TRACE_DEBUG(" Multicast Address = %s\r\n", ipv6AddrToString(&message->multicastAddr, NULL));
Sergunb 0:8918a71cdbe9 588 }
Sergunb 0:8918a71cdbe9 589
Sergunb 0:8918a71cdbe9 590 #endif
Sergunb 0:8918a71cdbe9 591