Beispiel #1
0
void nbnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
   const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *params)
{
   size_t length;
   NbnsHeader *message;

   //Make sure the NBNS message was received from an IPv4 peer
   if(pseudoHeader->length != sizeof(Ipv4PseudoHeader))
      return;

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

   //Ensure the NBNS message is valid
   if(length < sizeof(NbnsHeader))
      return;
   if(length > DNS_MESSAGE_MAX_SIZE)
      return;

   //Point to the NBNS message header
   message = netBufferAt(buffer, offset);
   //Sanity check
   if(message == NULL)
      return;

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

   //NBNS messages received with an opcode other than zero must be silently ignored
   if(message->opcode != DNS_OPCODE_QUERY)
      return;
   //NBNS messages received with non-zero response codes must be silently ignored
   if(message->rcode != DNS_RCODE_NO_ERROR)
      return;

   //NBNS query received?
   if(!message->qr)
   {
#if (NBNS_RESPONDER_SUPPORT == ENABLED)
      //Process incoming NBNS query message
      nbnsProcessQuery(interface, &pseudoHeader->ipv4Data,
         udpHeader, message, length);
#endif
   }
   //NBNS response received?
   else
   {
#if (NBNS_CLIENT_SUPPORT == ENABLED)
      //Process incoming NBNS response message
      nbnsProcessResponse(interface, &pseudoHeader->ipv4Data,
         udpHeader, message, length);
#endif
   }
}
error_t pppSendEchoRep(PppContext *context,
                       const PppEchoPacket *echoReqPacket, PppProtocol protocol)
{
    error_t error;
    size_t length;
    size_t offset;
    NetBuffer *buffer;
    PppEchoPacket *echoRepPacket;

    //Retrieve the length of the Echo-Request packet
    length = ntohs(echoReqPacket->length);

    //Make sure the length is valid
    if(length < sizeof(PppEchoPacket))
        return ERROR_INVALID_LENGTH;
    if(length > context->peerConfig.mru)
        return ERROR_INVALID_LENGTH;

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

    //Point to the Echo-Reply packet
    echoRepPacket = netBufferAt(buffer, offset);

    //Format packet header
    echoRepPacket->code = PPP_CODE_CODE_REJ;
    echoRepPacket->identifier = echoReqPacket->identifier;
    echoRepPacket->length = htons(length);
    echoRepPacket->magicNumber = context->localConfig.magicNumber;

    //The data field of the Echo-Request packet is copied into the data
    //field of the Echo-Reply packet
    error = netBufferAppend(buffer, echoReqPacket->data, length - sizeof(PppEchoPacket));

    //Check status code
    if(!error)
    {
        //Debug message
        TRACE_INFO("Sending Echo-Reply packet (%" PRIuSIZE " bytes)...\r\n", length);

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

    //Free previously allocated memory block
    netBufferFree(buffer);
    //Return status code
    return error;
}
error_t pppSendProtocolRej(PppContext *context, uint8_t identifier,
                           uint16_t protocol, const uint8_t *information, size_t length)
{
    error_t error;
    size_t offset;
    NetBuffer *buffer;
    PppProtocolRejPacket *protocolRejPacket;

    //Calculate the length of the Protocol-Reject packet
    length += sizeof(PppProtocolRejPacket);

    //The Rejected-Information must be truncated to comply with
    //the peer's established MRU
    length = MIN(length, context->peerConfig.mru);

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

    //Point to the Protocol-Reject packet
    protocolRejPacket = netBufferAt(buffer, offset);

    //Format packet header
    protocolRejPacket->code = PPP_CODE_PROTOCOL_REJ;
    protocolRejPacket->identifier = identifier;
    protocolRejPacket->length = htons(length);
    protocolRejPacket->rejectedProtocol = htons(protocol);

    //The Rejected-Information field contains a copy of the
    //packet which is being rejected
    error = netBufferAppend(buffer, information,
                            length - sizeof(PppProtocolRejPacket));

    //Check status code
    if(!error)
    {
        //Debug message
        TRACE_INFO("Sending Protocol-Reject packet (%" PRIuSIZE " bytes)...\r\n", length);

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

    //Free previously allocated memory block
    netBufferFree(buffer);
    //Return status code
    return error;
}
Beispiel #4
0
error_t chapSendResponse(PppContext *context, const uint8_t *value)
{
   error_t error;
   size_t n;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   ChapResponsePacket *responsePacket;

   //Retrieve the length of the username
   n = strlen(context->username);
   //Calculate the length of the Response packet
   length = sizeof(ChapResponsePacket) + MD5_DIGEST_SIZE + n;

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

   //Point to the Response packet
   responsePacket = netBufferAt(buffer, offset);

   //Format packet header
   responsePacket->code = CHAP_CODE_RESPONSE;
   responsePacket->identifier = context->chapFsm.peerIdentifier;
   responsePacket->length = htons(length);
   responsePacket->valueSize = MD5_DIGEST_SIZE;

   //Copy the Response value
   memcpy(responsePacket->value, value, MD5_DIGEST_SIZE);

   //The Name field is one or more octets representing the
   //identification of the system transmitting the packet
   memcpy(responsePacket->value + MD5_DIGEST_SIZE, context->username, n);

   //Debug message
   TRACE_INFO("Sending CHAP Response packet (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump packet contents for debugging purpose
   pppDumpPacket((PppPacket *) responsePacket, length, PPP_PROTOCOL_CHAP);

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

   //Free previously allocated memory block
   netBufferFree(buffer);
   //Return status code
   return error;
}
NetBuffer *mdnsCreateResponse(uint16_t id, size_t *offset,
   DnsHeader **response, size_t *responseLen)
{
   NetBuffer *buffer;
   DnsHeader *header;

   //Allocate a memory buffer to hold the mDNS message
   buffer = udpAllocBuffer(MDNS_MESSAGE_MAX_SIZE, offset);

   //Successful memory allocation?
   if(buffer != NULL)
   {
      //Point to the mDNS response header
      header = netBufferAt(buffer, *offset);

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

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

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

      //Pointer to the mDNS response header
      *response = header;
      //Actual length of the mDNS response message
      *responseLen = sizeof(DnsHeader);
   }

   //Return a pointer to the buffer that holds the mDNS message
   return buffer;
}
error_t pppSendTerminateAck(PppContext *context,
                            uint8_t identifier, PppProtocol protocol)
{
    error_t error;
    size_t length;
    size_t offset;
    NetBuffer *buffer;
    PppTerminatePacket *terminateAckPacket;

    //Length of the Terminate-Ack packet
    length = sizeof(PppTerminatePacket);

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

    //Point to the Terminate-Ack packet
    terminateAckPacket = netBufferAt(buffer, offset);

    //Format packet header
    terminateAckPacket->code = PPP_CODE_TERMINATE_ACK;
    terminateAckPacket->identifier = identifier;
    terminateAckPacket->length = htons(length);

    //Debug message
    TRACE_INFO("Sending Terminate-Ack packet (%" PRIuSIZE " bytes)...\r\n", length);
    //Dump packet contents for debugging purpose
    pppDumpPacket((PppPacket *) terminateAckPacket, length, protocol);

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

    //Free previously allocated memory block
    netBufferFree(buffer);
    //Return status code
    return error;
}
Beispiel #7
0
error_t chapSendFailure(PppContext *context)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   PppPacket *failurePacket;

   //Retrieve the length of the Failure packet
   length = sizeof(PppPacket);

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

   //Point to the Failure packet
   failurePacket = netBufferAt(buffer, offset);

   //Format packet header
   failurePacket->code = CHAP_CODE_FAILURE;
   failurePacket->identifier = context->chapFsm.localIdentifier;
   failurePacket->length = htons(length);

   //Debug message
   TRACE_INFO("Sending CHAP Failure packet (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump packet contents for debugging purpose
   pppDumpPacket((PppPacket *) failurePacket, length, PPP_PROTOCOL_CHAP);

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

   //Free previously allocated memory block
   netBufferFree(buffer);
   //Return status code
   return error;
}
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;
}
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;
}
Beispiel #10
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;
}
Beispiel #11
0
void dnsProcessResponse(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
   const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *params)
{
   uint_t i;
   uint_t j;
   size_t pos;
   size_t length;
   DnsHeader *message;
   DnsQuestion *question;
   DnsResourceRecord *resourceRecord;
   DnsCacheEntry *entry;

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

   //Ensure the DNS message is valid
   if(length < sizeof(DnsHeader))
      return;
   if(length > DNS_MESSAGE_MAX_SIZE)
      return;

   //Point to the DNS message header
   message = netBufferAt(buffer, offset);
   //Sanity check
   if(!message) return;

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

   //Check message type
   if(!message->qr)
      return;
   //The DNS message shall contain one question
   if(ntohs(message->qdcount) != 1)
      return;

   //Acquire exclusive access to the DNS cache
   osAcquireMutex(&dnsCacheMutex);

   //Loop through DNS cache entries
   for(i = 0; i < DNS_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &dnsCache[i];

      //DNS name resolution in progress?
      if(entry->state == DNS_STATE_IN_PROGRESS &&
         entry->protocol == HOST_NAME_RESOLVER_DNS)
      {
         //Check destination port number
         if(entry->port == ntohs(udpHeader->destPort))
         {
            //Compare identifier against the expected one
            if(ntohs(message->id) != entry->id)
               break;

            //Point to the first question
            pos = sizeof(DnsHeader);
            //Parse domain name
            pos = dnsParseName(message, length, pos, NULL, 0);

            //Invalid name?
            if(!pos)
               break;
            //Malformed mDNS message?
            if((pos + sizeof(DnsQuestion)) > length)
               break;

            //Compare domain name
            if(!dnsCompareName(message, length, sizeof(DnsHeader), entry->name, 0))
               break;

            //Point to the corresponding entry
            question = DNS_GET_QUESTION(message, pos);

            //Check the class of the query
            if(ntohs(question->qclass) != DNS_RR_CLASS_IN)
               break;
            //Check the type of the query
            if(entry->type == HOST_TYPE_IPV4 && ntohs(question->qtype) != DNS_RR_TYPE_A)
               break;
            if(entry->type == HOST_TYPE_IPV6 && ntohs(question->qtype) != DNS_RR_TYPE_AAAA)
               break;

            //Make sure recursion is available
            if(!message->ra)
            {
               //The entry should be deleted since name resolution has failed
               dnsDeleteEntry(entry);
               //Exit immediately
               break;
            }

            //Check return code
            if(message->rcode != DNS_RCODE_NO_ERROR)
            {
               //The entry should be deleted since name resolution has failed
               dnsDeleteEntry(entry);
               //Exit immediately
               break;
            }

            //Point to the first answer
            pos += sizeof(DnsQuestion);

            //Parse answer resource records
            for(j = 0; j < ntohs(message->ancount); j++)
            {
               //Parse domain name
               pos = dnsParseName(message, length, pos, NULL, 0);
               //Invalid name?
               if(!pos) break;

               //Point to the associated resource record
               resourceRecord = DNS_GET_RESOURCE_RECORD(message, pos);
               //Point to the resource data
               pos += sizeof(DnsResourceRecord);

               //Make sure the resource record is valid
               if(pos > length)
                  break;
               if((pos + ntohs(resourceRecord->rdlength)) > length)
                  break;

#if (IPV4_SUPPORT == ENABLED)
               //IPv4 address expected?
               if(entry->type == HOST_TYPE_IPV4)
               {
                  //A resource record found?
                  if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_A &&
                     ntohs(resourceRecord->rdlength) == sizeof(Ipv4Addr))
                  {
                     //Copy the IPv4 address
                     entry->ipAddr.length = sizeof(Ipv4Addr);
                     ipv4CopyAddr(&entry->ipAddr.ipv4Addr, resourceRecord->rdata);

                     //Save current time
                     entry->timestamp = osGetSystemTime();
                     //Save TTL value
                     entry->timeout = ntohl(resourceRecord->ttl) * 1000;
                     //Limit the lifetime of the DNS cache entries
                     entry->timeout = MIN(entry->timeout, DNS_MAX_LIFETIME);

                     //Unregister UDP callback function
                     udpDetachRxCallback(interface, entry->port);
                     //Host name successfully resolved
                     entry->state = DNS_STATE_RESOLVED;
                     //Exit immediately
                     break;
                  }
               }
#endif
#if (IPV6_SUPPORT == ENABLED)
               //IPv6 address expected?
               if(entry->type == HOST_TYPE_IPV6)
               {
                  //AAAA resource record found?
                  if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_AAAA &&
                     ntohs(resourceRecord->rdlength) == sizeof(Ipv6Addr))
                  {
                     //Copy the IPv6 address
                     entry->ipAddr.length = sizeof(Ipv6Addr);
                     ipv6CopyAddr(&entry->ipAddr.ipv6Addr, resourceRecord->rdata);

                     //Save current time
                     entry->timestamp = osGetSystemTime();
                     //Save TTL value
                     entry->timeout = ntohl(resourceRecord->ttl) * 1000;
                     //Limit the lifetime of the DNS cache entries
                     entry->timeout = MIN(entry->timeout, DNS_MAX_LIFETIME);

                     //Unregister UDP callback function
                     udpDetachRxCallback(interface, entry->port);
                     //Host name successfully resolved
                     entry->state = DNS_STATE_RESOLVED;
                     //Exit immediately
                     break;
                  }
               }
#endif
               //Point to the next resource record
               pos += ntohs(resourceRecord->rdlength);
            }

            //We are done
            break;
         }
      }
   }

   //Release exclusive access to the DNS cache
   osReleaseMutex(&dnsCacheMutex);
}
Beispiel #12
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;
}
Beispiel #13
0
error_t udpProcessDatagram(NetInterface *interface,
                           IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
{
    error_t error;
    uint_t i;
    size_t length;
    UdpHeader *header;
    Socket *socket;
    SocketQueueItem *queueItem;
    NetBuffer *p;

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

    //Ensure the UDP header is valid
    if(length < sizeof(UdpHeader))
    {
        //Debug message
        TRACE_WARNING("UDP datagram length is invalid!\r\n");
        //Report an error
        return ERROR_INVALID_HEADER;
    }

    //Point to the UDP header
    header = netBufferAt(buffer, offset);
    //Sanity check
    if(!header) return ERROR_FAILURE;

    //Debug message
    TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length);
    //Dump UDP header contents for debugging purpose
    udpDumpHeader(header);

    //When UDP runs over IPv6, the checksum is mandatory
    if(header->checksum || pseudoHeader->length == sizeof(Ipv6PseudoHeader))
    {
        //Verify UDP checksum
        if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
                                      pseudoHeader->length, buffer, offset, length) != 0xFFFF)
        {
            //Debug message
            TRACE_WARNING("Wrong UDP header checksum!\r\n");
            //Report an error
            return ERROR_WRONG_CHECKSUM;
        }
    }

    //Enter critical section
    osAcquireMutex(&socketMutex);

    //Loop through opened sockets
    for(i = 0; i < SOCKET_MAX_COUNT; i++)
    {
        //Point to the current socket
        socket = socketTable + i;

        //UDP socket found?
        if(socket->type != SOCKET_TYPE_DGRAM)
            continue;
        //Check whether the socket is bound to a particular interface
        if(socket->interface && socket->interface != interface)
            continue;
        //Check destination port number
        if(socket->localPort != ntohs(header->destPort))
            continue;
        //Source port number filtering
        if(socket->remotePort && socket->remotePort != ntohs(header->srcPort))
            continue;

#if (IPV4_SUPPORT == ENABLED)
        //An IPv4 packet was received?
        if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
        {
            //Destination IP address filtering
            if(socket->localIpAddr.length)
            {
                //An IPv4 address is expected
                if(socket->localIpAddr.length != sizeof(Ipv4Addr))
                    continue;
                //Filter out non-matching addresses
                if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
                    continue;
            }
            //Source IP address filtering
            if(socket->remoteIpAddr.length)
            {
                //An IPv4 address is expected
                if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
                    continue;
                //Filter out non-matching addresses
                if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
                    continue;
            }
        }
        else
#endif
#if (IPV6_SUPPORT == ENABLED)
            //An IPv6 packet was received?
            if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
            {
                //Destination IP address filtering
                if(socket->localIpAddr.length)
                {
                    //An IPv6 address is expected
                    if(socket->localIpAddr.length != sizeof(Ipv6Addr))
                        continue;
                    //Filter out non-matching addresses
                    if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
                        continue;
                }
                //Source IP address filtering
                if(socket->remoteIpAddr.length)
                {
                    //An IPv6 address is expected
                    if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
                        continue;
                    //Filter out non-matching addresses
                    if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
                        continue;
                }
            }
            else
#endif
                //An invalid packet was received?
            {
                //This should never occur...
                continue;
            }

        //The current socket meets all the criteria
        break;
    }

    //Point to the payload
    offset += sizeof(UdpHeader);
    length -= sizeof(UdpHeader);

    //No matching socket found?
    if(i >= SOCKET_MAX_COUNT)
    {
        //Leave critical section
        osReleaseMutex(&socketMutex);
        //Invoke user callback, if any
        error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer, offset);
        //Return status code
        return error;
    }

    //Empty receive queue?
    if(!socket->receiveQueue)
    {
        //Allocate a memory buffer to hold the data and the associated descriptor
        p = netBufferAlloc(sizeof(SocketQueueItem) + length);

        //Successful memory allocation?
        if(p != NULL)
        {
            //Point to the newly created item
            queueItem = netBufferAt(p, 0);
            queueItem->buffer = p;
            //Add the newly created item to the queue
            socket->receiveQueue = queueItem;
        }
        else
        {
            //Memory allocation failed
            queueItem = NULL;
        }
    }
    else
    {
        //Point to the very first item
        queueItem = socket->receiveQueue;
        //Reach the last item in the receive queue
        for(i = 1; queueItem->next; i++)
            queueItem = queueItem->next;

        //Make sure the receive queue is not full
        if(i >= UDP_RX_QUEUE_SIZE)
        {
            //Leave critical section
            osReleaseMutex(&socketMutex);
            //Notify the calling function that the queue is full
            return ERROR_RECEIVE_QUEUE_FULL;
        }

        //Allocate a memory buffer to hold the data and the associated descriptor
        p = netBufferAlloc(sizeof(SocketQueueItem) + length);

        //Successful memory allocation?
        if(p != NULL)
        {
            //Add the newly created item to the queue
            queueItem->next = netBufferAt(p, 0);
            //Point to the newly created item
            queueItem = queueItem->next;
            queueItem->buffer = p;
        }
        else
        {
            //Memory allocation failed
            queueItem = NULL;
        }
    }

    //Failed to allocate memory?
    if(!queueItem)
    {
        //Leave critical section
        osReleaseMutex(&socketMutex);
        //Return error code
        return ERROR_OUT_OF_MEMORY;
    }

    //Initialize next field
    queueItem->next = NULL;
    //Record the source port number
    queueItem->srcPort = ntohs(header->srcPort);

