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 igmp.c
Sergunb 0:8918a71cdbe9 3 * @brief IGMP (Internet Group Management Protocol)
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 * IGMP is used by IP hosts to report their multicast group memberships
Sergunb 0:8918a71cdbe9 28 * to routers. Refer to the following RFCs for complete details:
Sergunb 0:8918a71cdbe9 29 * - RFC 1112: Host Extensions for IP Multicasting
Sergunb 0:8918a71cdbe9 30 * - RFC 2236: Internet Group Management Protocol, Version 2
Sergunb 0:8918a71cdbe9 31 * - RFC 3376: Internet Group Management Protocol, Version 3
Sergunb 0:8918a71cdbe9 32 *
Sergunb 0:8918a71cdbe9 33 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 34 * @version 1.7.6
Sergunb 0:8918a71cdbe9 35 **/
Sergunb 0:8918a71cdbe9 36
Sergunb 0:8918a71cdbe9 37 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 38 #define TRACE_LEVEL IGMP_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 39
Sergunb 0:8918a71cdbe9 40 //Dependencies
Sergunb 0:8918a71cdbe9 41 #include "core/net.h"
Sergunb 0:8918a71cdbe9 42 #include "core/ip.h"
Sergunb 0:8918a71cdbe9 43 #include "ipv4/ipv4.h"
Sergunb 0:8918a71cdbe9 44 #include "ipv4/igmp.h"
Sergunb 0:8918a71cdbe9 45 #include "debug.h"
Sergunb 0:8918a71cdbe9 46
Sergunb 0:8918a71cdbe9 47 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 48 #if (IPV4_SUPPORT == ENABLED && IGMP_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 49
Sergunb 0:8918a71cdbe9 50 //Tick counter to handle periodic operations
Sergunb 0:8918a71cdbe9 51 systime_t igmpTickCounter;
Sergunb 0:8918a71cdbe9 52
Sergunb 0:8918a71cdbe9 53
Sergunb 0:8918a71cdbe9 54 /**
Sergunb 0:8918a71cdbe9 55 * @brief IGMP initialization
Sergunb 0:8918a71cdbe9 56 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 57 * @return Error code
Sergunb 0:8918a71cdbe9 58 **/
Sergunb 0:8918a71cdbe9 59
Sergunb 0:8918a71cdbe9 60 error_t igmpInit(NetInterface *interface)
Sergunb 0:8918a71cdbe9 61 {
Sergunb 0:8918a71cdbe9 62 //The default host compatibility mode is IGMPv2
Sergunb 0:8918a71cdbe9 63 interface->igmpv1RouterPresent = FALSE;
Sergunb 0:8918a71cdbe9 64
Sergunb 0:8918a71cdbe9 65 //Start IGMPv1 router present timer
Sergunb 0:8918a71cdbe9 66 interface->igmpv1RouterPresentTimer =
Sergunb 0:8918a71cdbe9 67 osGetSystemTime() + IGMP_V1_ROUTER_PRESENT_TIMEOUT;
Sergunb 0:8918a71cdbe9 68
Sergunb 0:8918a71cdbe9 69 //Successful initialization
Sergunb 0:8918a71cdbe9 70 return NO_ERROR;
Sergunb 0:8918a71cdbe9 71 }
Sergunb 0:8918a71cdbe9 72
Sergunb 0:8918a71cdbe9 73
Sergunb 0:8918a71cdbe9 74 /**
Sergunb 0:8918a71cdbe9 75 * @brief Join the specified host group
Sergunb 0:8918a71cdbe9 76 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 77 * @param[in] entry IPv4 filter entry identifying the host group to join
Sergunb 0:8918a71cdbe9 78 * @return Error code
Sergunb 0:8918a71cdbe9 79 **/
Sergunb 0:8918a71cdbe9 80
Sergunb 0:8918a71cdbe9 81 error_t igmpJoinGroup(NetInterface *interface, Ipv4FilterEntry *entry)
Sergunb 0:8918a71cdbe9 82 {
Sergunb 0:8918a71cdbe9 83 //The all-systems group (address 224.0.0.1) is handled as a special
Sergunb 0:8918a71cdbe9 84 //case. The host starts in Idle Member state for that group on every
Sergunb 0:8918a71cdbe9 85 //interface and never transitions to another state
Sergunb 0:8918a71cdbe9 86 if(entry->addr == IGMP_ALL_SYSTEMS_ADDR)
Sergunb 0:8918a71cdbe9 87 {
Sergunb 0:8918a71cdbe9 88 //Clear flag
Sergunb 0:8918a71cdbe9 89 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 90 //Enter the Idle Member state
Sergunb 0:8918a71cdbe9 91 entry->state = IGMP_STATE_IDLE_MEMBER;
Sergunb 0:8918a71cdbe9 92 }
Sergunb 0:8918a71cdbe9 93 else
Sergunb 0:8918a71cdbe9 94 {
Sergunb 0:8918a71cdbe9 95 //Link is up?
Sergunb 0:8918a71cdbe9 96 if(interface->linkState)
Sergunb 0:8918a71cdbe9 97 {
Sergunb 0:8918a71cdbe9 98 //When a host joins a multicast group, it should immediately transmit
Sergunb 0:8918a71cdbe9 99 //an unsolicited Membership Report for that group
Sergunb 0:8918a71cdbe9 100 igmpSendReportMessage(interface, entry->addr);
Sergunb 0:8918a71cdbe9 101
Sergunb 0:8918a71cdbe9 102 //Set flag
Sergunb 0:8918a71cdbe9 103 entry->flag = TRUE;
Sergunb 0:8918a71cdbe9 104 //Start timer
Sergunb 0:8918a71cdbe9 105 entry->timer = osGetSystemTime() + IGMP_UNSOLICITED_REPORT_INTERVAL;
Sergunb 0:8918a71cdbe9 106 //Enter the Delaying Member state
Sergunb 0:8918a71cdbe9 107 entry->state = IGMP_STATE_DELAYING_MEMBER;
Sergunb 0:8918a71cdbe9 108 }
Sergunb 0:8918a71cdbe9 109 //Link is down?
Sergunb 0:8918a71cdbe9 110 else
Sergunb 0:8918a71cdbe9 111 {
Sergunb 0:8918a71cdbe9 112 //Clear flag
Sergunb 0:8918a71cdbe9 113 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 114 //Enter the Idle Member state
Sergunb 0:8918a71cdbe9 115 entry->state = IGMP_STATE_IDLE_MEMBER;
Sergunb 0:8918a71cdbe9 116 }
Sergunb 0:8918a71cdbe9 117 }
Sergunb 0:8918a71cdbe9 118
Sergunb 0:8918a71cdbe9 119 //Successful processing
Sergunb 0:8918a71cdbe9 120 return NO_ERROR;
Sergunb 0:8918a71cdbe9 121 }
Sergunb 0:8918a71cdbe9 122
Sergunb 0:8918a71cdbe9 123
Sergunb 0:8918a71cdbe9 124 /**
Sergunb 0:8918a71cdbe9 125 * @brief Leave the specified host group
Sergunb 0:8918a71cdbe9 126 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 127 * @param[in] entry IPv4 filter entry identifying the host group to leave
Sergunb 0:8918a71cdbe9 128 * @return Error code
Sergunb 0:8918a71cdbe9 129 **/
Sergunb 0:8918a71cdbe9 130
Sergunb 0:8918a71cdbe9 131 error_t igmpLeaveGroup(NetInterface *interface, Ipv4FilterEntry *entry)
Sergunb 0:8918a71cdbe9 132 {
Sergunb 0:8918a71cdbe9 133 //Check link state
Sergunb 0:8918a71cdbe9 134 if(interface->linkState)
Sergunb 0:8918a71cdbe9 135 {
Sergunb 0:8918a71cdbe9 136 //Send a Leave Group message if the flag is set
Sergunb 0:8918a71cdbe9 137 if(entry->flag)
Sergunb 0:8918a71cdbe9 138 igmpSendLeaveGroupMessage(interface, entry->addr);
Sergunb 0:8918a71cdbe9 139 }
Sergunb 0:8918a71cdbe9 140
Sergunb 0:8918a71cdbe9 141 //Switch to the Non-Member state
Sergunb 0:8918a71cdbe9 142 entry->state = IGMP_STATE_NON_MEMBER;
Sergunb 0:8918a71cdbe9 143
Sergunb 0:8918a71cdbe9 144 //Successful processing
Sergunb 0:8918a71cdbe9 145 return NO_ERROR;
Sergunb 0:8918a71cdbe9 146 }
Sergunb 0:8918a71cdbe9 147
Sergunb 0:8918a71cdbe9 148
Sergunb 0:8918a71cdbe9 149 /**
Sergunb 0:8918a71cdbe9 150 * @brief IGMP timer handler
Sergunb 0:8918a71cdbe9 151 *
Sergunb 0:8918a71cdbe9 152 * This routine must be periodically called by the TCP/IP stack to
Sergunb 0:8918a71cdbe9 153 * handle IGMP related timers
Sergunb 0:8918a71cdbe9 154 *
Sergunb 0:8918a71cdbe9 155 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 156 **/
Sergunb 0:8918a71cdbe9 157
Sergunb 0:8918a71cdbe9 158 void igmpTick(NetInterface *interface)
Sergunb 0:8918a71cdbe9 159 {
Sergunb 0:8918a71cdbe9 160 uint_t i;
Sergunb 0:8918a71cdbe9 161 systime_t time;
Sergunb 0:8918a71cdbe9 162 Ipv4FilterEntry *entry;
Sergunb 0:8918a71cdbe9 163
Sergunb 0:8918a71cdbe9 164 //Get current time
Sergunb 0:8918a71cdbe9 165 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 166
Sergunb 0:8918a71cdbe9 167 //Check IGMPv1 router present timer
Sergunb 0:8918a71cdbe9 168 if(timeCompare(time, interface->igmpv1RouterPresentTimer) >= 0)
Sergunb 0:8918a71cdbe9 169 interface->igmpv1RouterPresent = FALSE;
Sergunb 0:8918a71cdbe9 170
Sergunb 0:8918a71cdbe9 171 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 172 for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 173 {
Sergunb 0:8918a71cdbe9 174 //Point to the current entry
Sergunb 0:8918a71cdbe9 175 entry = &interface->ipv4Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 176
Sergunb 0:8918a71cdbe9 177 //Valid entry?
Sergunb 0:8918a71cdbe9 178 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 179 {
Sergunb 0:8918a71cdbe9 180 //Delaying Member state?
Sergunb 0:8918a71cdbe9 181 if(entry->state == IGMP_STATE_DELAYING_MEMBER)
Sergunb 0:8918a71cdbe9 182 {
Sergunb 0:8918a71cdbe9 183 //Timer expired?
Sergunb 0:8918a71cdbe9 184 if(timeCompare(time, entry->timer) >= 0)
Sergunb 0:8918a71cdbe9 185 {
Sergunb 0:8918a71cdbe9 186 //Send a Membership Report message for the group on the interface
Sergunb 0:8918a71cdbe9 187 igmpSendReportMessage(interface, entry->addr);
Sergunb 0:8918a71cdbe9 188
Sergunb 0:8918a71cdbe9 189 //Set flag
Sergunb 0:8918a71cdbe9 190 entry->flag = TRUE;
Sergunb 0:8918a71cdbe9 191 //Switch to the Idle Member state
Sergunb 0:8918a71cdbe9 192 entry->state = IGMP_STATE_IDLE_MEMBER;
Sergunb 0:8918a71cdbe9 193 }
Sergunb 0:8918a71cdbe9 194 }
Sergunb 0:8918a71cdbe9 195 }
Sergunb 0:8918a71cdbe9 196 }
Sergunb 0:8918a71cdbe9 197 }
Sergunb 0:8918a71cdbe9 198
Sergunb 0:8918a71cdbe9 199
Sergunb 0:8918a71cdbe9 200 /**
Sergunb 0:8918a71cdbe9 201 * @brief Callback function for link change event
Sergunb 0:8918a71cdbe9 202 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 203 **/
Sergunb 0:8918a71cdbe9 204
Sergunb 0:8918a71cdbe9 205 void igmpLinkChangeEvent(NetInterface *interface)
Sergunb 0:8918a71cdbe9 206 {
Sergunb 0:8918a71cdbe9 207 uint_t i;
Sergunb 0:8918a71cdbe9 208 systime_t time;
Sergunb 0:8918a71cdbe9 209 Ipv4FilterEntry *entry;
Sergunb 0:8918a71cdbe9 210
Sergunb 0:8918a71cdbe9 211 //Get current time
Sergunb 0:8918a71cdbe9 212 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 213
Sergunb 0:8918a71cdbe9 214 //Link up event?
Sergunb 0:8918a71cdbe9 215 if(interface->linkState)
Sergunb 0:8918a71cdbe9 216 {
Sergunb 0:8918a71cdbe9 217 //The default host compatibility mode is IGMPv2
Sergunb 0:8918a71cdbe9 218 interface->igmpv1RouterPresent = FALSE;
Sergunb 0:8918a71cdbe9 219 //Start IGMPv1 router present timer
Sergunb 0:8918a71cdbe9 220 interface->igmpv1RouterPresentTimer = time + IGMP_V1_ROUTER_PRESENT_TIMEOUT;
Sergunb 0:8918a71cdbe9 221
Sergunb 0:8918a71cdbe9 222 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 223 for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 224 {
Sergunb 0:8918a71cdbe9 225 //Point to the current entry
Sergunb 0:8918a71cdbe9 226 entry = &interface->ipv4Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 227
Sergunb 0:8918a71cdbe9 228 //Valid entry?
Sergunb 0:8918a71cdbe9 229 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 230 {
Sergunb 0:8918a71cdbe9 231 //The all-systems group (address 224.0.0.1) is handled as a special
Sergunb 0:8918a71cdbe9 232 //case. The host starts in Idle Member state for that group on every
Sergunb 0:8918a71cdbe9 233 //interface and never transitions to another state
Sergunb 0:8918a71cdbe9 234 if(entry->addr != IGMP_ALL_SYSTEMS_ADDR)
Sergunb 0:8918a71cdbe9 235 {
Sergunb 0:8918a71cdbe9 236 //Send an unsolicited Membership Report for that group
Sergunb 0:8918a71cdbe9 237 igmpSendReportMessage(interface, entry->addr);
Sergunb 0:8918a71cdbe9 238
Sergunb 0:8918a71cdbe9 239 //Set flag
Sergunb 0:8918a71cdbe9 240 entry->flag = TRUE;
Sergunb 0:8918a71cdbe9 241 //Start timer
Sergunb 0:8918a71cdbe9 242 entry->timer = time + IGMP_UNSOLICITED_REPORT_INTERVAL;
Sergunb 0:8918a71cdbe9 243 //Enter the Delaying Member state
Sergunb 0:8918a71cdbe9 244 entry->state = IGMP_STATE_DELAYING_MEMBER;
Sergunb 0:8918a71cdbe9 245 }
Sergunb 0:8918a71cdbe9 246 }
Sergunb 0:8918a71cdbe9 247 }
Sergunb 0:8918a71cdbe9 248 }
Sergunb 0:8918a71cdbe9 249 //Link down event?
Sergunb 0:8918a71cdbe9 250 else
Sergunb 0:8918a71cdbe9 251 {
Sergunb 0:8918a71cdbe9 252 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 253 for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 254 {
Sergunb 0:8918a71cdbe9 255 //Point to the current entry
Sergunb 0:8918a71cdbe9 256 entry = &interface->ipv4Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 257
Sergunb 0:8918a71cdbe9 258 //Valid entry?
Sergunb 0:8918a71cdbe9 259 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 260 {
Sergunb 0:8918a71cdbe9 261 //Clear flag
Sergunb 0:8918a71cdbe9 262 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 263 //Enter the Idle Member state
Sergunb 0:8918a71cdbe9 264 entry->state = IGMP_STATE_IDLE_MEMBER;
Sergunb 0:8918a71cdbe9 265 }
Sergunb 0:8918a71cdbe9 266 }
Sergunb 0:8918a71cdbe9 267 }
Sergunb 0:8918a71cdbe9 268 }
Sergunb 0:8918a71cdbe9 269
Sergunb 0:8918a71cdbe9 270
Sergunb 0:8918a71cdbe9 271 /**
Sergunb 0:8918a71cdbe9 272 * @brief Process incoming IGMP message
Sergunb 0:8918a71cdbe9 273 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 274 * @param[in] buffer Multi-part buffer containing the incoming IGMP message
Sergunb 0:8918a71cdbe9 275 * @param[in] offset Offset to the first byte of the IGMP message
Sergunb 0:8918a71cdbe9 276 **/
Sergunb 0:8918a71cdbe9 277
Sergunb 0:8918a71cdbe9 278 void igmpProcessMessage(NetInterface *interface,
Sergunb 0:8918a71cdbe9 279 const NetBuffer *buffer, size_t offset)
Sergunb 0:8918a71cdbe9 280 {
Sergunb 0:8918a71cdbe9 281 size_t length;
Sergunb 0:8918a71cdbe9 282 IgmpMessage *message;
Sergunb 0:8918a71cdbe9 283
Sergunb 0:8918a71cdbe9 284 //Retrieve the length of the IGMP message
Sergunb 0:8918a71cdbe9 285 length = netBufferGetLength(buffer) - offset;
Sergunb 0:8918a71cdbe9 286
Sergunb 0:8918a71cdbe9 287 //Ensure the message length is correct
Sergunb 0:8918a71cdbe9 288 if(length < sizeof(IgmpMessage))
Sergunb 0:8918a71cdbe9 289 {
Sergunb 0:8918a71cdbe9 290 //Debug message
Sergunb 0:8918a71cdbe9 291 TRACE_WARNING("IGMP message length is invalid!\r\n");
Sergunb 0:8918a71cdbe9 292 //Silently discard incoming message
Sergunb 0:8918a71cdbe9 293 return;
Sergunb 0:8918a71cdbe9 294 }
Sergunb 0:8918a71cdbe9 295
Sergunb 0:8918a71cdbe9 296 //Point to the beginning of the IGMP message
Sergunb 0:8918a71cdbe9 297 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 298 //Sanity check
Sergunb 0:8918a71cdbe9 299 if(message == NULL)
Sergunb 0:8918a71cdbe9 300 return;
Sergunb 0:8918a71cdbe9 301
Sergunb 0:8918a71cdbe9 302 //Debug message
Sergunb 0:8918a71cdbe9 303 TRACE_INFO("IGMP message received (%" PRIuSIZE " bytes)...\r\n", length);
Sergunb 0:8918a71cdbe9 304 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 305 igmpDumpMessage(message);
Sergunb 0:8918a71cdbe9 306
Sergunb 0:8918a71cdbe9 307 //Verify checksum value
Sergunb 0:8918a71cdbe9 308 if(ipCalcChecksumEx(buffer, offset, length) != 0x0000)
Sergunb 0:8918a71cdbe9 309 {
Sergunb 0:8918a71cdbe9 310 //Debug message
Sergunb 0:8918a71cdbe9 311 TRACE_WARNING("Wrong IGMP header checksum!\r\n");
Sergunb 0:8918a71cdbe9 312 //Drop incoming message
Sergunb 0:8918a71cdbe9 313 return;
Sergunb 0:8918a71cdbe9 314 }
Sergunb 0:8918a71cdbe9 315
Sergunb 0:8918a71cdbe9 316 //Check the type field
Sergunb 0:8918a71cdbe9 317 switch(message->type)
Sergunb 0:8918a71cdbe9 318 {
Sergunb 0:8918a71cdbe9 319 //Membership Query message?
Sergunb 0:8918a71cdbe9 320 case IGMP_TYPE_MEMBERSHIP_QUERY:
Sergunb 0:8918a71cdbe9 321 //Process Membership Query message
Sergunb 0:8918a71cdbe9 322 igmpProcessQueryMessage(interface, message, length);
Sergunb 0:8918a71cdbe9 323 break;
Sergunb 0:8918a71cdbe9 324 //Membership Report message?
Sergunb 0:8918a71cdbe9 325 case IGMP_TYPE_MEMBERSHIP_REPORT_V1:
Sergunb 0:8918a71cdbe9 326 case IGMP_TYPE_MEMBERSHIP_REPORT_V2:
Sergunb 0:8918a71cdbe9 327 //Process Membership Query message
Sergunb 0:8918a71cdbe9 328 igmpProcessReportMessage(interface, message, length);
Sergunb 0:8918a71cdbe9 329 break;
Sergunb 0:8918a71cdbe9 330 //Unknown type?
Sergunb 0:8918a71cdbe9 331 default:
Sergunb 0:8918a71cdbe9 332 //Debug message
Sergunb 0:8918a71cdbe9 333 TRACE_WARNING("Unknown IGMP message type!\r\n");
Sergunb 0:8918a71cdbe9 334 //Discard incoming IGMP message
Sergunb 0:8918a71cdbe9 335 break;
Sergunb 0:8918a71cdbe9 336 }
Sergunb 0:8918a71cdbe9 337 }
Sergunb 0:8918a71cdbe9 338
Sergunb 0:8918a71cdbe9 339
Sergunb 0:8918a71cdbe9 340 /**
Sergunb 0:8918a71cdbe9 341 * @brief Process incoming Membership Query message
Sergunb 0:8918a71cdbe9 342 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 343 * @param[in] message Incoming Membership Query message
Sergunb 0:8918a71cdbe9 344 * @param[in] length Message length
Sergunb 0:8918a71cdbe9 345 **/
Sergunb 0:8918a71cdbe9 346
Sergunb 0:8918a71cdbe9 347 void igmpProcessQueryMessage(NetInterface *interface,
Sergunb 0:8918a71cdbe9 348 const IgmpMessage *message, size_t length)
Sergunb 0:8918a71cdbe9 349 {
Sergunb 0:8918a71cdbe9 350 uint_t i;
Sergunb 0:8918a71cdbe9 351 systime_t time;
Sergunb 0:8918a71cdbe9 352 systime_t maxRespTime;
Sergunb 0:8918a71cdbe9 353 Ipv4FilterEntry *entry;
Sergunb 0:8918a71cdbe9 354
Sergunb 0:8918a71cdbe9 355 //Get current time
Sergunb 0:8918a71cdbe9 356 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 357
Sergunb 0:8918a71cdbe9 358 //IGMPv1 Membership Query message?
Sergunb 0:8918a71cdbe9 359 if(message->maxRespTime == 0)
Sergunb 0:8918a71cdbe9 360 {
Sergunb 0:8918a71cdbe9 361 //The host receives a query with the Max Response Time field set to 0
Sergunb 0:8918a71cdbe9 362 interface->igmpv1RouterPresent = TRUE;
Sergunb 0:8918a71cdbe9 363 //Restart IGMPv1 router present timer
Sergunb 0:8918a71cdbe9 364 interface->igmpv1RouterPresentTimer = time + IGMP_V1_ROUTER_PRESENT_TIMEOUT;
Sergunb 0:8918a71cdbe9 365 //The maximum response time is 10 seconds by default
Sergunb 0:8918a71cdbe9 366 maxRespTime = IGMP_V1_MAX_RESPONSE_TIME;
Sergunb 0:8918a71cdbe9 367 }
Sergunb 0:8918a71cdbe9 368 //IGMPv2 Membership Query message?
Sergunb 0:8918a71cdbe9 369 else
Sergunb 0:8918a71cdbe9 370 {
Sergunb 0:8918a71cdbe9 371 //The Max Resp Time field specifies the maximum time allowed
Sergunb 0:8918a71cdbe9 372 //before sending a responding report
Sergunb 0:8918a71cdbe9 373 maxRespTime = message->maxRespTime * 10;
Sergunb 0:8918a71cdbe9 374 }
Sergunb 0:8918a71cdbe9 375
Sergunb 0:8918a71cdbe9 376 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 377 for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 378 {
Sergunb 0:8918a71cdbe9 379 //Point to the current entry
Sergunb 0:8918a71cdbe9 380 entry = &interface->ipv4Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 381
Sergunb 0:8918a71cdbe9 382 //Valid entry?
Sergunb 0:8918a71cdbe9 383 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 384 {
Sergunb 0:8918a71cdbe9 385 //The all-systems group (224.0.0.1) is handled as a special case. The
Sergunb 0:8918a71cdbe9 386 //host starts in Idle Member state for that group on every interface
Sergunb 0:8918a71cdbe9 387 //and never transitions to another state
Sergunb 0:8918a71cdbe9 388 if(entry->addr != IGMP_ALL_SYSTEMS_ADDR)
Sergunb 0:8918a71cdbe9 389 {
Sergunb 0:8918a71cdbe9 390 //A General Query applies to all memberships on the interface from which
Sergunb 0:8918a71cdbe9 391 //the Query is received. A Group-Specific Query applies to membership
Sergunb 0:8918a71cdbe9 392 //in a single group on the interface from which the Query is received
Sergunb 0:8918a71cdbe9 393 if(message->groupAddr == IPV4_UNSPECIFIED_ADDR ||
Sergunb 0:8918a71cdbe9 394 message->groupAddr == entry->addr)
Sergunb 0:8918a71cdbe9 395 {
Sergunb 0:8918a71cdbe9 396 //Delaying Member state?
Sergunb 0:8918a71cdbe9 397 if(entry->state == IGMP_STATE_DELAYING_MEMBER)
Sergunb 0:8918a71cdbe9 398 {
Sergunb 0:8918a71cdbe9 399 //The timer has not yet expired?
Sergunb 0:8918a71cdbe9 400 if(timeCompare(time, entry->timer) < 0)
Sergunb 0:8918a71cdbe9 401 {
Sergunb 0:8918a71cdbe9 402 //If a timer for the group is already running, it is reset to
Sergunb 0:8918a71cdbe9 403 //the random value only if the requested Max Response Time is
Sergunb 0:8918a71cdbe9 404 //less than the remaining value of the running timer
Sergunb 0:8918a71cdbe9 405 if(maxRespTime < (entry->timer - time))
Sergunb 0:8918a71cdbe9 406 {
Sergunb 0:8918a71cdbe9 407 //Restart delay timer
Sergunb 0:8918a71cdbe9 408 entry->timer = time + igmpRand(maxRespTime);
Sergunb 0:8918a71cdbe9 409 }
Sergunb 0:8918a71cdbe9 410 }
Sergunb 0:8918a71cdbe9 411 }
Sergunb 0:8918a71cdbe9 412 //Idle Member state?
Sergunb 0:8918a71cdbe9 413 else if(entry->state == IGMP_STATE_IDLE_MEMBER)
Sergunb 0:8918a71cdbe9 414 {
Sergunb 0:8918a71cdbe9 415 //Switch to the Delaying Member state
Sergunb 0:8918a71cdbe9 416 entry->state = IGMP_STATE_DELAYING_MEMBER;
Sergunb 0:8918a71cdbe9 417 //Delay the response by a random amount of time
Sergunb 0:8918a71cdbe9 418 entry->timer = time + igmpRand(maxRespTime);
Sergunb 0:8918a71cdbe9 419 }
Sergunb 0:8918a71cdbe9 420 }
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 * @brief Process incoming Membership Report message
Sergunb 0:8918a71cdbe9 429 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 430 * @param[in] message Incoming Membership Report message
Sergunb 0:8918a71cdbe9 431 * @param[in] length Message length
Sergunb 0:8918a71cdbe9 432 **/
Sergunb 0:8918a71cdbe9 433
Sergunb 0:8918a71cdbe9 434 void igmpProcessReportMessage(NetInterface *interface,
Sergunb 0:8918a71cdbe9 435 const IgmpMessage *message, size_t length)
Sergunb 0:8918a71cdbe9 436 {
Sergunb 0:8918a71cdbe9 437 uint_t i;
Sergunb 0:8918a71cdbe9 438 Ipv4FilterEntry *entry;
Sergunb 0:8918a71cdbe9 439
Sergunb 0:8918a71cdbe9 440 //Go through the multicast filter table
Sergunb 0:8918a71cdbe9 441 for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
Sergunb 0:8918a71cdbe9 442 {
Sergunb 0:8918a71cdbe9 443 //Point to the current entry
Sergunb 0:8918a71cdbe9 444 entry = &interface->ipv4Context.multicastFilter[i];
Sergunb 0:8918a71cdbe9 445
Sergunb 0:8918a71cdbe9 446 //Valid entry?
Sergunb 0:8918a71cdbe9 447 if(entry->refCount > 0)
Sergunb 0:8918a71cdbe9 448 {
Sergunb 0:8918a71cdbe9 449 //Report messages are ignored for memberships in
Sergunb 0:8918a71cdbe9 450 //the Non-Member or Idle Member state
Sergunb 0:8918a71cdbe9 451 if(entry->state == IGMP_STATE_DELAYING_MEMBER)
Sergunb 0:8918a71cdbe9 452 {
Sergunb 0:8918a71cdbe9 453 //The Membership Report message matches the current entry?
Sergunb 0:8918a71cdbe9 454 if(message->groupAddr == entry->addr)
Sergunb 0:8918a71cdbe9 455 {
Sergunb 0:8918a71cdbe9 456 //Clear flag
Sergunb 0:8918a71cdbe9 457 entry->flag = FALSE;
Sergunb 0:8918a71cdbe9 458 //Switch to the Idle Member state
Sergunb 0:8918a71cdbe9 459 entry->state = IGMP_STATE_IDLE_MEMBER;
Sergunb 0:8918a71cdbe9 460 }
Sergunb 0:8918a71cdbe9 461 }
Sergunb 0:8918a71cdbe9 462 }
Sergunb 0:8918a71cdbe9 463 }
Sergunb 0:8918a71cdbe9 464 }
Sergunb 0:8918a71cdbe9 465
Sergunb 0:8918a71cdbe9 466
Sergunb 0:8918a71cdbe9 467 /**
Sergunb 0:8918a71cdbe9 468 * @brief Send Membership Report message
Sergunb 0:8918a71cdbe9 469 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 470 * @param[in] ipAddr IPv4 address specifying the group address
Sergunb 0:8918a71cdbe9 471 * @return Error code
Sergunb 0:8918a71cdbe9 472 **/
Sergunb 0:8918a71cdbe9 473
Sergunb 0:8918a71cdbe9 474 error_t igmpSendReportMessage(NetInterface *interface, Ipv4Addr ipAddr)
Sergunb 0:8918a71cdbe9 475 {
Sergunb 0:8918a71cdbe9 476 error_t error;
Sergunb 0:8918a71cdbe9 477 size_t offset;
Sergunb 0:8918a71cdbe9 478 IgmpMessage *message;
Sergunb 0:8918a71cdbe9 479 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 480 Ipv4PseudoHeader pseudoHeader;
Sergunb 0:8918a71cdbe9 481
Sergunb 0:8918a71cdbe9 482 //Make sure the specified address is a valid multicast address
Sergunb 0:8918a71cdbe9 483 if(!ipv4IsMulticastAddr(ipAddr))
Sergunb 0:8918a71cdbe9 484 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 485
Sergunb 0:8918a71cdbe9 486 //The all-systems group (224.0.0.1) is handled as a special case.
Sergunb 0:8918a71cdbe9 487 //The host never sends a report for that group
Sergunb 0:8918a71cdbe9 488 if(ipAddr == IGMP_ALL_SYSTEMS_ADDR)
Sergunb 0:8918a71cdbe9 489 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 490
Sergunb 0:8918a71cdbe9 491 //Allocate a memory buffer to hold an IGMP message
Sergunb 0:8918a71cdbe9 492 buffer = ipAllocBuffer(sizeof(IgmpMessage), &offset);
Sergunb 0:8918a71cdbe9 493 //Failed to allocate memory?
Sergunb 0:8918a71cdbe9 494 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 495 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 496
Sergunb 0:8918a71cdbe9 497 //Point to the beginning of the IGMP message
Sergunb 0:8918a71cdbe9 498 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 499
Sergunb 0:8918a71cdbe9 500 //The type of report is determined by the state of the interface
Sergunb 0:8918a71cdbe9 501 if(interface->igmpv1RouterPresent)
Sergunb 0:8918a71cdbe9 502 message->type = IGMP_TYPE_MEMBERSHIP_REPORT_V1;
Sergunb 0:8918a71cdbe9 503 else
Sergunb 0:8918a71cdbe9 504 message->type = IGMP_TYPE_MEMBERSHIP_REPORT_V2;
Sergunb 0:8918a71cdbe9 505
Sergunb 0:8918a71cdbe9 506 //Format the Membership Report message
Sergunb 0:8918a71cdbe9 507 message->maxRespTime = 0;
Sergunb 0:8918a71cdbe9 508 message->checksum = 0;
Sergunb 0:8918a71cdbe9 509 message->groupAddr = ipAddr;
Sergunb 0:8918a71cdbe9 510
Sergunb 0:8918a71cdbe9 511 //Message checksum calculation
Sergunb 0:8918a71cdbe9 512 message->checksum = ipCalcChecksumEx(buffer, offset, sizeof(IgmpMessage));
Sergunb 0:8918a71cdbe9 513
Sergunb 0:8918a71cdbe9 514 //Format IPv4 pseudo header
Sergunb 0:8918a71cdbe9 515 pseudoHeader.srcAddr = interface->ipv4Context.addr;
Sergunb 0:8918a71cdbe9 516 pseudoHeader.destAddr = ipAddr;
Sergunb 0:8918a71cdbe9 517 pseudoHeader.reserved = 0;
Sergunb 0:8918a71cdbe9 518 pseudoHeader.protocol = IPV4_PROTOCOL_IGMP;
Sergunb 0:8918a71cdbe9 519 pseudoHeader.length = HTONS(sizeof(IgmpMessage));
Sergunb 0:8918a71cdbe9 520
Sergunb 0:8918a71cdbe9 521 //Debug message
Sergunb 0:8918a71cdbe9 522 TRACE_INFO("Sending IGMP message (%" PRIuSIZE " bytes)...\r\n", sizeof(IgmpMessage));
Sergunb 0:8918a71cdbe9 523 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 524 igmpDumpMessage(message);
Sergunb 0:8918a71cdbe9 525
Sergunb 0:8918a71cdbe9 526 //The Membership Report message is sent to the group being reported
Sergunb 0:8918a71cdbe9 527 error = ipv4SendDatagram(interface, &pseudoHeader, buffer, offset, IGMP_TTL);
Sergunb 0:8918a71cdbe9 528
Sergunb 0:8918a71cdbe9 529 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 530 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 531 //Return status code
Sergunb 0:8918a71cdbe9 532 return error;
Sergunb 0:8918a71cdbe9 533 }
Sergunb 0:8918a71cdbe9 534
Sergunb 0:8918a71cdbe9 535
Sergunb 0:8918a71cdbe9 536 /**
Sergunb 0:8918a71cdbe9 537 * @brief Send Leave Group message
Sergunb 0:8918a71cdbe9 538 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 539 * @param[in] ipAddr IPv4 address specifying the group address being left
Sergunb 0:8918a71cdbe9 540 * @return Error code
Sergunb 0:8918a71cdbe9 541 **/
Sergunb 0:8918a71cdbe9 542
Sergunb 0:8918a71cdbe9 543 error_t igmpSendLeaveGroupMessage(NetInterface *interface, Ipv4Addr ipAddr)
Sergunb 0:8918a71cdbe9 544 {
Sergunb 0:8918a71cdbe9 545 error_t error;
Sergunb 0:8918a71cdbe9 546 size_t offset;
Sergunb 0:8918a71cdbe9 547 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 548 IgmpMessage *message;
Sergunb 0:8918a71cdbe9 549 Ipv4PseudoHeader pseudoHeader;
Sergunb 0:8918a71cdbe9 550
Sergunb 0:8918a71cdbe9 551 //Make sure the specified address is a valid multicast address
Sergunb 0:8918a71cdbe9 552 if(!ipv4IsMulticastAddr(ipAddr))
Sergunb 0:8918a71cdbe9 553 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 554
Sergunb 0:8918a71cdbe9 555 //The all-systems group (224.0.0.1) is handled as a special case.
Sergunb 0:8918a71cdbe9 556 //The host never sends a Leave Group message for that group
Sergunb 0:8918a71cdbe9 557 if(ipAddr == IGMP_ALL_SYSTEMS_ADDR)
Sergunb 0:8918a71cdbe9 558 return ERROR_INVALID_ADDRESS;
Sergunb 0:8918a71cdbe9 559
Sergunb 0:8918a71cdbe9 560 //If the interface state says the querier is running
Sergunb 0:8918a71cdbe9 561 //IGMPv1, this action should be skipped
Sergunb 0:8918a71cdbe9 562 if(interface->igmpv1RouterPresent)
Sergunb 0:8918a71cdbe9 563 return NO_ERROR;
Sergunb 0:8918a71cdbe9 564
Sergunb 0:8918a71cdbe9 565 //Allocate a memory buffer to hold an IGMP message
Sergunb 0:8918a71cdbe9 566 buffer = ipAllocBuffer(sizeof(IgmpMessage), &offset);
Sergunb 0:8918a71cdbe9 567 //Failed to allocate memory?
Sergunb 0:8918a71cdbe9 568 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 569 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 570
Sergunb 0:8918a71cdbe9 571 //Point to the beginning of the IGMP message
Sergunb 0:8918a71cdbe9 572 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 573
Sergunb 0:8918a71cdbe9 574 //Format the Leave Group message
Sergunb 0:8918a71cdbe9 575 message->type = IGMP_TYPE_LEAVE_GROUP;
Sergunb 0:8918a71cdbe9 576 message->maxRespTime = 0;
Sergunb 0:8918a71cdbe9 577 message->checksum = 0;
Sergunb 0:8918a71cdbe9 578 message->groupAddr = ipAddr;
Sergunb 0:8918a71cdbe9 579
Sergunb 0:8918a71cdbe9 580 //Message checksum calculation
Sergunb 0:8918a71cdbe9 581 message->checksum = ipCalcChecksumEx(buffer, offset, sizeof(IgmpMessage));
Sergunb 0:8918a71cdbe9 582
Sergunb 0:8918a71cdbe9 583 //Format IPv4 pseudo header
Sergunb 0:8918a71cdbe9 584 pseudoHeader.srcAddr = interface->ipv4Context.addr;
Sergunb 0:8918a71cdbe9 585 pseudoHeader.destAddr = IGMP_ALL_ROUTERS_ADDR;
Sergunb 0:8918a71cdbe9 586 pseudoHeader.reserved = 0;
Sergunb 0:8918a71cdbe9 587 pseudoHeader.protocol = IPV4_PROTOCOL_IGMP;
Sergunb 0:8918a71cdbe9 588 pseudoHeader.length = HTONS(sizeof(IgmpMessage));
Sergunb 0:8918a71cdbe9 589
Sergunb 0:8918a71cdbe9 590 //Debug message
Sergunb 0:8918a71cdbe9 591 TRACE_INFO("Sending IGMP message (%" PRIuSIZE " bytes)...\r\n", sizeof(IgmpMessage));
Sergunb 0:8918a71cdbe9 592 //Dump message contents for debugging purpose
Sergunb 0:8918a71cdbe9 593 igmpDumpMessage(message);
Sergunb 0:8918a71cdbe9 594
Sergunb 0:8918a71cdbe9 595 //The Leave Group message is sent to the all-routers multicast group
Sergunb 0:8918a71cdbe9 596 error = ipv4SendDatagram(interface, &pseudoHeader, buffer, offset, IGMP_TTL);
Sergunb 0:8918a71cdbe9 597
Sergunb 0:8918a71cdbe9 598 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 599 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 600 //Return status code
Sergunb 0:8918a71cdbe9 601 return error;
Sergunb 0:8918a71cdbe9 602 }
Sergunb 0:8918a71cdbe9 603
Sergunb 0:8918a71cdbe9 604
Sergunb 0:8918a71cdbe9 605 /**
Sergunb 0:8918a71cdbe9 606 * @brief Get a random value in the specified range
Sergunb 0:8918a71cdbe9 607 * @param[in] max Upper bound
Sergunb 0:8918a71cdbe9 608 * @return Random value in the specified range
Sergunb 0:8918a71cdbe9 609 **/
Sergunb 0:8918a71cdbe9 610
Sergunb 0:8918a71cdbe9 611 uint32_t igmpRand(uint32_t max)
Sergunb 0:8918a71cdbe9 612 {
Sergunb 0:8918a71cdbe9 613 //Return a random value in the given range
Sergunb 0:8918a71cdbe9 614 return netGetRand() % (max + 1);
Sergunb 0:8918a71cdbe9 615 }
Sergunb 0:8918a71cdbe9 616
Sergunb 0:8918a71cdbe9 617
Sergunb 0:8918a71cdbe9 618 /**
Sergunb 0:8918a71cdbe9 619 * @brief Dump IGMP message for debugging purpose
Sergunb 0:8918a71cdbe9 620 * @param[in] message Pointer to the IGMP message
Sergunb 0:8918a71cdbe9 621 **/
Sergunb 0:8918a71cdbe9 622
Sergunb 0:8918a71cdbe9 623 void igmpDumpMessage(const IgmpMessage *message)
Sergunb 0:8918a71cdbe9 624 {
Sergunb 0:8918a71cdbe9 625 //Dump IGMP message
Sergunb 0:8918a71cdbe9 626 TRACE_DEBUG(" Type = 0x%02" PRIX8 "\r\n", message->type);
Sergunb 0:8918a71cdbe9 627 TRACE_DEBUG(" Max Resp Time = 0x%02" PRIX8 "\r\n", message->maxRespTime);
Sergunb 0:8918a71cdbe9 628 TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
Sergunb 0:8918a71cdbe9 629 TRACE_DEBUG(" Group Address = %s\r\n", ipv4AddrToString(message->groupAddr, NULL));
Sergunb 0:8918a71cdbe9 630 }
Sergunb 0:8918a71cdbe9 631
Sergunb 0:8918a71cdbe9 632 #endif
Sergunb 0:8918a71cdbe9 633