示例#1
0
ChunkedBuffer *chunkedBufferAlloc(size_t length)
{
   error_t error;
   ChunkedBuffer *buffer;

   //Allocate memory to hold the multi-part buffer
   buffer = memPoolAlloc(MEM_POOL_BUFFER_SIZE);
   //Failed to allocate memory?
   if(!buffer) return NULL;

   //The multi-part buffer consists of a single chunk
   buffer->chunkCount = 1;
   buffer->maxChunkCount = MAX_CHUNK_COUNT;
   buffer->chunk[0].address = (uint8_t *) buffer + MAX_CHUNK_COUNT * sizeof(ChunkDesc);
   buffer->chunk[0].length = MEM_POOL_BUFFER_SIZE - MAX_CHUNK_COUNT * sizeof(ChunkDesc);
   buffer->chunk[0].size = 0;

   //Adjust the length of the buffer
   error = chunkedBufferSetLength(buffer, length);
   //Any error to report?
   if(error)
   {
      //Clean up side effects
      chunkedBufferFree(buffer);
      //Report an failure
      return NULL;
   }

   //Successful memory allocation
   return buffer;
}
示例#2
0
文件: udp.c 项目: rpc-fw/analyzer
error_t udpReceiveDatagram(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort,
   IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
{
   SocketQueueItem *queueItem;

   //The receive queue is empty?
   if(!socket->receiveQueue)
   {
      //Set the events the application is interested in
      socket->eventMask = SOCKET_EVENT_RX_READY;
      //Reset the event object
      osEventReset(socket->event);
      //Leave critical section
      osMutexRelease(socketMutex);
      //Wait until an event is triggered
      osEventWait(socket->event, socket->timeout);
      //Enter critical section
      osMutexAcquire(socketMutex);
   }

   //Check whether the read operation timed out
   if(!socket->receiveQueue)
   {
      //No data can be read
      *received = 0;
      //Report a timeout error
      return ERROR_TIMEOUT;
   }

   //Point to the first item in the receive queue
   queueItem = socket->receiveQueue;
   //Copy data to user buffer
   *received = chunkedBufferRead(data, queueItem->buffer, queueItem->offset, size);

   //Save the source IP address
   if(srcIpAddr)
      *srcIpAddr = queueItem->srcIpAddr;
   //Save the source port number
   if(srcPort)
      *srcPort = queueItem->srcPort;
   //Save the destination IP address
   if(destIpAddr)
      *destIpAddr = queueItem->destIpAddr;

   //If the SOCKET_FLAG_PEEK flag is set, the data is copied
   //into the buffer but is not removed from the input queue
   if(!(flags & SOCKET_FLAG_PEEK))
   {
      //Remove the item from the receive queue
      socket->receiveQueue = queueItem->next;
      //Deallocate memory buffer
      chunkedBufferFree(queueItem->buffer);
   }

   //Update the state of events
   udpUpdateEvents(socket);

   //Successful read operation
   return NO_ERROR;
}
示例#3
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;
}
示例#4
0
文件: mld.c 项目: rpc-fw/analyzer
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;
}
示例#5
0
error_t rawSocketReceiveEthPacket(Socket *socket,
   void *data, size_t size, size_t *received, uint_t flags)
{
   SocketQueueItem *queueItem;

   //The receive queue is empty?
   if(!socket->receiveQueue)
   {
      //Set the events the application is interested in
      socket->eventMask = SOCKET_EVENT_RX_READY;
      //Reset the event object
      osResetEvent(&socket->event);
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Wait until an event is triggered
      osWaitForEvent(&socket->event, socket->timeout);
      //Enter critical section
      osAcquireMutex(&socketMutex);
   }

   //Check whether the read operation timed out
   if(!socket->receiveQueue)
   {
      //No data can be read
      *received = 0;
      //Report a timeout error
      return ERROR_TIMEOUT;
   }

   //Point to the first item in the receive queue
   queueItem = socket->receiveQueue;
   //Copy data to user buffer
   *received = chunkedBufferRead(data, queueItem->buffer, queueItem->offset, size);

   //If the SOCKET_FLAG_PEEK flag is set, the data is copied
   //into the buffer but is not removed from the input queue
   if(!(flags & SOCKET_FLAG_PEEK))
   {
      //Remove the item from the receive queue
      socket->receiveQueue = queueItem->next;
      //Deallocate memory buffer
      chunkedBufferFree(queueItem->buffer);
   }

   //Update the state of events
   rawSocketUpdateEvents(socket);

   //Successful read operation
   return NO_ERROR;
}
示例#6
0
文件: ndp.c 项目: nandojve/embedded
void ndpFlushQueuedPackets(NetInterface *interface, NdpCacheEntry *entry)
{
   uint_t i;

   //Check current state
   if(entry->state == NDP_STATE_INCOMPLETE)
   {
      //Drop packets that are waiting for address resolution
      for(i = 0; i < entry->queueSize; i++)
         chunkedBufferFree(entry->queue[i].buffer);
   }

   //The queue is now empty
   entry->queueSize = 0;
}
示例#7
0
文件: ndp.c 项目: nandojve/embedded
void ndpSendQueuedPackets(NetInterface *interface, NdpCacheEntry *entry)
{
   uint_t i;

   //Check current state
   if(entry->state == NDP_STATE_INCOMPLETE)
   {
      //Loop through queued packets
      for(i = 0; i < entry->queueSize; i++)
      {
         //Send current packet
         ethSendFrame(interface, &entry->macAddr, entry->queue[i].buffer,
            entry->queue[i].offset, ETH_TYPE_IPV6);
         //Release previously allocated memory
         chunkedBufferFree(entry->queue[i].buffer);
      }
   }

   //The queue is now empty
   entry->queueSize = 0;
}
示例#8
0
文件: arp.c 项目: hyper123/CycloneTCP
error_t arpSendReply(NetInterface *interface, Ipv4Addr targetIpAddr,
   const MacAddr *targetMacAddr, const MacAddr *destMacAddr)
{
   error_t error;
   size_t offset;
   ChunkedBuffer *buffer;
   ArpPacket *arpReply;

   //Allocate a memory buffer to hold an ARP packet
   buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
   //Failed to allocate buffer?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the ARP packet
   arpReply = chunkedBufferAt(buffer, offset);

   //Format ARP reply
   arpReply->hrd = htons(ARP_HARDWARE_TYPE_ETH);
   arpReply->pro = htons(ETH_TYPE_IPV4);
   arpReply->hln = sizeof(MacAddr);
   arpReply->pln = sizeof(Ipv4Addr);
   arpReply->op = htons(ARP_OPCODE_ARP_REPLY);
   arpReply->sha = interface->macAddr;
   arpReply->spa = interface->ipv4Config.addr;
   arpReply->tha = *targetMacAddr;
   arpReply->tpa = targetIpAddr;

   //Debug message
   TRACE_INFO("Sending ARP Reply (%u bytes)...\r\n", sizeof(ArpPacket));
   //Dump ARP packet contents for debugging purpose
   arpDumpPacket(arpReply);

   //Send ARP reply
   error = ethSendFrame(interface, destMacAddr, buffer, offset, ETH_TYPE_ARP);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
示例#9
0
文件: udp.c 项目: rpc-fw/analyzer
error_t udpSendDatagram(Socket *socket, const IpAddr *destIpAddr,
   uint16_t destPort, const void *data, size_t length, size_t *written)
{
   error_t error;
   size_t offset;
   ChunkedBuffer *buffer;

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

   //Copy data payload
   error = chunkedBufferAppend(buffer, data, length);

   //Successful processing?
   if(!error)
   {
      //Send UDP datagram
      error = udpSendDatagramEx(socket->interface, socket->localPort,
         destIpAddr, destPort, buffer, offset, socket->ttl);
   }

   //Successful processing?
   if(!error)
   {
      //Total number of data bytes successfully transmitted
      if(written != NULL)
         *written = length;
   }

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
示例#10
0
文件: icmp.c 项目: nandojve/embedded
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;
}
示例#11
0
文件: icmp.c 项目: nandojve/embedded
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);
}
示例#12
0
文件: ndp.c 项目: nandojve/embedded
error_t ndpEnqueuePacket(NetInterface *interface,
   const Ipv6Addr *ipAddr, ChunkedBuffer *buffer, size_t offset)
{
   error_t error;
   uint_t i;
   size_t length;
   NdpCacheEntry *entry;

   //Retrieve the length of the multi-part buffer
   length = chunkedBufferGetLength(buffer);

   //Acquire exclusive access to Neighbor cache
   osAcquireMutex(&interface->ndpCacheMutex);

   //Search the Neighbor cache for the specified Ipv6 address
   entry = ndpFindEntry(interface, ipAddr);

   //No matching entry in Neighbor cache?
   if(!entry)
   {
      //Release exclusive access to Neighbor cache
      osReleaseMutex(&interface->ndpCacheMutex);
      //Report an error to the calling function
      return ERROR_FAILURE;
   }

   //Check current state
   if(entry->state == NDP_STATE_INCOMPLETE)
   {
      //Check whether the packet queue is full
      if(entry->queueSize >= NDP_MAX_PENDING_PACKETS)
      {
         //When the queue overflows, the new arrival should replace the oldest entry
         chunkedBufferFree(entry->queue[0].buffer);

         //Make room for the new packet
         for(i = 1; i < NDP_MAX_PENDING_PACKETS; i++)
            entry->queue[i - 1] = entry->queue[i];

         //Adjust the number of pending packets
         entry->queueSize--;
      }

      //Index of the entry to be filled in
      i = entry->queueSize;
      //Allocate a memory buffer to store the packet
      entry->queue[i].buffer = chunkedBufferAlloc(length);

      //Failed to allocate memory?
      if(!entry->queue[i].buffer)
      {
         //Release exclusive access to Neighbor cache
         osReleaseMutex(&interface->ndpCacheMutex);
         //Report an error to the calling function
         return ERROR_OUT_OF_MEMORY;
      }

      //Copy packet contents
      chunkedBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
      //Offset to the first byte of the IPv6 header
      entry->queue[i].offset = offset;

      //Increment the number of queued packets
      entry->queueSize++;
      //The packet was successfully enqueued
      error = NO_ERROR;
   }
   else
   {
      //Send immediately the packet since the address is already resolved
      error = ethSendFrame(interface, &entry->macAddr, buffer, offset, ETH_TYPE_IPV6);
   }

   //Release exclusive access to Neighbor cache
   osReleaseMutex(&interface->ndpCacheMutex);
   //Return status code
   return error;
}
示例#13
0
error_t rawSocketSendEthPacket(Socket *socket,
   const void *data, size_t length, size_t *written)
{
   error_t error;
   uint32_t crc;
   ChunkedBuffer *buffer;
   NetInterface *interface;

   //Select the relevant network interface
   if(!socket->interface)
      interface = tcpIpStackGetDefaultInterface();
   else
      interface = socket->interface;

   //Allocate a buffer memory to hold the raw Ethernet packet
   buffer = chunkedBufferAlloc(0);
   //Failed to allocate buffer?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Copy the raw data
   error = chunkedBufferAppend(buffer, data, length);

   //Successful processing?
   if(!error)
   {
      //Automatic padding not supported by hardware?
      if(!interface->nicDriver->autoPadding)
      {
         //The host controller should manually add padding
         //to the packet before transmitting it
         if(length < (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE))
         {
            //Add padding as necessary
            size_t n = (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE) - length;

            //Append padding bytes
            error = chunkedBufferAppend(buffer, ethPadding, n);
            //Any error to report?
            if(error) return error;

            //Adjust frame length
            length += n;
         }
      }
      //CRC generation not supported by hardware?
      if(!interface->nicDriver->autoCrcGen)
      {
         //Compute CRC over the header and payload
         crc = ethCalcCrcEx(buffer, 0, length);
         //Convert from host byte order to little-endian byte order
         crc = htole32(crc);

         //Append the calculated CRC value
         error = chunkedBufferAppend(buffer, &crc, sizeof(crc));
         //Any error to report?
         if(error) return error;

         //Adjust frame length
         length += sizeof(crc);
      }

      //Debug message
      TRACE_DEBUG("Sending raw Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length);

      //Send the resulting packet over the specified link
      error = nicSendPacket(interface, buffer, 0);
   }

   //Successful processing?
   if(!error)
   {
      //Total number of bytes successfully transmitted
      if(written != NULL)
         *written = length;
   }

   //Free previously allocated memory block
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
示例#14
0
error_t dnsSendQuery(DnsCacheEntry *entry)
{
   error_t error;
   size_t length;
   size_t offset;
   ChunkedBuffer *buffer;
   DnsHeader *message;
   DnsQuestion *dnsQuestion;
   IpAddr destIpAddr;

#if (IPV4_SUPPORT == ENABLED)
   //An IPv4 address is expected?
   if(entry->type == HOST_TYPE_IPV4)
   {
      //Select the relevant DNS server
      destIpAddr.length = sizeof(Ipv4Addr);
      ipv4GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv4Addr);

      //Make sure the IP address is valid
      if(destIpAddr.ipv4Addr == IPV4_UNSPECIFIED_ADDR)
         return ERROR_NO_DNS_SERVER;
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //An IPv6 address is expected?
   if(entry->type == HOST_TYPE_IPV6)
   {
      //Select the relevant DNS server
      destIpAddr.length = sizeof(Ipv6Addr);
      ipv6GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv6Addr);

      //Make sure the IP address is valid
      if(ipv6CompAddr(&destIpAddr.ipv6Addr, &IPV6_UNSPECIFIED_ADDR))
         return ERROR_NO_DNS_SERVER;
   }
   else
#endif
   //Invalid host type?
   {
      //Report an error
      return ERROR_INVALID_PARAMETER;
   }

   //Allocate a memory buffer to hold the DNS query message
   buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset);
   //Failed to allocate buffer?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the DNS header
   message = chunkedBufferAt(buffer, offset);

   //Format DNS query message
   message->id = htons(entry->id);
   message->qr = 0;
   message->opcode = DNS_OPCODE_QUERY;
   message->aa = 0;
   message->tc = 0;
   message->rd = 1;
   message->ra = 0;
   message->z = 0;
   message->rcode = DNS_RCODE_NO_ERROR;

   //The DNS query contains one question
   message->qdcount = HTONS(1);
   message->ancount = 0;
   message->nscount = 0;
   message->arcount = 0;

   //Length of the DNS query message
   length = sizeof(DnsHeader);

   //Encode the host name using the DNS name notation
   length += dnsEncodeName(entry->name, message->questions);

   //Point to the corresponding question structure
   dnsQuestion = DNS_GET_QUESTION(message, length);

#if (IPV4_SUPPORT == ENABLED)
   //An IPv4 address is expected?
   if(entry->type == HOST_TYPE_IPV4)
   {
      //Fill in question structure
      dnsQuestion->qtype = HTONS(DNS_RR_TYPE_A);
      dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
   }
#endif
#if (IPV6_SUPPORT == ENABLED)
   //An IPv6 address is expected?
   if(entry->type == HOST_TYPE_IPV6)
   {
      //Fill in question structure
      dnsQuestion->qtype = HTONS(DNS_RR_TYPE_AAAA);
      dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
   }
#endif

   //Update the length of the DNS query message
   length += sizeof(DnsQuestion);

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

   //Debug message
   TRACE_INFO("Sending DNS message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message
   dnsDumpMessage(message, length);

   //Send DNS query message
   error = udpSendDatagramEx(entry->interface, entry->port,
      &destIpAddr, DNS_PORT, buffer, offset, 0);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
示例#15
0
文件: ndp.c 项目: nandojve/embedded
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;
}
示例#16
0
文件: ndp.c 项目: nandojve/embedded
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;
}
示例#17
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;
}
示例#18
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;
}
示例#19
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;
   ChunkedBuffer *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 = chunkedBufferAppend(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
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
示例#20
0
error_t nbnsSendResponse(NetInterface *interface,
   const IpAddr *destIpAddr, uint16_t destPort, uint16_t id)
{
   error_t error;
   size_t length;
   size_t offset;
   ChunkedBuffer *buffer;
   NbnsHeader *message;
   NbnsAddrEntry *addrEntry;
   DnsResourceRecord *resourceRecord;

   //Allocate a memory buffer to hold the NBNS response message
   buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset);
   //Failed to allocate buffer?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the NBNS header
   message = chunkedBufferAt(buffer, offset);

   //Take the identifier from the query message
   message->id = id;

   //Format NBNS response header
   message->qr = 1;
   message->opcode = DNS_OPCODE_QUERY;
   message->aa = 1;
   message->tc = 0;
   message->rd = 1;
   message->ra = 1;
   message->z = 0;
   message->b = 0;
   message->rcode = DNS_RCODE_NO_ERROR;

   //The NBNS response contains 1 answer resource record
   message->qdcount = 0;
   message->ancount = HTONS(1);
   message->nscount = 0;
   message->arcount = 0;

   //NBNS response message length
   length = sizeof(DnsHeader);

   //Encode the host name using the NBNS name notation
   length += nbnsEncodeName(interface->hostname, (uint8_t *) message + length);

   //Point to the corresponding resource record
   resourceRecord = DNS_GET_RESOURCE_RECORD(message, length);
   //Fill in resource record
   resourceRecord->rtype = HTONS(DNS_RR_TYPE_NB);
   resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN);
   resourceRecord->ttl = HTONL(NBNS_DEFAULT_RESOURCE_RECORD_TTL);
   resourceRecord->rdlength = HTONS(sizeof(NbnsAddrEntry));

   //Point to the address entry array
   addrEntry = (NbnsAddrEntry *) resourceRecord->rdata;
   //Fill in address entry
   addrEntry->flags = HTONS(NBNS_G_UNIQUE | NBNS_ONT_BNODE);
   addrEntry->addr = interface->ipv4Config.addr;

   //Update the length of the NBNS response message
   length += sizeof(DnsResourceRecord) + sizeof(NbnsAddrEntry);

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

   //Debug message
   TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message
   dnsDumpMessage((DnsHeader *) message, length);

   //A response packet is always sent to the source UDP port and
   //source IP address of the request packet
   error = udpSendDatagramEx(interface, NBNS_PORT, destIpAddr,
      destPort, buffer, offset, IPV4_DEFAULT_TTL);

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