444 lines
12 KiB
C
444 lines
12 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_inet_ntop.c,v $ $Revision: 1.9.70.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_inet_ntop.c,v $
|
|
* $Author: jren $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipcom_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include "ipcom_clib.h"
|
|
#include "ipcom_sock.h"
|
|
#include "ipcom_sock6.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Number of 16-bit parts in an IPv6 address
|
|
*/
|
|
#define IN6_16BIT_PART_CNT (sizeof (struct Ip_in6_addr) / sizeof (Ip_u16))
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ntopAfInetFmt - convert IPv4 address to string
|
|
*
|
|
* This routine convert a binary representation of an IPv4 address to a string
|
|
*
|
|
* RETURNS: pointer to the string, or IP_NULL if the buffer is too small
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
IP_STATIC const char * ntopAfInetFmt
|
|
(
|
|
const void * addrPtr, /**< binary representation of Internet address */
|
|
char * str, /**< storage for the string representation */
|
|
Ip_size_t strLen, /**< the length of 'str' buffer */
|
|
const char * fmt /**< address format */
|
|
)
|
|
{
|
|
const unsigned char * inAddr = (const unsigned char *)addrPtr;
|
|
|
|
if (strLen <= (Ip_size_t)ipcom_snprintf (str, strLen, fmt,
|
|
inAddr[0], inAddr[1], inAddr[2], inAddr[3]))
|
|
{
|
|
/*
|
|
* The string buffer is not large enough
|
|
*/
|
|
str = IP_NULL;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* appendFmt - append a string generated from a format specifier
|
|
*
|
|
* This routine try to append a string using a format specifier as template
|
|
*
|
|
* RETURNS: a pointer to the first available character in the string, or IP_NULL
|
|
* if the current string could not fit into the string buffer
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
IP_STATIC char * appendFmt
|
|
(
|
|
char * str,
|
|
Ip_size_t * strLen,
|
|
const char * fmt,
|
|
unsigned val
|
|
)
|
|
{
|
|
if (str != IP_NULL)
|
|
{
|
|
Ip_size_t charsRequired = (Ip_size_t)ipcom_snprintf (str, *strLen, fmt, val);
|
|
|
|
if (*strLen > charsRequired)
|
|
{
|
|
*strLen -= charsRequired;
|
|
str += charsRequired;
|
|
}
|
|
else
|
|
{
|
|
str = IP_NULL;
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* inet6ZeroRangeGet - get the longest range of zeros in an IPv6 address
|
|
*
|
|
* This routine get the index and length of the longest range of 16-bit zero
|
|
* fields in an IPv6 address, only ranges of length two or longer may be
|
|
* returned according to RFC5952.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
IP_STATIC void inet6ZeroRangeGet
|
|
(
|
|
const Ip_u16 * in6,
|
|
unsigned * zeroIdxPtr,
|
|
unsigned * zeroLenPtr
|
|
)
|
|
{
|
|
unsigned idx;
|
|
unsigned zIdx = IN6_16BIT_PART_CNT;
|
|
unsigned zLen = 0;
|
|
Ip_bool inZero = IP_FALSE;
|
|
|
|
*zeroIdxPtr = zIdx;
|
|
*zeroLenPtr = zLen;
|
|
|
|
for (idx = 0; idx < IN6_16BIT_PART_CNT; idx++)
|
|
{
|
|
if (inZero)
|
|
{
|
|
if (in6[idx] == 0)
|
|
{
|
|
zLen++;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* According to chapter 4.2.3 in RFC5952, the first zero-range
|
|
* must be selected if there are two ranges of the same
|
|
* size. A zero-range field must only be replaced with a
|
|
* double-colon if there is at least two consecutive zero
|
|
* fields.
|
|
*/
|
|
if (zLen > 1 && zLen > *zeroLenPtr)
|
|
{
|
|
*zeroIdxPtr = zIdx;
|
|
*zeroLenPtr = zLen;
|
|
}
|
|
|
|
inZero = IP_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (in6[idx] == 0)
|
|
{
|
|
inZero = IP_TRUE;
|
|
zIdx = idx;
|
|
zLen = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (zLen > 1 && zLen > *zeroLenPtr)
|
|
{
|
|
/*
|
|
* This case may happen when the zero-range is at the end of the
|
|
* IPv6-address.
|
|
*/
|
|
*zeroIdxPtr = zIdx;
|
|
*zeroLenPtr = zLen;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* hexFmt - return the format string for a hex16 value
|
|
*
|
|
* This routine return the format string to use for a hex16 value at a specific
|
|
* index into an IPv6 address.
|
|
*
|
|
* RETURNS: a string format specifier
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
IP_STATIC const char * hexFmt
|
|
(
|
|
unsigned idx,
|
|
unsigned cnt
|
|
)
|
|
{
|
|
const char * fmt = "%x:";
|
|
|
|
if (1 + idx == cnt)
|
|
{
|
|
fmt = "%x";
|
|
}
|
|
|
|
return fmt;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ntopAfInet6Pure - create a string representation of an IPv6 address
|
|
*
|
|
* This routine try to create a string representation of the binary format of
|
|
* an IPv6 address.
|
|
*
|
|
* RETURNS: a string representation of the IPv6 address, or IP_NULL if the string
|
|
* buffer is not large enough
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
IP_STATIC const char * ntopAfInet6Pure
|
|
(
|
|
const void * addrPtr, /**< binary representation of Internet address */
|
|
char * str, /**< storage for the string representation */
|
|
Ip_size_t strLen /**< the length of 'str' buffer */
|
|
)
|
|
{
|
|
const Ip_u16 * addr16Be = (const Ip_u16 *)addrPtr;
|
|
unsigned zeroIdx;
|
|
unsigned zeroLen;
|
|
unsigned idx;
|
|
const char * repr = str;
|
|
|
|
inet6ZeroRangeGet (addr16Be, &zeroIdx, &zeroLen);
|
|
|
|
for (idx = 0; idx < zeroIdx; idx++)
|
|
{
|
|
str = appendFmt (str,
|
|
&strLen,
|
|
hexFmt (idx, zeroIdx),
|
|
ip_ntohs (addr16Be[idx]));
|
|
}
|
|
|
|
if (zeroIdx < IN6_16BIT_PART_CNT)
|
|
{
|
|
str = appendFmt (str, &strLen, "::", 0);
|
|
}
|
|
|
|
for (idx = zeroIdx + zeroLen; idx < IN6_16BIT_PART_CNT; idx++)
|
|
{
|
|
str = appendFmt (str,
|
|
&strLen,
|
|
hexFmt (idx, IN6_16BIT_PART_CNT),
|
|
ip_htons (addr16Be[idx]));
|
|
}
|
|
|
|
if (str == IP_NULL)
|
|
{
|
|
repr = IP_NULL;
|
|
}
|
|
|
|
return repr;
|
|
}
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ntopAfInet - convert IPv6 address to string
|
|
*
|
|
* This routine convert a binary representation of an IPv6 address to a string
|
|
*
|
|
* RETURNS: pointer to the string, or IP_NULL if the buffer is too small
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
IP_STATIC const char * ntopAfInet6
|
|
(
|
|
const void * addrPtr, /**< binary representation of Internet address */
|
|
char * str, /**< storage for the string representation */
|
|
Ip_size_t strLen /**< the length of 'str' buffer */
|
|
)
|
|
{
|
|
struct Ip_in6_addr in6;
|
|
const Ip_u16 * addr16Be = (const Ip_u16 *)&in6;
|
|
const char * repr = IP_NULL;
|
|
|
|
(void)ipcom_memcpy (&in6, addrPtr, sizeof in6);
|
|
if (IP_IN6_IS_ADDR_V4COMPAT (&in6))
|
|
{
|
|
/*
|
|
* IPv4-compatible-IPv6 addresses has the format '::x.y.z.w' where the
|
|
* dotted quad is the last 4 octets of the IPv6 address.
|
|
*/
|
|
repr = ntopAfInetFmt (addr16Be + 6, str, strLen, "::%u.%u.%u.%u");
|
|
}
|
|
else if (IP_IN6_IS_ADDR_V4MAPPED (&in6))
|
|
{
|
|
/*
|
|
* IPv4-mapped-IPv6 addresses has the format '::ffff:x.y.z.w' where
|
|
* the dotted quad is the last 4 octets of the IPv6 address.
|
|
*
|
|
* RFC5952 chapter 4.3 state that lowercase letters must be used when
|
|
* representing hexadecimal numbers.
|
|
*/
|
|
repr = ntopAfInetFmt (addr16Be + 6, str, strLen, "::ffff:%u.%u.%u.%u");
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* IPv6 address without embedded IPv4
|
|
*/
|
|
repr = ntopAfInet6Pure (&in6, str, strLen);
|
|
}
|
|
|
|
return repr;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_inet_ntop
|
|
*===========================================================================
|
|
* Description: Converts the network address into a character string.
|
|
* Parameters: family - The address family for the address to convert.
|
|
* strptr - A pointer to the buffer that will receive the
|
|
* string representation of the address.
|
|
* len - The length of the strptr buffer.
|
|
* Returns: The strptr value if the call was successful or IP_NULL
|
|
* if failed (get error code from ipcom_errno).
|
|
*
|
|
*/
|
|
IP_PUBLIC IP_CONST char *
|
|
ipcom_inet_ntop(int family, IP_CONST void *addrptr, char *strptr, Ip_size_t len)
|
|
{
|
|
const char * repr = IP_NULL;
|
|
Ip_bool afNoSupp = IP_FALSE;
|
|
|
|
if (addrptr == IP_NULL || strptr == IP_NULL)
|
|
return IP_NULL;
|
|
|
|
switch (family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
repr = ntopAfInetFmt (addrptr, strptr, len, "%u.%u.%u.%u");
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
repr = ntopAfInet6 (addrptr, strptr, len);
|
|
break;
|
|
#endif
|
|
default:
|
|
afNoSupp = IP_TRUE;
|
|
break;
|
|
}
|
|
|
|
if (repr == IP_NULL)
|
|
{
|
|
if (afNoSupp)
|
|
{
|
|
(void)ipcom_errno_set (IP_ERRNO_EAFNOSUPPORT);
|
|
}
|
|
else
|
|
{
|
|
(void)ipcom_errno_set (IP_ERRNO_ENOSPC);
|
|
}
|
|
}
|
|
|
|
return repr;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|