Пример #1
0
error_t ipv4SendDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
   NetBuffer *buffer, size_t offset, uint8_t ttl)
{
   error_t error;
   size_t length;
   uint16_t id;

   //Retrieve the length of payload
   length = netBufferGetLength(buffer) - offset;

   //Check whether the TTL value is zero
   if(ttl == 0)
   {
      //Use default Time-To-Live value
      ttl = IPV4_DEFAULT_TTL;
   }

   //Identification field is primarily used to identify
   //fragments of an original IP datagram
   id = osAtomicInc16(&interface->ipv4Identification);

   //If the payload length is smaller than the network
   //interface MTU then no fragmentation is needed
   if((length + sizeof(Ipv4Header)) <= interface->ipv4Config.mtu)
   {
      //Send data as is
      error = ipv4SendPacket(interface,
         pseudoHeader, id, 0, buffer, offset, ttl);
   }
   //If the payload length exceeds the network interface MTU
   //then the device must fragment the data
   else
   {
#if (IPV4_FRAG_SUPPORT == ENABLED)
      //Fragment IP datagram into smaller packets
      error = ipv4FragmentDatagram(interface,
         pseudoHeader, id, buffer, offset, ttl);
#else
      //Fragmentation is not supported
      error = ERROR_MESSAGE_TOO_LONG;
#endif
   }

   //Return status code
   return error;
}
Пример #2
0
error_t ipv4SendDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
                         ChunkedBuffer *buffer, size_t offset, uint8_t timeToLive)
{
    error_t error;
    size_t length;
    uint16_t id;

    //Retrieve the length of payload
    length = chunkedBufferGetLength(buffer) - offset;

    //Identification field is primarily used to identify
    //fragments of an original IP datagram
    id = osAtomicInc16(&interface->ipv4Identification);

    //If the payload length is smaller than the network
    //interface MTU then no fragmentation is needed
    if(length <= IPV4_MAX_PAYLOAD_SIZE)
    {
        //Send data as is
        error = ipv4SendPacket(interface,
                               pseudoHeader, id, 0, buffer, offset, timeToLive);
    }
    //If the payload length exceeds the network interface MTU
    //then the device must fragment the data
    else
    {
#if (IPV4_FRAG_SUPPORT == ENABLED)
        //Fragment IP datagram into smaller packets
        error = ipv4FragmentDatagram(interface,
                                     pseudoHeader, id, buffer, offset, timeToLive);
#else
        //Fragmentation is not supported
        error = ERROR_MESSAGE_TOO_LONG;
#endif
    }

    //Return status code
    return error;
}
Пример #3
0
error_t ping(NetInterface *interface, const IpAddr *ipAddr, time_t timeout, time_t *rtt)
{
   error_t error;
   uint_t i;
   size_t length;
   uint16_t identifier;
   uint16_t sequenceNumber;
   time_t startTime;
   time_t roundTripTime;
   Socket *socket;
   IcmpEchoMessage *message;

   //Debug message
   TRACE_INFO("Pinging %s with 64 bytes of data...\r\n", ipAddrToString(ipAddr, NULL));

   //Length of the complete ICMP message including header and data
   length = sizeof(IcmpEchoMessage) + PING_DATA_SIZE;

   //Allocate memory buffer to hold an ICMP message
   message = osMemAlloc(length);
   //Failed to allocate memory?
   if(!message) return ERROR_OUT_OF_MEMORY;

   //Identifier field is used to help matching requests and replies
   identifier = rand();
   //Sequence Number field is increment each time an Echo Request is sent
   sequenceNumber = osAtomicInc16(&pingSequenceNumber);

   //Format ICMP Echo Request message
   message->type = ICMP_TYPE_ECHO_REQUEST;
   message->code = 0;
   message->checksum = 0;
   message->identifier = identifier;
   message->sequenceNumber = sequenceNumber;

   //Copy data
   for(i = 0; i < PING_DATA_SIZE; i++)
      message->data[i] = i;

#if (IPV4_SUPPORT == ENABLED)
   //Target address is an IPv4 address?
   if(ipAddr->length == sizeof(Ipv4Addr))
   {
      Ipv4Addr srcIpAddr;

      //Select the source IPv4 address and the relevant network
      //interface to use when pinging the specified host
      error = ipv4SelectSourceAddr(&interface, ipAddr->ipv4Addr, &srcIpAddr);

      //Any error to report?
      if(error)
      {
         //Free previously allocated memory
         osMemFree(message);
         //Return the corresponding error code
         return error;
      }

      //ICMP Echo Request message
      message->type = ICMP_TYPE_ECHO_REQUEST;
      //Message checksum calculation
      message->checksum = ipCalcChecksum(message, length);

      //Open a raw socket
      socket = socketOpen(SOCKET_TYPE_RAW, SOCKET_PROTOCOL_ICMP);
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //Target address is an IPv6 address?
   if(ipAddr->length == sizeof(Ipv6Addr))
   {
      Ipv6PseudoHeader pseudoHeader;

      //Select the source IPv6 address and the relevant network
      //interface to use when pinging the specified host
      error = ipv6SelectSourceAddr(&interface, &ipAddr->ipv6Addr, &pseudoHeader.srcAddr);

      //Any error to report?
      if(error)
      {
         //Free previously allocated memory
         osMemFree(message);
         //Return the corresponding error code
         return error;
      }

      //ICMPv6 Echo Request message
      message->type = ICMPV6_TYPE_ECHO_REQUEST;
      //Format IPv6 pseudo header
      pseudoHeader.destAddr = ipAddr->ipv6Addr;
      pseudoHeader.length = htonl(length);
      pseudoHeader.reserved = 0;
      pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

      //Message checksum calculation
      message->checksum = ipCalcUpperLayerChecksum(
         &pseudoHeader, sizeof(Ipv6PseudoHeader), message, length);

      //Open a raw socket
      socket = socketOpen(SOCKET_TYPE_RAW, SOCKET_PROTOCOL_ICMPV6);
   }
   else
#endif
   //Target address is not valid?
   {
      //Free previously allocated memory
      osMemFree(message);
      //Report an error
      return ERROR_INVALID_ADDRESS;
   }

   //Failed to open socket?
   if(!socket)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Report an error
      return ERROR_OPEN_FAILED;
   }

   //Associate the newly created socket with the relevant interface
   error = socketBindToInterface(socket, interface);

   //Unable to bind the socket to the desired interface?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Connect the socket to the target host
   error = socketConnect(socket, ipAddr, 0);

   //Any error to report?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Send Echo Request message
   error = socketSend(socket, message, length, NULL, 0);

   //Failed to send message ?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Save the time at which the request was sent
   startTime = osGetTickCount();

   //Timeout value exceeded?
   while((osGetTickCount() - startTime) < timeout)
   {
      //Adjust receive timeout
      error = socketSetTimeout(socket, timeout);
      //Any error to report?
      if(error) break;

      //Wait for an incoming ICMP message
      error = socketReceive(socket, message,
         sizeof(IcmpEchoMessage) + PING_DATA_SIZE, &length, 0);
      //Any error to report?
      if(error) break;

      //Check message length
      if(length != (sizeof(IcmpEchoMessage) + PING_DATA_SIZE))
         continue;
      //Verify message type
      if(ipAddr->length == sizeof(Ipv4Addr) && message->type != ICMP_TYPE_ECHO_REPLY)
         continue;
      if(ipAddr->length == sizeof(Ipv6Addr) && message->type != ICMPV6_TYPE_ECHO_REPLY)
         continue;
      //Response identifier matches request identifier?
      if(message->identifier != identifier)
         continue;
      //Make sure the sequence number is correct
      if(message->sequenceNumber != sequenceNumber)
         continue;

      //Loop through data field
      for(i = 0; i < PING_DATA_SIZE; i++)
      {
         //Compare received data against expected data
         if(message->data[i] != i) break;
      }

      //Valid Echo Reply message received?
      if(i == PING_DATA_SIZE)
      {
         //Calculate round-trip time
         roundTripTime = osGetTickCount() - startTime;
         //Debug message
         TRACE_INFO("Echo received (round-trip time = %ums)...\r\n", roundTripTime);

         //Free previously allocated memory
         osMemFree(message);
         //Close socket
         socketClose(socket);

         //Return round-trip time
         if(rtt) *rtt = roundTripTime;

         //No error to report
         return NO_ERROR;
      }
   }

   //Debug message
   TRACE_INFO("No echo received!\r\n");
   //Free previously allocated memory
   osMemFree(message);
   //Close socket
   socketClose(socket);

   //No Echo Reply received from host...
   return ERROR_NO_RESPONSE;
}