Beispiel #1
0
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);
}
Beispiel #2
0
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
                       uint16_t fragId, uint16_t fragOffset, ChunkedBuffer *buffer, size_t offset, uint8_t timeToLive)
{
    error_t error;
    size_t length;
    Ipv4Addr destIpAddr = 0;
    MacAddr destMacAddr;
    Ipv4Header *packet;

    //Is there enough space for the IPv4 header?
    if(offset < sizeof(Ipv4Header))
        return ERROR_INVALID_PARAMETER;

    //Make room for the header
    offset -= sizeof(Ipv4Header);
    //Calculate the size of the entire packet, including header and data
    length = chunkedBufferGetLength(buffer) - offset;

    //Point to the IPv4 header
    packet = chunkedBufferAt(buffer, offset);

    //Format IPv4 header
    packet->version = IPV4_VERSION;
    packet->headerLength = 5;
    packet->typeOfService = 0;
    packet->totalLength = htons(length);
    packet->identification = htons(fragId);
    packet->fragmentOffset = htons(fragOffset);
    packet->timeToLive = timeToLive;
    packet->protocol = pseudoHeader->protocol;
    packet->headerChecksum = 0;
    packet->srcAddr = pseudoHeader->srcAddr;
    packet->destAddr = pseudoHeader->destAddr;

    //Calculate IP header checksum
    packet->headerChecksum = ipCalcChecksumEx(buffer, offset, packet->headerLength * 4);

    //Ensure the source address is valid
    error = ipv4CheckSourceAddr(interface, pseudoHeader->srcAddr);
    //Invalid source address?
    if(error) return error;

    //Destination address is the unspecified address?
    if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR)
    {
        //Destination address is not acceptable
        error = ERROR_INVALID_ADDRESS;
    }
    //Destination address is the loopback address?
    else if(pseudoHeader->destAddr == IPV4_LOOPBACK_ADDR)
    {
        //Not yet implemented...
        error = ERROR_NOT_IMPLEMENTED;
    }
    //Destination address is a broadcast address?
    else if(ipv4IsBroadcastAddr(interface, pseudoHeader->destAddr))
    {
        //Destination IPv4 address
        destIpAddr = pseudoHeader->destAddr;
        //Make use of the broadcast MAC address
        destMacAddr = MAC_BROADCAST_ADDR;
        //No error to report
        error = NO_ERROR;
    }
    //Destination address is a multicast address?
    else if(ipv4IsMulticastAddr(pseudoHeader->destAddr))
    {
        //Destination IPv4 address
        destIpAddr = pseudoHeader->destAddr;
        //Map IPv4 multicast address to MAC-layer multicast address
        error = ipv4MapMulticastAddrToMac(pseudoHeader->destAddr, &destMacAddr);
    }
    //Destination host is in the local subnet?
    else if(ipv4IsInLocalSubnet(interface, pseudoHeader->destAddr))
    {
        //Destination IPv4 address
        destIpAddr = pseudoHeader->destAddr;
        //Resolve host address before sending the packet
        error = arpResolve(interface, pseudoHeader->destAddr, &destMacAddr);
    }
    //Destination host is outside the local subnet?
    else
    {
        //Make sure the default gateway is properly set
        if(interface->ipv4Config.defaultGateway != IPV4_UNSPECIFIED_ADDR)
        {
            //Use the default gateway to forward the packet
            destIpAddr = interface->ipv4Config.defaultGateway;
            //Perform address resolution
            error = arpResolve(interface, interface->ipv4Config.defaultGateway, &destMacAddr);
        }
        else
        {
            //There is no route to the outside world...
            error = ERROR_NO_ROUTE;
        }
    }

    //Successful address resolution?
    if(!error)
    {
        //Debug message
        TRACE_INFO("Sending IPv4 packet (%u bytes)...\r\n", length);
        //Dump IP header contents for debugging purpose
        ipv4DumpHeader(packet);

        //Send Ethernet frame
        error = ethSendFrame(interface, &destMacAddr, buffer, offset, ETH_TYPE_IPV4);
    }
    //Address resolution is in progress?
    else if(error == ERROR_IN_PROGRESS)
    {
        //Debug message
        TRACE_INFO("Enqueuing IPv4 packet (%u bytes)...\r\n", length);
        //Dump IP header contents for debugging purpose
        ipv4DumpHeader(packet);

        //Enqueue packets waiting for address resolution
        error = arpEnqueuePacket(interface, destIpAddr, buffer, offset);
    }
    //Address resolution failed?
    else
    {
        //Debug message
        TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n");
    }

    //Return status code
    return error;
}
Beispiel #3
0
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);
    }
}
Beispiel #4
0
void ipv4ProcessPacket(NetInterface *interface,
                       const MacAddr *srcMacAddr, Ipv4Header *packet, size_t length)
{
    //Ensure the packet length is greater than 20 bytes
    if(length < sizeof(Ipv4Header))
        return;

    //Debug message
    TRACE_INFO("IPv4 packet received (%u bytes)...\r\n", length);
    //Dump IP header contents for debugging purpose
    ipv4DumpHeader(packet);

    //A packet whose version number is not 4 must be silently discarded
    if(packet->version != IPV4_VERSION)
        return;
    //Valid IPv4 header shall contains more than five 32-bit words
    if(packet->headerLength < 5)
        return;
    //Ensure the total length is correct before processing the packet
    if(ntohs(packet->totalLength) < (packet->headerLength * 4))
        return;
    if(ntohs(packet->totalLength) > length)
        return;
    //Destination address filtering
    if(ipv4CheckDestAddr(interface, packet->destAddr))
        return;
    //Source address filtering
    if(ipv4CheckSourceAddr(interface, packet->srcAddr))
        return;

    //The host must verify the IP header checksum on every received
    //datagram and silently discard every datagram that has a bad
    //checksum (see RFC 1122 3.2.1.2)
    if(ipCalcChecksum(packet, packet->headerLength * 4) != 0x0000)
    {
        //Debug message
        TRACE_WARNING("Wrong IP header checksum!\r\n");
        //Discard incoming packet
        return;
    }

    //Convert the total length from network byte order
    length = ntohs(packet->totalLength);

    //A fragmented packet was received?
    if(ntohs(packet->fragmentOffset) & (IPV4_FLAG_MF | IPV4_OFFSET_MASK))
    {
#if (IPV4_FRAG_SUPPORT == ENABLED)
        //Acquire exclusive access to the reassembly queue
        osMutexAcquire(interface->ipv4FragQueueMutex);
        //Reassemble the original datagram
        ipv4ReassembleDatagram(interface, srcMacAddr, packet, length);
        //Release exclusive access to the reassembly queue
        osMutexRelease(interface->ipv4FragQueueMutex);
#endif
    }
    else
    {
        ChunkedBuffer1 buffer;

        //Unfragmented datagrams fit in a single chunk
        buffer.chunkCount = 1;
        buffer.maxChunkCount = 1;
        buffer.chunk[0].address = packet;
        buffer.chunk[0].length = length;

        //Pass the IPv4 datagram to the higher protocol layer
        ipv4ProcessDatagram(interface, srcMacAddr, (ChunkedBuffer *) &buffer);
    }
}