/***************************************************************************** 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: LONG ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ LONG ICMPGetReply(void) { switch(ICMPState) { case SM_ARP_RESOLVE: // See if the ARP reponse was successfully received if(ARPIsResolved(&ICMPRemote.IPAddr, &ICMPRemote.MACAddr)) { // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Create IP header in TX memory IPPutHeader(&ICMPRemote, IP_PROT_ICMP, sizeof(ICMP_HEADER) + 2); MACPutArray((BYTE*)&ICMPHeader, sizeof(ICMPHeader)); MACPut(0x00); // Send two dummy bytes as ping payload MACPut(0x00); // (needed for compatibility with some buggy NAT routers) MACFlush(); // MAC Address resolved and echo sent, advance state ICMPState = SM_GET_ECHO; return -2; } // See if the ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No ARP response back yet return -2; case SM_GET_ECHO: // See if the echo was successfully received if(ICMPFlags.bReplyValid) { return (LONG)ICMPTimer; } // See if the ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No echo response back yet return -2; // SM_IDLE or illegal/impossible state: default: return -1; } }
/********************************************************************* * Function: SHORT ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ SHORT ICMPGetReply(void) { switch(ICMPState) { case SM_IDLE: return -1; case SM_ARP_RESOLVE: // See if the ARP reponse was successfully received if(ARPIsResolved(&ICMPRemote.IPAddr, &ICMPRemote.MACAddr)) { // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Create IP header in TX memory IPPutHeader(&ICMPRemote, IP_PROT_ICMP, sizeof(ICMP_HEADER)); MACPutArray((BYTE*)&ICMPHeader, sizeof(ICMPHeader)); MACFlush(); // MAC Address resolved and echo sent, advance state ICMPState = SM_GET_ECHO; return -2; } // See if the ARP/echo request timed out if((WORD)TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No ARP response back yet return -2; case SM_GET_ECHO: // See if the echo was successfully received if(ICMPFlags.bReplyValid) { return (SHORT)ICMPTimer; } // See if the ARP/echo request timed out if((WORD)TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No echo response back yet return -2; } }
/********************************************************************* * Function: void HTTPInit(void) * * PreCondition: TCP must already be initialized. * * Input: None * * Output: None * * Side Effects: None * * Overview: Sets all HTTP sockets to listening state. * Initialize state machine for each connection. * * Note: This function is called only one during lifetime * of the application. ********************************************************************/ void HTTPInit(void) { WORD oldPtr; // Make sure the file handles are invalidated curHTTP.file = MPFS_INVALID_HANDLE; curHTTP.offsets = MPFS_INVALID_HANDLE; for(curHTTPID = 0; curHTTPID < MAX_HTTP_CONNECTIONS; curHTTPID++) { smHTTP = SM_HTTP_IDLE; sktHTTP = TCPListen(HTTP_PORT); // Save the default record (just invalid file handles) oldPtr = MACSetWritePtr(BASE_HTTPB_ADDR + curHTTPID*sizeof(HTTP_CONN)); MACPutArray((BYTE*)&curHTTP, sizeof(HTTP_CONN)); MACSetWritePtr(oldPtr); } }
/********************************************************************* * Function: static void HTTPLoadConn(BYTE connID) * * PreCondition: None * * Input: connID the connection ID to load * * Output: curHTTP has a new connection loaded * * Side Effects: None * * Overview: Loads the current HTTP connection out of Ethernet * buffer RAM and into local RAM for processing. * * Note: None ********************************************************************/ static void HTTPLoadConn(BYTE connID) { WORD oldPtr; // Return if already loaded if(connID == curHTTPID) return; // Save the old one oldPtr = MACSetWritePtr(BASE_HTTPB_ADDR + curHTTPID*sizeof(HTTP_CONN)); MACPutArray((BYTE*)&curHTTP, sizeof(HTTP_CONN)); MACSetWritePtr(oldPtr); // Load the new one oldPtr = MACSetReadPtr(BASE_HTTPB_ADDR + connID*sizeof(HTTP_CONN)); MACGetArray((BYTE*)&curHTTP, sizeof(HTTP_CONN)); MACSetReadPtr(oldPtr); // Remember which one is loaded curHTTPID = connID; }
/********************************************************************* * Function: LONG ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -3: Could not resolve hostname (DNS timeout or * hostname invalid) * -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ LONG ICMPGetReply(void) { ICMP_PACKET ICMPPacket; switch(ICMPState) { #if defined(STACK_USE_DNS) case SM_DNS_SEND_QUERY: // Obtain DNS module ownership if(!DNSBeginUsage()) break; // Send DNS query if(ICMPFlags.bRemoteHostIsROM) DNSResolveROM(StaticVars.RemoteHost.szROM, DNS_TYPE_A); else DNSResolve(StaticVars.RemoteHost.szRAM, DNS_TYPE_A); ICMPState = SM_DNS_GET_RESPONSE; break; case SM_DNS_GET_RESPONSE: // See if DNS is done, and if so, get the remote IP address if(!DNSIsResolved(&StaticVars.ICMPRemote.IPAddr)) break; // Free the DNS module DNSEndUsage(); // Return error code if the DNS query failed if(StaticVars.ICMPRemote.IPAddr.Val == 0x00000000ul) { ICMPState = SM_IDLE; return -3; } ICMPState = SM_ARP_SEND_QUERY; // No break; #endif case SM_ARP_SEND_QUERY: ARPResolve(&StaticVars.ICMPRemote.IPAddr); ICMPState = SM_ARP_GET_RESPONSE; break; case SM_ARP_GET_RESPONSE: // See if the ARP reponse was successfully received if(!ARPIsResolved(&StaticVars.ICMPRemote.IPAddr, &StaticVars.ICMPRemote.MACAddr)) break; ICMPState = SM_ICMP_SEND_ECHO_REQUEST; // No break; case SM_ICMP_SEND_ECHO_REQUEST: if(!IPIsTxReady()) break; // Set up the ping packet ICMPPacket.vType = 0x08; // 0x08: Echo (ping) request ICMPPacket.vCode = 0x00; ICMPPacket.wChecksum = 0x0000; ICMPPacket.wIdentifier = 0xEFBE; wICMPSequenceNumber++; ICMPPacket.wSequenceNumber = wICMPSequenceNumber; ICMPPacket.wData = 0x2860; ICMPPacket.wChecksum = CalcIPChecksum((BYTE*)&ICMPPacket, sizeof(ICMPPacket)); // Record the current time. This will be used as a basis for // finding the echo response time, which exludes the ARP and DNS // steps ICMPTimer = TickGet(); // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Create IP header in TX memory IPPutHeader(&StaticVars.ICMPRemote, IP_PROT_ICMP, sizeof(ICMPPacket)); MACPutArray((BYTE*)&ICMPPacket, sizeof(ICMPPacket)); MACFlush(); // Echo sent, advance state ICMPState = SM_ICMP_GET_ECHO_RESPONSE; break; case SM_ICMP_GET_ECHO_RESPONSE: // See if the echo was successfully received if(ICMPFlags.bReplyValid) return (LONG)ICMPTimer; break; // SM_IDLE or illegal/impossible state: default: return -1; } // See if the DNS/ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { // Free DNS module if we have it in use #if defined(STACK_USE_DNS) if(ICMPState == SM_DNS_GET_RESPONSE) DNSEndUsage(); #endif // Stop ICMP echo test and return error to caller ICMPState = SM_IDLE; return -1; } // Still working. No response to report yet. return -2; }
/********************************************************************* * Function: void ICMPProcess(void) * * PreCondition: MAC buffer contains ICMP type packet. * * Input: *remote: Pointer to a NODE_INFO structure of the * ping requester * len: Count of how many bytes the ping header and * payload are in this IP packet * * Output: Generates an echo reply, if requested * Validates and sets ICMPFlags.bReplyValid if a * correct ping response to one of ours is received. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void ICMPProcess(NODE_INFO *remote, WORD len) { DWORD_VAL dwVal; // Obtain the ICMP header Type, Code, and Checksum fields MACGetArray((BYTE*)&dwVal, sizeof(dwVal)); // See if this is an ICMP echo (ping) request if(dwVal.w[0] == 0x0008u) { // Validate the checksum using the Microchip MAC's DMA module // The checksum data includes the precomputed checksum in the // header, so a valid packet will always have a checksum of // 0x0000 if the packet is not disturbed. if(MACCalcRxChecksum(0+sizeof(IP_HEADER), len)) return; // Calculate new Type, Code, and Checksum values dwVal.v[0] = 0x00; // Type: 0 (ICMP echo/ping reply) dwVal.v[2] += 8; // Subtract 0x0800 from the checksum if(dwVal.v[2] < 8u) { dwVal.v[3]++; if(dwVal.v[3] == 0u) dwVal.v[2]++; } // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Position the write pointer for the next IPPutHeader operation // NOTE: do not put this before the IPIsTxReady() call for WF compatbility MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Create IP header in TX memory IPPutHeader(remote, IP_PROT_ICMP, len); // Copy ICMP response into the TX memory MACPutArray((BYTE*)&dwVal, sizeof(dwVal)); MACMemCopyAsync(-1, -1, len-4); while(!MACIsMemCopyDone()); // Transmit the echo reply packet MACFlush(); } #if defined(STACK_USE_ICMP_CLIENT) else if(dwVal.w[0] == 0x0000u) // See if this an ICMP Echo reply to our request { // Get the sequence number and identifier fields MACGetArray((BYTE*)&dwVal, sizeof(dwVal)); // See if the identifier matches the one we sent if(dwVal.w[0] != 0xEFBE) return; if(dwVal.w[1] != wICMPSequenceNumber) return; // Validate the ICMP checksum field IPSetRxBuffer(0); if(CalcIPBufferChecksum(sizeof(ICMP_PACKET))) // Two bytes of payload were sent in the echo request return; // Flag that we received the response and stop the timer ticking ICMPFlags.bReplyValid = 1; ICMPTimer = TickGet() - ICMPTimer; } #endif }
/***************************************************************************** Function: void UDPFlush(void) Summary: Transmits all pending data in a UDP socket. Description: This function builds a UDP packet with the pending TX data and marks it for transmission over the network interface. Since UDP is a frame-based protocol, this function must be called before returning to the main stack loop whenever any data is written. Precondition: UDPIsPutReady() was previously called to specify the current socket, and data has been written to the socket using the UDPPut family of functions. Parameters: None Returns: None Remarks: Note that unlike TCPFlush, UDPFlush must be called before returning to the main stack loop. There is no auto transmit for UDP segments. ***************************************************************************/ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; WORD wUDPLength; p = &UDPSocketInfo[activeUDPSocket]; wUDPLength = UDPTxCount + sizeof(UDP_HEADER); // Generate the correct UDP header h.SourcePort = swaps(p->localPort); h.DestinationPort = swaps(p->remotePort); h.Length = swaps(wUDPLength); h.Checksum = 0x0000; // Calculate IP pseudoheader checksum if we are going to enable // the checksum field #if defined(UDP_USE_TX_CHECKSUM) { PSEUDO_HEADER pseudoHeader; pseudoHeader.SourceAddress = AppConfig.MyIPAddr; pseudoHeader.DestAddress = p->remote.remoteNode.IPAddr; pseudoHeader.Zero = 0x0; pseudoHeader.Protocol = IP_PROT_UDP; pseudoHeader.Length = wUDPLength; SwapPseudoHeader(pseudoHeader); h.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader)); } #endif // Position the hardware write pointer where we will need to // begin writing the IP header MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Write IP header to packet IPPutHeader(&p->remote.remoteNode, IP_PROT_UDP, wUDPLength); // Write UDP header to packet MACPutArray((BYTE*)&h, sizeof(h)); // Calculate the final UDP checksum and write it in, if enabled #if defined(UDP_USE_TX_CHECKSUM) { PTR_BASE wReadPtrSave; WORD wChecksum; wReadPtrSave = MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER)); wChecksum = CalcIPBufferChecksum(wUDPLength); if(wChecksum == 0x0000u) wChecksum = 0xFFFF; MACSetReadPtr(wReadPtrSave); MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 6); // 6 is the offset to the Checksum field in UDP_HEADER MACPutArray((BYTE*)&wChecksum, sizeof(wChecksum)); } #endif // Transmit the packet MACFlush(); // Reset packet size counter for the next TX operation UDPTxCount = 0; LastPutSocket = INVALID_UDP_SOCKET; }
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; } } }
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; } } }