/***************************************************************************** Function: static bool ARPPut(ARP_PACKET* packet) Description: Writes an ARP packet to the MAC. Precondition: None Parameters: packet - A pointer to an ARP_PACKET structure with correct operation and target preconfigured. Return Values: true - The ARP packet was generated properly false - Not a possible return value ***************************************************************************/ static bool ARPPut(ARP_PACKET* packet) { while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); packet->HardwareType = HW_ETHERNET; packet->Protocol = ARP_IP; packet->MACAddrLen = sizeof(MAC_ADDR); packet->ProtocolLen = sizeof(IP_ADDR); // packet->SenderMACAddr = AppConfig.MyMACAddr; // HI-TECH PICC-18 compiler can't handle this statement, use memcpy() as a workaround memcpy(&packet->SenderMACAddr, (void*)&AppConfig.MyMACAddr, sizeof(packet->SenderMACAddr)); #ifdef STACK_USE_ZEROCONF_LINK_LOCAL //packet->SenderIPAddr = AppConfig.MyIPAddr; /* Removed for ZCLL, SenderIPAddr should be filled in */ #else packet->SenderIPAddr = AppConfig.MyIPAddr; #endif SwapARPPacket(packet); MACPutHeader(&packet->TargetMACAddr, MAC_ARP, sizeof(*packet)); MACPutArray((uint8_t*)packet, sizeof(*packet)); MACFlush(); return true; }
/********************************************************************* * Function: WORD IPPutHeader(NODE_INFO *remote, * BYTE protocol, * WORD len) * * PreCondition: IPIsTxReady() == TRUE * * Input: *remote - Destination node address * protocol - Current packet protocol * len - Current packet data length * * Output: (WORD)0 * * Side Effects: None * * Note: Only one IP message can be transmitted at any * time. ********************************************************************/ WORD IPPutHeader(NODE_INFO *remote, BYTE protocol, WORD len) { IP_HEADER header; IPHeaderLen = sizeof(IP_HEADER); header.VersionIHL = IP_VERSION | IP_IHL; header.TypeOfService = IP_SERVICE; header.TotalLength = sizeof(header) + len; header.Identification = ++_Identifier; header.FragmentInfo = 0; header.TimeToLive = MY_IP_TTL; header.Protocol = protocol; header.HeaderChecksum = 0; header.SourceAddress = AppConfig.MyIPAddr; header.DestAddress.Val = remote->IPAddr.Val; SwapIPHeader(&header); header.HeaderChecksum = CalcIPChecksum((BYTE*)&header, sizeof(header)); MACPutHeader(&remote->MACAddr, MAC_IP, (sizeof(header)+len)); MACPutArray((BYTE*)&header, sizeof(header)); return 0x0000; }
/***************************************************************************** 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: void ARPPut(NODE_INFO* more, BYTE opCode) * * PreCondition: None * * Input: remote - Remote node info * opCode - ARP op code to send * * Output: TRUE - The ARP packet was generated properly * FALSE - Unable to allocate a TX buffer * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ BOOL ARPPut(NODE_INFO *remote, BYTE opCode) { ARP_PACKET packet; BUFFER MyTxBuffer; MyTxBuffer = MACGetTxBuffer(TRUE); // Do not respond if there is no room to generate the ARP reply if(MyTxBuffer == INVALID_BUFFER) return FALSE; MACSetTxBuffer(MyTxBuffer, 0); packet.HardwareType = HW_ETHERNET; packet.Protocol = ARP_IP; packet.MACAddrLen = sizeof(MAC_ADDR); packet.ProtocolLen = sizeof(IP_ADDR); if ( opCode == ARP_REQUEST ) { packet.Operation = ARP_OPERATION_REQ; packet.TargetMACAddr.v[0] = 0xff; packet.TargetMACAddr.v[1] = 0xff; packet.TargetMACAddr.v[2] = 0xff; packet.TargetMACAddr.v[3] = 0xff; packet.TargetMACAddr.v[4] = 0xff; packet.TargetMACAddr.v[5] = 0xff; } else { packet.Operation = ARP_OPERATION_RESP; packet.TargetMACAddr = remote->MACAddr; } packet.SenderMACAddr = AppConfig.MyMACAddr; packet.SenderIPAddr = AppConfig.MyIPAddr; // Check to see if target is on same subnet, if not, find Gateway MAC. // Once we get Gateway MAC, all access to remote host will go through Gateway. if((packet.SenderIPAddr.Val ^ remote->IPAddr.Val) & AppConfig.MyMask.Val) { packet.TargetIPAddr = AppConfig.MyGateway; } else packet.TargetIPAddr = remote->IPAddr; SwapARPPacket(&packet); MACPutHeader(&packet.TargetMACAddr, MAC_ARP, sizeof(packet)); //MACPutArray((int8*)&packet, sizeof(packet)); MACPutArray(&packet, sizeof(ARP_PACKET)); MACFlush(); return TRUE; }
/** * Write the Ethernet Header (MAC Header) and IP Header to the current TX buffer. * The last parameter (len) is the length of the data to follow. * This function will do the following: <ul> * <li> Reset the NIC Remote DMA write pointer to the first byte of the current TX Buffer </li> * <li> Write the given header </li> * <li> Set the NIC Remote DMA byte count to the given len. This configures the Remote DMA * to send the given number of bytes. Only one IP message can be transmitted at any time. * Caller may not transmit and receive a message at the same time.</li></ul> * * @preCondition IPIsTxReady() == TRUE * * @param remote Destination node address * @param protocol Protocol of data to follow, for example IP_PROT_ICMP, IP_PROT_TCP.... * @param len Total length of IP data bytes to follow, excluding IP header. This * is the length of the bytes to follow. * * @return Handle to current packet - For use by IPSendByte() function. * */ WORD IPPutHeader(NODE_INFO *remote, BYTE protocol, WORD len) { IP_HEADER header; header.VersionIHL = IP_VERSION | IP_IHL; header.TypeOfService = IP_SERVICE; header.TotalLength.Val = sizeof(header) + len; header.Identification.Val = ++_Identifier; /** Set the Don't fragment flag for all IP message we sent. We do NOT want to get fragmented data! */ header.FragmentInfo.Val = IP_FLAG_MASK_DF; header.TimeToLive = MY_IP_TTL; header.Protocol = protocol; header.HeaderChecksum.Val = 0; header.SourceAddress.v[0] = MY_IP_BYTE1; header.SourceAddress.v[1] = MY_IP_BYTE2; header.SourceAddress.v[2] = MY_IP_BYTE3; header.SourceAddress.v[3] = MY_IP_BYTE4; header.DestAddress.Val = remote->IPAddr.Val; SwapIPHeader(&header); header.HeaderChecksum.Val = CalcIPChecksum((BYTE*)&header, sizeof(header)); //Write the Ethernet Header to the current TX buffer. The last parameter (dataLen) is the length //of the data to follow. This function will do the following: // - Reset the NIC Remote DMA write pointer to the first byte of the current TX Buffer // - Write the given header // - Set the NIC Remote DMA byte count to the given len. This configures the Remote DMA to // receive the given number of bytes MACPutHeader(&remote->MACAddr, MAC_IP, (sizeof(header)+len)); //Write the IP header to the MAC's TX buffer. MACPutArray((BYTE*)&header, sizeof(header)); return 0x0; }
/********************************************************************* * Function: WORD IPPutHeader(NODE_INFO *remote, * BYTE protocol, * WORD len) * * PreCondition: IPIsTxReady() == TRUE * * Input: *remote - Destination node address * protocol - Current packet protocol * len - Current packet data length * * Output: (WORD)0 * * Side Effects: None * * Note: Only one IP message can be transmitted at any * time. ********************************************************************/ WORD IPPutHeader(NODE_INFO *remote, BYTE protocol, WORD len) { IP_HEADER header; IPHeaderLen = sizeof(IP_HEADER); header.VersionIHL = IP_VERSION | IP_IHL; header.TypeOfService = IP_SERVICE; header.TotalLength = sizeof(header) + len; header.Identification = ++_Identifier; header.FragmentInfo = 0; header.TimeToLive = MY_IP_TTL; header.Protocol = protocol; header.HeaderChecksum = 0; header.SourceAddress = AppConfig.MyIPAddr; header.DestAddress.Val = remote->IPAddr.Val; SwapIPHeader(&header); #if defined(NON_MCHP_MAC) header.HeaderChecksum = CalcIPChecksum((BYTE*)&header, sizeof(header)); #endif MACPutHeader(&remote->MACAddr, MAC_IP, (sizeof(header)+len)); MACPutArray((BYTE*)&header, sizeof(header)); #if !defined(NON_MCHP_MAC) header.HeaderChecksum = MACCalcTxChecksum(0, sizeof(header)); MACSetTxBuffer(CurrentTxBuffer, 10); // 10 is the offset in header to the HeaderChecksum member MACPutArray((BYTE*)&header.HeaderChecksum, 2); MACSetTxBuffer(CurrentTxBuffer, sizeof(header)); // Seek back to the end of the packet #endif return 0x0; }
void AutoIPTasks(void) { BYTE i; for (i = 0; i < NETWORK_INTERFACES; i++) { LoadState (i); AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(); 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; AppConfig.MyIPAddr.Val = AppConfig.DefaultIPAddr.Val; AppConfig.MyMask.Val = AppConfig.DefaultMask.Val; } else { AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } } #if defined (STACK_USE_DHCP_CLIENT) if (DHCPIsBound(i)) { 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 (((DWORD)AppConfig.MyMACAddr.v[0] + ((DWORD)AppConfig.MyMACAddr.v[1] << 8) + \ ((DWORD)AppConfig.MyMACAddr.v[2] << 16) + ((DWORD)AppConfig.MyMACAddr.v[3] << 24) + \ ((DWORD)AppConfig.MyMACAddr.v[4]) + ((DWORD)AppConfig.MyMACAddr.v[5] << 8)), i); AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; // Check the address to see if it's in use before we write it into AppConfig case SM_AUTOIP_CHECK_ADDRESS: if (AutoIPClient.flags.bits.checkAddress == FALSE) { AutoIPClient.flags.bits.checkAddress = TRUE; AppConfig.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(i) % 256; AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(i) % 254) + 1; AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9; ARPResolve (&AutoIPClient.packet.TargetIPAddr); AutoIPClient.eventTime = TickGet(); } if (!ARPIsResolved (&AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr)) { if (TickGet() - AutoIPClient.eventTime > TICK_SECOND) { 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; AppConfig.MyIPAddr = AutoIPClient.packet.TargetIPAddr; AppConfig.MyMask.Val = 0x0000FFFF; memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&AppConfig.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 = ((rand() % 20) * TICK_SECOND) / 20; // Store the current time AutoIPClient.eventTime = TickGet(); // 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 (TickGet() - AutoIPClient.eventTime > AutoIPClient.randomDelay) { // Store the new event time AutoIPClient.eventTime = TickGet(); // Generate a new random delay between 1 and 2 seconds AutoIPClient.randomDelay = TICK_SECOND + (((rand() % 20) * TICK_SECOND) / 20); // Transmit the packet while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); MACPutHeader(&AutoIPClient.packet.TargetMACAddr, MAC_ARP, sizeof(AutoIPClient.packet)); MACPutArray((BYTE*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(); // 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 (TickGet() - 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 = TickGet(); AppConfig.MyIPAddr.v[0] = MY_DEFAULT_IP_ADDR_BYTE1; AppConfig.MyIPAddr.v[1] = MY_DEFAULT_IP_ADDR_BYTE2; AppConfig.MyIPAddr.v[2] = MY_DEFAULT_IP_ADDR_BYTE3; AppConfig.MyIPAddr.v[3] = MY_DEFAULT_IP_ADDR_BYTE4; 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 (TickGet() - AutoIPClient.eventTime > TICK_SECOND * 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 AutoIPClient.packet.Operation = ARP_OPERATION_RESP; AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; SwapARPPacket(&AutoIPClient.packet); while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); MACPutHeader(&AutoIPClient.packet.TargetMACAddr, MAC_ARP, sizeof(AutoIPClient.packet)); MACPutArray((BYTE*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(); AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; } } }
/********************************************************************* * Function: void ARPPut(NODE_INFO* more, BYTE opCode) * * PreCondition: MACIsTxReady() == TRUE * * Input: remote - Remote node info * opCode - ARP op code to send * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void ARPPut(NODE_INFO *remote, BYTE opCode) { ARP_PACKET packet; packet.HardwareType = HW_ETHERNET; packet.Protocol = ARP_IP; packet.MACAddrLen = sizeof(MAC_ADDR); packet.ProtocolLen = sizeof(IP_ADDR); if ( opCode == ARP_REQUEST ) { packet.Operation = ARP_OPERATION_REQ; packet.TargetMACAddr.v[0] = 0xff; packet.TargetMACAddr.v[1] = 0xff; packet.TargetMACAddr.v[2] = 0xff; packet.TargetMACAddr.v[3] = 0xff; packet.TargetMACAddr.v[4] = 0xff; packet.TargetMACAddr.v[5] = 0xff; } else { packet.Operation = ARP_OPERATION_RESP; packet.TargetMACAddr = remote->MACAddr; } packet.SenderMACAddr.v[0] = MY_MAC_BYTE1; packet.SenderMACAddr.v[1] = MY_MAC_BYTE2; packet.SenderMACAddr.v[2] = MY_MAC_BYTE3; packet.SenderMACAddr.v[3] = MY_MAC_BYTE4; packet.SenderMACAddr.v[4] = MY_MAC_BYTE5; packet.SenderMACAddr.v[5] = MY_MAC_BYTE6; packet.SenderIPAddr.v[0] = MY_IP_BYTE1; packet.SenderIPAddr.v[1] = MY_IP_BYTE2; packet.SenderIPAddr.v[2] = MY_IP_BYTE3; packet.SenderIPAddr.v[3] = MY_IP_BYTE4; /* * Check to see if target is on same subnet, if not, find * Gateway MAC. * Once we get Gateway MAC, all access to remote host will * go through Gateway. */ if (((packet.SenderIPAddr.v[0] ^ remote->IPAddr.v[0]) & MY_MASK_BYTE1) || ((packet.SenderIPAddr.v[1] ^ remote->IPAddr.v[1]) & MY_MASK_BYTE2) || ((packet.SenderIPAddr.v[2] ^ remote->IPAddr.v[2]) & MY_MASK_BYTE3) || ((packet.SenderIPAddr.v[3] ^ remote->IPAddr.v[3]) & MY_MASK_BYTE4) ) { packet.TargetIPAddr.v[0] = MY_GATE_BYTE1; packet.TargetIPAddr.v[1] = MY_GATE_BYTE2; packet.TargetIPAddr.v[2] = MY_GATE_BYTE3; packet.TargetIPAddr.v[3] = MY_GATE_BYTE4; } else packet.TargetIPAddr = remote->IPAddr; SwapARPPacket(&packet); MACPutHeader(&packet.TargetMACAddr, MAC_ARP, sizeof(packet)); MACPutArray((BYTE*)&packet, sizeof(packet)); MACFlush(); }
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; } } }