Ejemplo n.º 1
0
void ipv4FragTick(NetInterface *interface)
{
   error_t error;
   uint_t i;
   systime_t time;
   Ipv4HoleDesc *hole;

   //Acquire exclusive access to the reassembly queue
   osAcquireMutex(&interface->ipv4FragQueueMutex);

   //Get current time
   time = osGetSystemTime();

   //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 = netBufferSetLength((NetBuffer *) &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, (NetBuffer *) &frag->buffer);
               }
            }

            //Drop the partially reconstructed datagram
            netBufferSetLength((NetBuffer *) &frag->buffer, 0);
         }
      }
   }

   //Release exclusive access to the reassembly queue
   osReleaseMutex(&interface->ipv4FragQueueMutex);
}
Ejemplo n.º 2
0
void ipv4FlushFragQueue(NetInterface *interface)
{
   uint_t i;

   //Acquire exclusive access to the reassembly queue
   osAcquireMutex(&interface->ipv4FragQueueMutex);

   //Loop through the reassembly queue
   for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
   {
      //Drop any partially reconstructed datagram
      netBufferSetLength((NetBuffer *) &interface->ipv4FragQueue[i].buffer, 0);
   }

   //Release exclusive access to the reassembly queue
   osReleaseMutex(&interface->ipv4FragQueueMutex);
}
Ejemplo n.º 3
0
error_t nbnsSendQuery(DnsCacheEntry *entry)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   NbnsHeader *message;
   DnsQuestion *dnsQuestion;
   IpAddr destIpAddr;

   //Allocate a memory buffer to hold the NBNS query 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 = netBufferAt(buffer, offset);

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

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

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

   //Encode the NetBIOS name
   length += nbnsEncodeName(entry->name, message->questions);

   //Point to the corresponding question structure
   dnsQuestion = DNS_GET_QUESTION(message, length);
   //Fill in question structure
   dnsQuestion->qtype = HTONS(DNS_RR_TYPE_NB);
   dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);

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

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

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

   //The destination address is the broadcast address
   destIpAddr.length = sizeof(Ipv4Addr);
   ipv4GetBroadcastAddr(entry->interface, &destIpAddr.ipv4Addr);

   //A request packet is always sent to the well known port 137
   error = udpSendDatagramEx(entry->interface, NBNS_PORT,
      &destIpAddr, NBNS_PORT, buffer, offset, IPV4_DEFAULT_TTL);

   //Free previously allocated memory
   netBufferFree(buffer);
   //Return status code
   return error;
}
Ejemplo n.º 4
0
Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
{
   error_t error;
   Socket *newSocket;
   TcpSynQueueItem *queueItem;

   //Ensure the socket was previously placed in the listening state
   if(tcpGetState(socket) != TCP_STATE_LISTEN)
      return NULL;

   //Enter critical section
   osAcquireMutex(&socketMutex);

   //Wait for an connection attempt
   while(1)
   {
      //The SYN queue is empty?
      if(!socket->synQueue)
      {
         //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 a SYN message is received from a client
         osWaitForEvent(&socket->event, socket->timeout);
         //Enter critical section
         osAcquireMutex(&socketMutex);
      }

      //Check whether the queue is still empty
      if(!socket->synQueue)
      {
         //Timeout error
         newSocket = NULL;
         //Exit immediately
         break;
      }

      //Point to the first item in the receive queue
      queueItem = socket->synQueue;

      //Return the client IP address and port number
      if(clientIpAddr)
         *clientIpAddr = queueItem->srcAddr;
      if(clientPort)
         *clientPort = queueItem->srcPort;

      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Create a new socket to handle the incoming connection request
      newSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
      //Enter critical section
      osAcquireMutex(&socketMutex);

      //Socket successfully created?
      if(newSocket != NULL)
      {
         //The user owns the socket
         newSocket->ownedFlag = TRUE;

         //Inherit settings from the listening socket
         newSocket->txBufferSize = socket->txBufferSize;
         newSocket->rxBufferSize = socket->rxBufferSize;

         //Number of chunks that comprise the TX and the RX buffers
         newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk);
         newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk);

         //Allocate transmit buffer
         error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer, newSocket->txBufferSize);

         //Check status code
         if(!error)
         {
            //Allocate receive buffer
            error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer, newSocket->rxBufferSize);
         }

         //Transmit and receive buffers successfully allocated?
         if(!error)
         {
            //Bind the newly created socket to the appropriate interface
            newSocket->interface = queueItem->interface;
            //Bind the socket to the specified address
            newSocket->localIpAddr = queueItem->destAddr;
            newSocket->localPort = socket->localPort;
            //Save the port number and the IP address of the remote host
            newSocket->remoteIpAddr = queueItem->srcAddr;
            newSocket->remotePort = queueItem->srcPort;
            //Save the maximum segment size
            newSocket->mss = queueItem->mss;

            //Initialize TCP control block
            newSocket->iss = netGetRand();
            newSocket->irs = queueItem->isn;
            newSocket->sndUna = newSocket->iss;
            newSocket->sndNxt = newSocket->iss + 1;
            newSocket->rcvNxt = newSocket->irs + 1;
            newSocket->rcvUser = 0;
            newSocket->rcvWnd = newSocket->rxBufferSize;

            //Default retransmission timeout
            newSocket->rto = TCP_INITIAL_RTO;

#if (TCP_CONGESTION_CONTROL_SUPPORT == ENABLED)
            //Initial congestion window
            newSocket->cwnd = MIN(TCP_INITIAL_WINDOW * newSocket->mss, newSocket->txBufferSize);
            //Slow start threshold should be set arbitrarily high
            newSocket->ssthresh = UINT16_MAX;
#endif

            //Send a SYN ACK control segment
            error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
               newSocket->iss, newSocket->rcvNxt, 0, TRUE);

            //TCP segment successfully sent?
            if(!error)
            {
               //Remove the item from the SYN queue
               socket->synQueue = queueItem->next;
               //Deallocate memory buffer
               memPoolFree(queueItem);
               //Update the state of events
               tcpUpdateEvents(socket);

               //The connection state should be changed to SYN-RECEIVED
               tcpChangeState(newSocket, TCP_STATE_SYN_RECEIVED);

               //We are done...
               break;
            }
         }

         //Dispose the socket
         tcpAbort(newSocket);
      }

      //Debug message
      TRACE_WARNING("Cannot accept TCP connection!\r\n");

      //Remove the item from the SYN queue
      socket->synQueue = queueItem->next;
      //Deallocate memory buffer
      memPoolFree(queueItem);

      //Wait for the next connection attempt
   }

   //Leave critical section
   osReleaseMutex(&socketMutex);

   //Return a handle to the newly created socket
   return newSocket;
}
Ejemplo n.º 5
0
error_t tcpConnect(Socket *socket)
{
   error_t error;
   uint_t event;

   //Socket already connected?
   if(socket->state != TCP_STATE_CLOSED)
      return ERROR_ALREADY_CONNECTED;

   //The user owns the socket
   socket->ownedFlag = TRUE;

   //Number of chunks that comprise the TX and the RX buffers
   socket->txBuffer.maxChunkCount = arraysize(socket->txBuffer.chunk);
   socket->rxBuffer.maxChunkCount = arraysize(socket->rxBuffer.chunk);

   //Allocate transmit buffer
   error = netBufferSetLength((NetBuffer *) &socket->txBuffer, socket->txBufferSize);
   //Allocate receive buffer
   if(!error)
      error = netBufferSetLength((NetBuffer *) &socket->rxBuffer, socket->rxBufferSize);

   //Failed to allocate memory?
   if(error)
   {
      //Free any previously allocated memory
      tcpDeleteControlBlock(socket);
      //Report an error to the caller
      return error;
   }

   //Default MSS value
   socket->mss = MIN(TCP_DEFAULT_MSS, TCP_MAX_MSS);
   //An initial send sequence number is selected
   socket->iss = netGetRand();
   //Initialize TCP control block
   socket->sndUna = socket->iss;
   socket->sndNxt = socket->iss + 1;
   socket->rcvUser = 0;
   socket->rcvWnd = socket->rxBufferSize;
   //Default retransmission timeout
   socket->rto = TCP_INITIAL_RTO;

   //Send a SYN segment
   error = tcpSendSegment(socket, TCP_FLAG_SYN, socket->iss, 0, 0, TRUE);
   //Failed to send TCP segment?
   if(error) return error;

   //Switch to the SYN-SENT state
   tcpChangeState(socket, TCP_STATE_SYN_SENT);
   //Wait for the connection to be established
   event = tcpWaitForEvents(socket, SOCKET_EVENT_CONNECTED |
      SOCKET_EVENT_CLOSED, socket->timeout);

   //Connection successfully established?
   if(event == SOCKET_EVENT_CONNECTED)
      return NO_ERROR;
   //Failed to establish connection?
   else if(event == SOCKET_EVENT_CLOSED)
      return ERROR_CONNECTION_FAILED;
   //Timeout exception?
   else
      return ERROR_TIMEOUT;
}
Ejemplo n.º 6
0
error_t mdnsSendResponse(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
   const UdpHeader *udpHeader, NetBuffer *buffer, size_t offset, size_t length)
{
   uint16_t destPort;
   IpAddr destIpAddr;
   DnsHeader *response;

#if (IPV4_SUPPORT == ENABLED)
   //Check whether the mDNS query was received from an IPv4 peer
   if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
   {
      //If the source UDP port in a received Multicast DNS query is not port 5353,
      //this indicates that the querier originating the query is a simple resolver
      if(udpHeader->srcPort != HTONS(MDNS_PORT))
      {
         //the mDNS responder must send a UDP response directly back to the querier,
         //via unicast, to the query packet's source IP address and port
         destIpAddr.length = sizeof(Ipv4Addr);
         destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
      }
      else
      {
         //Use mDNS IPv4 multicast address
         destIpAddr.length = sizeof(Ipv4Addr);
         destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;
      }
   }
#endif
#if (IPV6_SUPPORT == ENABLED)
   //Check whether the mDNS query was received from an IPv6 peer
   if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
   {
      //If the source UDP port in a received Multicast DNS query is not port 5353,
      //this indicates that the querier originating the query is a simple resolver
      if(udpHeader->srcPort != HTONS(MDNS_PORT))
      {
         //the mDNS responder must send a UDP response directly back to the querier,
         //via unicast, to the query packet's source IP address and port
         destIpAddr.length = sizeof(Ipv6Addr);
         destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
      }
      else
      {
         //Use mDNS IPv6 multicast address
         destIpAddr.length = sizeof(Ipv6Addr);
         destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;
      }
   }
#endif

   //Destination port
   destPort = ntohs(udpHeader->srcPort);

   //Point to the mDNS response header
   response = netBufferAt(buffer, offset);
   //Convert 16-bit value to network byte order
   response->ancount = htons(response->ancount);

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

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

   //All multicast DNS responses should be sent with an IP TTL set to 255
   return udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr,
      destPort, buffer, offset, MDNS_DEFAULT_IP_TTL);
}
Ejemplo n.º 7
0
error_t mdnsSendAnnouncement(NetInterface *interface)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   DnsHeader *message;
   IpAddr destIpAddr;

   //Initialize error code
   error = NO_ERROR;

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

   //Point to the mDNS header
   message = netBufferAt(buffer, offset);

   //Format mDNS query message
   message->id = 0;
   message->qr = 1;
   message->opcode = DNS_OPCODE_QUERY;
   message->aa = 1;
   message->tc = 0;
   message->rd = 0;
   message->ra = 0;
   message->z = 0;
   message->rcode = DNS_RCODE_NO_ERROR;

   //Multicast DNS responses must not contain any questions
   message->qdcount = 0;
   message->ancount = 0;
   message->nscount = 0;
   message->arcount = 0;

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

   //Start of exception handling block
   do
   {
      //Format A resource record
      error = mdnsAddIpv4ResourceRecord(interface, message, &length, TRUE);
      //Any error to report?
      if(error) break;

      //Format AAAA resource record
      error = mdnsAddIpv6ResourceRecord(interface, message, &length, TRUE);
      //Any error to report?
      if(error) break;

      //Convert 16-bit value to network byte order
      message->ancount = htons(message->ancount);

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

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

#if (IPV4_SUPPORT == ENABLED)
      //Select the relevant multicast address (224.0.0.251)
      destIpAddr.length = sizeof(Ipv4Addr);
      destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;

      //All multicast DNS queries should be sent with an IP TTL set to 255
      error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr,
         MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL);
      //Any error to report?
      if(error)break;
