// Processes an ICMP packet and generates an echo reply, if requested // Note: the srcAdd parameter could be detected from the pNetIf // However, when support for multiple IP addresses per interface is implemented // passing the source address explicitely is better void TCPIP_ICMP_Process(TCPIP_NET_IF* pNetIf, TCPIP_MAC_PACKET* pRxPkt, uint32_t destAdd, uint32_t srcAdd) { ICMP_HEADER *pRxHdr; TCPIP_MAC_DATA_SEGMENT *pSeg; TCPIP_UINT16_VAL checksum; TCPIP_MAC_PKT_ACK_RES ackRes; pRxHdr = (ICMP_HEADER*)pRxPkt->pTransportLayer; ackRes = TCPIP_MAC_PKT_ACK_RX_OK; while(true) { if(pRxPkt->totTransportLen < sizeof(*pRxHdr)) { ackRes = TCPIP_MAC_PKT_ACK_STRUCT_ERR; break; } // Validate the checksum // The checksum data includes the precomputed checksum in the header // so a valid packet will always have a checksum of 0x0000 // 1st segment checksum.Val = ~TCPIP_Helper_CalcIPChecksum(pRxPkt->pTransportLayer, pRxPkt->pDSeg->segLen, 0); // add the other possible data segments for(pSeg = pRxPkt->pDSeg->next; pSeg != 0; pSeg = pSeg->next) { checksum.Val = ~TCPIP_Helper_CalcIPChecksum(pSeg->segLoad, pSeg->segLen, checksum.Val); } if((uint16_t)~checksum.Val != 0) { ackRes = TCPIP_MAC_PKT_ACK_CHKSUM_ERR; break; } if(pRxHdr->vType == ICMP_TYPE_ECHO_REQUEST && pRxHdr->vCode == ICMP_CODE_ECHO_REQUEST) { // echo request ackRes = _ICMPProcessEchoRequest(pNetIf, pRxPkt, destAdd, srcAdd); break; } #if defined(TCPIP_STACK_USE_ICMP_CLIENT) if(pRxHdr->vType == ICMP_TYPE_ECHO_REPLY && pRxHdr->vCode == ICMP_CODE_ECHO_REPLY) { // echo reply; check if our own // Get the sequence number and identifier fields TCPIP_UINT32_VAL userData; IPV4_ADDR remoteIPAddr; userData.w[0] = pRxHdr->wIdentifier; userData.w[1] = pRxHdr->wSequenceNumber; remoteIPAddr.Val = srcAdd; // Send a message to the application-level Ping driver that we've received an Echo Reply _ICMPNotifyClients(pNetIf, &remoteIPAddr, (void *)userData.v); ackRes = TCPIP_MAC_PKT_ACK_RX_OK; } #endif break; } TCPIP_PKT_PacketAcknowledge(pRxPkt, ackRes); return; }
// Processes an ICMP packet and generates an echo reply, if requested static void TCPIP_ICMP_Process(void) { TCPIP_NET_IF* pNetIf; TCPIP_MAC_PACKET* pRxPkt; IPV4_HEADER* pIpv4Header; uint32_t destAdd; uint32_t srcAdd; ICMP_HEADER* pRxHdr; uint16_t icmpTotLength; uint16_t checksum; TCPIP_MAC_PKT_ACK_RES ackRes; // extract queued ICMP packets while((pRxPkt = _TCPIPStackModuleRxExtract(TCPIP_THIS_MODULE_ID)) != 0) { pNetIf = (TCPIP_NET_IF*)pRxPkt->pktIf; pRxHdr = (ICMP_HEADER*)pRxPkt->pTransportLayer; ackRes = TCPIP_MAC_PKT_ACK_RX_OK; pIpv4Header = (IPV4_HEADER*)pRxPkt->pNetLayer; destAdd = pIpv4Header->DestAddress.Val; srcAdd = pIpv4Header->SourceAddress.Val; while(true) { icmpTotLength = pRxPkt->totTransportLen; if(icmpTotLength < sizeof(*pRxHdr)) { ackRes = TCPIP_MAC_PKT_ACK_STRUCT_ERR; break; } // Validate the checksum // The checksum data includes the precomputed checksum in the header // so a valid packet will always have a checksum of 0x0000 // 1st segment if((pRxPkt->pktFlags & TCPIP_MAC_PKT_FLAG_SPLIT) != 0) { checksum = TCPIP_Helper_PacketChecksum(pRxPkt, (uint8_t*)pRxHdr, icmpTotLength, 0); } else { checksum = TCPIP_Helper_CalcIPChecksum((uint8_t*)pRxHdr, icmpTotLength, 0); } if(checksum != 0) { ackRes = TCPIP_MAC_PKT_ACK_CHKSUM_ERR; break; } if(pRxHdr->vType == ICMP_TYPE_ECHO_REQUEST && pRxHdr->vCode == ICMP_CODE_ECHO_REQUEST) { // echo request ackRes = _ICMPProcessEchoRequest(pNetIf, pRxPkt, destAdd, srcAdd); break; } #if defined(TCPIP_STACK_USE_ICMP_CLIENT) if(pRxHdr->vType == ICMP_TYPE_ECHO_REPLY && pRxHdr->vCode == ICMP_CODE_ECHO_REPLY) { // echo reply; check if our own // Get the sequence number and identifier fields #if (TCPIP_ICMP_CLIENT_USER_NOTIFICATION != 0) TCPIP_UINT32_VAL userData; IPV4_ADDR remoteIPAddr; userData.w[0] = pRxHdr->wIdentifier; userData.w[1] = pRxHdr->wSequenceNumber; remoteIPAddr.Val = srcAdd; // Send a message to the application-level Ping driver that we've received an Echo Reply _ICMPNotifyClients(pNetIf, &remoteIPAddr, (void *)userData.v); #endif // (TCPIP_ICMP_CLIENT_USER_NOTIFICATION != 0) ackRes = TCPIP_MAC_PKT_ACK_RX_OK; break; } #endif // unknown type ackRes = TCPIP_MAC_PKT_ACK_TYPE_ERR; break; } TCPIP_PKT_FlightLog(pRxPkt, TCPIP_THIS_MODULE_ID, ackRes, 0); TCPIP_PKT_PacketAcknowledge(pRxPkt, ackRes); } }