/***************************************************************************** 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: 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: 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; }
/********************************************************************* * Function: BOOL ARPGet(NODE_INFO* remote, BYTE* opCode) * * PreCondition: ARP packet is ready in MAC buffer. * * Input: remote - Remote node info * opCode - Buffer to hold ARP op code. * * Output: TRUE if a valid ARP packet was received. * FALSE otherwise. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ int1 ARPGet(NODE_INFO *remote, int8 *opCode) { ARP_PACKET packet; //MACGetArray((int8*)&packet, sizeof(packet)); MACGetArray(&packet, sizeof(ARP_PACKET)); MACDiscardRx(); SwapARPPacket(&packet); debug_arp("\r\nARP: HW:%LX PR:%LX ML:%U PL:%U O:%LX TI:%U.%U.%U.%U FI:%U.%U.%U.%U", packet.HardwareType, packet.Protocol, packet.MACAddrLen, packet.ProtocolLen, packet.Operation, packet.TargetIPAddr.v[0],packet.TargetIPAddr.v[1], packet.TargetIPAddr.v[2],packet.TargetIPAddr.v[3], packet.SenderIPAddr.v[0],packet.SenderIPAddr.v[1],packet.SenderIPAddr.v[2],packet.SenderIPAddr.v[3]); if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) return FALSE; if ( packet.Operation == ARP_OPERATION_RESP ) *opCode = ARP_REPLY; else if ( packet.Operation == ARP_OPERATION_REQ ) *opCode = ARP_REQUEST; else { *opCode = ARP_UNKNOWN; return FALSE; } if(packet.TargetIPAddr.Val == AppConfig.MyIPAddr.Val) { remote->MACAddr = packet.SenderMACAddr; remote->IPAddr = packet.SenderIPAddr; return TRUE; } else return FALSE; }
/********************************************************************* * Function: BOOL ARPGet(NODE_INFO* remote, BYTE* opCode) * * PreCondition: ARP packet is ready in MAC buffer. * * Input: remote - Remote node info * opCode - Buffer to hold ARP op code. * * Output: TRUE if a valid ARP packet was received. * FALSE otherwise. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ BOOL ARPGet(NODE_INFO *remote, BYTE *opCode) { ARP_PACKET packet; MACGetArray((BYTE*)&packet, sizeof(packet)); MACDiscardRx(); SwapARPPacket(&packet); if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) { return FALSE; } if ( packet.Operation == ARP_OPERATION_RESP ) { *opCode = ARP_REPLY; } else if ( packet.Operation == ARP_OPERATION_REQ ) *opCode = ARP_REQUEST; else { *opCode = ARP_UNKNOWN; return FALSE; } if(packet.TargetIPAddr.Val == AppConfig.MyIPAddr.Val) { remote->MACAddr = packet.SenderMACAddr; remote->IPAddr = packet.SenderIPAddr; return TRUE; } else return FALSE; }
/***************************************************************************** Function: bool ARPProcess(void) 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: true - All processing of this ARP packet is complete. Do not call again until a new ARP packet is waiting in the RX buffer. false - This function must be called again. More time is needed to send an ARP response. ***************************************************************************/ bool ARPProcess(void) { ARP_PACKET packet; static NODE_INFO Target; #if defined(STACK_USE_AUTO_IP) uint8_t i; #endif static enum { SM_ARP_IDLE = 0, SM_ARP_REPLY } smARP = SM_ARP_IDLE; switch(smARP) { case SM_ARP_IDLE: // Obtain the incoming ARP packet MACGetArray((uint8_t*)&packet, sizeof(packet)); MACDiscardRx(); SwapARPPacket(&packet); // Validate the ARP packet if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) { return true; } #ifdef STACK_USE_ZEROCONF_LINK_LOCAL ARPProcessRxPkt(&packet); #endif #ifdef STACK_USE_AUTO_IP if (packet.SenderIPAddr.Val == AppConfig.MyIPAddr.Val) { AutoIPConflict(0); return true; } #endif // Handle incoming ARP responses #ifdef STACK_CLIENT_MODE if(packet.Operation == ARP_OPERATION_RESP) { /* #if defined(STACK_USE_AUTO_IP) for (i = 0; i < NETWORK_INTERFACES; i++) if (AutoIPConfigIsInProgress(i)) AutoIPConflict(i); #endif*/ Cache.MACAddr = packet.SenderMACAddr; Cache.IPAddr = packet.SenderIPAddr; //putsUART("ARPProcess: SM_ARP_IDLE: ARP_OPERATION_RESP \r\n"); return true; } #endif // Handle incoming ARP requests for our MAC address if(packet.Operation == ARP_OPERATION_REQ) { if(packet.TargetIPAddr.Val != AppConfig.MyIPAddr.Val) { return true; } #ifdef 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, &AppConfig.MyMACAddr, 6)) { putsUART("Loopback answer suppressed \r\n"); return true; } #endif #if defined(STACK_USE_AUTO_IP) for (i = 0; i < NETWORK_INTERFACES; i++) if (AutoIPConfigIsInProgress(i)) { AutoIPConflict(i); return true; } #endif Target.IPAddr = packet.SenderIPAddr; Target.MACAddr = packet.SenderMACAddr; //putsUART("ARPProcess: SM_ARP_IDLE: ARP_OPERATION_REQ \r\n"); smARP = SM_ARP_REPLY; } // Do not break. If we get down here, we need to send a reply. case SM_ARP_REPLY: packet.Operation = ARP_OPERATION_RESP; #if defined(STACK_USE_AUTO_IP) if (AutoIPIsConfigured(0)) { 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 #endif packet.TargetMACAddr = Target.MACAddr; packet.TargetIPAddr = Target.IPAddr; #ifdef STACK_USE_ZEROCONF_LINK_LOCAL packet.SenderIPAddr = AppConfig.MyIPAddr; #endif //putsUART("ARPProcess: SM_ARP_REPLY \r\n"); // Send an ARP response to a previously received request if(!ARPPut(&packet)) { return false; } // Begin listening for ARP requests again smARP = SM_ARP_IDLE; break; } return true; }
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(); }
/***************************************************************************** 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; }
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; } } }