#endif

#if (IPV6_SUPPORT == ENABLED)
      //Select the relevant multicast address (ff02::fb)
      destIpAddr.length = sizeof(Ipv6Addr);
      destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;

      //All multicast DNS queries should be sent with an IP TTL set to 255
      error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr,
         MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL);
      //Any error to report?
      if(error)break;
#endif

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

   //Free previously allocated memory
   netBufferFree(buffer);
   //Return status code
   return error;
}
Ejemplo n.º 8
0
error_t mdnsSendProbe(NetInterface *interface)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   DnsHeader *message;
   DnsQuestion *dnsQuestion;
   IpAddr destIpAddr;

   //Initialize error code
   error = NO_ERROR;

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

   //Point to the mDNS header
   message = netBufferAt(buffer, offset);

   //Format mDNS query message
   message->id = 0;
   message->qr = 0;
   message->opcode = DNS_OPCODE_QUERY;
   message->aa = 0;
   message->tc = 0;
   message->rd = 0;
   message->ra = 0;
   message->z = 0;
   message->rcode = DNS_RCODE_NO_ERROR;

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

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

   //Encode the host name using the DNS name notation
   length += mdnsEncodeName(interface->hostname, "",
      ".local", (uint8_t *) message + length);

   //Point to the corresponding question structure
   dnsQuestion = DNS_GET_QUESTION(message, length);
   //Fill in question structure
   dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY);
   dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);

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

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

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

