Esempio n. 1
0
error_t ipv4FragmentDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
   uint16_t id, const ChunkedBuffer *payload, size_t payloadOffset, uint8_t timeToLive)
{
   error_t error;
   size_t offset;
   size_t length;
   size_t payloadLength;
   size_t fragmentOffset;
   ChunkedBuffer *fragment;

   //Retrieve the length of the payload
   payloadLength = chunkedBufferGetLength(payload) - payloadOffset;

   //Allocate a memory buffer to hold IP fragments
   fragment = ipAllocBuffer(0, &fragmentOffset);
   //Failed to allocate memory?
   if(!fragment)
      return ERROR_OUT_OF_MEMORY;

   //Split the payload into multiple IP fragments
   for(offset = 0; offset < payloadLength; offset += length)
   {
      //Flush the contents of the fragment
      error = chunkedBufferSetLength(fragment, fragmentOffset);
      //Sanity check
      if(error) break;

      //Process the last fragment?
      if((payloadLength - offset) <= IPV4_MAX_FRAG_SIZE)
      {
         //Size of the current fragment
         length = payloadLength - offset;
         //Copy fragment data
         chunkedBufferConcat(fragment, payload, payloadOffset + offset, length);

         //Do not set the MF flag for the last fragment
         error = ipv4SendPacket(interface, pseudoHeader, id,
            offset / 8, fragment, fragmentOffset, timeToLive);
      }
      else
      {
         //Size of the current fragment (must be a multiple of 8-byte blocks)
         length = IPV4_MAX_FRAG_SIZE;
         //Copy fragment data
         chunkedBufferConcat(fragment, payload, payloadOffset + offset, length);

         //Fragmented packets must have the MF flag set
         error = ipv4SendPacket(interface, pseudoHeader, id,
            IPV4_FLAG_MF | (offset / 8), fragment, fragmentOffset, timeToLive);
      }

      //Failed to send current IP packet?
      if(error) break;
   }

   //Free previously allocated memory
   chunkedBufferFree(fragment);
   //Return status code
   return error;
}
Esempio n. 2
0
error_t mldSendListenerDone(NetInterface *interface, Ipv6Addr *ipAddr)
{
   error_t error;
   size_t offset;
   MldMessage *message;
   ChunkedBuffer *buffer;
   Ipv6PseudoHeader pseudoHeader;

   //Make sure the specified address is a valid multicast address
   if(!ipv6IsMulticastAddr(ipAddr))
      return ERROR_INVALID_ADDRESS;

   //The link-scope all-nodes address (FF02::1) is handled as a special
   //case. The host never sends a report for that address
   if(ipv6CompAddr(ipAddr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
      return ERROR_INVALID_ADDRESS;

   //Allocate a memory buffer to hold a MLD message
   buffer = ipAllocBuffer(sizeof(MldMessage), &offset);
   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the MLD message
   message = chunkedBufferAt(buffer, offset);

   //Format the Multicast Listener Done message
   message->type = ICMPV6_TYPE_MULTICAST_LISTENER_DONE_V1;
   message->code = 0;
   message->checksum = 0;
   message->maxRespDelay = 0;
   message->reserved = 0;
   message->multicastAddr = *ipAddr;

   //Format IPv6 pseudo header
   pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr;
   pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR;
   pseudoHeader.length = HTONS(sizeof(MldMessage));
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Message checksum calculation
   message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(MldMessage));

   //Debug message
   TRACE_INFO("Sending MLD message (%" PRIuSIZE " bytes)...\r\n", sizeof(MldMessage));
   //Dump message contents for debugging purpose
   mldDumpMessage(message);

   //The Multicast Listener Done message is sent to the all-routers multicast address
   error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, MLD_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Esempio n. 3
0
NetBuffer *udpAllocBuffer(size_t length, size_t *offset)
{
    NetBuffer *buffer;

    //Allocate a buffer to hold the UDP header and the payload
    buffer = ipAllocBuffer(length + sizeof(UdpHeader), offset);
    //Failed to allocate buffer?
    if(!buffer) return NULL;

    //Offset to the first byte of the payload
    *offset += sizeof(UdpHeader);

    //Return a pointer to the freshly allocated buffer
    return buffer;
}
Esempio n. 4
0
error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type,
                             uint8_t code, uint8_t parameter, const ChunkedBuffer *ipPacket)
{
    error_t error;
    size_t offset;
    size_t length;
    Ipv4Header *ipHeader;
    ChunkedBuffer *icmpMessage;
    IcmpErrorMessage *icmpHeader;
    Ipv4PseudoHeader pseudoHeader;

    //Retrieve the length of the invoking IPv4 packet
    length = chunkedBufferGetLength(ipPacket);

    //Check the length of the IPv4 packet
    if(length < sizeof(Ipv4Header))
        return ERROR_INVALID_LENGTH;

    //Point to the header of the invoking packet
    ipHeader = chunkedBufferAt(ipPacket, 0);
    //Sanity check
    if(!ipHeader) return ERROR_FAILURE;

    //Never respond to a packet destined to a broadcast or a multicast address
    if(ipv4IsBroadcastAddr(interface, ipHeader->destAddr) ||
            ipv4IsMulticastAddr(ipHeader->destAddr))
    {
        //Report an error
        return ERROR_INVALID_ADDRESS;
    }

    //Length of the data that will be returned along with the ICMP header
    length = MIN(length, ipHeader->headerLength * 4 + 8);

    //Allocate a memory buffer to hold the ICMP message
    icmpMessage = ipAllocBuffer(sizeof(IcmpErrorMessage), &offset);
    //Failed to allocate memory?
    if(!icmpMessage) return ERROR_OUT_OF_MEMORY;

    //Point to the ICMP header
    icmpHeader = chunkedBufferAt(icmpMessage, offset);

    //Format ICMP message
    icmpHeader->type = type;
    icmpHeader->code = code;
    icmpHeader->checksum = 0;
    icmpHeader->parameter = parameter;
    icmpHeader->unused = 0;

    //Copy the IP header and the first 8 bytes of the original datagram data
    error = chunkedBufferConcat(icmpMessage, ipPacket, 0, length);
    //Any error to report?
    if(error)
    {
        //Clean up side effects
        chunkedBufferFree(icmpMessage);
        //Exit immediately
        return error;
    }

    //Get the length of the resulting message
    length = chunkedBufferGetLength(icmpMessage) - offset;
    //Message checksum calculation
    icmpHeader->checksum = ipCalcChecksumEx(icmpMessage, offset, length);

    //Format IPv4 pseudo header
    pseudoHeader.srcAddr = ipHeader->destAddr;
    pseudoHeader.destAddr = ipHeader->srcAddr;
    pseudoHeader.reserved = 0;
    pseudoHeader.protocol = IPV4_PROTOCOL_ICMP;
    pseudoHeader.length = htons(length);

    //Debug message
    TRACE_INFO("Sending ICMP Error message (%" PRIuSIZE " bytes)...\r\n", length);
    //Dump message contents for debugging purpose
    icmpDumpErrorMessage(icmpHeader);

    //Send ICMP Error message
    error = ipv4SendDatagram(interface, &pseudoHeader,
                             icmpMessage, offset, IPV4_DEFAULT_TTL);

    //Free previously allocated memory
    chunkedBufferFree(icmpMessage);
    //Return status code
    return error;
}
Esempio n. 5
0
void icmpProcessEchoRequest(NetInterface *interface,
                            Ipv4Addr srcIpAddr, const ChunkedBuffer *request, size_t requestOffset)
{
    error_t error;
    size_t requestLength;
    size_t replyOffset;
    size_t replyLength;
    ChunkedBuffer *reply;
    IcmpEchoMessage *requestHeader;
    IcmpEchoMessage *replyHeader;
    Ipv4PseudoHeader pseudoHeader;

    //Retrieve the length of the Echo Request message
    requestLength = chunkedBufferGetLength(request) - requestOffset;

    //Ensure the packet length is correct
    if(requestLength < sizeof(IcmpEchoMessage))
        return;

    //Point to the Echo Request header
    requestHeader = chunkedBufferAt(request, requestOffset);
    //Sanity check
    if(!requestHeader) return;

    //Debug message
    TRACE_INFO("ICMP Echo Request message received (%" PRIuSIZE " bytes)...\r\n", requestLength);
    //Dump message contents for debugging purpose
    icmpDumpEchoMessage(requestHeader);

    //Allocate memory to hold the Echo Reply message
    reply = ipAllocBuffer(sizeof(IcmpEchoMessage), &replyOffset);
    //Failed to allocate memory?
    if(!reply) return;

    //Point to the Echo Reply header
    replyHeader = chunkedBufferAt(reply, replyOffset);

    //Format Echo Reply header
    replyHeader->type = ICMP_TYPE_ECHO_REPLY;
    replyHeader->code = 0;
    replyHeader->checksum = 0;
    replyHeader->identifier = requestHeader->identifier;
    replyHeader->sequenceNumber = requestHeader->sequenceNumber;

    //Point to the first data byte
    requestOffset += sizeof(IcmpEchoMessage);
    requestLength -= sizeof(IcmpEchoMessage);

    //Copy data
    error = chunkedBufferConcat(reply, request, requestOffset, requestLength);
    //Any error to report?
    if(error)
    {
        //Clean up side effects
        chunkedBufferFree(reply);
        //Exit immediately
        return;
    }

    //Get the length of the resulting message
    replyLength = chunkedBufferGetLength(reply) - replyOffset;
    //Calculate ICMP header checksum
    replyHeader->checksum = ipCalcChecksumEx(reply, replyOffset, replyLength);

    //Format IPv4 pseudo header
    pseudoHeader.srcAddr = interface->ipv4Config.addr;
    pseudoHeader.destAddr = srcIpAddr;
    pseudoHeader.reserved = 0;
    pseudoHeader.protocol = IPV4_PROTOCOL_ICMP;
    pseudoHeader.length = htons(replyLength);

    //Debug message
    TRACE_INFO("Sending ICMP Echo Reply message (%" PRIuSIZE " bytes)...\r\n", replyLength);
    //Dump message contents for debugging purpose
    icmpDumpEchoMessage(replyHeader);

    //Send Echo Reply message
    ipv4SendDatagram(interface, &pseudoHeader, reply, replyOffset, IPV4_DEFAULT_TTL);

    //Free previously allocated memory block
    chunkedBufferFree(reply);
}
Esempio n. 6
0
error_t ndpSendNeighborAdv(NetInterface *interface,
   const Ipv6Addr *targetIpAddr, const Ipv6Addr *destIpAddr)
{
   error_t error;
   size_t offset;
   size_t length;
   ChunkedBuffer *buffer;
   NdpNeighborAdvMessage *message;
   Ipv6PseudoHeader pseudoHeader;

   //Allocate a memory buffer to hold the Neighbor Advertisement
   //message and the Target Link-Layer Address option
   buffer = ipAllocBuffer(sizeof(NdpNeighborAdvMessage) +
      sizeof(NdpLinkLayerAddrOption), &offset);

   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the message
   message = chunkedBufferAt(buffer, offset);

   //Format Neighbor Advertisement message
   message->type = ICMPV6_TYPE_NEIGHBOR_ADV;
   message->code = 0;
   message->checksum = 0;
   message->reserved1 = 0;
   message->o = TRUE;
   message->s = FALSE;
   message->r = FALSE;
   message->reserved2 = 0;
   message->targetAddr = *targetIpAddr;

   //Length of the message, excluding any option
   length = sizeof(NdpNeighborAdvMessage);

   //Add Target Link-Layer Address option
   ndpAddOption(message, &length, NDP_OPT_TARGET_LINK_LAYER_ADDR,
      &interface->macAddr, sizeof(MacAddr));

   //Adjust the length of the multi-part buffer
   chunkedBufferSetLength(buffer, offset + length);

   //Format IPv6 pseudo header
   pseudoHeader.srcAddr = *targetIpAddr;
   pseudoHeader.destAddr = *destIpAddr;
   pseudoHeader.length = htonl(length);
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Destination IP address is the unspecified address?
   if(ipv6CompAddr(destIpAddr, &IPV6_UNSPECIFIED_ADDR))
   {
      //If the destination is the unspecified address, the node
      //must set the Solicited flag to zero and multicast the
      //advertisement to the all-nodes address
      pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_NODES_ADDR;
   }
   else
   {
      //Otherwise, the node must set the Solicited flag to one and
      //unicast the advertisement to the destination IP address
      message->s = TRUE;
   }

   //Calculate ICMPv6 header checksum
   message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), buffer, offset, length);

   //Debug message
   TRACE_INFO("Sending Neighbor Advertisement message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   ndpDumpNeighborAdvMessage(message);

   //Send Neighbor Advertisement message
   error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Esempio n. 7
0
error_t ndpSendNeighborSol(NetInterface *interface, const Ipv6Addr *targetIpAddr)
{
   error_t error;
   size_t offset;
   size_t length;
   ChunkedBuffer *buffer;
   NdpNeighborSolMessage *message;
   Ipv6PseudoHeader pseudoHeader;

   //Allocate a memory buffer to hold the Neighbor Solicitation
   //message and the Source Link-Layer Address option
   buffer = ipAllocBuffer(sizeof(NdpNeighborSolMessage) +
      sizeof(NdpLinkLayerAddrOption), &offset);

   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the message
   message = chunkedBufferAt(buffer, offset);

   //Format Neighbor Solicitation message
   message->type = ICMPV6_TYPE_NEIGHBOR_SOL;
   message->code = 0;
   message->checksum = 0;
   message->reserved = 0;
   message->targetAddr = *targetIpAddr;

   //Length of the message, excluding any option
   length = sizeof(NdpNeighborSolMessage);

   //Check whether the target address is a tentative address
   if(ipv6IsTentativeAddr(interface, targetIpAddr))
   {
      //The IPv6 source is set to the unspecified address
      pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
   }
   else
   {
      //The Source Link-Layer Address option must not be included
      //when the host IPv6 address is unspecified
      if(!ipv6CompAddr(&interface->ipv6Config.linkLocalAddr, &IPV6_UNSPECIFIED_ADDR))
      {
         //Add Source Link-Layer Address option
         ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR,
            &interface->macAddr, sizeof(MacAddr));
      }

      //Set the IPv6 source address
      pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr;
   }

   //Adjust the length of the multi-part buffer
   chunkedBufferSetLength(buffer, offset + length);

   //Compute the solicited-node multicast address that
   //corresponds to the target IPv6 address
   ipv6ComputeSolicitedNodeAddr(targetIpAddr, &pseudoHeader.destAddr);

   //Format IPv6 pseudo header
   pseudoHeader.length = htonl(length);
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Calculate ICMPv6 header checksum
   message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), buffer, offset, length);

   //Debug message
   TRACE_INFO("Sending Neighbor Solicitation message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   ndpDumpNeighborSolMessage(message);

   //Send Neighbor Solicitation message
   error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Esempio n. 8
0
error_t icmpv6SendErrorMessage(NetInterface *interface, uint8_t type,
   uint8_t code, uint32_t parameter, const ChunkedBuffer *ipPacket)
{
   error_t error;
   size_t offset;
   size_t length;
   Ipv6Header *ipHeader;
   ChunkedBuffer *icmpMessage;
   Icmpv6ErrorMessage *icmpHeader;
   Ipv6PseudoHeader pseudoHeader;

   //Retrieve the length of the invoking IPv6 packet
   length = chunkedBufferGetLength(ipPacket);

   //Check the length of the IPv6 packet
   if(length < sizeof(Ipv6Header))
      return ERROR_INVALID_LENGTH;

   //Point to the header of the invoking packet
   ipHeader = chunkedBufferAt(ipPacket, 0);
   //Sanity check
   if(!ipHeader) return ERROR_FAILURE;

   //Never respond to a packet destined to an IPv6 multicast address
   if(ipv6IsMulticastAddr(&ipHeader->destAddr))
      return ERROR_INVALID_ADDRESS;

   //Return as much of invoking IPv6 packet as possible without
   //the ICMPv6 packet exceeding the minimum IPv6 MTU
   length = MIN(length, IPV6_DEFAULT_MTU -
      sizeof(Ipv6Header) - sizeof(Icmpv6ErrorMessage));

   //Allocate a memory buffer to hold the ICMPv6 message
   icmpMessage = ipAllocBuffer(sizeof(Icmpv6ErrorMessage), &offset);
   //Failed to allocate memory?
   if(!icmpMessage) return ERROR_OUT_OF_MEMORY;

   //Point to the ICMPv6 header
   icmpHeader = chunkedBufferAt(icmpMessage, offset);

   //Format ICMPv6 Error message
   icmpHeader->type = type;
   icmpHeader->code = code;
   icmpHeader->checksum = 0;
   icmpHeader->parameter = htonl(parameter);

   //Copy incoming IPv6 packet contents
   error = chunkedBufferConcat(icmpMessage, ipPacket, 0, length);
   //Any error to report?
   if(error)
   {
      //Clean up side effects
      chunkedBufferFree(icmpMessage);
      //Exit immediately
      return error;
   }

   //Get the length of the resulting message
   length = chunkedBufferGetLength(icmpMessage) - offset;

   //Format IPv6 pseudo header
   pseudoHeader.srcAddr = ipHeader->destAddr;
   pseudoHeader.destAddr = ipHeader->srcAddr;
   pseudoHeader.length = htonl(length);
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Message checksum calculation
   icmpHeader->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), icmpMessage, offset, length);

   //Debug message
   TRACE_INFO("Sending ICMPv6 Error message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   icmpv6DumpErrorMessage(icmpHeader);

   //Send ICMPv6 Error message
   error = ipv6SendDatagram(interface, &pseudoHeader,
      icmpMessage, offset, IPV6_DEFAULT_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(icmpMessage);
   //Return status code
   return error;
}
Esempio n. 9
0
error_t ipv6FragmentDatagram(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
   const ChunkedBuffer *payload, size_t payloadOffset, uint8_t hopLimit)
{
   error_t error;
   uint32_t id;
   size_t offset;
   size_t length;
   size_t payloadLength;
   size_t fragmentOffset;
   ChunkedBuffer *fragment;

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

   //Retrieve the length of the payload
   payloadLength = chunkedBufferGetLength(payload) - payloadOffset;

   //Allocate a memory buffer to hold IP fragments
   fragment = ipAllocBuffer(0, &fragmentOffset);
   //Failed to allocate memory?
   if(!fragment)
      return ERROR_OUT_OF_MEMORY;

   //Split the payload into multiple IP fragments
   for(offset = 0; offset < payloadLength; offset += length)
   {
      //Flush the contents of the fragment
      error = chunkedBufferSetLength(fragment, fragmentOffset);
      //Sanity check
      if(error) break;

      //Process the last fragment?
      if((payloadLength - offset) <= IPV6_MAX_FRAG_SIZE)
      {
         //Size of the current fragment
         length = payloadLength - offset;
         //Copy fragment data
         chunkedBufferConcat(fragment, payload, payloadOffset + offset, length);

         //Do not set the MF flag for the last fragment
         error = ipv6SendPacket(interface, pseudoHeader, id,
            offset, fragment, fragmentOffset, hopLimit);
      }
      else
      {
         //Size of the current fragment (must be a multiple of 8-byte blocks)
         length = IPV6_MAX_FRAG_SIZE;
         //Copy fragment data
         chunkedBufferConcat(fragment, payload, payloadOffset + offset, length);

         //Fragmented packets must have the M flag set
         error = ipv6SendPacket(interface, pseudoHeader, id,
            offset | IPV6_FLAG_M, fragment, fragmentOffset, hopLimit);
      }

      //Failed to send current IP fragment?
      if(error) break;
   }

   //Free previously allocated memory
   chunkedBufferFree(fragment);
   //Return status code
   return error;
}
Esempio n. 10
0
error_t rawSocketSendIpPacket(Socket *socket, const IpAddr *destIpAddr,
   const void *data, size_t length, size_t *written)
{
   error_t error;
   size_t offset;
   uint_t timeToLive;
   NetBuffer *buffer;
   NetInterface *interface;
   IpPseudoHeader pseudoHeader;

   //The socket may be bound to a particular network interface
   interface = socket->interface;

   //Allocate a buffer memory to hold the raw IP datagram
   buffer = ipAllocBuffer(0, &offset);
   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Copy the raw data
      error = netBufferAppend(buffer, data, length);
      //Any error to report?
      if(error) break;

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

         //Select the source IPv4 address and the relevant network interface
         //to use when sending data to the specified destination host
         error = ipv4SelectSourceAddr(&interface, destIpAddr->ipv4Addr, &srcIpAddr);
         //Any error to report?
         if(error) break;

         //Format IPv4 pseudo header
         pseudoHeader.length = sizeof(Ipv4PseudoHeader);
         pseudoHeader.ipv4Data.srcAddr = srcIpAddr;
         pseudoHeader.ipv4Data.destAddr = destIpAddr->ipv4Addr;
         pseudoHeader.ipv4Data.reserved = 0;
         pseudoHeader.ipv4Data.protocol = socket->protocol;
         pseudoHeader.ipv4Data.length = htons(length);

         //Set TTL value
         timeToLive = IPV4_DEFAULT_TTL;
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //Destination address is an IPv6 address?
      if(destIpAddr->length == sizeof(Ipv6Addr))
      {
         //Select the source IPv6 address and the relevant network interface
         //to use when sending data to the specified destination host
         error = ipv6SelectSourceAddr(&interface,
            &destIpAddr->ipv6Addr, &pseudoHeader.ipv6Data.srcAddr);

         //Any error to report?
         if(error) break;

         //Format IPv6 pseudo header
         pseudoHeader.length = sizeof(Ipv6PseudoHeader);
         pseudoHeader.ipv6Data.destAddr = destIpAddr->ipv6Addr;
         pseudoHeader.ipv6Data.length = htonl(length);
         pseudoHeader.ipv6Data.reserved = 0;
         pseudoHeader.ipv6Data.nextHeader = socket->protocol;

         //Set Hop Limit value
         timeToLive = IPV6_DEFAULT_HOP_LIMIT;
      }
      else
#endif
      //Invalid destination address?
      {
         //An internal error has occurred
         error = ERROR_FAILURE;
         //Exit immediately
         break;
      }

      //Send raw IP datagram
      error = ipSendDatagram(interface, &pseudoHeader, buffer, offset, timeToLive);
      //Failed to send data?
      if(error) break;

      //Total number of bytes successfully transmitted
      if(written != NULL)
         *written = length;

      //End of exception handling block
   } while(0);

   //Free previously allocated memory block
   netBufferFree(buffer);
   //Return status code
   return error;
}