void ipv4FragTick(NetInterface *interface) { error_t error; uint_t i; time_t time; Ipv4HoleDesc *hole; //Acquire exclusive access to the reassembly queue osMutexAcquire(interface->ipv4FragQueueMutex); //Get current time time = osGetTickCount(); //Loop through the reassembly queue for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++) { //Point to the current entry in the reassembly queue Ipv4FragDesc *frag = &interface->ipv4FragQueue[i]; //Make sure the entry is currently in use if(frag->buffer.chunkCount > 0) { //If the timer runs out, the partially-reassembled datagram must be //discarded and ICMP Time Exceeded message sent to the source host if((time - frag->timestamp) >= IPV4_FRAG_TIME_TO_LIVE) { //Debug message TRACE_INFO("IPv4 fragment reassembly timeout...\r\n"); //Dump IP header contents for debugging purpose ipv4DumpHeader(frag->buffer.chunk[0].address); //Point to the first hole descriptor hole = ipv4FindHole(frag, frag->firstHole); //Make sure the fragment zero has been received //before sending an ICMP message if(hole != NULL && hole->first > 0) { //Fix the size of the reconstructed datagram error = chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, frag->headerLength + hole->first); //Check status code if(!error) { //Send an ICMP Time Exceeded message icmpSendErrorMessage(interface, ICMP_TYPE_TIME_EXCEEDED, ICMP_CODE_REASSEMBLY_TIME_EXCEEDED, 0, (ChunkedBuffer *) &frag->buffer); } } //Drop the partially reconstructed datagram chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, 0); } } } //Release exclusive access to the reassembly queue osMutexRelease(interface->ipv4FragQueueMutex); }
void ipv4ProcessDatagram(NetInterface *interface, const MacAddr *srcMacAddr, const ChunkedBuffer *buffer) { error_t error; size_t offset; size_t length; Ipv4Header *header; IpPseudoHeader pseudoHeader; //Retrieve the length of the IPv4 datagram length = chunkedBufferGetLength(buffer); //Point to the IPv4 header header = chunkedBufferAt(buffer, 0); //Sanity check if(!header) return; //Debug message TRACE_INFO("IPv4 datagram received (%u bytes)...\r\n", length); //Dump IP header contents for debugging purpose ipv4DumpHeader(header); //Get the offset to the payload offset = header->headerLength * 4; //Compute the length of the payload length -= header->headerLength * 4; //Form the IPv4 pseudo header pseudoHeader.length = sizeof(Ipv4PseudoHeader); pseudoHeader.ipv4Data.srcAddr = header->srcAddr; pseudoHeader.ipv4Data.destAddr = header->destAddr; pseudoHeader.ipv4Data.reserved = 0; pseudoHeader.ipv4Data.protocol = header->protocol; pseudoHeader.ipv4Data.length = htons(length); //Check the protocol field switch(header->protocol) { //ICMP protocol? case IPV4_PROTOCOL_ICMP: //Process incoming ICMP message icmpProcessMessage(interface, header->srcAddr, buffer, offset); #if (RAW_SOCKET_SUPPORT == ENABLED) //Allow raw sockets to process ICMP messages rawSocketProcessDatagram(interface, &pseudoHeader, buffer, offset); #endif //No error to report error = NO_ERROR; //Continue processing break; #if (IGMP_SUPPORT == ENABLED) //IGMP protocol? case IPV4_PROTOCOL_IGMP: //Process incoming IGMP message igmpProcessMessage(interface, buffer, offset); #if (RAW_SOCKET_SUPPORT == ENABLED) //Allow raw sockets to process IGMP messages rawSocketProcessDatagram(interface, &pseudoHeader, buffer, offset); #endif //No error to report error = NO_ERROR; //Continue processing break; #endif #if (TCP_SUPPORT == ENABLED) //TCP protocol? case IPV4_PROTOCOL_TCP: //Process incoming TCP segment tcpProcessSegment(interface, &pseudoHeader, buffer, offset); //No error to report error = NO_ERROR; //Continue processing break; #endif #if (UDP_SUPPORT == ENABLED) //UDP protocol? case IPV4_PROTOCOL_UDP: //Process incoming UDP datagram error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset); //Continue processing break; #endif //Unknown protocol? default: #if (RAW_SOCKET_SUPPORT == ENABLED) //Allow raw sockets to process IPv4 packets error = rawSocketProcessDatagram(interface, &pseudoHeader, buffer, offset); #else //Report an error error = ERROR_PROTOCOL_UNREACHABLE; #endif //Continue processing break; } //Unreachable protocol? if(error == ERROR_PROTOCOL_UNREACHABLE) { //Send a Destination Unreachable message icmpSendErrorMessage(interface, ICMP_TYPE_DEST_UNREACHABLE, ICMP_CODE_PROTOCOL_UNREACHABLE, 0, buffer); } //Unreachable port? else if(error == ERROR_PORT_UNREACHABLE) { //Send a Destination Unreachable message icmpSendErrorMessage(interface, ICMP_TYPE_DEST_UNREACHABLE, ICMP_CODE_PORT_UNREACHABLE, 0, buffer); } }