#if (IPV4_SUPPORT == ENABLED)
   //Check status code
   if(!error)
   {
      //Select the relevant multicast address (224.0.0.251)
      destIpAddr.length = sizeof(Ipv4Addr);
      destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;

      //All multicast DNS queries should be sent with an IP TTL set to 255
      error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr,
         MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL);
   }
#endif

#if (IPV6_SUPPORT == ENABLED)
   //Check status code
   if(!error)
   {
      //Select the relevant multicast address (ff02::fb)
      destIpAddr.length = sizeof(Ipv6Addr);
      destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;

      //All multicast DNS queries should be sent with an IP TTL set to 255
      error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr,
         MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL);
   }
#endif

   //Free previously allocated memory
   netBufferFree(buffer);
   //Return status code
   return error;
}
Ejemplo n.º 9
0
error_t lcpSendConfigureReq(PppContext *context)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   PppConfigurePacket *configureReqPacket;

   //Debug message
   TRACE_INFO("LCP Send-Configure-Request callback\r\n");

   //Calculate the maximum size of the Configure-Request packet
   length = sizeof(PppConfigurePacket) +
      sizeof(LcpMruOption) + sizeof(LcpAccmOption);

   //Allocate a buffer memory to hold the packet
   buffer = pppAllocBuffer(length, &offset);
   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the Configure-Request packet
   configureReqPacket = netBufferAt(buffer, offset);

   //Format packet header
   configureReqPacket->code = PPP_CODE_CONFIGURE_REQ;
   configureReqPacket->identifier = ++context->lcpFsm.identifier;
   configureReqPacket->length = sizeof(PppConfigurePacket);

   //Make sure the Maximum-Receive-Unit option has not been previously rejected
   if(!context->localConfig.mruRejected)
   {
      //Convert MRU to network byte order
      uint16_t value = htons(context->localConfig.mru);
      //Add option
      pppAddOption(configureReqPacket, LCP_OPTION_MRU, &value, sizeof(uint16_t));
   }

   //Make sure the Async-Control-Character-Map option has not been previously rejected
   if(!context->localConfig.accmRejected)
   {
      //Convert ACCM to network byte order
      uint32_t value = htonl(context->localConfig.accm);
      //Add option
      pppAddOption(configureReqPacket, LCP_OPTION_ACCM, &value, sizeof(uint32_t));
   }

   //Save packet length
   length = configureReqPacket->length;
   //Convert length field to network byte order
   configureReqPacket->length = htons(length);

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

   //Debug message
   TRACE_INFO("Sending Configure-Request packet (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump packet contents for debugging purpose
   pppDumpPacket((PppPacket *) configureReqPacket, length, PPP_PROTOCOL_LCP);

   //Send PPP frame
   error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_LCP);

   //The restart counter is decremented each time a Configure-Request is sent
   if(context->lcpFsm.restartCounter > 0)
      context->lcpFsm.restartCounter--;

   //Save the time at which the packet was sent
   context->lcpFsm.timestamp = osGetSystemTime();

   //Free previously allocated memory block
   netBufferFree(buffer);
   //Return status code
   return error;
}
Ejemplo n.º 10
0
error_t dnsSendQuery(DnsCacheEntry *entry)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *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 = netBufferAt(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
   netBufferSetLength(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
   netBufferFree(buffer);
   //Return status code
   return error;
}
Ejemplo n.º 11
0
error_t pppSendConfigureAckNak(PppContext *context,
                               const PppConfigurePacket *configureReqPacket, PppProtocol protocol, PppCode code)
{
    error_t error;
    size_t length;
    size_t offset;
    NetBuffer *buffer;
    PppConfigurePacket *configureAckNakPacket;
    PppOption *option;

    //Initialize status code
    error = NO_ERROR;
    //Retrieve the length of the Configure-Request packet
    length = ntohs(configureReqPacket->length);

    //Allocate a buffer memory to hold the Configure-Ack, Nak or Reject packet
    buffer = pppAllocBuffer(length, &offset);
    //Failed to allocate memory?
    if(!buffer) return ERROR_OUT_OF_MEMORY;

    //Point to the beginning of the packet
    configureAckNakPacket = netBufferAt(buffer, offset);

    //Format packet header
    configureAckNakPacket->code = code;
    configureAckNakPacket->identifier = configureReqPacket->identifier;
    configureAckNakPacket->length = sizeof(PppConfigurePacket);

    //Retrieve the length of the option list
    length -= sizeof(PppConfigurePacket);
    //Point to the first option
    option = (PppOption *) configureReqPacket->options;

    //Parse configuration options
    while(length > 0)
    {
        //LCP protocol?
        if(protocol == PPP_PROTOCOL_LCP)
        {
            //Parse LCP option
            lcpParseOption(context, option, length, configureAckNakPacket);
        }
#if (IPV4_SUPPORT)
        //IPCP protocol?
        else if(protocol == PPP_PROTOCOL_IPCP)
        {
            //Parse IPCP option
            ipcpParseOption(context, option, length, configureAckNakPacket);
        }
#endif

        //Remaining bytes to process
        length -= option->length;
        //Jump to the next option
        option = (PppOption *) ((uint8_t *) option + option->length);
    }

    //Adjust the length of the multi-part buffer
    netBufferSetLength(buffer, offset + configureAckNakPacket->length);
    //Convert length field to network byte order
    configureAckNakPacket->length = htons(configureAckNakPacket->length);

    //Debug message
    if(code == PPP_CODE_CONFIGURE_ACK)
    {
        TRACE_INFO("Sending Configure-Ack packet (%" PRIuSIZE " bytes)...\r\n",
                   ntohs(configureAckNakPacket->length));
    }
    else if(code == PPP_CODE_CONFIGURE_NAK)
    {
        TRACE_INFO("Sending Configure-Nak packet (%" PRIuSIZE " bytes)...\r\n",
                   ntohs(configureAckNakPacket->length));
    }
    else if(code == PPP_CODE_CONFIGURE_REJ)
    {
        TRACE_INFO("Sending Configure-Reject packet (%" PRIuSIZE " bytes)...\r\n",
                   ntohs(configureAckNakPacket->length));
    }

    //Dump packet contents for debugging purpose
    pppDumpPacket((PppPacket *) configureAckNakPacket,
                  ntohs(configureAckNakPacket->length), protocol);

    //Send PPP frame
    error = pppSendFrame(context->interface, buffer, offset, protocol);

    //Free previously allocated memory block
    netBufferFree(buffer);
    //Return status code
    return error;
}
Ejemplo n.º 12
0
error_t ipv4FragmentDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
   uint16_t id, const NetBuffer *payload, size_t payloadOffset, uint8_t timeToLive)
{
   error_t error;
   size_t offset;
   size_t length;
   size_t payloadLength;
   size_t fragmentOffset;
   size_t maxFragmentSize;
   NetBuffer *fragment;

   //Retrieve the length of the payload
   payloadLength = netBufferGetLength(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;

   //Maximum payload size for fragmented packets
   maxFragmentSize = interface->ipv4Config.mtu - sizeof(Ipv4Header);
   //The size shall be a multiple of 8-byte blocks
   maxFragmentSize -= (maxFragmentSize % 8);

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

      //Process the last fragment?
      if((payloadLength - offset) <= maxFragmentSize)
      {
         //Size of the current fragment
         length = payloadLength - offset;
         //Copy fragment data
         netBufferConcat(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 = maxFragmentSize;
         //Copy fragment data
         netBufferConcat(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
   netBufferFree(fragment);
   //Return status code
   return error;
}
Ejemplo n.º 13
0
Ipv4FragDesc *ipv4SearchFragQueue(NetInterface *interface, const Ipv4Header *packet)
{
   error_t error;
   uint_t i;
   Ipv4Header *datagram;
   Ipv4FragDesc *frag;
   Ipv4HoleDesc *hole;

   //Search for a matching IP datagram being reassembled
   for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
   {
      //Point to the current entry in the reassembly queue
      frag = &interface->ipv4FragQueue[i];

      //Check whether the current entry is used?
      if(frag->buffer.chunkCount > 0)
      {
         //Point to the corresponding datagram
         datagram = netBufferAt((NetBuffer *) &frag->buffer, 0);

         //Check source and destination addresses
         if(datagram->srcAddr != packet->srcAddr)
            continue;
         if(datagram->destAddr != packet->destAddr)
            continue;
         //Compare identification and protocol fields
         if(datagram->identification != packet->identification)
            continue;
         if(datagram->protocol != packet->protocol)
            continue;

         //A matching entry has been found in the reassembly queue
         return frag;
      }
   }

   //If the current packet does not match an existing entry
   //in the reassembly queue, then create a new entry
   for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
   {
      //Point to the current entry in the reassembly queue
      frag = &interface->ipv4FragQueue[i];

      //The current entry is free?
      if(!frag->buffer.chunkCount)
      {
         //Number of chunks that comprise the reassembly buffer
         frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);

         //Allocate sufficient memory to hold the IPv4 header and
         //the first hole descriptor
         error = netBufferSetLength((NetBuffer *) &frag->buffer,
            NET_MEM_POOL_BUFFER_SIZE + sizeof(Ipv4HoleDesc));

         //Failed to allocate memory?
         if(error)
         {
            //Clean up side effects
            netBufferSetLength((NetBuffer *) &frag->buffer, 0);
            //Exit immediately
            return NULL;
         }

         //Initial length of the reconstructed datagram
         frag->headerLength = packet->headerLength * 4;
         frag->dataLength = 0;

         //Fix the length of the first chunk
         frag->buffer.chunk[0].length = frag->headerLength;
         //Copy IPv4 header from the incoming fragment
         netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);

         //Save current time
         frag->timestamp = osGetSystemTime();
         //Create a new entry in the hole descriptor list
         frag->firstHole = 0;

         //Point to first hole descriptor
         hole = ipv4FindHole(frag, frag->firstHole);
         //The entry describes the datagram as being completely missing
         hole->first = 0;
         hole->last = IPV4_INFINITY;
         hole->next = IPV4_INFINITY;

         //Dump hole descriptor list
         ipv4DumpHoleList(frag);

         //Return the matching fragment descriptor
         return frag;
      }
   }

   //The reassembly queue is full
   return NULL;
}
Ejemplo n.º 14
0
void ipv4ReassembleDatagram(NetInterface *interface,
   const Ipv4Header *packet, size_t length)
{
   error_t error;
   uint16_t offset;
   uint16_t dataFirst;
   uint16_t dataLast;
   Ipv4FragDesc *frag;
   Ipv4HoleDesc *hole;
   Ipv4HoleDesc *prevHole;

   //Get the length of the payload
   length -= packet->headerLength * 4;
   //Convert the fragment offset from network byte order
   offset = ntohs(packet->fragmentOffset);

   //Every fragment except the last must contain a multiple of 8 bytes of data
   if((offset & IPV4_FLAG_MF) && (length % 8))
   {
      //Drop incoming packet
      return;
   }

   //Calculate the index of the first byte
   dataFirst = (offset & IPV4_OFFSET_MASK) * 8;
   //Calculate the index immediately following the last byte
   dataLast = dataFirst + length;

   //Search for a matching IP datagram being reassembled
   frag = ipv4SearchFragQueue(interface, packet);
   //No matching entry in the reassembly queue?
   if(!frag) return;

   //The very first fragment requires special handling
   if(!(offset & IPV4_OFFSET_MASK))
   {
      //Calculate the length of the IP header including options
      frag->headerLength = packet->headerLength * 4;

      //Enforce the size of the reconstructed datagram
      if((frag->headerLength + frag->dataLength) > IPV4_MAX_FRAG_DATAGRAM_SIZE)
      {
         //Drop any allocated resources
         netBufferSetLength((NetBuffer *) &frag->buffer, 0);
         //Exit immediately
         return;
      }

      //Make sure the IP header entirely fits in the first chunk
      if(frag->headerLength > frag->buffer.chunk[0].size)
      {
         //Drop the reconstructed datagram
         netBufferSetLength((NetBuffer *) &frag->buffer, 0);
         //Exit immediately
         return;
      }

      //Fix the length of the first chunk
      frag->buffer.chunk[0].length = frag->headerLength;
      //Always take the IP header from the first fragment
      netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);
   }

   //It may be necessary to increase the size of the buffer...
   if(dataLast > frag->dataLength)
   {
      //Enforce the size of the reconstructed datagram
      if((frag->headerLength + dataLast) > IPV4_MAX_FRAG_DATAGRAM_SIZE)
      {
         //Drop any allocated resources
         netBufferSetLength((NetBuffer *) &frag->buffer, 0);
         //Exit immediately
         return;
      }

      //Adjust the size of the reconstructed datagram
      error = netBufferSetLength((NetBuffer *) &frag->buffer,
         frag->headerLength + dataLast + sizeof(Ipv4HoleDesc));

      //Any error to report?
      if(error)
      {
         //Drop the reconstructed datagram
         netBufferSetLength((NetBuffer *) &frag->buffer, 0);
         //Exit immediately
         return;
      }

      //Actual length of the payload
      frag->dataLength = dataLast;
   }

   //Select the first hole descriptor from the list
   hole = ipv4FindHole(frag, frag->firstHole);
   //Keep track of the previous hole in the list
   prevHole = NULL;

   //Iterate through the hole descriptors
   while(hole != NULL)
   {
      //Save lower and upper boundaries for later use
      uint16_t holeFirst = hole->first;
      uint16_t holeLast = hole->last;

      //Check whether the newly arrived fragment
      //interacts with this hole in some way
      if(dataFirst < holeLast && dataLast > holeFirst)
      {
         //The current descriptor is no longer valid. We will destroy
         //it, and in the next two steps, we will determine whether
         //or not it is necessary to create any new hole descriptors
         if(prevHole != NULL)
            prevHole->next = hole->next;
         else
            frag->firstHole = hole->next;

         //Is there still a hole at the beginning of the segment?
         if(dataFirst > holeFirst)
         {
            //Create a new entry that describes this hole
            hole = ipv4FindHole(frag, holeFirst);
            hole->first = holeFirst;
            hole->last = dataFirst;

            //Insert the newly created entry into the hole descriptor list
            if(prevHole != NULL)
            {
               hole->next = prevHole->next;
               prevHole->next = hole->first;
            }
            else
            {
               hole->next = frag->firstHole;
               frag->firstHole = hole->first;
            }

            //Always keep track of the previous hole
            prevHole = hole;
         }

         //Is there still a hole at the end of the segment?
         if(dataLast < holeLast && (offset & IPV4_FLAG_MF))
         {
            //Create a new entry that describes this hole
            hole = ipv4FindHole(frag, dataLast);
            hole->first = dataLast;
            hole->last = holeLast;

            //Insert the newly created entry into the hole descriptor list
            if(prevHole != NULL)
            {
               hole->next = prevHole->next;
               prevHole->next = hole->first;
            }
            else
            {
               hole->next = frag->firstHole;
               frag->firstHole = hole->first;
            }

            //Always keep track of the previous hole
            prevHole = hole;
         }
      }
      else
      {
         //The newly arrived fragment does not interact with the current hole
         prevHole = hole;
      }

      //Select the next hole descriptor from the list
      hole = ipv4FindHole(frag, prevHole ? prevHole->next : frag->firstHole);
   }

   //Copy data from the fragment to the reassembly buffer
   netBufferWrite((NetBuffer *) &frag->buffer,
      frag->headerLength + dataFirst, IPV4_DATA(packet), length);

   //Dump hole descriptor list
   ipv4DumpHoleList(frag);

   //If the hole descriptor list is empty, the reassembly process is now complete
   if(!ipv4FindHole(frag, frag->firstHole))
   {
      //Discard the extra hole descriptor that follows the reconstructed datagram
      error = netBufferSetLength((NetBuffer *) &frag->buffer,
         frag->headerLength + frag->dataLength);

      //Check status code
      if(!error)
      {
         //Point to the IP header
         Ipv4Header *datagram = netBufferAt((NetBuffer *) &frag->buffer, 0);

         //Fix IP header
         datagram->totalLength = htons(frag->headerLength + frag->dataLength);
         datagram->fragmentOffset = 0;
         datagram->headerChecksum = 0;

         //Recalculate IP header checksum
         datagram->headerChecksum = ipCalcChecksum(datagram, frag->buffer.chunk[0].length);

         //Pass the original IPv4 datagram to the higher protocol layer
         ipv4ProcessDatagram(interface, (NetBuffer *) &frag->buffer);
      }

      //Release previously allocated memory
      netBufferSetLength((NetBuffer *) &frag->buffer, 0);
   }
}