mirror of
https://github.com/FreeRTOS/FreeRTOS-Plus-TCP
synced 2025-10-24 03:32:36 +08:00

* updating doxygen config * fixing doxygen comments * adding IPv6 files and fixing comments * fix doxygen cfg and file names in comments * wip doxygen v6 docs * adding doxygen comments * include RA src file to doxgendocs generation * fix spell check issues * Uncrustify: triggered by comment. * fix minor build issue * fix spell check issues * Uncrustify: triggered by comment * fix trailing white space * Dev integration hein.v8 (#738) * Updating tcp utilities * Some more change in dev_integration_hein.v8 * In FreeRTOS_DNS_Parser.c : use 'ipUDP_PAYLOAD_OFFSET_IPv4' in stead of 'ipIP_PAYLOAD_OFFSET' * And a few more corrections * Changes to WinPCap network interface, removed debugging code * After applying uncrustify * Oops, I forgot the push changes in include files. * Now removing it, hopefully --------- Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com> Co-authored-by: Monika Singh <108652024+moninom1@users.noreply.github.com> * Fix CBMC proofs for DNS (#718) * Use CBMC XML output to enable VSCode debugger (#673) Prior to this commit, CBMC would emit logging information in plain text format, which does not contain information required for the CBMC VSCode debugger. This commit makes CBMC use XML instead of plain text. Co-authored-by: Mark Tuttle <tuttle@acm.org> * wip * wip DNSgetHostByName * wip DNSgetHostByName * fixed cbmc proof for DNS_ReadNameField * wip DNSgetHostByName_a_harness * Fix CBMC prooff for DNSgetHostByName * wip fix DNSgetHostByName_a CBMC proof * fixed cbmc target func not called issue in DNSclear * fixed cbmc target func not called issue in DNSlookup * fix DNSgetHostByName_a CBMC proof * update comments * more asserts * fixing formatting * updating as per review comments * fix dns after review comments * adding more asserts * adds more asserts * minor fix * fixing comments * fixing comments * fixing minor issue * fixing DNS_ReadReply() signature * making code more consistant * adding more asserts * making code more consistent --------- Co-authored-by: Kareem Khazem <karkhaz@amazon.com> Co-authored-by: Mark Tuttle <tuttle@acm.org> * Uncrustify: triggered by comment * fixing formatting --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Hein Tibosch <hein_tibosch@yahoo.es> Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com> Co-authored-by: Monika Singh <108652024+moninom1@users.noreply.github.com> Co-authored-by: Kareem Khazem <karkhaz@amazon.com> Co-authored-by: Mark Tuttle <tuttle@acm.org>
663 lines
22 KiB
C
663 lines
22 KiB
C
/*
|
|
* FreeRTOS+TCP <DEVELOPMENT BRANCH>
|
|
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* http://aws.amazon.com/freertos
|
|
* http://www.FreeRTOS.org
|
|
*/
|
|
|
|
/**
|
|
* @file FreeRTOS_IPv6_Sockets.c
|
|
* @brief Implements the Sockets API based on Berkeley sockets for the FreeRTOS+TCP network stack.
|
|
* Sockets are used by the application processes to interact with the IP-task which in turn
|
|
* interacts with the hardware.
|
|
*/
|
|
|
|
/* Standard includes. */
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
|
|
/* FreeRTOS+TCP includes. */
|
|
#include "FreeRTOS_IP.h"
|
|
#include "FreeRTOS_IPv6_Sockets.h"
|
|
|
|
/* *INDENT-OFF* */
|
|
#if( ipconfigUSE_IPv6 != 0 )
|
|
/* *INDENT-ON* */
|
|
|
|
#if ( ipconfigUSE_TCP == 1 )
|
|
|
|
/**
|
|
* @brief Called by pxTCPSocketLookup(), this function will check if a socket
|
|
* is connected to a remote IP-address. It will be called from a loop
|
|
* iterating through all sockets.
|
|
* @param[in] pxSocket: The socket to be inspected.
|
|
* @param[in] pxAddress_IPv6: The IPv6 address, or NULL if the peer has a IPv4 address.
|
|
* @param[in] ulRemoteIP: The IPv4 address
|
|
* @return The socket in case it is connected to the remote IP-address
|
|
*/
|
|
FreeRTOS_Socket_t * pxTCPSocketLookup_IPv6( FreeRTOS_Socket_t * pxSocket,
|
|
const IPv6_Address_t * pxAddress_IPv6,
|
|
uint32_t ulRemoteIP )
|
|
{
|
|
FreeRTOS_Socket_t * pxResult = NULL;
|
|
|
|
if( pxSocket->bits.bIsIPv6 != pdFALSE_UNSIGNED )
|
|
{
|
|
if( pxAddress_IPv6 != NULL )
|
|
{
|
|
if( memcmp( pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, pxAddress_IPv6->ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 )
|
|
{
|
|
/* For sockets not in listening mode, find a match with
|
|
* uxLocalPort, ulRemoteIP AND uxRemotePort. */
|
|
pxResult = pxSocket;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pxAddress_IPv6 == NULL )
|
|
{
|
|
if( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 == ulRemoteIP )
|
|
{
|
|
/* For sockets not in listening mode, find a match with
|
|
* uxLocalPort, ulRemoteIP AND uxRemotePort. */
|
|
pxResult = pxSocket;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pxResult;
|
|
}
|
|
|
|
#endif /* if ( ( ipconfigUSE_TCP == 1 ) */
|
|
|
|
/**
|
|
* @brief Called by prvSendUDPPacket(), this function will UDP packet
|
|
* fields and IPv6 address for the packet to be send.
|
|
* @param[in] pxNetworkBuffer : The packet to be sent.
|
|
* @param[in] pxDestinationAddress: The IPv4 socket address.
|
|
* @return Returns NULL, always.
|
|
*/
|
|
void * xSend_UDP_Update_IPv6( NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
const struct freertos_sockaddr * pxDestinationAddress )
|
|
{
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
UDPPacket_IPv6_t * pxUDPPacket_IPv6 = ( ( UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
|
|
|
|
pxNetworkBuffer->xIPAddress.ulIP_IPv4 = 0U;
|
|
|
|
configASSERT( pxDestinationAddress != NULL );
|
|
( void ) memcpy( pxUDPPacket_IPv6->xIPHeader.xDestinationAddress.ucBytes, pxDestinationAddress->sin_address.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
|
|
( void ) memcpy( pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, pxDestinationAddress->sin_address.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
|
|
pxUDPPacket_IPv6->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief Called by FreeRTOS_recvfrom(), this function will update socket
|
|
* address with IPv6 address from the packet received.
|
|
* @param[in] pxNetworkBuffer : The packet received.
|
|
* @param[in] pxSourceAddress: The IPv4 socket address.
|
|
* @return The Payload Offset.
|
|
*/
|
|
size_t xRecv_Update_IPv6( const NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
struct freertos_sockaddr * pxSourceAddress )
|
|
{
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
const UDPPacket_IPv6_t * pxUDPPacketV6 = ( ( const UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
|
|
size_t uxPayloadOffset = 0;
|
|
|
|
if( pxUDPPacketV6->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
|
|
{
|
|
if( pxSourceAddress != NULL )
|
|
{
|
|
( void ) memcpy( ( void * ) pxSourceAddress->sin_address.xIP_IPv6.ucBytes,
|
|
( const void * ) pxUDPPacketV6->xIPHeader.xSourceAddress.ucBytes,
|
|
ipSIZE_OF_IPv6_ADDRESS );
|
|
pxSourceAddress->sin_family = ( uint8_t ) FREERTOS_AF_INET6;
|
|
pxSourceAddress->sin_address.ulIP_IPv4 = 0U;
|
|
pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
|
|
}
|
|
|
|
uxPayloadOffset = ipUDP_PAYLOAD_OFFSET_IPv6;
|
|
}
|
|
|
|
return uxPayloadOffset;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Converts a hex value to a readable hex character, e.g. 14 becomes 'e'.
|
|
* @param usValue : The value to be converted, must be between 0 and 15.
|
|
* @return The character, between '0' and '9', or between 'a' and 'f'.
|
|
*/
|
|
char cHexToChar( uint16_t usValue )
|
|
{
|
|
char cReturn = '0';
|
|
|
|
if( usValue <= 9U )
|
|
{
|
|
cReturn += usValue;
|
|
}
|
|
else if( usValue <= 15U )
|
|
{
|
|
cReturn = 'a';
|
|
cReturn += ( usValue - 10U );
|
|
}
|
|
else
|
|
{
|
|
/* The value passed to 'usValue' has been and-ed with 0x0f,
|
|
* so this else clause should never be reached. */
|
|
configASSERT( 0 == 1 );
|
|
}
|
|
|
|
return cReturn;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Convert a short numeric value to a hex string of at most 4 characters.
|
|
* The resulting string is **not** null-terminated. The resulting string
|
|
* will not have leading zero's, except when 'usValue' equals zero.
|
|
* @param[in] pcBuffer : The buffer to which the string is written.
|
|
* @param[in] uxBufferSize : The size of the buffer pointed to by 'pcBuffer'.
|
|
* @param[in] usValue : The 16-bit value to be converted.
|
|
* @return The number of bytes written to 'pcBuffer'.
|
|
*/
|
|
socklen_t uxHexPrintShort( char * pcBuffer,
|
|
size_t uxBufferSize,
|
|
uint16_t usValue )
|
|
{
|
|
const size_t uxNibbleCount = 4U;
|
|
size_t uxNibble;
|
|
size_t uxIndex = 0U;
|
|
uint16_t usShifter = usValue;
|
|
BaseType_t xHadNonZero = pdFALSE;
|
|
|
|
for( uxNibble = 0; uxNibble < uxNibbleCount; uxNibble++ )
|
|
{
|
|
uint16_t usNibble = ( usShifter >> 12 ) & 0x0FU;
|
|
|
|
if( usNibble != 0U )
|
|
{
|
|
xHadNonZero = pdTRUE;
|
|
}
|
|
|
|
if( ( xHadNonZero != pdFALSE ) || ( uxNibble == ( uxNibbleCount - 1U ) ) )
|
|
{
|
|
if( uxIndex >= ( uxBufferSize - 1U ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pcBuffer[ uxIndex ] = cHexToChar( usNibble );
|
|
uxIndex++;
|
|
}
|
|
|
|
usShifter <<= 4;
|
|
}
|
|
|
|
return uxIndex;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Scan the binary IPv6 address and find the longest train of consecutive zero's.
|
|
* The result of this search will be stored in 'xZeroStart' and 'xZeroLength'.
|
|
* @param pxSet: the set of parameters as used by FreeRTOS_inet_ntop6().
|
|
*/
|
|
void prv_ntop6_search_zeros( struct sNTOP6_Set * pxSet )
|
|
{
|
|
BaseType_t xIndex = 0; /* The index in the IPv6 address: 0..7. */
|
|
BaseType_t xCurStart = 0; /* The position of the first zero found so far. */
|
|
BaseType_t xCurLength = 0; /* The number of zero's seen so far. */
|
|
const BaseType_t xShortCount = 8; /* An IPv6 address consists of 8 shorts. */
|
|
|
|
/* Default: when xZeroStart is negative, it won't match with any xIndex. */
|
|
pxSet->xZeroStart = -1;
|
|
|
|
/* Look for the longest train of zero's 0:0:0:... */
|
|
for( ; xIndex < xShortCount; xIndex++ )
|
|
{
|
|
uint16_t usValue = pxSet->pusAddress[ xIndex ];
|
|
|
|
if( usValue == 0U )
|
|
{
|
|
if( xCurLength == 0 )
|
|
{
|
|
/* Remember the position of the first zero. */
|
|
xCurStart = xIndex;
|
|
}
|
|
|
|
/* Count consecutive zeros. */
|
|
xCurLength++;
|
|
}
|
|
|
|
if( ( usValue != 0U ) || ( xIndex == ( xShortCount - 1 ) ) )
|
|
{
|
|
/* Has a longer train of zero's been found? */
|
|
if( ( xCurLength > 1 ) && ( pxSet->xZeroLength < xCurLength ) )
|
|
{
|
|
/* Remember the number of consecutive zeros. */
|
|
pxSet->xZeroLength = xCurLength;
|
|
/* Remember the index of the first zero found. */
|
|
pxSet->xZeroStart = xCurStart;
|
|
}
|
|
|
|
/* Reset the counter of consecutive zeros. */
|
|
xCurLength = 0;
|
|
}
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief The location is now at the longest train of zero's. Two colons have to
|
|
* be printed without a numeric value, e.g. "ff02::1".
|
|
* @param pcDestination: the output buffer where the colons will be printed.
|
|
* @param uxSize: the remaining length of the output buffer.
|
|
* @param pxSet: the set of parameters as used by FreeRTOS_inet_ntop6().
|
|
* @return pdPASS in case the output buffer is big enough to contain the colons.
|
|
* @note uxSize must be at least 2, enough to print "::". The string will get
|
|
* null-terminated later on.
|
|
*/
|
|
static BaseType_t prv_ntop6_write_zeros( char * pcDestination,
|
|
size_t uxSize,
|
|
struct sNTOP6_Set * pxSet )
|
|
{
|
|
BaseType_t xReturn = pdPASS;
|
|
const BaseType_t xShortCount = 8; /* An IPv6 address consists of 8 shorts. */
|
|
|
|
if( pxSet->uxTargetIndex <= ( uxSize - 1U ) )
|
|
{
|
|
pcDestination[ pxSet->uxTargetIndex ] = ':';
|
|
pxSet->uxTargetIndex++;
|
|
|
|
if( ( pxSet->xIndex + pxSet->xZeroLength ) == xShortCount )
|
|
{
|
|
/* Reached the last index, write a second ";". */
|
|
if( pxSet->uxTargetIndex <= ( uxSize - 1U ) )
|
|
{
|
|
pcDestination[ pxSet->uxTargetIndex ] = ':';
|
|
pxSet->uxTargetIndex++;
|
|
}
|
|
else
|
|
{
|
|
/* Can not write the second colon. */
|
|
xReturn = pdFAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise the function prv_ntop6_write_short() will places the second colon. */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Can not write the first colon. */
|
|
xReturn = pdFAIL;
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Write a short value, as a hex number with at most 4 characters. E.g. the
|
|
* value 15 will be printed as "f".
|
|
* @param pcDestination: the output buffer where the hex number is to be printed.
|
|
* @param uxSize: the remaining length of the output buffer.
|
|
* @param pxSet: the set of parameters as used by FreeRTOS_inet_ntop6().
|
|
* @return pdPASS in case the output buffer is big enough to contain the string.
|
|
* @note uxSize must be at least 4, enough to print "abcd". The string will get
|
|
* null-terminated later on.
|
|
*/
|
|
static BaseType_t prv_ntop6_write_short( char * pcDestination,
|
|
size_t uxSize,
|
|
struct sNTOP6_Set * pxSet )
|
|
{
|
|
socklen_t uxLength;
|
|
BaseType_t xReturn = pdPASS;
|
|
const size_t uxBytesPerShortValue = 4U;
|
|
|
|
if( pxSet->xIndex > 0 )
|
|
{
|
|
if( pxSet->uxTargetIndex >= ( uxSize - 1U ) )
|
|
{
|
|
xReturn = pdFAIL;
|
|
}
|
|
else
|
|
{
|
|
pcDestination[ pxSet->uxTargetIndex ] = ':';
|
|
pxSet->uxTargetIndex++;
|
|
}
|
|
}
|
|
|
|
if( xReturn == pdPASS )
|
|
{
|
|
/* If there is enough space to write a short. */
|
|
if( pxSet->uxTargetIndex <= ( uxSize - uxBytesPerShortValue ) )
|
|
{
|
|
/* Write hex value of short. at most 4 + 1 bytes. */
|
|
uxLength = uxHexPrintShort( &( pcDestination[ pxSet->uxTargetIndex ] ),
|
|
uxBytesPerShortValue + 1U,
|
|
FreeRTOS_ntohs( pxSet->pusAddress[ pxSet->xIndex ] ) );
|
|
|
|
if( uxLength <= 0U )
|
|
{
|
|
xReturn = pdFAIL;
|
|
}
|
|
else
|
|
{
|
|
pxSet->uxTargetIndex += uxLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief This function converts a binary IPv6 address to a human readable notation.
|
|
*
|
|
* @param[in] pvSource: The binary address, 16 bytes long..
|
|
* @param[out] pcDestination: The human-readable ( hexadecimal ) notation of the
|
|
* address.
|
|
* @param[in] uxSize: The size of pvDestination. A value of 40 is recommended.
|
|
*
|
|
* @return pdPASS if the translation was successful or else pdFAIL.
|
|
*/
|
|
const char * FreeRTOS_inet_ntop6( const void * pvSource,
|
|
char * pcDestination,
|
|
socklen_t uxSize )
|
|
{
|
|
const char * pcReturn; /* The return value, which is either 'pcDestination' or NULL. */
|
|
struct sNTOP6_Set xSet; /* A set of values for easy exchange with the helper functions prv_ntop6_xxx(). */
|
|
|
|
( void ) memset( &( xSet ), 0, sizeof( xSet ) );
|
|
|
|
xSet.pusAddress = pvSource;
|
|
|
|
if( uxSize < 3U )
|
|
{
|
|
/* Can not even print :: */
|
|
}
|
|
else
|
|
{
|
|
prv_ntop6_search_zeros( &( xSet ) );
|
|
|
|
while( xSet.xIndex < 8 )
|
|
{
|
|
if( xSet.xIndex == xSet.xZeroStart )
|
|
{
|
|
if( prv_ntop6_write_zeros( pcDestination, uxSize, &( xSet ) ) == pdFAIL )
|
|
{
|
|
break;
|
|
}
|
|
|
|
xSet.xIndex += xSet.xZeroLength;
|
|
}
|
|
else
|
|
{
|
|
if( prv_ntop6_write_short( pcDestination, uxSize, &( xSet ) ) == pdFAIL )
|
|
{
|
|
break;
|
|
}
|
|
|
|
xSet.xIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( xSet.xIndex < 8 )
|
|
{
|
|
/* Didn't reach the last nibble: clear the string. */
|
|
pcReturn = NULL;
|
|
}
|
|
else
|
|
{
|
|
pcDestination[ xSet.uxTargetIndex ] = '\0';
|
|
pcReturn = pcDestination;
|
|
}
|
|
|
|
return pcReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Converting a readable IPv6 address to its binary form, add one nibble.
|
|
*
|
|
* @param[in] pxSet : A set of variables describing the conversion.
|
|
* @param[in] ucNew : The hex value, between 0 and 15
|
|
* @param[in] ch : The character, such as '5', 'f', or ':'.
|
|
*
|
|
* @return pdTRUE when the nibble was added, otherwise pdFALSE.
|
|
*/
|
|
static BaseType_t prv_inet_pton6_add_nibble( struct sPTON6_Set * pxSet,
|
|
uint8_t ucNew,
|
|
char ch )
|
|
{
|
|
BaseType_t xReturn = pdPASS;
|
|
|
|
if( ucNew != ( uint8_t ) socketINVALID_HEX_CHAR )
|
|
{
|
|
/* Shift in 4 bits. */
|
|
pxSet->ulValue <<= 4;
|
|
pxSet->ulValue |= ( uint32_t ) ucNew;
|
|
|
|
/* Remember that ulValue is valid now. */
|
|
pxSet->xHadDigit = pdTRUE;
|
|
|
|
/* Check if the number is not becoming larger than 16 bits. */
|
|
if( pxSet->ulValue > 0xffffU )
|
|
{
|
|
/* The highest nibble has already been set,
|
|
* an overflow would occur. Break out of the for-loop. */
|
|
xReturn = pdFAIL;
|
|
}
|
|
}
|
|
else if( ch == ':' )
|
|
{
|
|
if( pxSet->xHadDigit == pdFALSE )
|
|
{
|
|
/* A "::" sequence has been received. Check if it is not a third colon. */
|
|
if( pxSet->xColon >= 0 )
|
|
{
|
|
xReturn = pdFAIL;
|
|
}
|
|
else
|
|
{
|
|
/* Two or more zero's are expected, starting at position 'xColon'. */
|
|
pxSet->xColon = pxSet->xTargetIndex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pxSet->xTargetIndex <= pxSet->xHighestIndex )
|
|
{
|
|
/* Store a short value at position 'xTargetIndex'. */
|
|
pxSet->pucTarget[ pxSet->xTargetIndex ] = ( uint8_t ) ( ( pxSet->ulValue >> 8 ) & 0xffU );
|
|
pxSet->pucTarget[ pxSet->xTargetIndex + 1 ] = ( uint8_t ) ( pxSet->ulValue & 0xffU );
|
|
pxSet->xTargetIndex += 2;
|
|
pxSet->xHadDigit = pdFALSE;
|
|
pxSet->ulValue = 0U;
|
|
}
|
|
else
|
|
{
|
|
xReturn = pdFAIL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* When an IPv4 address or rubbish is provided, this statement will be reached. */
|
|
xReturn = pdFAIL;
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Convert an ASCII character to its corresponding hexadecimal value.
|
|
* A :: block was found, now fill in the zero's.
|
|
* @param[in] pxSet : A set of variables describing the conversion.
|
|
*/
|
|
static void prv_inet_pton6_set_zeros( struct sPTON6_Set * pxSet )
|
|
{
|
|
/* The number of bytes that were written after the :: */
|
|
const BaseType_t xCount = pxSet->xTargetIndex - pxSet->xColon;
|
|
const BaseType_t xTopIndex = ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS;
|
|
BaseType_t xIndex;
|
|
BaseType_t xTarget = xTopIndex - 1;
|
|
BaseType_t xSource = pxSet->xColon + ( xCount - 1 );
|
|
|
|
/* Inserting 'xCount' zero's. */
|
|
for( xIndex = 0; xIndex < xCount; xIndex++ )
|
|
{
|
|
pxSet->pucTarget[ xTarget ] = pxSet->pucTarget[ xSource ];
|
|
pxSet->pucTarget[ xSource ] = 0;
|
|
xTarget--;
|
|
xSource--;
|
|
}
|
|
|
|
pxSet->xTargetIndex = ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Convert an IPv6 address in hexadecimal notation to a binary format of 16 bytes.
|
|
*
|
|
* @param[in] pcSource: The address in hexadecimal notation.
|
|
* @param[out] pvDestination: The address in binary format, 16 bytes long.
|
|
*
|
|
* @return The 32-bit representation of IP(v4) address.
|
|
*/
|
|
BaseType_t FreeRTOS_inet_pton6( const char * pcSource,
|
|
void * pvDestination )
|
|
{
|
|
char ch;
|
|
uint8_t ucNew;
|
|
BaseType_t xResult;
|
|
struct sPTON6_Set xSet;
|
|
|
|
const char * pcIterator = pcSource;
|
|
|
|
( void ) memset( &( xSet ), 0, sizeof( xSet ) );
|
|
xSet.xColon = -1;
|
|
xSet.pucTarget = pvDestination;
|
|
|
|
( void ) memset( xSet.pucTarget, 0, ipSIZE_OF_IPv6_ADDRESS );
|
|
|
|
xResult = 0;
|
|
|
|
/* Leading :: requires some special handling. */
|
|
if( strcmp( pcIterator, "::" ) == 0 )
|
|
{
|
|
xResult = 1;
|
|
}
|
|
else
|
|
{
|
|
if( pcIterator[ 0 ] == ':' )
|
|
{
|
|
pcIterator++;
|
|
}
|
|
|
|
/* The last bytes will be written at position 14 and 15. */
|
|
xSet.xHighestIndex = ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS;
|
|
xSet.xHighestIndex -= ( BaseType_t ) sizeof( uint16_t );
|
|
|
|
/* The value in ulValue is not yet valid. */
|
|
xSet.xHadDigit = pdFALSE;
|
|
xSet.ulValue = 0U;
|
|
|
|
for( ; ; )
|
|
{
|
|
ch = *( pcIterator );
|
|
pcIterator++;
|
|
|
|
if( ch == ( char ) '\0' )
|
|
{
|
|
/* The string is parsed now.
|
|
* Store the last short, if present. */
|
|
if( ( xSet.xHadDigit != pdFALSE ) &&
|
|
( xSet.xTargetIndex <= xSet.xHighestIndex ) )
|
|
{
|
|
/* Add the last value seen, network byte order ( MSB first ). */
|
|
xSet.pucTarget[ xSet.xTargetIndex ] = ( uint8_t ) ( ( xSet.ulValue >> 8 ) & 0xffU );
|
|
xSet.pucTarget[ xSet.xTargetIndex + 1 ] = ( uint8_t ) ( xSet.ulValue & 0xffU );
|
|
xSet.xTargetIndex += 2;
|
|
}
|
|
|
|
/* Break out of the for-ever loop. */
|
|
break;
|
|
}
|
|
|
|
/* Convert from a readable character to a hex value. */
|
|
ucNew = ucASCIIToHex( ch );
|
|
/* See if this is a digit or a colon. */
|
|
xResult = prv_inet_pton6_add_nibble( &( xSet ), ucNew, ch );
|
|
|
|
if( xResult == pdFALSE )
|
|
{
|
|
/* The new character was not accepted. */
|
|
break;
|
|
}
|
|
} /* for( ;; ) */
|
|
|
|
if( xSet.xColon >= 0 )
|
|
{
|
|
/* The address contains a block of zero. */
|
|
prv_inet_pton6_set_zeros( &( xSet ) );
|
|
}
|
|
|
|
if( xSet.xTargetIndex == ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS )
|
|
{
|
|
xResult = 1;
|
|
}
|
|
}
|
|
|
|
if( xResult != 1 )
|
|
{
|
|
xSet.pucTarget = ( uint8_t * ) pvDestination;
|
|
( void ) memset( xSet.pucTarget, 0, ipSIZE_OF_IPv6_ADDRESS );
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
/* *INDENT-OFF* */
|
|
#endif /* ipconfigUSE_IPv6 != 0 */
|
|
/* *INDENT-ON* */
|