/***************************************************************************** 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 ICMPPut(NODE_INFO *remote, * ICMP_CODE code, * BYTE *data, * BYTE len, * WORD id, * WORD seq) * * PreCondition: ICMPIsTxReady() == TRUE * * Input: remote - Remote node info * code - ICMP_ECHO_REPLY or ICMP_ECHO_REQUEST * data - Data bytes * len - Number of bytes to send * id - ICMP identifier * seq - ICMP sequence number * * Output: None * * Side Effects: None * * Note: A ICMP packet is created and put on MAC. * ********************************************************************/ void ICMPPut(NODE_INFO *remote, ICMP_CODE code, BYTE *data, BYTE len, WORD id, WORD seq) { ICMP_PACKET packet; packet.Code = 0; packet.Type = code; packet.Checksum = 0; packet.Identifier = id; packet.SequenceNumber = seq; memcpy((void*)packet.Data, (void*)data, len); SwapICMPPacket(&packet); packet.Checksum = CalcIPChecksum((BYTE*)&packet, (WORD)(ICMP_HEADER_SIZE + len)); IPPutHeader(remote, IP_PROT_ICMP, (WORD)(ICMP_HEADER_SIZE + len)); IPPutArray((BYTE*)&packet, (WORD)(ICMP_HEADER_SIZE + len)); MACFlush(); }
/***************************************************************************** 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: 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: 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; } }
/** * A ICMP packet is created and put on MAC. * * @preCondition ICMPIsTxReady() == TRUE * * @param remote Remote node info * @param code ICMP_ECHO_REPLY or ICMP_ECHO_REQUEST * @param data Data bytes * @param len Number of bytes to send * @param id ICMP identifier * @param seq ICMP sequence number */ void ICMPPut(NODE_INFO *remote, ICMP_CODE code, BYTE *data, BYTE len, WORD id, WORD seq) { ICMP_PACKET packet; WORD ICMPLen; BUFFER MyTxBuffer; MyTxBuffer = MACGetTxBuffer(TRUE); // Abort if there is no where in the Ethernet controller to // store this packet. if(MyTxBuffer == INVALID_BUFFER) return; IPSetTxBuffer(MyTxBuffer, 0); ICMPLen = ICMP_HEADER_SIZE + (WORD)len; packet.Code = 0; packet.Type = code; packet.Checksum = 0; packet.Identifier = id; packet.SequenceNumber = seq; memcpy((void*)packet.Data, (void*)data, len); SwapICMPPacket(&packet); #if defined(NON_MCHP_MAC) //This is NOT a Microchip MAC packet.Checksum = CalcIPChecksum((BYTE*)&packet, ICMPLen); #endif IPPutHeader(remote, IP_PROT_ICMP, (WORD)(ICMP_HEADER_SIZE + len)); IPPutArray((BYTE*)&packet, ICMPLen); #if !defined(NON_MCHP_MAC) //This is a Microchip MAC // Calculate and write the ICMP checksum using the Microchip MAC's DMA packet.Checksum = MACCalcTxChecksum(sizeof(IP_HEADER), ICMPLen); IPSetTxBuffer(MyTxBuffer, 2); MACPutArray((BYTE*)&packet.Checksum, 2); #endif MACFlush(); }
/********************************************************************* * Function: BOOL UDPFlush(void) * * PreCondition: UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * Input: None * * Output: All and any data associated with active UDP socket * buffer is marked as ready for transmission. * * Side Effects: None * * Overview: None * * Note: This function transmit all data from * an active UDP socket. ********************************************************************/ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; /* * When using SLIP (USART), packet transmission takes some time * and hence before sending another packet, we must make sure * that, last packet is transmitted. * When using ethernet controller, transmission occurs very fast * and by the time next packet is transmitted, previous is * transmitted and we do not need to check for last packet. */ //while( !IPIsTxReady() ); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort = swaps(p->localPort); h.DestinationPort = swaps(p->remotePort); h.Length = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum = 0x00; IPSetTxBuffer(p->TxBuffer, 0); /* * Load IP header. */ IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length ); // Now swap h.Length. h.Length = swaps(h.Length); /* * Now load UDP header. */ IPPutArray((BYTE*)&h, sizeof(h)); /* * Update checksum. * TO BE IMPLEMENTED */ MACFlush(); p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/****************************************************************************** * Function: BOOL MACIsTxReady(void) * * PreCondition: None * * Input: None * * Output: TRUE: If no Ethernet transmission is in progress * FALSE: If a previous transmission was started, and it has * not completed yet. While FALSE, the data in the * transmit buffer and the TXST/TXND pointers must not * be changed. * * Side Effects: None * * Overview: Returns the ECON1.TXRTS bit * * Note: None *****************************************************************************/ BOOL MACIsTxReady(void) { if (!ECON1bits.TXRTS) return TRUE; // Retry transmission if the current packet seems to be not completing // Wait 3ms before triggering the retry. if ((WORD) clock_time() - wTXWatchdog >= (3ull * CLOCK_SECOND / 1000ull)) { ECON1bits.TXRTS = 0; MACFlush(); } return FALSE; }
/** * This function transmit all data from the active UDP socket. * * @preCondition UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * @return All and any data associated with active UDP socket * buffer is marked as ready for transmission. * */ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ) FAST_USER_PROCESS(); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort.Val = swaps(p->localPort); h.DestinationPort.Val = swaps(p->remotePort); h.Length.Val = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum.Val = 0x00; //Makes the given TX Buffer active, and set's the pointer to the first byte after the IP //header. This is the first byte of the UDP header. The UDP header follows the IP header. IPSetTxBuffer(p->TxBuffer, 0); //Load IP header. IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length.Val ); //Now swap h.Length.Val h.Length.Val = swaps(h.Length.Val); //Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); //Update checksum. !!!!!!!!!!!!!!! TO BE IMPLEMENTED !!!!!!!!!!!!!!!!!!! //Send data contained in TX Buffer via MAC MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/********************************************************************* * 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 }
/** * This function transmit all data from the active UDP socket. * * @preCondition UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * @return All and any data associated with active UDP socket * buffer is marked as ready for transmission. * */ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; WORD csLength; DWORD_VAL csChecksum; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ) FAST_USER_PROCESS(); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort.Val = swaps(p->localPort); h.DestinationPort.Val = swaps(p->remotePort); h.Length.Val = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum.Val = 0x00; //Makes the given TX Buffer active, and set's the pointer to the first byte after the IP //header. This is the first byte of the UDP header. The UDP header follows the IP header. IPSetTxBuffer(p->TxBuffer, 0); //Load IP header. IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length.Val ); // save length before swap for checksum calculation csLength = p->TxCount; //Now swap h.Length.Val h.Length.Val = swaps(h.Length.Val); //Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); //Update checksum. !!!!!!!!!!!!!!! TO BE IMPLEMENTED !!!!!!!!!!!!!!!!!!! // Update checksum. // start the checksum with value for UDP protocol & length from pseudo header (and in the actual packet) csChecksum.Val = (WORD)IP_PROT_UDP + (WORD)csLength + sizeof(UDP_HEADER); // add in my address and the remoteNode address csChecksum.Val += ((WORD)MY_IP_BYTE1 << 8) + MY_IP_BYTE2; csChecksum.Val += ((WORD)MY_IP_BYTE3 << 8) + MY_IP_BYTE4; csChecksum.Val += ((WORD)p->remoteNode.IPAddr.v[0] << 8) + ((WORD)p->remoteNode.IPAddr.v[1] ) + ((WORD)p->remoteNode.IPAddr.v[2] << 8) + ((WORD)p->remoteNode.IPAddr.v[3] ); // set mac pointer to the ip_addr of the source, so all of pseudo header but length is included. // length of pseudo header is already included in previous instruction. //MACSetRxBuffer( sizeof(IP_HEADER)+sizeof(UDP_HEADER) ); csChecksum.Val += (WORD)p->localPort; csChecksum.Val += (WORD)p->remotePort; csChecksum.Val += (WORD)csLength + sizeof(UDP_HEADER); //IPSetRxBuffer(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) - ( sizeof(IP_ADDR) * 2 ) ); // handled in UdpPut routines csChecksum.Val += udpChecksum; // add any carry over to the last word while((DWORD)csChecksum.word.MSW) { csChecksum.Val = (DWORD)csChecksum.word.LSW + (DWORD)csChecksum.word.MSW; } // add any carry over from adding the carry over //csChecksum.Val = (DWORD)csChecksum.word.LSW + (DWORD)csChecksum.word.MSW; // invert csChecksum.Val = ~csChecksum.Val; // set write pointer to location of checksum in packet //MACSetWritePtr( sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + sizeof(UDP_HEADER) - 2 ); IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER) - 2); // write the swapped checksum to the packet //MACPut( csChecksum.v[1] ); //MACPut( csChecksum.v[0] ); MACPut(0); MACPut(0); //Send data contained in TX Buffer via MAC MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/********************************************************************* * Function: BOOL UDPFlush(void) * * PreCondition: UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * Input: None * * Output: All and any data associated with active UDP socket * buffer is marked as ready for transmission. * * Side Effects: None * * Overview: None * * Note: This function transmit all data from * an active UDP socket. ********************************************************************/ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ); p = &UDPSocketInfo[activeUDPSocket]; debug_udp("\r\nUDP FLUSH - Sok:%U TxC:%LU SP:%LU DP:%LU ", activeUDPSocket, p->TxCount, p->localPort, p->remotePort ); debug_udp("MAC-%X:%X:%X:%X:%X:%X", p->remoteNode.MACAddr.v[0], p->remoteNode.MACAddr.v[1], p->remoteNode.MACAddr.v[2], p->remoteNode.MACAddr.v[3], p->remoteNode.MACAddr.v[4], p->remoteNode.MACAddr.v[5] ); h.SourcePort = swaps(p->localPort); h.DestinationPort = swaps(p->remotePort); h.Length = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum = 0x0000; IPSetTxBuffer(p->TxBuffer, 0); /* * Load IP header. */ IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length ); // Now swap h.Length. h.Length = swaps(h.Length); // Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); // Update checksum. // TO BE IMPLEMENTED MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/***************************************************************************** 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(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; } } }
/********************************************************************* * 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(); }
BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type) { /* * This marks that all future accesses to MACGet and MACPut * be applied to Receive buffer. */ bIsRxActive = TRUE; if ( RxBuffer.PacketCount ) { /* * Set up packet access index. */ RxBuffer.CallerAccess = RxBuffer.CurrentPacket; RxBuffer.CallerAccess++; if ( RxBuffer.CallerAccess >= MAX_SLIP_BUFFER_SIZE ) RxBuffer.CallerAccess = 0; /* * Handle modem commands differently. */ if ( RxBuffer.Data[RxBuffer.CallerAccess] == 'A' ) { /* * Once a modem command is detected, we are not interested * in detail. */ MACDiscardRx(); //Discard the contents of the current RX buffer /* * Mark TxBuffer for Modem String. * This will make sure that Transmit ISR does nottransmit END * at the end. */ TxBuffer.Flags.bits.bIsModemString = TRUE; /* * Since this special handling does not follow standard * SLIP buffer logic, we will setup all required variables * manually. */ TxBuffer.Length = 4; TxBuffer.CallerAccess = 0; /* * Remember to use transmit buffer for MACPut */ bIsRxActive = FALSE; /* * Now load modem response. */ MACPut('O'); MACPut('K'); MACPut('\r'); MACPut('\n'); /* * Transmit it. */ MACFlush(); } else { /* * This was not a modem command. * It must be IP packet. Mark it accordingly and return. */ *type = MAC_IP; return TRUE; } } return FALSE; }
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; } } }