#if (IPV4_SUPPORT == ENABLED)
    //IPv4 remote address?
    if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
    {
        //Save the source IPv4 address
        queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
        queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
        //Save the destination IPv4 address
        queueItem->destIpAddr.length = sizeof(Ipv4Addr);
        queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
    }
#endif
#if (IPV6_SUPPORT == ENABLED)
    //IPv6 remote address?
    if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
    {
        //Save the source IPv6 address
        queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
        queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
        //Save the destination IPv6 address
        queueItem->destIpAddr.length = sizeof(Ipv6Addr);
        queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
    }
#endif

    //Offset to the payload
    queueItem->offset = sizeof(SocketQueueItem);
    //Copy the payload
    netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);

    //Notify user that data is available
    udpUpdateEvents(socket);

    //Leave critical section
    osReleaseMutex(&socketMutex);
    //Successful processing
    return NO_ERROR;
}
Beispiel #14
0
error_t chapSendChallenge(PppContext *context)
{
   error_t error;
   size_t n;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   ChapChallengePacket *challengePacket;

   //Retrieve the length of the username
   n = strlen(context->username);
   //Calculate the length of the Challenge packet
   length = sizeof(ChapChallengePacket) + MD5_DIGEST_SIZE + n;

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

   //Point to the Challenge packet
   challengePacket = netBufferAt(buffer, offset);

   //Format packet header
   challengePacket->code = CHAP_CODE_CHALLENGE;
   challengePacket->identifier = ++context->chapFsm.localIdentifier;
   challengePacket->length = htons(length);
   challengePacket->valueSize = MD5_DIGEST_SIZE;

   //Make sure that the callback function has been registered
   if(context->settings.randCallback != NULL)
   {
      //Generate a random challenge value
      error = context->settings.randCallback(
         context->chapFsm.challenge, MD5_DIGEST_SIZE);
   }
   else
   {
      //Report an error
      error = ERROR_FAILURE;
   }

   //Check status code
   if(!error)
   {
      //Copy the challenge value
      memcpy(challengePacket->value, context->chapFsm.challenge, MD5_DIGEST_SIZE);

      //The Name field is one or more octets representing the
      //identification of the system transmitting the packet
      memcpy(challengePacket->value + MD5_DIGEST_SIZE, context->username, n);

      //Debug message
      TRACE_INFO("Sending CHAP Challenge packet (%" PRIuSIZE " bytes)...\r\n", length);
      //Dump packet contents for debugging purpose
      pppDumpPacket((PppPacket *) challengePacket, length, PPP_PROTOCOL_CHAP);

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

      //The restart counter is decremented each time a Challenge packet is sent
      if(context->chapFsm.restartCounter > 0)
         context->chapFsm.restartCounter--;

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

   //Free previously allocated memory block
   netBufferFree(buffer);
   //Return status code
   return error;
}
Beispiel #15
0
void tcpProcessSegment(NetInterface *interface,
   IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
{
   uint_t i;
   size_t length;
   Socket *socket;
   Socket *passiveSocket;
   TcpHeader *segment;

   //Total number of segments received, including those received in error
   MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInSegs, 1);
   MIB2_INC_COUNTER64(mib2Base.tcpGroup.tcpHCInSegs, 1);

   //A TCP implementation must silently discard an incoming
   //segment that is addressed to a broadcast or multicast
   //address (see RFC 1122 4.2.3.10)
#if (IPV4_SUPPORT == ENABLED)
   if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
   {
      //Ensure the destination address is not a broadcast address
      if(ipv4IsBroadcastAddr(interface, pseudoHeader->ipv4Data.destAddr))
         return;
      //Ensure the destination address is not a multicast address
      if(ipv4IsMulticastAddr(pseudoHeader->ipv4Data.destAddr))
         return;
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
   {
      //Ensure the destination address is not a multicast address
      if(ipv6IsMulticastAddr(&pseudoHeader->ipv6Data.destAddr))
         return;
   }
   else
#endif
   {
      //This should never occur...
      return;
   }

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

   //Point to the TCP header
   segment = netBufferAt(buffer, offset);
   //Sanity check
   if(segment == NULL)
      return;

   //Ensure the TCP header is valid
   if(length < sizeof(TcpHeader))
   {
      //Debug message
      TRACE_WARNING("TCP segment length is invalid!\r\n");
      //Total number of segments received in error
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1);
      //Exit immediately
      return;
   }

   //Check header length
   if(segment->dataOffset < 5 || (segment->dataOffset * 4) > length)
   {
      //Debug message
      TRACE_WARNING("TCP header length is invalid!\r\n");
      //Total number of segments received in error
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1);
      //Exit immediately
      return;
   }

   //Verify TCP checksum
   if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
      pseudoHeader->length, buffer, offset, length) != 0x0000)
   {
      //Debug message
      TRACE_WARNING("Wrong TCP header checksum!\r\n");
      //Total number of segments received in error
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1);
      //Exit immediately
      return;
   }

   //No matching socket in the LISTEN state for the moment
   passiveSocket = NULL;

   //Look through opened sockets
   for(i = 0; i < SOCKET_MAX_COUNT; i++)
   {
      //Point to the current socket
      socket = socketTable + i;

      //TCP socket found?
      if(socket->type != SOCKET_TYPE_STREAM)
         continue;
      //Check whether the socket is bound to a particular interface
      if(socket->interface && socket->interface != interface)
         continue;
      //Check destination port number
      if(socket->localPort != ntohs(segment->destPort))
         continue;

#if (IPV4_SUPPORT == ENABLED)
      //An IPv4 packet was received?
      if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
      {
         //Destination IP address filtering
         if(socket->localIpAddr.length)
         {
            //An IPv4 address is expected
            if(socket->localIpAddr.length != sizeof(Ipv4Addr))
               continue;
            //Filter out non-matching addresses
            if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
               continue;
         }
         //Source IP address filtering
         if(socket->remoteIpAddr.length)
         {
            //An IPv4 address is expected
            if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
               continue;
            //Filter out non-matching addresses
            if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
               continue;
         }
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //An IPv6 packet was received?
      if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
      {
         //Destination IP address filtering
         if(socket->localIpAddr.length)
         {
            //An IPv6 address is expected
            if(socket->localIpAddr.length != sizeof(Ipv6Addr))
               continue;
            //Filter out non-matching addresses
            if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
               continue;
         }
         //Source IP address filtering
         if(socket->remoteIpAddr.length)
         {
            //An IPv6 address is expected
            if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
               continue;
            //Filter out non-matching addresses
            if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
               continue;
         }
      }
      else
#endif
      //An invalid packet was received?
      {
         //This should never occur...
         continue;
      }

      //Keep track of the first matching socket in the LISTEN state
      if(socket->state == TCP_STATE_LISTEN && !passiveSocket)
         passiveSocket = socket;
      //Source port filtering
      if(socket->remotePort != ntohs(segment->srcPort))
         continue;

      //A matching socket has been found
      break;
   }

   //If no matching socket has been found then try to
   //use the first matching socket in the LISTEN state
   if(i >= SOCKET_MAX_COUNT) socket = passiveSocket;

   //Offset to the first data byte
   offset += segment->dataOffset * 4;
   //Calculate the length of the data
   length -= segment->dataOffset * 4;

   //Debug message
   TRACE_DEBUG("%s: TCP segment received (%" PRIuSIZE " data bytes)...\r\n",
      formatSystemTime(osGetSystemTime(), NULL), length);

   //Dump TCP header contents for debugging purpose
   if(!socket)
      tcpDumpHeader(segment, length, 0, 0);
   else
      tcpDumpHeader(segment, length, socket->irs, socket->iss);

   //Convert from network byte order to host byte order
   segment->srcPort = ntohs(segment->srcPort);
   segment->destPort = ntohs(segment->destPort);
   segment->seqNum = ntohl(segment->seqNum);
   segment->ackNum = ntohl(segment->ackNum);
   segment->window = ntohs(segment->window);
   segment->urgentPointer = ntohs(segment->urgentPointer);

   //Specified port is unreachable?
   if(!socket)
   {
      //An incoming segment not containing a RST causes
      //a reset to be sent in response
      if(!(segment->flags & TCP_FLAG_RST))
         tcpSendResetSegment(interface, pseudoHeader, segment, length);

      //Return immediately
      return;
   }

   //Check current state
   switch(socket->state)
   {
   //Process CLOSED state
   case TCP_STATE_CLOSED:
      //This is the default state that each connection starts in before
      //the process of establishing it begins
      tcpStateClosed(interface, pseudoHeader, segment, length);
      break;
   //Process LISTEN state
   case TCP_STATE_LISTEN:
      //A device (normally a server) is waiting to receive a synchronize (SYN)
      //message from a client. It has not yet sent its own SYN message
      tcpStateListen(socket, interface, pseudoHeader, segment, length);
      break;
   //Process SYN_SENT state
   case TCP_STATE_SYN_SENT:
      //The device (normally a client) has sent a synchronize (SYN) message and
      //is waiting for a matching SYN from the other device (usually a server)
      tcpStateSynSent(socket, segment, length);
      break;
   //Process SYN_RECEIVED state
   case TCP_STATE_SYN_RECEIVED:
      //The device has both received a SYN from its partner and sent its own SYN.
      //It is now waiting for an ACK to its SYN to finish connection setup
      tcpStateSynReceived(socket, segment, buffer, offset, length);
      break;
   //Process ESTABLISHED state
   case TCP_STATE_ESTABLISHED:
      //Data can be exchanged freely once both devices in the connection enter
      //this state. This will continue until the connection is closed
      tcpStateEstablished(socket, segment, buffer, offset, length);
      break;
   //Process CLOSE_WAIT state
   case TCP_STATE_CLOSE_WAIT:
      //The device has received a close request (FIN) from the other device. It
      //must now wait for the application to acknowledge this request and
      //generate a matching request
      tcpStateCloseWait(socket, segment, length);
      break;
   //Process LAST_ACK state
   case TCP_STATE_LAST_ACK:
      //A device that has already received a close request and acknowledged it,
      //has sent its own FIN and is waiting for an ACK to this request
      tcpStateLastAck(socket, segment, length);
      break;
   //Process FIN_WAIT_1 state
   case TCP_STATE_FIN_WAIT_1:
      //A device in this state is waiting for an ACK for a FIN it has sent, or
      //is waiting for a connection termination request from the other device
      tcpStateFinWait1(socket, segment, buffer, offset, length);
      break;
   //Process FIN_WAIT_2 state
   case TCP_STATE_FIN_WAIT_2:
      //A device in this state has received an ACK for its request to terminate the
      //connection and is now waiting for a matching FIN from the other device
      tcpStateFinWait2(socket, segment, buffer, offset, length);
      break;
   //Process CLOSING state
   case TCP_STATE_CLOSING:
      //The device has received a FIN from the other device and sent an ACK for
      //it, but not yet received an ACK for its own FIN message
      tcpStateClosing(socket, segment, length);
      break;
   //Process TIME_WAIT state
   case TCP_STATE_TIME_WAIT:
      //The device has now received a FIN from the other device and acknowledged
      //it, and sent its own FIN and received an ACK for it. We are done, except
      //for waiting to ensure the ACK is received and prevent potential overlap
      //with new connections
      tcpStateTimeWait(socket, segment, length);
      break;
   //Invalid state...
   default:
      //Back to the CLOSED state
      tcpChangeState(socket, TCP_STATE_CLOSED);
      //Silently discard incoming packet
      break;
   }
}
Beispiel #16
0
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
   uint16_t fragId, uint16_t fragOffset, NetBuffer *buffer, size_t offset, uint8_t ttl)
{
   error_t error;
   size_t length;
   Ipv4Header *packet;

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

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

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

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

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

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

   //Destination address is the unspecified address?
   if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR)
   {
      //Destination address is not acceptable
      return ERROR_INVALID_ADDRESS;
   }
   //Destination address is the loopback address?
   else if(pseudoHeader->destAddr == IPV4_LOOPBACK_ADDR)
   {
      //Not yet implemented...
      return ERROR_NOT_IMPLEMENTED;
   }

