/***************************************************************************** Function: static bool ARP_SendIfPkt(NET_CONFIG* pIf, uint16_t oper, uint32_t srcIP, uint32_t dstIP, MAC_ADDR* dstMAC) Description: Writes an ARP packet to the MAC using the interface pointer for src IP and MAC address. Precondition: None Parameters: Return Values: true - The ARP packet was generated properly false - otherwise ***************************************************************************/ static bool ARP_SendIfPkt(NET_CONFIG* pIf, uint16_t oper, uint32_t srcIP, uint32_t dstIP, MAC_ADDR* dstMAC) { ARP_PACKET packet; TCPIP_MAC_HANDLE hMac; packet.HardwareType = HW_ETHERNET; packet.Protocol = ARP_IP; packet.MACAddrLen = sizeof(MAC_ADDR); packet.ProtocolLen = sizeof(IP_ADDR); packet.Operation = oper; packet.SenderMACAddr = pIf->MyMACAddr; packet.SenderIPAddr.Val = srcIP; packet.TargetMACAddr = *dstMAC; packet.TargetIPAddr.Val = dstIP; SwapARPPacket(&packet); hMac = _TCPIPStackNetToMac(pIf); if(!MACIsTxReady(hMac)) { return false; } MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(packet)); MACPutArray(hMac, (uint8_t*)&packet, sizeof(packet)); MACFlush(hMac); return true; }
/***************************************************************************** Function: ARP_RESULT ARPProcess(NET_CONFIG* pIf) Summary: Processes an incoming ARP packet. Description: Retrieves an ARP packet from the MAC buffer and determines if it is a response to our request (in which case the ARP is resolved) or if it is a request requiring our response (in which case we transmit one.) Precondition: ARP packet is ready in the MAC buffer. Parameters: None Return Values: ARP_RES_OK - processing OK. ARP_RES_error - some error occurred ***************************************************************************/ ARP_RESULT ARPProcess(NET_CONFIG* pIf) { ARP_PACKET packet; MAC_ADDR *dstMAC; OA_HASH_ENTRY *hE; ARP_CACHE_DCPT *pArpDcpt; int netIx; TCPIP_MAC_HANDLE hMac; ARP_RESULT arpReqRes; netIx = _TCPIPStackNetIx(pIf); pArpDcpt = arpCache + netIx; hMac = _TCPIPStackNetToMac(pIf); // Obtain the incoming ARP packet and process MACGetArray(hMac, (uint8_t*)&packet, sizeof(packet)); MACDiscardRx(hMac); SwapARPPacket(&packet); // Validate the ARP packet if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) { return ARP_RES_OK; } #ifdef TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL ARPProcessRxPkt(pIf, &packet); #endif arpReqRes = ARP_RES_OK; // Handle incoming ARP packet hE = OAHashLookUp(pArpDcpt->cacheDcpt, &packet.SenderIPAddr.Val); if(hE != 0) { // we already have this sender and we should update it _ARPUpdateEntry(pIf, (ARP_HASH_ENTRY*)hE, &packet.SenderMACAddr); } while(packet.TargetIPAddr.Val == pIf->MyIPAddr.Val) { // we are the target and we should add to cache anyway if(hE == 0) { // not there yet arpReqRes = _ARPAddCompleteEntry(pIf, &packet.SenderIPAddr, &packet.SenderMACAddr); } // Handle incoming ARP operation if(packet.Operation == ARP_OPERATION_REQ) { // ARP packet asking for this host IP address #ifdef TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL /* Fix for Loop-Back suppression: * For ZCLL-Claim packets, host should not respond. * Check Sender's MAC-address with own MAC-address and * if it is matched, response will not be sent back. This * was leading to flooding of ARP-answeres */ if(!memcmp (&packet.SenderMACAddr, &pIf->MyMACAddr, 6)) { SYS_CONSOLE_MESSAGE("Loopback answer suppressed \r\n"); break; } #endif #if defined(TCPIP_STACK_USE_AUTO_IP) if ((packet.SenderIPAddr.Val == pIf->MyIPAddr.Val) || AutoIPConfigIsInProgress(pIf)) { AutoIPConflict(pIf); break; } #endif // Need to send a reply to the requestor #if defined(TCPIP_STACK_USE_AUTO_IP) if (AutoIPIsConfigured(pIf)) { dstMAC = &arpBcastAdd; } else #endif { dstMAC = &packet.SenderMACAddr; } // Send an ARP response to the received request if(!ARP_SendIfPkt(pIf, ARP_OPERATION_RESP, (uint32_t)pIf->MyIPAddr.Val, (uint32_t)packet.SenderIPAddr.Val, dstMAC)) { arpReqRes = ARP_RES_TX_FAILED; } } break; } return arpReqRes; }
/***************************************************************************** Function: void UDPPerformanceTask(NET_CONFIG* pConfig) Summary: Tests the transmit performance of the UDP module. Description: This function tests the transmit performance of the UDP module. At boot, this module will transmit 1024 large UDP broadcast packets of 1024 bytes each. Using a packet sniffer, one can determine how long this process takes and calculate the transmit rate of the stack. This function tests true UDP performance in that it will open a socket, transmit one packet, and close the socket for each loop. After this initial transmission, the module can be re-enabled by holding button 3. This function is particularly useful after development to determine the impact of your application code on the stack's performance. A before and after comparison will indicate if your application is unacceptably blocking the processor or taking too long to execute. Precondition: UDP is initialized. Parameters: pConfig - network to run on Returns: None ***************************************************************************/ void UDPPerformanceTask(NET_CONFIG* pConfig) { UDP_SOCKET MySocket; NODE_INFO Remote; uint16_t wTemp; static uint32_t dwCounter = 1; if((BUTTON3_IO) && (dwCounter > 1024u)) return; // Suppress transmissions if we don't have an Ethernet link so our counter starts correctly at 0x00000001 if(!MACIsLinked(_TCPIPStackNetToMac(pConfig))) return; #if defined(TCPIP_STACK_USE_DHCP_CLIENT) && defined(DELAY_UDP_PERFORMANCE_TEST) { static SYS_TICK dwTimer = 0; // Wait until DHCP module is finished if(!DHCPIsBound(pConfig)) { dwTimer = SYS_TICK_Get(); return; } // Wait an additional half second after DHCP is finished to let the announce module and any other stack state machines to reach normal operation if(SYS_TICK_Get() - dwTimer < SYS_TICK_TicksPerSecondGet()/2) return; } #endif // Set the socket's destination to be a broadcast over our IP // subnet // Set the MAC destination to be a broadcast memset(&Remote, 0xFF, sizeof(Remote)); // Open a UDP socket for outbound transmission MySocket = UDPOpen((uint32_t)&Remote,UDP_OPEN_NODE_INFO,0,PERFORMANCE_PORT); // Abort operation if no UDP sockets are available // If this ever happens, incrementing UDP_MAX_SOCKETS in // udp_config.h may help (at the expense of more global memory // resources). if(MySocket == INVALID_UDP_SOCKET) return; UDPSocketSetNet(MySocket, pConfig); // Make certain the socket can be written to if(!UDPIsPutReady(MySocket)) { UDPClose(MySocket); return; } // Put counter value into first 4 bytes of the packet UDPPutArray(MySocket, (uint8_t*)&dwCounter, sizeof(dwCounter)); dwCounter++; wTemp = UDPPutArray(MySocket, (const uint8_t*) "The quick brown fox tried to jump over the yellow dog. Unfortunately, the yellow dog stood up while the fox was in mid-jump. As a result, the two collided. Then, the dog, being the omnivore that it is, ate the quick brown fox. This line is 256 bytes.\r\n" "The quick brown fox tried to jump over the yellow dog. Unfortunately, the yellow dog stood up while the fox was in mid-jump. As a result, the two collided. Then, the dog, being the omnivore that it is, ate the quick brown fox. This line is 256 bytes.\r\n" "The quick brown fox tried to jump over the yellow dog. Unfortunately, the yellow dog stood up while the fox was in mid-jump. As a result, the two collided. Then, the dog, being the omnivore that it is, ate the quick brown fox. This line is 256 bytes.\r\n" "The quick brown fox tried to jump over the yellow dog. Unfortunately, the yellow dog stood up while the fox was in mid-jump. As a result, the two collided. Then, the dog, being the omnivore that it is, ate the quick brown fox. This line is 252b. \r\n", 1020); // Send the packet UDPFlush(MySocket); // Close the socket so it can be used by other modules UDPClose(MySocket); }
void ANNOUNCE_Send(void) { UDP_SOCKET announceSocket; int netIx; uint16_t dataLen; uint16_t minimumDataLen; uint16_t txLen; bool truncated; NET_CONFIG * pNetIf; ANNOUNCE_LIST_NODE * node = (ANNOUNCE_LIST_NODE *)announceEvents.head; ANNOUNCE_FIELD_PAYLOAD payloadType; uint16_t terminatorLen = strlen ((const char *)announceFieldTerminator); #if defined (TCPIP_STACK_USE_IPV6) IPV6_ADDR_STRUCT * addressPointer; #endif while (node != NULL) { pNetIf = (NET_CONFIG *)node->handle; netIx = TCPIP_STACK_NetIx (pNetIf); truncated = false; dataLen = ((terminatorLen + 1) * 4) + sizeof (IPV4_ADDR) + sizeof (MAC_ADDR); dataLen += strlen(TCPIP_HOSTS_CONFIGURATION[netIx].interface); dataLen += strlen((char *)pNetIf->NetBIOSName); minimumDataLen = dataLen + 1 + terminatorLen; if(!MACIsLinked(_TCPIPStackNetToMac(pNetIf))) // Check for link before blindly opening and transmitting (similar to DHCP case) { return; } announceSocket = UDPOpenClient(IP_ADDRESS_TYPE_IPV4, ANNOUNCE_PORT, 0); if (announceSocket == INVALID_UDP_SOCKET) { return; } UDPSocketSetNet (announceSocket, pNetIf); #if defined (TCPIP_STACK_USE_IPV6) addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6UnicastAddresses.head; while(addressPointer != NULL) { dataLen += sizeof (IPV6_ADDR) + 1 + terminatorLen; addressPointer = addressPointer->next; } addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6MulticastAddresses.head; while(addressPointer != NULL) { dataLen += sizeof (IPV6_ADDR) + 1 + terminatorLen; addressPointer = addressPointer->next; } #endif if (dataLen > ANNOUNCE_MAX_PAYLOAD) { dataLen = ANNOUNCE_MAX_PAYLOAD; } if ((txLen = UDPIsTxPutReady(announceSocket, dataLen)) < dataLen) { truncated = true; if ((txLen = UDPIsTxPutReady(announceSocket, minimumDataLen)) < minimumDataLen) { UDPClose (announceSocket); return; } } // Put Mac Address payloadType = ANNOUNCE_FIELD_MAC_ADDR; UDPPut (announceSocket, payloadType); UDPPutArray(announceSocket, (const uint8_t *)&pNetIf->MyMACAddr, sizeof (MAC_ADDR)); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); if (truncated) { payloadType = ANNOUNCE_FIELD_TRUNCATED; UDPPut (announceSocket, payloadType); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); } // Put Mac Type payloadType = ANNOUNCE_FIELD_MAC_TYPE; UDPPut (announceSocket, payloadType); UDPPutArray(announceSocket, (const uint8_t *)TCPIP_HOSTS_CONFIGURATION[netIx].interface, strlen ((const char *)TCPIP_HOSTS_CONFIGURATION[netIx].interface)); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); // Put Host Name payloadType = ANNOUNCE_FIELD_HOST_NAME; UDPPut (announceSocket, payloadType); UDPPutArray(announceSocket, (const uint8_t *)&pNetIf->NetBIOSName, strlen((char*)pNetIf->NetBIOSName)); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); // Put IPv4 Address payloadType = ANNOUNCE_FIELD_IPV4_ADDRESS; UDPPut (announceSocket, payloadType); UDPPutArray(announceSocket, (const uint8_t *)&pNetIf->MyIPAddr, sizeof (IP_ADDR)); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); #if defined (TCPIP_STACK_USE_IPV6) // Put IPv6 unicast addresses minimumDataLen = sizeof (IPV6_ADDR) + 1 + terminatorLen; addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6UnicastAddresses.head; payloadType = ANNOUNCE_FIELD_IPV6_UNICAST; while(addressPointer != NULL && (UDPIsTxPutReady(announceSocket, minimumDataLen) >= minimumDataLen)) { UDPPut (announceSocket, payloadType); UDPPutArray(announceSocket, (const uint8_t *)&addressPointer->address, sizeof (IPV6_ADDR)); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); addressPointer = addressPointer->next; } // Put IPv6 multicast listeners addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6MulticastAddresses.head; payloadType = ANNOUNCE_FIELD_IPV6_MULTICAST; while(addressPointer != NULL && (UDPIsTxPutReady(announceSocket, minimumDataLen) >= minimumDataLen)) { UDPPut (announceSocket, payloadType); UDPPutArray(announceSocket, (const uint8_t *)&addressPointer->address, sizeof (IPV6_ADDR)); UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen); addressPointer = addressPointer->next; } #endif UDPFlush (announceSocket); UDPClose (announceSocket); SingleListRemoveHead(&announceEvents); TCPIP_HEAP_Free (announceMemH, node); node = (ANNOUNCE_LIST_NODE *)announceEvents.head; if (node == NULL) { announceEventPending = false; } } }
void AutoIPTasks(NET_CONFIG* pConfig) { // uint8_t i; TCPIP_MAC_HANDLE hMac; // for (i = 0; i < NETWORK_INTERFACES; i++) { LoadState(_TCPIPStackNetIx(pConfig)); hMac = _TCPIPStackNetToMac(pConfig); AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(hMac); if(AutoIPClient.flags.bits.bCurrentLinkState != AutoIPClient.flags.bits.bLastLinkState) { AutoIPClient.flags.bits.bLastLinkState = AutoIPClient.flags.bits.bCurrentLinkState; if(!AutoIPClient.flags.bits.bCurrentLinkState) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val; pConfig->MyMask.Val = pConfig->DefaultMask.Val; } else { AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } } #if defined (TCPIP_STACK_USE_DHCP_CLIENT) if (DHCPIsBound(pConfig)) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AutoIPClient.flags.bits.bLastDHCPState = true; } else { if (AutoIPClient.flags.bits.bLastDHCPState == true) { if (AutoIPClient.flags.bits.bCurrentLinkState) AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } AutoIPClient.flags.bits.bLastDHCPState = false; } #endif if (AutoIPClient.flags.bits.gDisableAutoIP == true) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; } switch (AutoIPClient.smAUTOIPState) { // Default no-AutoIP case case SM_AUTOIP_DISABLED: break; // Initializes the random number generator with a seed based on the MAC address case SM_AUTOIP_INIT_RNG: AutoIPRandSeed (((uint32_t)pConfig->MyMACAddr.v[0] + ((uint32_t)pConfig->MyMACAddr.v[1] << 8) + \ ((uint32_t)pConfig->MyMACAddr.v[2] << 16) + ((uint32_t)pConfig->MyMACAddr.v[3] << 24) + \ ((uint32_t)pConfig->MyMACAddr.v[4]) + ((uint32_t)pConfig->MyMACAddr.v[5] << 8)), pConfig); AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; // Check the address to see if it's in use before we write it into NetConfig case SM_AUTOIP_CHECK_ADDRESS: if (AutoIPClient.flags.bits.checkAddress == false) { AutoIPClient.flags.bits.checkAddress = true; pConfig->MyMask.Val = 0x00000000; // Generate a random IP address (based on the MAC address) to try and claim. // Dynamic link-local addresses can fall within the range: // 169.254.1.0 - 169.254.254.255 AutoIPClient.packet.TargetIPAddr.byte.MB = AutoIPRand(pConfig) % 256; AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(pConfig) % 254) + 1; AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9; ARPResolve (pConfig, &AutoIPClient.packet.TargetIPAddr); AutoIPClient.eventTime = SYS_TICK_Get(); } if (!ARPIsResolved (pConfig, &AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr)) { if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet()) { AutoIPClient.smAUTOIPState = SM_AUTOIP_SETUP_MESSAGE; } } else { AutoIPClient.flags.bits.checkAddress = false; } break; // Set up an ARP packet case SM_AUTOIP_SETUP_MESSAGE: AutoIPClient.flags.bits.checkAddress = false; // Set the bConfigureAutoIP flag- This flag will cause an AutoIP conflict // if a response packet is received from the address we're trying to claim. AutoIPClient.flags.bits.bConfigureAutoIP = true; // Configure the fields for a gratuitous ARP packet AutoIPClient.packet.Operation = ARP_OPERATION_REQ; AutoIPClient.packet.TargetMACAddr.v[0] = 0xff; AutoIPClient.packet.TargetMACAddr.v[1] = 0xff; AutoIPClient.packet.TargetMACAddr.v[2] = 0xff; AutoIPClient.packet.TargetMACAddr.v[3] = 0xff; AutoIPClient.packet.TargetMACAddr.v[4] = 0xff; AutoIPClient.packet.TargetMACAddr.v[5] = 0xff; pConfig->MyIPAddr = AutoIPClient.packet.TargetIPAddr; pConfig->MyMask.Val = 0x0000FFFF; memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&pConfig->MyMACAddr, sizeof(AutoIPClient.packet.SenderMACAddr)); AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; AutoIPClient.packet.MACAddrLen = sizeof(MAC_ADDR); AutoIPClient.packet.ProtocolLen = sizeof(IP_ADDR); AutoIPClient.packet.SenderIPAddr.Val = AutoIPClient.packet.TargetIPAddr.Val; SwapARPPacket(&AutoIPClient.packet); // Generate a random delay between 0 and 1 second AutoIPClient.randomDelay = ((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20; // Store the current time AutoIPClient.eventTime = SYS_TICK_Get(); // Set the state to send the ARP packet AutoIPClient.smAUTOIPState = SM_AUTOIP_GRATUITOUS_ARP1; break; // Send a gratuitous ARP packet to try and claim our address case SM_AUTOIP_GRATUITOUS_ARP1: case SM_AUTOIP_GRATUITOUS_ARP2: case SM_AUTOIP_GRATUITOUS_ARP3: // Check to ensure we've passed the delay time if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay) { if(!MACIsTxReady(hMac)) { break; } // Store the new event time AutoIPClient.eventTime = SYS_TICK_Get(); // Generate a new random delay between 1 and 2 seconds AutoIPClient.randomDelay = SYS_TICK_TicksPerSecondGet() + (((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20); // Transmit the packet MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet)); MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(hMac); // Increment the probe iteration or increment to the delay state AutoIPClient.smAUTOIPState++; } break; // Delay for 1-2 seconds after sending the third ARP request before // entering the configured state case SM_AUTOIP_DELAY: if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay) AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; // Configure the module to limit the rate at which packets are sent case SM_AUTOIP_RATE_LIMIT_SET: AutoIPClient.eventTime = SYS_TICK_Get(); pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val; AutoIPClient.smAUTOIPState = SM_AUTOIP_RATE_LIMIT_WAIT; break; // Ensure that we don't try more than one address every 60 seconds case SM_AUTOIP_RATE_LIMIT_WAIT: if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet() * 60) AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; break; // Configured state case SM_AUTOIP_CONFIGURED: AutoIPClient.flags.bits.bConfigureAutoIP = false; break; // Address defense state case SM_AUTOIP_DEFEND: // Prepare and send an ARP response if(!MACIsTxReady(hMac)) { break; } AutoIPClient.packet.Operation = ARP_OPERATION_RESP; AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; SwapARPPacket(&AutoIPClient.packet); MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet)); MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(hMac); AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; } } }