/********************************************************************* * 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, uint16_t len) { TCPIP_UINT32_VAL dwVal; // Obtain the ICMP header Type, Code, and Checksum fields MACGetArray((uint8_t*)&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((uint8_t*)&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((uint8_t*)&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: BOOL IPGetHeader( IP_ADDR *localIP, * NODE_INFO *remote, * BYTE *Protocol, * WORD *len) * * PreCondition: MACGetHeader() == TRUE * * Input: localIP - Local node IP Address as received * in current IP header. * If this information is not required * caller may pass NULL value. * remote - Remote node info * Protocol - Current packet protocol * len - Current packet data length * * Output: TRUE, if valid packet was received * FALSE otherwise * * Side Effects: None * * Note: Only one IP message can be received. * Caller may not transmit and receive a message * at the same time. * ********************************************************************/ BOOL IPGetHeader(IP_ADDR *localIP, NODE_INFO *remote, BYTE *protocol, WORD *len) { WORD_VAL CalcChecksum; IP_HEADER header; #if defined(NON_MCHP_MAC) WORD_VAL ReceivedChecksum; WORD checksums[2]; BYTE optionsLen; #define MAX_OPTIONS_LEN (40u) // As per RFC 791. BYTE options[MAX_OPTIONS_LEN]; #endif // Read IP header. MACGetArray((BYTE*)&header, sizeof(header)); // Make sure that this is an IPv4 packet. if((header.VersionIHL & 0xf0) != IP_VERSION) return FALSE; // Throw this packet away if it is a fragment. // We don't have enough RAM for IP fragment reconstruction. if(header.FragmentInfo & 0xFF1F) return FALSE; IPHeaderLen = (header.VersionIHL & 0x0f) << 2; #if !defined(NON_MCHP_MAC) // Validate the IP header. If it is correct, the checksum // will come out to 0x0000 (because the header contains a // precomputed checksum). A corrupt header will have a // nonzero checksum. CalcChecksum.Val = MACCalcRxChecksum(0, IPHeaderLen); // Seek to the end of the IP header MACSetReadPtrInRx(IPHeaderLen); if(CalcChecksum.Val) #else // Calculate options length in this header, if there is any. // IHL is in terms of numbers of 32-bit DWORDs; i.e. actual // length is 4 times IHL. optionsLen = IPHeaderLen - sizeof(header); // If there is any option(s), read it so that we can include them // in checksum calculation. if ( optionsLen > MAX_OPTIONS_LEN ) return FALSE; if ( optionsLen > 0u ) MACGetArray(options, optionsLen); // Save header checksum; clear it and recalculate it ourselves. ReceivedChecksum.Val = header.HeaderChecksum; header.HeaderChecksum = 0; // Calculate checksum of header including options bytes. checksums[0] = ~CalcIPChecksum((BYTE*)&header, sizeof(header)); // Calculate Options checksum too, if they are present. if ( optionsLen > 0u ) checksums[1] = ~CalcIPChecksum((BYTE*)options, optionsLen); else checksums[1] = 0; CalcChecksum.Val = CalcIPChecksum((BYTE*)checksums, 2 * sizeof(WORD)); // Make sure that checksum is correct if ( ReceivedChecksum.Val != CalcChecksum.Val ) #endif { // Bad packet. The function caller will be notified by means of the FALSE // return value and it should discard the packet. return FALSE; } // Network to host conversion. SwapIPHeader(&header); // If caller is intrested, return destination IP address // as seen in this IP header. if ( localIP ) localIP->Val = header.DestAddress.Val; remote->IPAddr.Val = header.SourceAddress.Val; *protocol = header.Protocol; *len = header.TotalLength - IPHeaderLen; return TRUE; }