#if (ETH_SUPPORT == ENABLED)
   //Ethernet interface?
   if(interface->nicDriver->type == NIC_TYPE_ETHERNET)
   {
      Ipv4Addr destIpAddr;
      MacAddr destMacAddr;

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

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

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

         //Enqueue packets waiting for address resolution
         error = arpEnqueuePacket(interface, destIpAddr, buffer, offset);
      }
      //Address resolution failed?
      else
      {
         //Debug message
         TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n");
      }
   }
   else
#endif
#if (PPP_SUPPORT == ENABLED)
   //PPP interface?
   if(interface->nicDriver->type == NIC_TYPE_PPP)
   {
      //Debug message
      TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
      //Dump IP header contents for debugging purpose
      ipv4DumpHeader(packet);

      //Send PPP frame
      error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IP);
   }
   else
#endif
   //Unknown interface type?
   {
      //Report an error
      error = ERROR_INVALID_INTERFACE;
   }

   //Return status code
   return error;
}
Beispiel #17
0
void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer)
{
   error_t error;
   size_t offset;
   size_t length;
   Ipv4Header *header;
   IpPseudoHeader pseudoHeader;

   //Retrieve the length of the IPv4 datagram
   length = netBufferGetLength(buffer);

   //Point to the IPv4 header
   header = netBufferAt(buffer, 0);
   //Sanity check
   if(!header) return;

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

   //Get the offset to the payload
   offset = header->headerLength * 4;
   //Compute the length of the payload
   length -= header->headerLength * 4;

   //Form the IPv4 pseudo header
   pseudoHeader.length = sizeof(Ipv4PseudoHeader);
   pseudoHeader.ipv4Data.srcAddr = header->srcAddr;
   pseudoHeader.ipv4Data.destAddr = header->destAddr;
   pseudoHeader.ipv4Data.reserved = 0;
   pseudoHeader.ipv4Data.protocol = header->protocol;
   pseudoHeader.ipv4Data.length = htons(length);

#if defined(IPV4_DATAGRAM_FORWARD_HOOK)
   IPV4_DATAGRAM_FORWARD_HOOK(interface, &pseudoHeader, buffer, offset);
#endif

   //Check the protocol field
   switch(header->protocol)
   {
   //ICMP protocol?
   case IPV4_PROTOCOL_ICMP:
      //Process incoming ICMP message
      icmpProcessMessage(interface, header->srcAddr, buffer, offset);
#if (RAW_SOCKET_SUPPORT == ENABLED)
      //Allow raw sockets to process ICMP messages
      rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset);
#endif
      //No error to report
      error = NO_ERROR;
      //Continue processing
      break;

#if (IGMP_SUPPORT == ENABLED)
   //IGMP protocol?
   case IPV4_PROTOCOL_IGMP:
      //Process incoming IGMP message
      igmpProcessMessage(interface, buffer, offset);
#if (RAW_SOCKET_SUPPORT == ENABLED)
      //Allow raw sockets to process IGMP messages
      rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset);
