Webserver+3d print

Dependents:   Nucleo

Revision:
0:8918a71cdbe9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyclone_tcp/ipv4/auto_ip.c	Sat Feb 04 18:15:49 2017 +0000
@@ -0,0 +1,562 @@
+/**
+ * @file auto_ip.c
+ * @brief Auto-IP (Dynamic Configuration of IPv4 Link-Local Addresses)
+ *
+ * @section License
+ *
+ * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
+ *
+ * This file is part of CycloneTCP Open.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * @section Description
+ *
+ * Auto-IP describes a method by which a host may automatically configure an
+ * interface with an IPv4 address in the 169.254/16 prefix that is valid for
+ * Link-Local communication on that interface. This is especially valuable in
+ * environments where no other configuration mechanism is available. Refer to
+ * the following RFCs for complete details:
+ * - RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses
+ * - RFC 5227: IPv4 Address Conflict Detection
+ *
+ * @author Oryx Embedded SARL (www.oryx-embedded.com)
+ * @version 1.7.6
+ **/
+
+//Switch to the appropriate trace level
+#define TRACE_LEVEL AUTO_IP_TRACE_LEVEL
+
+//Dependencies
+#include "core/net.h"
+#include "core/ethernet.h"
+#include "ipv4/arp.h"
+#include "ipv4/auto_ip.h"
+#include "mdns/mdns_responder.h"
+#include "debug.h"
+
+//Check TCP/IP stack configuration
+#if (IPV4_SUPPORT == ENABLED && AUTO_IP_SUPPORT == ENABLED)
+
+//Tick counter to handle periodic operations
+systime_t autoIpTickCounter;
+
+
+/**
+ * @brief Initialize settings with default values
+ * @param[out] settings Structure that contains Auto-IP settings
+ **/
+
+void autoIpGetDefaultSettings(AutoIpSettings *settings)
+{
+   //Use default interface
+   settings->interface = netGetDefaultInterface();
+
+   //Initial link-local address to be used
+   settings->linkLocalAddr = IPV4_UNSPECIFIED_ADDR;
+   //Link state change event
+   settings->linkChangeEvent = NULL;
+   //FSM state change event
+   settings->stateChangeEvent = NULL;
+}
+
+
+/**
+ * @brief Auto-IP initialization
+ * @param[in] context Pointer to the Auto-IP context
+ * @param[in] settings Auto-IP specific settings
+ * @return Error code
+ **/
+
+error_t autoIpInit(AutoIpContext *context, const AutoIpSettings *settings)
+{
+   NetInterface *interface;
+
+   //Debug message
+   TRACE_INFO("Initializing Auto-IP...\r\n");
+
+   //Ensure the parameters are valid
+   if(context == NULL || settings == NULL)
+      return ERROR_INVALID_PARAMETER;
+
+   //A valid pointer to the interface being configured is required
+   if(settings->interface == NULL)
+      return ERROR_INVALID_PARAMETER;
+
+   //Point to the underlying network interface
+   interface = settings->interface;
+
+   //Clear the Auto-IP context
+   memset(context, 0, sizeof(AutoIpContext));
+   //Save user settings
+   context->settings = *settings;
+
+   //Use default link-local address
+   context->linkLocalAddr = settings->linkLocalAddr;
+   //Reset conflict counter
+   context->conflictCount = 0;
+
+   //Auto-IP operation is currently suspended
+   context->running = FALSE;
+   //Initialize state machine
+   context->state = AUTO_IP_STATE_INIT;
+
+   //Attach the Auto-IP context to the network interface
+   interface->autoIpContext = context;
+
+   //Successful initialization
+   return NO_ERROR;
+}
+
+
+/**
+ * @brief Start Auto-IP process
+ * @param[in] context Pointer to the Auto-IP context
+ * @return Error code
+ **/
+
+error_t autoIpStart(AutoIpContext *context)
+{
+   //Check parameter
+   if(context == NULL)
+      return ERROR_INVALID_PARAMETER;
+
+   //Debug message
+   TRACE_INFO("Starting Auto-IP...\r\n");
+
+   //Get exclusive access
+   osAcquireMutex(&netMutex);
+
+   //Start Auto-IP operation
+   context->running = TRUE;
+   //Initialize state machine
+   context->state = AUTO_IP_STATE_INIT;
+   //Reset conflict counter
+   context->conflictCount = 0;
+
+   //Release exclusive access
+   osReleaseMutex(&netMutex);
+
+   //Successful processing
+   return NO_ERROR;
+}
+
+
+/**
+ * @brief Stop Auto-IP process
+ * @param[in] context Pointer to the Auto-IP context
+ * @return Error code
+ **/
+
+error_t autoIpStop(AutoIpContext *context)
+{
+   //Check parameter
+   if(context == NULL)
+      return ERROR_INVALID_PARAMETER;
+
+   //Debug message
+   TRACE_INFO("Stopping Auto-IP...\r\n");
+
+   //Get exclusive access
+   osAcquireMutex(&netMutex);
+
+   //Suspend Auto-IP operation
+   context->running = FALSE;
+   //Reinitialize state machine
+   context->state = AUTO_IP_STATE_INIT;
+
+   //Release exclusive access
+   osReleaseMutex(&netMutex);
+
+   //Successful processing
+   return NO_ERROR;
+}
+
+
+/**
+ * @brief Retrieve current state
+ * @param[in] context Pointer to the Auto-IP context
+ * @return Current Auto-IP state
+ **/
+
+AutoIpState autoIpGetState(AutoIpContext *context)
+{
+   AutoIpState state;
+
+   //Get exclusive access
+   osAcquireMutex(&netMutex);
+   //Get current state
+   state = context->state;
+   //Release exclusive access
+   osReleaseMutex(&netMutex);
+
+   //Return current state
+   return state;
+}
+
+
+/**
+ * @brief Auto-IP timer handler
+ *
+ * This routine must be periodically called by the TCP/IP stack to
+ * manage Auto-IP operation
+ *
+ * @param[in] context Pointer to the Auto-IP context
+ **/
+
+void autoIpTick(AutoIpContext *context)
+{
+   systime_t time;
+   systime_t delay;
+   NetInterface *interface;
+
+   //Make sure Auto-IP has been properly instantiated
+   if(context == NULL)
+      return;
+
+   //Point to the underlying network interface
+   interface = context->settings.interface;
+
+   //Get current time
+   time = osGetSystemTime();
+
+   //Check current state
+   if(context->state == AUTO_IP_STATE_INIT)
+   {
+      //Wait for the link to be up before starting Auto-IP
+      if(context->running && interface->linkState)
+      {
+         //Configure subnet mask
+         interface->ipv4Context.subnetMask = AUTO_IP_MASK;
+
+         //The address must be in the range from 169.54.1.0 to 169.254.254.255
+         if(ntohl(context->linkLocalAddr) < ntohl(AUTO_IP_ADDR_MIN) ||
+            ntohl(context->linkLocalAddr) > ntohl(AUTO_IP_ADDR_MAX))
+         {
+            //Generate a random link-local address
+            autoIpGenerateAddr(&context->linkLocalAddr);
+         }
+
+         //Use the link-local address as a tentative address
+         interface->ipv4Context.addr = context->linkLocalAddr;
+         interface->ipv4Context.addrState = IPV4_ADDR_STATE_TENTATIVE;
+
+         //Clear conflict flag
+         interface->ipv4Context.addrConflict = FALSE;
+
+         //Initial random delay
+         delay = netGetRandRange(0, AUTO_IP_PROBE_WAIT);
+
+         //The number of conflicts exceeds the maximum acceptable value?
+         if(context->conflictCount >= AUTO_IP_MAX_CONFLICTS)
+         {
+            //The host must limit the rate at which it probes for new addresses
+            delay += AUTO_IP_RATE_LIMIT_INTERVAL;
+         }
+
+         //Verify the uniqueness of the link-local address
+         autoIpChangeState(context, AUTO_IP_STATE_PROBING, delay);
+      }
+   }
+   else if(context->state == AUTO_IP_STATE_PROBING)
+   {
+      //Any conflict detected?
+      if(interface->ipv4Context.addrConflict)
+      {
+         //The address is already in use by some other host and
+         //must not be assigned to the interface
+         interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
+         interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
+
+         //The host should maintain a counter of the number of address
+         //conflicts it has experienced
+         context->conflictCount++;
+
+         //The host must pick a new random address...
+         autoIpGenerateAddr(&context->linkLocalAddr);
+         //...and repeat the process
+         autoIpChangeState(context, AUTO_IP_STATE_INIT, 0);
+      }
+      else
+      {
+         //Check current time
+         if(timeCompare(time, context->timestamp + context->timeout) >= 0)
+         {
+            //Address Conflict Detection is on-going?
+            if(context->retransmitCount < AUTO_IP_PROBE_NUM)
+            {
+               //Conflict detection is done using ARP probes
+               arpSendProbe(interface, context->linkLocalAddr);
+
+               //Save the time at which the packet was sent
+               context->timestamp = time;
+               //Increment retransmission counter
+               context->retransmitCount++;
+
+               //Last probe packet sent?
+               if(context->retransmitCount == AUTO_IP_PROBE_NUM)
+               {
+                  //Delay before announcing
+                  context->timeout = AUTO_IP_ANNOUNCE_WAIT;
+               }
+               else
+               {
+                  //Maximum delay till repeated probe
+                  context->timeout = netGetRandRange(AUTO_IP_PROBE_MIN,
+                     AUTO_IP_PROBE_MAX);
+               }
+            }
+            else
+            {
+               //The use of the IPv4 address is now unrestricted
+               interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID;
+
+#if (MDNS_RESPONDER_SUPPORT == ENABLED)
+               //Restart mDNS probing process
+               mdnsResponderStartProbing(interface->mdnsResponderContext);
+#endif
+               //The host must then announce its claimed address
+               autoIpChangeState(context, AUTO_IP_STATE_ANNOUNCING, 0);
+            }
+         }
+      }
+   }
+   else if(context->state == AUTO_IP_STATE_ANNOUNCING)
+   {
+      //Check current time
+      if(timeCompare(time, context->timestamp + context->timeout) >= 0)
+      {
+         //An ARP announcement is identical to an ARP probe, except that
+         //now the sender and target IP addresses are both set to the
+         //host's newly selected IPv4 address
+         arpSendRequest(interface, context->linkLocalAddr, &MAC_BROADCAST_ADDR);
+
+         //Save the time at which the packet was sent
+         context->timestamp = time;
+         //Time interval between announcement packets
+         context->timeout = AUTO_IP_ANNOUNCE_INTERVAL;
+         //Increment retransmission counter
+         context->retransmitCount++;
+
+         //Announcing is complete?
+         if(context->retransmitCount >= AUTO_IP_ANNOUNCE_NUM)
+         {
+            //Successful address autoconfiguration
+            autoIpChangeState(context, AUTO_IP_STATE_CONFIGURED, 0);
+            //Reset conflict counter
+            context->conflictCount = 0;
+
+            //Dump current IPv4 configuration for debugging purpose
+            autoIpDumpConfig(context);
+         }
+      }
+   }
+   else if(context->state == AUTO_IP_STATE_CONFIGURED)
+   {
+      //Address Conflict Detection is an ongoing process that is in effect
+      //for as long as a host is using an IPv4 link-local address
+      if(interface->ipv4Context.addrConflict)
+      {
+         //The host may elect to attempt to defend its address by recording
+         //the time that the conflicting ARP packet was received, and then
+         //broadcasting one single ARP announcement, giving its own IP and
+         //hardware addresses as the sender addresses of the ARP
+#if (AUTO_IP_BCT_SUPPORT == ENABLED)
+         arpSendProbe(interface, context->linkLocalAddr);
+#else
+         arpSendRequest(interface, context->linkLocalAddr, &MAC_BROADCAST_ADDR);
+#endif
+         //Clear conflict flag
+         interface->ipv4Context.addrConflict = FALSE;
+
+         //The host can then continue to use the address normally without
+         //any further special action
+         autoIpChangeState(context, AUTO_IP_STATE_DEFENDING, 0);
+      }
+   }
+   else if(context->state == AUTO_IP_STATE_DEFENDING)
+   {
+      //if this is not the first conflicting ARP packet the host has seen, and
+      //the time recorded for the previous conflicting ARP packet is recent,
+      //within DEFEND_INTERVAL seconds, then the host must immediately cease
+      //using this address
+      if(interface->ipv4Context.addrConflict)
+      {
+         //The link-local address cannot be used anymore
+         interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
+         interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
+
+#if (MDNS_RESPONDER_SUPPORT == ENABLED)
+         //Restart mDNS probing process
+         mdnsResponderStartProbing(interface->mdnsResponderContext);
+#endif
+         //The host must pick a new random address...
+         autoIpGenerateAddr(&context->linkLocalAddr);
+         //...and probes/announces again
+         autoIpChangeState(context, AUTO_IP_STATE_INIT, 0);
+      }
+      else
+      {
+         //Check whether the DEFEND_INTERVAL has elapsed
+         if(timeCompare(time, context->timestamp + AUTO_IP_DEFEND_INTERVAL) >= 0)
+         {
+            //The host can continue to use its link-local address
+            autoIpChangeState(context, AUTO_IP_STATE_CONFIGURED, 0);
+         }
+      }
+   }
+}
+
+
+/**
+ * @brief Callback function for link change event
+ * @param[in] context Pointer to the Auto-IP context
+ **/
+
+void autoIpLinkChangeEvent(AutoIpContext *context)
+{
+   NetInterface *interface;
+
+   //Make sure Auto-IP has been properly instantiated
+   if(context == NULL)
+      return;
+
+   //Point to the underlying network interface
+   interface = context->settings.interface;
+
+   //Check whether Auto-IP is enabled
+   if(context->running)
+   {
+      //The host address is not longer valid
+      interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
+      interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
+
+#if (MDNS_RESPONDER_SUPPORT == ENABLED)
+      //Restart mDNS probing process
+      mdnsResponderStartProbing(interface->mdnsResponderContext);
+#endif
+
+      //Clear subnet mask
+      interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR;
+   }
+
+   //Reinitialize state machine
+   context->state = AUTO_IP_STATE_INIT;
+   //Reset conflict counter
+   context->conflictCount = 0;
+
+   //Any registered callback?
+   if(context->settings.linkChangeEvent != NULL)
+   {
+      //Release exclusive access
+      osReleaseMutex(&netMutex);
+      //Invoke user callback function
+      context->settings.linkChangeEvent(context, interface, interface->linkState);
+      //Get exclusive access
+      osAcquireMutex(&netMutex);
+   }
+}
+
+
+/**
+ * @brief Update Auto-IP FSM state
+ * @param[in] context Pointer to the Auto-IP context
+ * @param[in] newState New Auto-IP state to switch to
+ * @param[in] delay Initial delay
+ **/
+
+void autoIpChangeState(AutoIpContext *context,
+   AutoIpState newState, systime_t delay)
+{
+   NetInterface *interface;
+
+   //Point to the underlying network interface
+   interface = context->settings.interface;
+
+   //Set time stamp
+   context->timestamp = osGetSystemTime();
+   //Set initial delay
+   context->timeout = delay;
+   //Reset retransmission counter
+   context->retransmitCount = 0;
+   //Switch to the new state
+   context->state = newState;
+
+   //Any registered callback?
+   if(context->settings.stateChangeEvent != NULL)
+   {
+      //Release exclusive access
+      osReleaseMutex(&netMutex);
+      //Invoke user callback function
+      context->settings.stateChangeEvent(context, interface, newState);
+      //Get exclusive access
+      osAcquireMutex(&netMutex);
+   }
+}
+
+
+/**
+ * @brief Generate a random link-local address
+ * @param[out] ipAddr Random link-local address
+ **/
+
+void autoIpGenerateAddr(Ipv4Addr *ipAddr)
+{
+   uint32_t n;
+
+   //Generate a random address in the range from 169.254.1.0 to 169.254.254.255
+   n = netGetRand() % ntohl(AUTO_IP_ADDR_MAX - AUTO_IP_ADDR_MIN);
+   n += ntohl(AUTO_IP_ADDR_MIN);
+
+   //Convert the resulting address to network byte order
+   *ipAddr = htonl(n);
+}
+
+
+/**
+ * @brief Dump Auto-IP configuration for debugging purpose
+ * @param[in] context Pointer to the Auto-IP context
+ **/
+
+void autoIpDumpConfig(AutoIpContext *context)
+{
+#if (AUTO_IP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
+   NetInterface *interface;
+   Ipv4Context *ipv4Context;
+
+   //Point to the underlying network interface
+   interface = context->settings.interface;
+   //Point to the IPv4 context
+   ipv4Context = &interface->ipv4Context;
+
+   //Debug message
+   TRACE_INFO("\r\n");
+   TRACE_INFO("Auto-IP configuration:\r\n");
+
+   //Link-local address
+   TRACE_INFO("  Link-local Address = %s\r\n",
+      ipv4AddrToString(ipv4Context->addr, NULL));
+
+   //Subnet mask
+   TRACE_INFO("  Subnet Mask = %s\r\n",
+      ipv4AddrToString(ipv4Context->subnetMask, NULL));
+
+   //Debug message
+   TRACE_INFO("\r\n");
+#endif
+}
+
+#endif
+