Example #1
0
error_t socketSend(Socket *socket, const void *data,
   size_t length, size_t *written, uint_t flags)
{
   //Use default remote IP address for connectionless or raw sockets
   return socketSendTo(socket, &socket->remoteIpAddr,
      socket->remotePort, data, length, written, flags);
}
Example #2
0
void udpEchoTask(void *param)
{
   error_t error;
   uint_t length;
   uint16_t port;
   IpAddr ipAddr;
   EchoServiceContext *context;

   //Get a pointer to the context
   context = (EchoServiceContext *) param;

   //Main loop
   while(1)
   {
      //Wait for an incoming datagram
      error = socketReceiveFrom(context->socket, &ipAddr, &port,
         context->buffer, ECHO_BUFFER_SIZE, &length, 0);

      //Any datagram received?
      if(!error)
      {
         //Debug message
         TRACE_INFO("Echo service: %u bytes received from %s port %u\r\n",
            length, ipAddrToString(&ipAddr, NULL), port);

         //Send the data back to the source
         error = socketSendTo(context->socket, &ipAddr, port,
            context->buffer, length, NULL, 0);
      }
   }
}
Example #3
0
void udpChargenTask(void *param)
{
   error_t error;
   size_t i;
   size_t k;
   size_t n;
   size_t length;
   uint16_t port;
   IpAddr ipAddr;
   ChargenServiceContext *context;

   //Get a pointer to the context
   context = (ChargenServiceContext *) param;

   //Main loop
   while(1)
   {
      //Wait for an incoming datagram
      error = socketReceiveFrom(context->socket, &ipAddr, &port,
         context->buffer, CHARGEN_BUFFER_SIZE, &n, 0);

      //Any datagram received?
      if(!error)
      {
         //When a datagram is received, an answering datagram is sent
         //containing a random number (between 0 and 512) of characters
         length = tcpIpStackGetRand() % 513;

         //Reset line counter
         n = 0;

         //Format output data
         for(i = 0; i < length; i += 74)
         {
            //Calculate the length of the current line
            k = min(length - i, 74);
            //Copy character pattern
            memcpy(context->buffer + i, pattern + n, k);

            //End each line with carriage return and line feed
            if(k == 74)
            {
               context->buffer[i + 72] = '\r';
               context->buffer[i + 73] = '\n';
            }

            //Increment line counter
            if(++n >= 95) n = 0;
         }

         //Send data to the remote host
         error = socketSendTo(context->socket, &ipAddr, port,
            context->buffer, length, &n, 0);

         //Debug message
         TRACE_INFO("Chargen service: %" PRIuSIZE " bytes sent to %s port %" PRIu16 "\r\n",
            n, ipAddrToString(&ipAddr, NULL), port);
      }
   }
}
Example #4
0
int_t sendto(int_t s, const void *data, int_t length,
   int_t flags, const sockaddr *addr, int_t addrlen)
{
   error_t error;
   size_t written;
   uint16_t port;
   IpAddr ipAddr;
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Check the length of the address
   if(addrlen < sizeof(sockaddr))
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 address?
   if(addr->sa_family == AF_INET && addrlen == sizeof(sockaddr_in))
   {
      //Point to the IPv4 address information
      sockaddr_in *sa = (sockaddr_in *) addr;

      //Get port number
      port = ntohs(sa->sin_port);
      //Copy IPv4 address
      ipAddr.length = sizeof(Ipv4Addr);
      ipAddr.ipv4Addr = sa->sin_addr.s_addr;
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 address?
   if(addr->sa_family == AF_INET6 && addrlen == sizeof(sockaddr_in6))
   {
      //Point to the IPv6 address information
      sockaddr_in6 *sa = (sockaddr_in6 *) addr;

      //Get port number
      port = ntohs(sa->sin6_port);
      //Copy IPv6 address
      ipAddr.length = sizeof(Ipv6Addr);
      ipv6CopyAddr(&ipAddr.ipv6Addr, sa->sin6_addr.s6_addr);
   }
   else
#endif
   //Invalid address?
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

   //Send data
   error = socketSendTo(socket, &ipAddr, port, data, length, &written, flags << 8);

   //Any error to report?
   if(error)
   {
      socketError(socket, error);
      return SOCKET_ERROR;
   }

   //Return the number of bytes sent
   return written;
}
Example #5
0
error_t snmpParseMessage(SnmpAgentContext *context, const uint8_t *p, size_t length)
{
   error_t error;
   int32_t version;
   Asn1Tag tag;

   //Debug message
   TRACE_INFO("SNMP message received from %s port %" PRIu16 " (%" PRIuSIZE " bytes)...\r\n",
      ipAddrToString(&context->remoteIpAddr, NULL), context->remotePort, length);

   //Display the contents of the SNMP message
   TRACE_DEBUG_ARRAY("  ", p, length);

   //Dump ASN.1 structure
   error = asn1DumpObject(p, length, 0);
   //Any error to report?
   if(error) return error;

   //The SNMP message is encapsulated within a sequence
   error = asn1ReadTag(p, length, &tag);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //Enforce encoding, class and type
   error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
   //The tag does not match the criteria?
   if(error) return error;

   //Point to the first field of the sequence
   p = tag.value;
   length = tag.length;

   //Read version identifier
   error = asn1ReadInt32(p, length, &tag, &version);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //The SNMP agent verifies the version number. If there is a mismatch,
   //it discards the datagram and performs no further actions
   if(version != context->version)
      return ERROR_INVALID_VERSION;

   //Point to the next field
   p += tag.totalLength;
   length -= tag.totalLength;

   //Read SNMP community name
   error = asn1ReadTag(p, length, &tag);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //Enforce encoding, class and type
   error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING);
   //The tag does not match the criteria?
   if(error) return error;

   //Save community name
   context->request.community = tag.value;
   context->request.communityLen = tag.length;

   //Point to the next field
   p += tag.totalLength;
   length -= tag.totalLength;

   //Read PDU
   error = asn1ReadTag(p, length, &tag);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //Check encoding
   if(tag.constructed != TRUE)
      return ERROR_WRONG_ENCODING;
   //Enforce class
   if(tag.class != ASN1_CLASS_CONTEXT_SPECIFIC)
      return ERROR_INVALID_CLASS;

   //Save PDU type
   context->request.pduType = (SnmpPduType) tag.type;

   //Process the protocol data unit
   switch(context->request.pduType)
   {
   case SNMP_PDU_GET_REQUEST:
   case SNMP_PDU_GET_NEXT_REQUEST:
      //Parse GetRequest-PDU or GetNextRequest-PDU
      error = snmpParseGetRequestPdu(context, tag.value, tag.length);
      break;
   case SNMP_PDU_GET_BULK_REQUEST:
      //Parse GetBulkRequest-PDU
      error = snmpParseGetBulkRequestPdu(context, tag.value, tag.length);
      break;
   case SNMP_PDU_SET_REQUEST:
      //Parse SetRequest-PDU
      error = snmpParseSetRequestPdu(context, tag.value, tag.length);
      break;
   default:
      //Invalid PDU type
      error = ERROR_INVALID_TYPE;
      break;
   }

   //Failed to parse PDU?
   if(error)
      return error;

   //Format response PDU header
   error = snmpWritePduHeader(context);
   //Any error to report?
   if(error) return error;

   //Debug message
   TRACE_INFO("SNMP message sent (%" PRIuSIZE " bytes)...\r\n", context->response.messageLen);
   //Display the contents of the SNMP message
   TRACE_DEBUG_ARRAY("  ", context->response.message, context->response.messageLen);

   //Display ASN.1 structure
   error = asn1DumpObject(context->response.message, context->response.messageLen, 0);
   //Any error to report?
   if(error) return error;

   //Send SNMP response message
   error = socketSendTo(context->socket, &context->remoteIpAddr, context->remotePort,
      context->response.message, context->response.messageLen, NULL, 0);

   //Return status code
   return error;
}
Example #6
0
error_t dhcpv6ForwardRelayReplyMessage(Dhcpv6RelayCtx *context)
{
   error_t error;
   uint_t i;
   uint32_t interfaceId;
   size_t inputMessageLen;
   size_t outputMessageLen;
   Dhcpv6RelayMessage *inputMessage;
   Dhcpv6Message *outputMessage;
   Dhcpv6Option *option;
   IpAddr ipAddr;
   uint16_t port;

   //Point to the buffer where to store the incoming DHCPv6 message
   inputMessage = (Dhcpv6RelayMessage *) context->buffer;

   //Read incoming message
   error = socketReceiveFrom(context->serverSocket, &ipAddr, &port,
      inputMessage, DHCPV6_MAX_MSG_SIZE, &inputMessageLen, 0);
   //Any error to report?
   if(error) return error;

   //Debug message
   TRACE_INFO("\r\nDHCPv6 message received on network-facing interface %s (%" PRIuSIZE " bytes)...\r\n",
      context->serverInterface->name, inputMessageLen);
   //Dump the contents of the message for debugging purpose
   dhcpv6DumpMessage(inputMessage, inputMessageLen);

   //Check the length of the DHCPv6 message
   if(inputMessageLen < sizeof(Dhcpv6RelayMessage))
      return ERROR_INVALID_MESSAGE;

   //Inspect the message type and only forward Relay-Reply messages.
   //Other DHCPv6 message types must be silently discarded
   if(inputMessage->msgType != DHCPV6_MSG_TYPE_RELAY_REPL)
      return ERROR_INVALID_MESSAGE;

   //Get the length of the Options field
   inputMessageLen -= sizeof(Dhcpv6Message);

   //Check whether an Interface ID option is included in the Relay-Reply
   option = dhcpv6GetOption(inputMessage->options, inputMessageLen, DHCPV6_OPTION_INTERFACE_ID);
   //Failed to retrieve specified option?
   if(!option || ntohs(option->length) != sizeof(interfaceId))
      return ERROR_INVALID_MESSAGE;

   //Read the Interface ID option contents
   memcpy(&interfaceId, option->value, sizeof(interfaceId));
   //Convert the 32-bit integer from network byte order
   interfaceId = ntohl(interfaceId);

   //The Relay-Reply message must include a Relay Message option
   option = dhcpv6GetOption(inputMessage->options, inputMessageLen, DHCPV6_OPTION_RELAY_MSG);
   //Failed to retrieve specified option?
   if(!option || ntohs(option->length) < sizeof(Dhcpv6Message))
      return ERROR_INVALID_MESSAGE;

   //Extract the message from the Relay Message option
   outputMessage = (Dhcpv6Message *) option->value;
   //Save the length of the message
   outputMessageLen = ntohs(option->length);

   //Loop through client-facing interfaces
   for(i = 0; i < context->clientInterfaceCount; i++)
   {
      //Check whether the current interface matches the Interface ID option
      if(context->clientInterface[i]->id == interfaceId)
      {
         //Debug message
         TRACE_INFO("Forwarding DHCPv6 message on client-facing interface %s (%" PRIuSIZE " bytes)...\r\n",
            context->clientInterface[i]->name, outputMessageLen);
         //Dump the contents of the message for debugging purpose
         dhcpv6DumpMessage(outputMessage, outputMessageLen);

         //Copy the peer-address into the destination IP address
         ipAddr.length = sizeof(Ipv6Addr);
         ipAddr.ipv6Addr = inputMessage->peerAddress;

         //Select the relevant port number to use
          if(outputMessage->msgType == DHCPV6_MSG_TYPE_RELAY_REPL)
            port = DHCPV6_SERVER_PORT;
         else
            port = DHCPV6_CLIENT_PORT;

         //Relay the DHCPv6 message to the client on the link
         //identified by the Interface ID option
         return socketSendTo(context->clientSocket[i], &ipAddr,
            port, outputMessage, outputMessageLen, NULL, 0);
      }
   }

   //Unknown interface identifier...
   return ERROR_INVALID_OPTION;
}
Example #7
0
error_t dhcpv6ForwardClientMessage(Dhcpv6RelayCtx *context, uint_t index)
{
   error_t error;
   uint32_t interfaceId;
   size_t inputMessageLen;
   size_t outputMessageLen;
   Dhcpv6RelayMessage *inputMessage;
   Dhcpv6RelayMessage *outputMessage;
   Dhcpv6Option *option;
   IpAddr ipAddr;

   //Point to the buffer where to store the incoming DHCPv6 message
   inputMessage = (Dhcpv6RelayMessage *) (context->buffer + DHCPV6_RELAY_FORW_OVERHEAD);
   //Message that will be forwarded by the DHCPv6 relay agent
   outputMessage = (Dhcpv6RelayMessage *) context->buffer;

   //Read incoming message
   error = socketReceiveFrom(context->clientSocket[index], &ipAddr, NULL, inputMessage,
      DHCPV6_MAX_MSG_SIZE - DHCPV6_RELAY_FORW_OVERHEAD, &inputMessageLen, 0);
   //Any error to report?
   if(error) return error;

   //Debug message
   TRACE_INFO("\r\nDHCPv6 message received on client-facing interface %s (%" PRIuSIZE " bytes)...\r\n",
      context->clientInterface[index]->name, inputMessageLen);
   //Dump the contents of the message for debugging purpose
   dhcpv6DumpMessage(inputMessage, inputMessageLen);

   //The source address must be a valid IPv6 address
   if(ipAddr.length != sizeof(Ipv6Addr))
      return ERROR_INVALID_ADDRESS;
   //Check the length of the DHCPv6 message
   if(inputMessageLen < sizeof(Dhcpv6Message))
      return ERROR_INVALID_MESSAGE;

   //When the relay agent receives a valid message to be relayed,
   //it constructs a new Relay-Forward message
   outputMessage->msgType = DHCPV6_MSG_TYPE_RELAY_FORW;

   //Inspect the message type
   switch(inputMessage->msgType)
   {
   //Message received from a client?
   case DHCPV6_MSG_TYPE_SOLICIT:
   case DHCPV6_MSG_TYPE_REQUEST:
   case DHCPV6_MSG_TYPE_CONFIRM:
   case DHCPV6_MSG_TYPE_RENEW:
   case DHCPV6_MSG_TYPE_REBIND:
   case DHCPV6_MSG_TYPE_RELEASE:
   case DHCPV6_MSG_TYPE_DECLINE:
   case DHCPV6_MSG_TYPE_INFO_REQUEST:
      //If the relay agent received the message to be relayed from a client
      //the hop-count in the Relay-Forward message is set to 0
      outputMessage->hopCount = 0;
      //Continue processing
      break;

   //Message received from another relay agent?
   case DHCPV6_MSG_TYPE_RELAY_FORW:
      //If the message received by the relay agent is a Relay-Forward message
      //and the hop-count in the message is greater than or equal to 32, the
      //relay agent discards the received message
      if(inputMessage->hopCount >= DHCPV6_HOP_COUNT_LIMIT)
         return ERROR_INVALID_MESSAGE;
      //Set the hop-count field to the value of the hop-count field in
      //the received message incremented by 1
      outputMessage->hopCount = inputMessage->hopCount + 1;
      //Continue processing
      break;

   //Message received from a server?
   default:
      //Discard ADVERTISE, REPLY, RECONFIGURE and RELAY-REPL messages
      return ERROR_INVALID_MESSAGE;
   }

   //Set the link-address field to the unspecified address
   outputMessage->linkAddress = IPV6_UNSPECIFIED_ADDR;
   //Copy the source address from the header of the IP datagram in
   //which the message was received to the peer-address field
   outputMessage->peerAddress = ipAddr.ipv6Addr;
   //Size of the Relay-Forward message
   outputMessageLen = sizeof(Dhcpv6RelayMessage);

   //Get the interface identifier
   interfaceId = context->clientInterface[index]->id;
   //Convert the 32-bit integer to network byte order
   interfaceId = htonl(interfaceId);
   //If the relay agent cannot use the address in the link-address field
   //to identify the interface through which the response to the client
   //will be relayed, the relay agent must include an Interface ID option
   dhcpv6AddOption(outputMessage, &outputMessageLen,
      DHCPV6_OPTION_INTERFACE_ID, &interfaceId, sizeof(interfaceId));

   //Copy the received DHCPv6 message into a Relay Message option
   option = dhcpv6AddOption(outputMessage, &outputMessageLen,
      DHCPV6_OPTION_RELAY_MSG, NULL, 0);
   //Set the appropriate length of the option
   option->length = htons(inputMessageLen);
   //Adjust the length of the Relay-Forward message
   outputMessageLen += inputMessageLen;

   //Debug message
   TRACE_INFO("Forwarding DHCPv6 message on network-facing interface %s (%" PRIuSIZE " bytes)...\r\n",
      context->serverInterface->name, outputMessageLen);
   //Dump the contents of the message for debugging purpose
   dhcpv6DumpMessage(outputMessage, outputMessageLen);

   //Destination address to be used when relaying the client message
   ipAddr.length = sizeof(Ipv6Addr);
   ipAddr.ipv6Addr = context->serverAddress;

   //Relay the client message to the server
   return socketSendTo(context->serverSocket, &ipAddr,
      DHCPV6_SERVER_PORT, outputMessage, outputMessageLen, NULL, 0);
}