#endif
      //No error to report
      error = NO_ERROR;
      //Continue processing
      break;
#endif

#if (TCP_SUPPORT == ENABLED)
   //TCP protocol?
   case IPV4_PROTOCOL_TCP:
      //Process incoming TCP segment
      tcpProcessSegment(interface, &pseudoHeader, buffer, offset);
      //No error to report
      error = NO_ERROR;
      //Continue processing
      break;
#endif

#if (UDP_SUPPORT == ENABLED)
   //UDP protocol?
   case IPV4_PROTOCOL_UDP:
      //Process incoming UDP datagram
      error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset);
      //Continue processing
      break;
#endif

   //Unknown protocol?
   default:
#if (RAW_SOCKET_SUPPORT == ENABLED)
      //Allow raw sockets to process IPv4 packets
      error = rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset);
#else
      //Report an error
      error = ERROR_PROTOCOL_UNREACHABLE;
#endif
      //Continue processing
      break;
   }

   //Unreachable protocol?
   if(error == ERROR_PROTOCOL_UNREACHABLE)
   {
      //Send a Destination Unreachable message
      icmpSendErrorMessage(interface, ICMP_TYPE_DEST_UNREACHABLE,
         ICMP_CODE_PROTOCOL_UNREACHABLE, 0, buffer);
   }
   //Unreachable port?
   else if(error == ERROR_PORT_UNREACHABLE)
   {
      //Send a Destination Unreachable message
      icmpSendErrorMessage(interface, ICMP_TYPE_DEST_UNREACHABLE,
         ICMP_CODE_PORT_UNREACHABLE, 0, buffer);
   }
}
Beispiel #18
0
error_t rawSocketProcessIpPacket(NetInterface *interface,
   IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
{
   uint_t i;
   size_t length;
   Socket *socket;
   SocketQueueItem *queueItem;
   NetBuffer *p;

   //Retrieve the length of the raw IP packet
   length = netBufferGetLength(buffer) - offset;

   //Enter critical section
   osAcquireMutex(&socketMutex);

   //Loop through opened sockets
   for(i = 0; i < SOCKET_MAX_COUNT; i++)
   {
      //Point to the current socket
      socket = socketTable + i;

      //Raw socket found?
      if(socket->type != SOCKET_TYPE_RAW_IP)
         continue;
      //Check whether the socket is bound to a particular interface
      if(socket->interface && socket->interface != interface)
         continue;

#if (IPV4_SUPPORT == ENABLED)
      //An IPv4 packet was received?
      if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
      {
         //Check protocol field
         if(socket->protocol != pseudoHeader->ipv4Data.protocol)
            continue;
         //Destination IP address filtering
         if(socket->localIpAddr.length)
         {
            //An IPv4 address is expected
            if(socket->localIpAddr.length != sizeof(Ipv4Addr))
               continue;
            //Filter out non-matching addresses
            if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
               continue;
         }
         //Source IP address filtering
         if(socket->remoteIpAddr.length)
         {
            //An IPv4 address is expected
            if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
               continue;
            //Filter out non-matching addresses
            if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
               continue;
         }
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //An IPv6 packet was received?
      if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
      {
         //Check protocol field
         if(socket->protocol != pseudoHeader->ipv6Data.nextHeader)
            continue;
         //Destination IP address filtering
         if(socket->localIpAddr.length)
         {
            //An IPv6 address is expected
            if(socket->localIpAddr.length != sizeof(Ipv6Addr))
               continue;
            //Filter out non-matching addresses
            if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
               continue;
         }
         //Source IP address filtering
         if(socket->remoteIpAddr.length)
         {
            //An IPv6 address is expected
            if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
               continue;
            //Filter out non-matching addresses
            if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
               continue;
         }
      }
      else
#endif
      //An invalid packet was received?
      {
         //This should never occur...
         continue;
      }

      //The current socket meets all the criteria
      break;
   }

   //Drop incoming packet if no matching socket was found
   if(i >= SOCKET_MAX_COUNT)
   {
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Unreachable protocol...
      return ERROR_PROTOCOL_UNREACHABLE;
   }

   //Empty receive queue?
   if(!socket->receiveQueue)
   {
      //Allocate a memory buffer to hold the data and the associated descriptor
      p = netBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Point to the newly created item
         queueItem = netBufferAt(p, 0);
         queueItem->buffer = p;
         //Add the newly created item to the queue
         socket->receiveQueue = queueItem;
      }
      else
      {
         //Memory allocation failed
         queueItem = NULL;
      }
   }
   else
   {
      //Point to the very first item
      queueItem = socket->receiveQueue;
      //Reach the last item in the receive queue
      for(i = 1; queueItem->next; i++)
         queueItem = queueItem->next;

      //Make sure the receive queue is not full
      if(i >= RAW_SOCKET_RX_QUEUE_SIZE)
      {
         //Leave critical section
         osReleaseMutex(&socketMutex);
         //Notify the calling function that the queue is full
         return ERROR_RECEIVE_QUEUE_FULL;
      }

      //Allocate a memory buffer to hold the data and the associated descriptor
      p = netBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Add the newly created item to the queue
         queueItem->next = netBufferAt(p, 0);
         //Point to the newly created item
         queueItem = queueItem->next;
         queueItem->buffer = p;
      }
      else
      {
         //Memory allocation failed
         queueItem = NULL;
      }
   }

   //Failed to allocate memory?
   if(!queueItem)
   {
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Return error code
      return ERROR_OUT_OF_MEMORY;
   }

   //Initialize next field
   queueItem->next = NULL;
   //Port number is unused
   queueItem->srcPort = 0;

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 remote address?
   if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
   {
      //Save the source IPv4 address
      queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
      queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
      //Save the destination IPv4 address
      queueItem->destIpAddr.length = sizeof(Ipv4Addr);
      queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
   }
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 remote address?
   if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
   {
      //Save the source IPv6 address
      queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
      queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
      //Save the destination IPv6 address
      queueItem->destIpAddr.length = sizeof(Ipv6Addr);
      queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
   }
#endif

   //Offset to the raw IP packet
   queueItem->offset = sizeof(SocketQueueItem);
   //Copy the raw data
   netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);

   //Notify user that data is available
   rawSocketUpdateEvents(socket);

   //Leave critical section
   osReleaseMutex(&socketMutex);
   //Successful processing
   return NO_ERROR;
}
Beispiel #19
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);
}
Beispiel #20
0
Ipv4HoleDesc *ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
{
   //Return a pointer to the hole descriptor
   return netBufferAt((NetBuffer *) &frag->buffer, frag->headerLength + offset);
}
Beispiel #21
0
void rawSocketProcessEthPacket(NetInterface *interface,
   EthHeader *ethFrame, size_t length)
{
   uint_t i;
   Socket *socket;
   SocketQueueItem *queueItem;
   NetBuffer *p;

   //Enter critical section
   osAcquireMutex(&socketMutex);

   //Loop through opened sockets
   for(i = 0; i < SOCKET_MAX_COUNT; i++)
   {
      //Point to the current socket
      socket = socketTable + i;

      //Raw socket found?
      if(socket->type != SOCKET_TYPE_RAW_ETH)
         continue;
      //Check whether the socket is bound to a particular interface
      if(socket->interface && socket->interface != interface)
         continue;
      //Check protocol field
      if(socket->protocol != SOCKET_ETH_PROTO_ALL && socket->protocol != ntohs(ethFrame->type))
         continue;

      //The current socket meets all the criteria
      break;
   }

   //Drop incoming packet if no matching socket was found
   if(i >= SOCKET_MAX_COUNT)
   {
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Return immediately
      return;
   }

   //Empty receive queue?
   if(!socket->receiveQueue)
   {
      //Allocate a memory buffer to hold the data and the associated descriptor
      p = netBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Point to the newly created item
         queueItem = netBufferAt(p, 0);
         queueItem->buffer = p;
         //Add the newly created item to the queue
         socket->receiveQueue = queueItem;
      }
      else
      {
         //Memory allocation failed
         queueItem = NULL;
      }
   }
   else
   {
      //Point to the very first item
      queueItem = socket->receiveQueue;
      //Reach the last item in the receive queue
      for(i = 1; queueItem->next; i++)
         queueItem = queueItem->next;

      //Make sure the receive queue is not full
      if(i >= RAW_SOCKET_RX_QUEUE_SIZE)
      {
         //Leave critical section
         osReleaseMutex(&socketMutex);
         //Return immediately
         return;
      }

      //Allocate a memory buffer to hold the data and the associated descriptor
      p = netBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Add the newly created item to the queue
         queueItem->next = netBufferAt(p, 0);
         //Point to the newly created item
         queueItem = queueItem->next;
         queueItem->buffer = p;
      }
      else
      {
         //Memory allocation failed
         queueItem = NULL;
      }
   }

   //Failed to allocate memory?
   if(!queueItem)
   {
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Return immediately
      return;
   }

   //Initialize next field
   queueItem->next = NULL;
   //Other fields are meaningless
   queueItem->srcPort = 0;
   queueItem->srcIpAddr = IP_ADDR_ANY;
   queueItem->destIpAddr = IP_ADDR_ANY;

   //Offset to the raw datagram
   queueItem->offset = sizeof(SocketQueueItem);
   //Copy the raw data
   netBufferWrite(queueItem->buffer, queueItem->offset, ethFrame, length);

   //Notify user that data is available
   rawSocketUpdateEvents(socket);

   //Leave critical section
   osReleaseMutex(&socketMutex);
}
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;
}
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;
}
Beispiel #24
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;
}
Beispiel #25
0
error_t udpSendDatagramEx(NetInterface *interface, uint16_t srcPort, const IpAddr *destIpAddr,
                          uint16_t destPort, NetBuffer *buffer, size_t offset, uint8_t ttl)
{
    error_t error;
    size_t length;
    UdpHeader *header;
    IpPseudoHeader pseudoHeader;

    //Make room for the UDP header
    offset -= sizeof(UdpHeader);
    //Retrieve the length of the datagram
    length = netBufferGetLength(buffer) - offset;

    //Point to the UDP header
    header = netBufferAt(buffer, offset);
    //Sanity check
    if(!header) return ERROR_FAILURE;

    //Format UDP header
    header->srcPort = htons(srcPort);
    header->destPort = htons(destPort);
    header->length = htons(length);
    header->checksum = 0;

#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) return error;

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

        //Calculate UDP header checksum
        header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv4Data,
                           sizeof(Ipv4PseudoHeader), buffer, offset, length);
    }
    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) return error;

            //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 = IPV6_UDP_HEADER;

            //Calculate UDP header checksum
            header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv6Data,
                               sizeof(Ipv6PseudoHeader), buffer, offset, length);
        }
        else
#endif
            //Invalid destination address?
        {
            //An internal error has occurred
            return ERROR_FAILURE;
        }

    //Debug message
    TRACE_INFO("Sending UDP datagram (%" PRIuSIZE " bytes)\r\n", length);
    //Dump UDP header contents for debugging purpose
    udpDumpHeader(header);

    //Send UDP datagram
    return ipSendDatagram(interface, &pseudoHeader, buffer, offset, ttl);
}
Beispiel #26
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);
   }
}