error_t statelessAddrConfig(NetInterface *interface) { error_t error; Eui64 interfaceId; Ipv6Addr linkLocalAddr; Ipv6Addr solicitedNodeAddr; //Generate the 64-bit interface identifier macAddrToEui64(&interface->macAddr, &interfaceId); //A link-local address is formed by combining the well-known //link-local prefix fe80::0 with the interface identifier linkLocalAddr.w[0] = htons(0xFE80); linkLocalAddr.w[1] = htons(0x0000); linkLocalAddr.w[2] = htons(0x0000); linkLocalAddr.w[3] = htons(0x0000); linkLocalAddr.w[4] = interfaceId.w[0]; linkLocalAddr.w[5] = interfaceId.w[1]; linkLocalAddr.w[6] = interfaceId.w[2]; linkLocalAddr.w[7] = interfaceId.w[3]; //Form the Solicited-Node address ipv6ComputeSolicitedNodeAddr(&linkLocalAddr, &solicitedNodeAddr); //Join the Solicited-Node multicast group for the tentative address ipv6JoinMulticastGroup(interface, &solicitedNodeAddr); //Ensure that the address is not already in use on the local network error = slaacDetectDuplicateAddr(&linkLocalAddr); //If a duplicate address is discovered during the procedure, //the address cannot be assigned to the interface if(error) { ipv6LeaveMulticastGroup(interface, &solicitedNodeAddr); return error; } //Assign the link-local address to the local IPv6 address interface->ipv6Config.linkLocalAddr = linkLocalAddr; //The node next attempts to contact a local router for more //information on continuing the configuration //The global address is formed by appending the interface //identifier to a prefix of appropriate length //Successful configuration return NO_ERROR; }
void slaacProcessRouterAdv(SlaacContext *context, const Ipv6Addr *srcAddr, NdpRouterAdvMessage *message, size_t length) { uint_t i; uint_t n; NdpPrefixInfoOption *prefixInfoOption; NdpRdnssOption *rdnssOption; Eui64 interfaceId; Ipv6Addr globalAddr; //Check current state if(context->state != SLAAC_STATE_ROUTER_SOLICIT) return; //Save router address ipv6SetRouter(context->interface, srcAddr); //Calculate the length of the Options field length -= sizeof(NdpRouterAdvMessage); //Search for the Prefix Information option prefixInfoOption = ndpGetOption(message->options, length, NDP_OPT_PREFIX_INFORMATION); //Prefix Information option not found? if(prefixInfoOption == NULL || prefixInfoOption->length != 4) return; //If the Autonomous flag is not set, silently ignore the Prefix //Information option if(!prefixInfoOption->a) return; //If the prefix is the link-local prefix, silently ignore the //Prefix Information option if(ipv6CompPrefix(&prefixInfoOption->prefix, &IPV6_LINK_LOCAL_ADDR_PREFIX, 64)) return; //If the preferred lifetime is greater than the valid lifetime, //silently ignore the Prefix Information option if(prefixInfoOption->preferredLifetime > prefixInfoOption->validLifetime) return; //If the sum of the prefix length and interface identifier length does //not equal 128 bits, the Prefix Information option must be ignored if(prefixInfoOption->prefixLength != 64) return; //Save IPv6 prefix ipv6SetPrefix(context->interface, &prefixInfoOption->prefix, prefixInfoOption->prefixLength); //Generate the 64-bit interface identifier macAddrToEui64(&context->interface->macAddr, &interfaceId); //Form an address by combining the advertised prefix //with the interface identifier globalAddr.w[0] = prefixInfoOption->prefix.w[0]; globalAddr.w[1] = prefixInfoOption->prefix.w[1]; globalAddr.w[2] = prefixInfoOption->prefix.w[2]; globalAddr.w[3] = prefixInfoOption->prefix.w[3]; globalAddr.w[4] = interfaceId.w[0]; globalAddr.w[5] = interfaceId.w[1]; globalAddr.w[6] = interfaceId.w[2]; globalAddr.w[7] = interfaceId.w[3]; //Use the global address as a tentative address ipv6SetGlobalAddr(context->interface, &globalAddr, IPV6_ADDR_STATE_TENTATIVE); //Use the DNS servers provided by the router? if(!context->manualDnsConfig) { //Search for the Recursive DNS Server (RDNSS) option rdnssOption = ndpGetOption(message->options, length, NDP_OPT_RECURSIVE_DNS_SERVER); //RDNSS option found? if(rdnssOption != NULL && rdnssOption->length >= 1) { //Retrieve the number of addresses n = (rdnssOption->length - 1) / 2; //Save DNS servers for(i = 0; i < n; i++) ipv6SetDnsServer(context->interface, i, &rdnssOption->address[i]); } } //Set time stamp context->timestamp = osGetSystemTime(); //Reset timeout value context->timeout = 0; //Reset retransmission counter context->retransmitCount = 0; //Verify the uniqueness of the global address context->state = SLAAC_STATE_GLOBAL_ADDR_DAD; }
void slaacTick(SlaacContext *context) { systime_t time; //Get current time time = osGetSystemTime(); //Enter critical section osAcquireMutex(&context->mutex); //Check current state if(context->state == SLAAC_STATE_INIT) { //Check link state if(context->running && context->interface->linkState) { Eui64 interfaceId; Ipv6Addr linkLocalAddr; //Generate the 64-bit interface identifier macAddrToEui64(&context->interface->macAddr, &interfaceId); //A link-local address is formed by combining the well-known //link-local prefix fe80::0 with the interface identifier linkLocalAddr.w[0] = htons(0xFE80); linkLocalAddr.w[1] = htons(0x0000); linkLocalAddr.w[2] = htons(0x0000); linkLocalAddr.w[3] = htons(0x0000); linkLocalAddr.w[4] = interfaceId.w[0]; linkLocalAddr.w[5] = interfaceId.w[1]; linkLocalAddr.w[6] = interfaceId.w[2]; linkLocalAddr.w[7] = interfaceId.w[3]; //Use the link-local address as a tentative address ipv6SetLinkLocalAddr(context->interface, &linkLocalAddr, IPV6_ADDR_STATE_TENTATIVE); //Set time stamp context->timestamp = time; //Reset timeout value context->timeout = 0; //Reset retransmission counter context->retransmitCount = 0; //Verify the uniqueness of the link-local address context->state = SLAAC_STATE_LINK_LOCAL_ADDR_DAD; } } else if(context->state == SLAAC_STATE_LINK_LOCAL_ADDR_DAD) { //Check current time if((time - context->timestamp) >= context->timeout) { //Duplicate Address Detection failed? if(context->interface->ipv6Config.linkLocalAddrDup) { //A tentative address that is determined to be a duplicate //must not be assigned to an interface ipv6SetLinkLocalAddr(context->interface, &IPV6_UNSPECIFIED_ADDR, IPV6_ADDR_STATE_INVALID); //Address autoconfiguration failed context->state = SLAAC_STATE_ERROR; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } #if (NDP_DUP_ADDR_DETECT_TRANSMITS > 0) //Duplicate Address Detection is on-going? else if(context->retransmitCount < NDP_DUP_ADDR_DETECT_TRANSMITS) { //Send Neighbor Solicitation message ndpSendNeighborSol(context->interface, &context->interface->ipv6Config.linkLocalAddr); //Save the time at which the message was sent context->timestamp = time; //Set timeout value context->timeout = NDP_RETRANS_TIMER; //Increment retransmission counter context->retransmitCount++; } #endif //Duplicate Address Detection is complete? else { //The use of the link-local address is now unrestricted context->interface->ipv6Config.linkLocalAddrState = IPV6_ADDR_STATE_PREFERRED; //Set time stamp context->timestamp = time; //Delay before transmitting the first Router Solicitation message context->timeout = tcpIpStackGetRandRange(0, NDP_MAX_RTR_SOLICITATION_DELAY); //Reset retransmission counter context->retransmitCount = 0; //To obtain an advertisement quickly, a host sends out Router Solicitations context->state = SLAAC_STATE_ROUTER_SOLICIT; } } } else if(context->state == SLAAC_STATE_ROUTER_SOLICIT) { //Check current time if((time - context->timestamp) >= context->timeout) { //Check retransmission counter if(context->retransmitCount < NDP_MAX_RTR_SOLICITATIONS) { //Send Router Solicitation message ndpSendRouterSol(context->interface); //Save the time at which the message was sent context->timestamp = time; //Set timeout value context->timeout = NDP_RTR_SOLICITATION_INTERVAL; //Increment retransmission counter context->retransmitCount++; } else { //A link has no routers if no Router Advertisements are received //after having sent a small number of Router Solicitations context->state = SLAAC_STATE_ERROR; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } } } else if(context->state == SLAAC_STATE_GLOBAL_ADDR_DAD) { //Check current time if((time - context->timestamp) >= context->timeout) { //Duplicate Address Detection failed? if(context->interface->ipv6Config.globalAddrDup) { //A tentative address that is determined to be a duplicate //must not be assigned to an interface ipv6SetGlobalAddr(context->interface, &IPV6_UNSPECIFIED_ADDR, IPV6_ADDR_STATE_INVALID); //Address autoconfiguration failed context->state = SLAAC_STATE_ERROR; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } #if (NDP_DUP_ADDR_DETECT_TRANSMITS > 0) //Duplicate Address Detection is on-going? else if(context->retransmitCount < NDP_DUP_ADDR_DETECT_TRANSMITS) { //Send Neighbor Solicitation message ndpSendNeighborSol(context->interface, &context->interface->ipv6Config.globalAddr); //Save the time at which the message was sent context->timestamp = time; //Set timeout value context->timeout = NDP_RETRANS_TIMER; //Increment retransmission counter context->retransmitCount++; } #endif //Duplicate Address Detection is complete? else { //The use of the global address is now unrestricted context->interface->ipv6Config.globalAddrState = IPV6_ADDR_STATE_PREFERRED; //Successful address autoconfiguration context->state = SLAAC_STATE_CONFIGURED; //Dump current IPv6 configuration for debugging purpose slaacDumpConfig(context); } } } //Leave critical section osReleaseMutex(&context->mutex); }
error_t wilc1000Init(NetInterface *interface) { int8_t status; tstrWifiInitParam param; //STA or AP mode? if(interface->nicDriver == &wilc1000StaDriver) { //Debug message TRACE_INFO("Initializing WILC1000 (STA mode)...\r\n"); } else { //Debug message TRACE_INFO("Initializing WILC1000 (AP mode)...\r\n"); } //Start of exception handling block do { //Initialization sequence is performed once at startup if(wilc1000StaInterface == NULL && wilc1000ApInterface == NULL) { //Low-level initialization status = nm_bsp_init(); //Check status code if(status != M2M_SUCCESS) break; //Set default parameters memset(¶m, 0, sizeof(param)); //Register callback functions param.pfAppWifiCb = wilc1000AppWifiEvent; param.pfAppMonCb = NULL; param.strEthInitParam.pfAppWifiCb = NULL; param.strEthInitParam.pfAppEthCb = wilc1000AppEthEvent; //Set receive buffer param.strEthInitParam.au8ethRcvBuf = rxBuffer; param.strEthInitParam.u16ethRcvBufSize = WILC1000_RX_BUFFER_SIZE - ETH_CRC_SIZE; //Initialize WILC1000 controller status = m2m_wifi_init(¶m); //Check status code if(status != M2M_SUCCESS) break; //Optionally set the station MAC address if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR)) { //Use the factory preprogrammed station address status = m2m_wifi_get_mac_address(interface->macAddr.b); //Check status code if(status != M2M_SUCCESS) break; //Generate the 64-bit interface identifier macAddrToEui64(&interface->macAddr, &interface->eui64); } else { //Override the factory preprogrammed address status = m2m_wifi_set_mac_address(interface->macAddr.b); //Check status code if(status != M2M_SUCCESS) break; } } else { //Initialization was already done status = M2M_SUCCESS; } //STA or AP mode? if(interface->nicDriver == &wilc1000StaDriver) { //Save underlying network interface (STA mode) wilc1000StaInterface = interface; if(wilc1000ApInterface != NULL) { wilc1000StaInterface->macAddr = wilc1000ApInterface->macAddr; wilc1000StaInterface->eui64 = wilc1000ApInterface->eui64; } } else { //Save underlying network interface (AP mode) wilc1000ApInterface = interface; if(wilc1000StaInterface != NULL) { wilc1000ApInterface->macAddr = wilc1000StaInterface->macAddr; wilc1000ApInterface->eui64 = wilc1000StaInterface->eui64; } } //End of exception handling block } while(0); //WILC1000 is now ready to send osSetEvent(&interface->nicTxEvent); //Return status code if(status == M2M_SUCCESS) return NO_ERROR; else return ERROR_FAILURE; }