error_t wilc1000SetMulticastFilter(NetInterface *interface) { uint_t i; MacFilterEntry *entry; //Debug message TRACE_INFO("Updating WILC1000 multicast filter...\r\n"); //The MAC filter table contains the multicast MAC addresses //to accept when receiving an Ethernet frame for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++) { //Point to the current entry entry = &interface->macMulticastFilter[i]; //Check whether the MAC filter table should be updated for the //current multicast address if(!macCompAddr(&entry->addr, &MAC_UNSPECIFIED_ADDR)) { if(entry->addFlag) { //Add a new entry to the MAC filter table m2m_wifi_enable_mac_mcast(entry->addr.b, TRUE); } else if(entry->deleteFlag) { //Remove the current entry from the MAC filter table m2m_wifi_enable_mac_mcast(entry->addr.b, FALSE); } } } //Successful processing return NO_ERROR; }
void ndpProcessNeighborAdv(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit) { size_t length; NdpNeighborAdvMessage *message; NdpLinkLayerAddrOption *option; NdpCacheEntry *entry; //Retrieve the length of the message length = chunkedBufferGetLength(buffer) - offset; //Check the length of the Neighbor Advertisement message if(length < sizeof(NdpNeighborAdvMessage)) return; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("Neighbor Advertisement message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborAdvMessage(message); //The IPv6 Hop Limit field must have a value of 255 to ensure //that the packet has not been forwarded by a router if(hopLimit != NDP_HOP_LIMIT) return; //ICMPv6 Code must be 0 if(message->code) return; //Check whether the target address is tentative or matches //a unicast address assigned to the interface if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.linkLocalAddr) && interface->ipv6Config.linkLocalAddrState != IPV6_ADDR_STATE_INVALID) { //Debug message TRACE_WARNING("The address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, NULL)); //The address is a duplicate and should not be used interface->ipv6Config.linkLocalAddrDup = TRUE; //Exit immediately return; } else if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr) && interface->ipv6Config.globalAddrState != IPV6_ADDR_STATE_INVALID) { //Debug message TRACE_WARNING("The address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.globalAddr, NULL)); //The address is a duplicate and should not be used interface->ipv6Config.globalAddrDup = TRUE; //Exit immediately return; } //The target address must not be a multicast address if(ipv6IsMulticastAddr(&message->targetAddr)) { //Debug message TRACE_WARNING("Target address must not be a multicast address!\r\n"); //Exit immediately return; } //If the destination address is a multicast address //then the Solicited flag must be zero if(ipv6IsMulticastAddr(&pseudoHeader->destAddr) && message->s) { //Debug message TRACE_WARNING("Solicited flag must be zero!\r\n"); //Exit immediately return; } //Calculate the length of the Options field length -= sizeof(NdpNeighborSolMessage); //Search for the Target Link-Layer Address option option = ndpGetOption(message->options, length, NDP_OPT_TARGET_LINK_LAYER_ADDR); //Source Link-Layer Address option found? if(option && option->length == 1) { //Debug message TRACE_DEBUG(" Target Link-Layer Address = %s\r\n", macAddrToString(&option->linkLayerAddr, NULL)); //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Search the Neighbor cache for the specified target address entry = ndpFindEntry(interface, &message->targetAddr); //If no entry exists, the advertisement should be silently discarded if(entry) { //INCOMPLETE state? if(entry->state == NDP_STATE_INCOMPLETE) { //Record link-layer address entry->macAddr = option->linkLayerAddr; //Send all the packets that are pending for transmission ndpSendQueuedPackets(interface, entry); //Save current time entry->timestamp = osGetSystemTime(); //Solicited flag is set? if(message->s) { //Computing the random ReachableTime value entry->timeout = NDP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = NDP_STATE_REACHABLE; } //Solicited flag is cleared? else { //Enter the STALE state entry->state = NDP_STATE_STALE; } } //REACHABLE, STALE, DELAY or PROBE state? else { //Solicited flag is set and Override flag is cleared? if(message->s && !message->o) { //Same link-layer address than cached? if(macCompAddr(&entry->macAddr, &option->linkLayerAddr)) { //Save current time entry->timestamp = osGetSystemTime(); //Computing the random ReachableTime value entry->timeout = NDP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = NDP_STATE_REACHABLE; } //Different link-layer address than cached? else { //REACHABLE state? if(entry->state == NDP_STATE_REACHABLE) { //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } } //Both Solicited and Override flags are set? else if(message->s && message->o) { //Record link-layer address (if different) entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Computing the random ReachableTime value entry->timeout = NDP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = NDP_STATE_REACHABLE; } //Solicited flag is cleared and Override flag is set? else if(!message->s && message->o) { //Different link-layer address than cached? if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr)) { //Record link-layer address entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } } } } //Source Link-Layer Address option not found? else { //Update content of IsRouter flag } //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); }
void ndpProcessNeighborSol(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit) { size_t length; NdpNeighborSolMessage *message; NdpLinkLayerAddrOption *option; NdpCacheEntry *entry; //Retrieve the length of the message length = chunkedBufferGetLength(buffer) - offset; //Check the length of the Neighbor Solicitation message if(length < sizeof(NdpNeighborSolMessage)) return; //Point to the beginning of the message message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("Neighbor Solicitation message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message contents for debugging purpose ndpDumpNeighborSolMessage(message); //The IPv6 Hop Limit field must have a value of 255 to ensure //that the packet has not been forwarded by a router if(hopLimit != NDP_HOP_LIMIT) return; //ICMPv6 Code must be 0 if(message->code) return; //The target address must a valid unicast address assigned to the interface //or a tentative address on which DAD is being performed if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.linkLocalAddr)) { //Check whether the target address is tentative if(interface->ipv6Config.linkLocalAddrState == IPV6_ADDR_STATE_TENTATIVE) { //If the source address of the Neighbor Solicitation is the unspecified //address, the solicitation is from a node performing Duplicate Address //Detection if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR)) { //Debug message TRACE_WARNING("The tentative address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, NULL)); //The tentative address is a duplicate and should not be used interface->ipv6Config.linkLocalAddrDup = TRUE; } //In all cases, a node must not respond to a Neighbor Solicitation //for a tentative address return; } } else if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr)) { //Check whether the target address is tentative if(interface->ipv6Config.globalAddrState == IPV6_ADDR_STATE_TENTATIVE) { //If the source address of the Neighbor Solicitation is the unspecified //address, the solicitation is from a node performing Duplicate Address //Detection if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR)) { //Debug message TRACE_WARNING("The tentative address %s is a duplicate!\r\n", ipv6AddrToString(&interface->ipv6Config.globalAddr, NULL)); //The tentative address is a duplicate and should not be used interface->ipv6Config.globalAddrDup = TRUE; } //In all cases, a node must not respond to a Neighbor Solicitation //for a tentative address return; } } else { //Debug message TRACE_WARNING("Wrong target address!\r\n"); //Exit immediately return; } //If the IP source address is the unspecified address, the IP //destination address must be a solicited-node multicast address if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) && !ipv6IsSolicitedNodeAddr(&pseudoHeader->destAddr)) { //Debug message TRACE_WARNING("Destination address must be a solicited-node address!\r\n"); //Exit immediately return; } //Calculate the length of the Options field length -= sizeof(NdpNeighborSolMessage); //Search for the Source Link-Layer Address option option = ndpGetOption(message->options, length, NDP_OPT_SOURCE_LINK_LAYER_ADDR); //Source Link-Layer Address option found? if(option && option->length == 1) { //Debug message TRACE_DEBUG(" Source Link-Layer Address = %s\r\n", macAddrToString(&option->linkLayerAddr, NULL)); //If the Source Address is not the unspecified address, then the Neighbor //cache should be updated for the IP source address of the solicitation if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR)) return; //Acquire exclusive access to Neighbor cache osAcquireMutex(&interface->ndpCacheMutex); //Search the Neighbor cache for the source address of the solicitation entry = ndpFindEntry(interface, &pseudoHeader->srcAddr); //No matching entry has been found? if(!entry) { //Create an entry entry = ndpCreateEntry(interface); //Neighbor cache entry successfully created? if(entry) { //Record the IPv6 and the corresponding MAC address entry->ipAddr = pseudoHeader->srcAddr; entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } else { //INCOMPLETE state? if(entry->state == NDP_STATE_INCOMPLETE) { //Record link-layer address entry->macAddr = option->linkLayerAddr; //Send all the packets that are pending for transmission ndpSendQueuedPackets(interface, entry); //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } //REACHABLE, STALE, DELAY or PROBE state? else { //Different link-layer address than cached? if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr)) { //Update link-layer address entry->macAddr = option->linkLayerAddr; //Save current time entry->timestamp = osGetSystemTime(); //Enter the STALE state entry->state = NDP_STATE_STALE; } } } //Release exclusive access to Neighbor cache osReleaseMutex(&interface->ndpCacheMutex); } //Source Link-Layer Address option not found? else { //This option must be included in multicast solicitations if(ipv6IsMulticastAddr(&pseudoHeader->destAddr)) { //Debug message TRACE_WARNING("The Source Link-Layer Address must be included!\r\n"); //Exit immediately return; } } //After any updates to the Neighbor cache, the node sends a Neighbor //Advertisement response as described in RFC 4861 7.2.4 ndpSendNeighborAdv(interface, &message->targetAddr, &pseudoHeader->srcAddr); }
void arpProcessReply(NetInterface *interface, ArpPacket *arpReply) { ArpCacheEntry *entry; //Debug message TRACE_INFO("ARP Reply received...\r\n"); //Check sender protocol address if(arpReply->spa == IPV4_UNSPECIFIED_ADDR) return; if(ipv4IsMulticastAddr(arpReply->spa)) return; if(ipv4IsBroadcastAddr(interface, arpReply->spa)) return; //Check sender hardware address if(macCompAddr(&arpReply->sha, &MAC_UNSPECIFIED_ADDR)) return; if(macCompAddr(&arpReply->sha, &MAC_BROADCAST_ADDR)) return; //Acquire exclusive access to ARP cache osMutexAcquire(interface->arpCacheMutex); //Search the ARP cache for the specified IPv4 address entry = arpFindEntry(interface, arpReply->spa); //A matching ARP entry has been found if(entry) { //Check current state if(entry->state == ARP_STATE_INCOMPLETE) { //Record the corresponding MAC address entry->macAddr = arpReply->sha; //Send all the packets that are pending for transmission arpSendQueuedPackets(interface, entry); //Save current time entry->timestamp = osGetTickCount(); //The validity of the ARP entry is limited in time entry->timeout = ARP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = ARP_STATE_REACHABLE; } else if(entry->state == ARP_STATE_REACHABLE) { //Different link-layer address than cached? if(!macCompAddr(&arpReply->sha, &entry->macAddr)) { //Enter STALE state entry->state = ARP_STATE_STALE; } } else if(entry->state == ARP_STATE_PROBE) { //Record IPv4/MAC address pair entry->ipAddr = arpReply->spa; entry->macAddr = arpReply->sha; //Save current time entry->timestamp = osGetTickCount(); //The validity of the ARP entry is limited in time entry->timeout = ARP_REACHABLE_TIME; //Switch to the REACHABLE state entry->state = ARP_STATE_REACHABLE; } } //Release exclusive access to ARP cache osMutexRelease(interface->arpCacheMutex); }
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; }