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; }
error_t ndpSendNeighborSol(NetInterface *interface, const Ipv6Addr *targetIpAddr) { error_t error; size_t offset; size_t length; ChunkedBuffer *buffer; NdpNeighborSolMessage *message; Ipv6PseudoHeader pseudoHeader; //Allocate a memory buffer to hold the Neighbor Solicitation //message and the Source Link-Layer Address option buffer = ipAllocBuffer(sizeof(NdpNeighborSolMessage) + sizeof(NdpLinkLayerAddrOption), &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Format Neighbor Solicitation message message->type = ICMPV6_TYPE_NEIGHBOR_SOL; message->code = 0; message->checksum = 0; message->reserved = 0; message->targetAddr = *targetIpAddr; //Length of the message, excluding any option length = sizeof(NdpNeighborSolMessage); //Check whether the target address is a tentative address if(ipv6IsTentativeAddr(interface, targetIpAddr)) { //The IPv6 source is set to the unspecified address pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR; } else { //The Source Link-Layer Address option must not be included //when the host IPv6 address is unspecified if(!ipv6CompAddr(&interface->ipv6Config.linkLocalAddr, &IPV6_UNSPECIFIED_ADDR)) { //Add Source Link-Layer Address option ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR, &interface->macAddr, sizeof(MacAddr)); } //Set the IPv6 source address pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr; } //Adjust the length of the multi-part buffer chunkedBufferSetLength(buffer, offset + length); //Compute the solicited-node multicast address that //corresponds to the target IPv6 address ipv6ComputeSolicitedNodeAddr(targetIpAddr, &pseudoHeader.destAddr); //Format IPv6 pseudo header pseudoHeader.length = htonl(length); pseudoHeader.reserved = 0; pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER; //Calculate ICMPv6 header checksum message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader, sizeof(Ipv6PseudoHeader), buffer, offset, length); //Debug message TRACE_INFO("Sending Neighbor Solicitation message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborSolMessage(message); //Send Neighbor Solicitation message error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t tcpIpStackConfigInterface(NetInterface *interface) { error_t error; //IPv6 specific variables #if (IPV6_SUPPORT == ENABLED) Ipv6Addr solicitedNodeAddr; #endif //Disable Ethernet controller interrupts interface->nicDriver->disableIrq(interface); //Start of exception handling block do { //Receive notifications when the transmitter is ready to send interface->nicTxEvent = osEventCreate(FALSE, FALSE); //Out of resources? if(interface->nicTxEvent == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop immediately break; } //Receive notifications when a Ethernet frame has been received, //or the link status has changed interface->nicRxEvent = osEventCreate(FALSE, FALSE); //Out of resources? if(interface->nicRxEvent == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop immediately break; } //Create a mutex to prevent simultaneous access to the NIC driver interface->nicDriverMutex = osMutexCreate(FALSE); //Out of resources? if(interface->nicDriverMutex == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop immediately break; } //Ethernet controller configuration error = interface->nicDriver->init(interface); //Any error to report? if(error) break; //Ethernet related initialization error = ethInit(interface); //Any error to report? if(error) break; //IPv4 specific initialization #if (IPV4_SUPPORT == ENABLED) //Network layer initialization error = ipv4Init(interface); //Any error to report? if(error) break; //ARP cache initialization error = arpInit(interface); //Any error to report? if(error) break; #if (IGMP_SUPPORT == ENABLED) //IGMP related initialization error = igmpInit(interface); //Any error to report? if(error) break; //Join the all-systems group error = ipv4JoinMulticastGroup(interface, IGMP_ALL_SYSTEMS_ADDR); //Any error to report? if(error) break; #endif #endif //IPv6 specific initialization #if (IPV6_SUPPORT == ENABLED) //Network layer initialization error = ipv6Init(interface); //Any error to report? if(error) break; //Neighbor cache initialization error = ndpInit(interface); //Any error to report? if(error) break; #if (MLD_SUPPORT == ENABLED) ///MLD related initialization error = mldInit(interface); //Any error to report? if(error) break; #endif //Join the All-Nodes multicast address error = ipv6JoinMulticastGroup(interface, &IPV6_LINK_LOCAL_ALL_NODES_ADDR); //Any error to report? if(error) break; //Form the Solicited-Node address for the link-local address error = ipv6ComputeSolicitedNodeAddr(&interface->ipv6Config.linkLocalAddr, &solicitedNodeAddr); //Any error to report? if(error) break; //Join the Solicited-Node multicast group for each assigned address error = ipv6JoinMulticastGroup(interface, &solicitedNodeAddr); //Any error to report? if(error) break; #endif //Create a task to process incoming frames interface->rxTask = osTaskCreate("TCP/IP Stack (RX)", tcpIpStackRxTask, interface, TCP_IP_RX_STACK_SIZE, TCP_IP_RX_PRIORITY); //Unable to create the task? if(interface->rxTask == OS_INVALID_HANDLE) error = ERROR_OUT_OF_RESOURCES; //End of exception handling block } while(0); //Check whether the interface is fully configured if(!error) { //Successful interface configuration interface->configured = TRUE; //Interrupts can be safely enabled interface->nicDriver->enableIrq(interface); } else { //Clean up side effects before returning osEventClose(interface->nicTxEvent); osEventClose(interface->nicRxEvent); osMutexClose(interface->nicDriverMutex); } //Return status code return error; }