ICMP_ECHO_RESULT TCPIP_ICMP_EchoRequestSend (IPV4_ADDR * targetAddr, uint16_t sequenceNumber, uint16_t identifier) { IPV4_PACKET* pTxPkt; ICMP_PACKET* pICMPPkt; uint32_t payload = 0x44332211; uint16_t pktSize = sizeof(ICMP_PACKET); ICMP_ECHO_RESULT res; while(true) { // allocate TX packet pTxPkt = _ICMPAllocateTxPacketStruct(pktSize); if(pTxPkt == 0) { res = ICMP_ECHO_ALLOC_ERROR; break; } pICMPPkt = (ICMP_PACKET*)pTxPkt->macPkt.pTransportLayer; pICMPPkt->vType = ICMP_TYPE_ECHO_REQUEST; pICMPPkt->vCode = ICMP_CODE_ECHO_REQUEST; pICMPPkt->wChecksum = 0x0000; pICMPPkt->wIdentifier = identifier; pICMPPkt->wSequenceNumber = sequenceNumber; pICMPPkt->wData = payload; pICMPPkt->wChecksum = TCPIP_Helper_CalcIPChecksum((uint8_t*)pICMPPkt, pktSize, 0); pTxPkt->destAddress.Val = targetAddr->Val; pTxPkt->netIfH = TCPIP_IPV4_SelectSourceInterface(0, targetAddr, &pTxPkt->srcAddress, false); if(pTxPkt->netIfH == 0) { // could not find an route res = ICMP_ECHO_ROUTE_ERROR; break; } pTxPkt->macPkt.pDSeg->segLen += pktSize; TCPIP_IPV4_PacketFormatTx(pTxPkt, IP_PROT_ICMP, pktSize); if(!TCPIP_IPV4_PacketTransmit(pTxPkt)) { res = ICMP_ECHO_TRANSMIT_ERROR; break; } res = ICMP_ECHO_OK; break; } if(res < 0 && pTxPkt != 0) { TCPIP_PKT_PacketFree(&pTxPkt->macPkt); } return res; }
// 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); } }