938 lines
29 KiB
C
938 lines
29 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_inet_pton.c,v $ $Revision: 1.27.10.5 $
|
|
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_inet_pton.c,v $
|
|
* $Author: hxie $
|
|
* $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_sock2.h"
|
|
#ifdef IPCOM_USE_INET6
|
|
#include "ipcom_sock6.h"
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_DEEP_CPY(pdst, psrc) ipcom_memcpy(pdst, psrc, sizeof(*pdst))
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
struct Ipcom_inet_pton_ctx {
|
|
char *str;
|
|
int next_part;
|
|
Ip_u32 part[4];
|
|
};
|
|
#endif
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
struct Ipcom_inet6_pton_ctx {
|
|
char *str;
|
|
int *next_part;
|
|
Ip_u16 *part;
|
|
int next_head_part;
|
|
Ip_u16 head_part[8];
|
|
int next_tail_part;
|
|
Ip_u16 tail_part[8];
|
|
#ifdef IPCOM_USE_INET
|
|
Ip_bool has_inaddr;
|
|
struct Ip_in_addr inaddr;
|
|
#endif
|
|
};
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_is_valid_addr_end
|
|
*===========================================================================
|
|
* Description: Checks if the character is a valid address delimiter.
|
|
* Parameters: tkn - first character after an IP address.
|
|
* Returns: IP_TRUE - is a valid character to end an address
|
|
* IP_FALSE - not valid
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_is_valid_addr_end(char tkn)
|
|
{
|
|
return tkn == '\0'
|
|
|| tkn == '/' /* support for "A/prefix" format */
|
|
|| tkn == '%'; /* support for "A%scope" format */
|
|
}
|
|
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_num
|
|
*===========================================================================
|
|
* Description: Parses a hex, octal or decimal number
|
|
* Parameters: ctx - parser context
|
|
* limit - maximum allowed value of the number
|
|
* base - interpret the number to the given base, 0 means base
|
|
* is determined by prefix.
|
|
* Returns: IP_FALSE - failed to parse the number or out of limit
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_num(struct Ipcom_inet_pton_ctx *ctx, Ip_u32 limit, int base)
|
|
{
|
|
char *endptr;
|
|
unsigned long val;
|
|
|
|
if ((base == 10 && !ipcom_isdigit(*ctx->str))
|
|
|| !ipcom_isxdigit(*ctx->str))
|
|
/* Must contain a valid number as the first character */
|
|
return IP_FALSE;
|
|
|
|
val = ipcom_strtoul(ctx->str, &endptr, base);
|
|
if (ctx->str == endptr)
|
|
/* String cannot be parsed as a number in the specified base */
|
|
return IP_FALSE;
|
|
|
|
if (val > (unsigned long)limit)
|
|
/* Not within limit */
|
|
return IP_FALSE;
|
|
|
|
ctx->part[ctx->next_part] = (Ip_u32)val;
|
|
|
|
ctx->str = endptr;
|
|
ctx->next_part++;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_num8_base10
|
|
*===========================================================================
|
|
* Description: Parses a 8-bit number
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse number
|
|
* IP_TRUE - success
|
|
*/
|
|
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_num8_base10(struct Ipcom_inet_pton_ctx *ctx)
|
|
{
|
|
return ipcom_parse_num(ctx, 0xff, 10);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_num8
|
|
*===========================================================================
|
|
* Description: Parses a 8-bit number
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse number
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_num8(struct Ipcom_inet_pton_ctx *ctx)
|
|
{
|
|
return ipcom_parse_num(ctx, 0xff, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_num16
|
|
*===========================================================================
|
|
* Description: Parses a 16-bit number
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse number
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_num16(struct Ipcom_inet_pton_ctx *ctx)
|
|
{
|
|
return ipcom_parse_num(ctx, 0xffff, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_num24
|
|
*===========================================================================
|
|
* Description: Parses a 24-bit number
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse number
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_num24(struct Ipcom_inet_pton_ctx *ctx)
|
|
{
|
|
return ipcom_parse_num(ctx, 0xffffff, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_num32
|
|
*===========================================================================
|
|
* Description: Parses a 32-bit number
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse number
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_num32(struct Ipcom_inet_pton_ctx *ctx)
|
|
{
|
|
return ipcom_parse_num(ctx, 0xffffffff, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_dot
|
|
*===========================================================================
|
|
* Description: Parses a single dot ('.')
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse a dot
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_dot(struct Ipcom_inet_pton_ctx *ctx)
|
|
{
|
|
if (ctx->str[0] != '.')
|
|
return IP_FALSE;
|
|
++ctx->str;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_inet_ctx_to_addr
|
|
*===========================================================================
|
|
* Description: Converts the context to a binary form of a IPv4 address
|
|
* Parameters: ctx - parser context
|
|
* addr - pointer to where the binary form should be stored
|
|
* Returns: 0 - parser error detected
|
|
* 1 - success
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_inet_ctx_to_addr(struct Ipcom_inet_pton_ctx *ctx,
|
|
struct Ip_in_addr *addr)
|
|
{
|
|
if (!ipcom_is_valid_addr_end(*ctx->str))
|
|
/* Garbage at end of address */
|
|
return 0;
|
|
|
|
switch (ctx->next_part)
|
|
{
|
|
case 1:
|
|
/* num32 */
|
|
addr->s_addr = ctx->part[0];
|
|
break;
|
|
case 2:
|
|
/* num8.num24 */
|
|
addr->s_addr = ((ctx->part[0] << 24)
|
|
+ ctx->part[1]);
|
|
break;
|
|
case 3:
|
|
/* num8.num8.num16 */
|
|
addr->s_addr = ((ctx->part[0] << 24)
|
|
+ (ctx->part[1] << 16)
|
|
+ ctx->part[2]);
|
|
break;
|
|
default:
|
|
/* num8.num8.num8.num8 */
|
|
addr->s_addr = ((ctx->part[0] << 24)
|
|
+ (ctx->part[1] << 16)
|
|
+ (ctx->part[2] << 8)
|
|
+ ctx->part[3]);
|
|
break;
|
|
}
|
|
addr->s_addr = ip_htonl(addr->s_addr);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_inet_init
|
|
*===========================================================================
|
|
* Description: Initializes the parser context.
|
|
* Parameters: ctx - context placeholder.
|
|
* strptr - string to parse
|
|
* Returns:
|
|
*/
|
|
IP_STATIC void
|
|
ipcom_parse_inet_init(struct Ipcom_inet_pton_ctx *ctx, IP_CONST char *strptr)
|
|
{
|
|
ctx->next_part = 0;
|
|
ctx->str = (char *) strptr;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_dotted_quad
|
|
*===========================================================================
|
|
* Description: Parses an IPv4 address represented as a dotted quad.
|
|
* Parameters: strptr - a string representation of a dotted quad
|
|
* addrptr - buffer to store the binary form
|
|
* Returns: 0 = not a valid IPv4 address
|
|
* 1 = parse successful
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_parse_dotted_quad(IP_CONST char *strptr, void *addrptr)
|
|
{
|
|
struct Ipcom_inet_pton_ctx ctx;
|
|
/*
|
|
* <dotted-quad> ::= <num8_base10>.<num8_base10>.<num8_base10>.<num8_base10>
|
|
*/
|
|
|
|
/* Try num8.num8.num8.num8 */
|
|
ipcom_parse_inet_init(&ctx, strptr);
|
|
if (ipcom_parse_num8_base10(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8_base10(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8_base10(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8_base10(&ctx))
|
|
return ipcom_inet_ctx_to_addr(&ctx, addrptr);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_inet_addr
|
|
*===========================================================================
|
|
* Description: Tries to parse a string as an IPv4 address
|
|
* Parameters: strptr - pointer to string
|
|
* addrptr - pointer to where the binary representation should
|
|
* be stored.
|
|
* Returns: 0 = not a valid IPv4 address
|
|
* 1 = parse successful
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_parse_inet_addr(IP_CONST char *strptr, void *addrptr)
|
|
{
|
|
struct Ipcom_inet_pton_ctx ctx;
|
|
|
|
/*
|
|
* <inet-addr> ::= <num8>.<num8>.<num8>.<num8>
|
|
* | <num8>.<num8>.<num16>
|
|
* | <num8>.<num24>
|
|
* | <num32>
|
|
*
|
|
* num8 is any number between 0-255
|
|
* num16 is any number between 0-65535
|
|
* num24 is any number between 0-16777215
|
|
* num32 is any number between 0-4294967295
|
|
*/
|
|
|
|
/* Try num8.num8.num8.num8 */
|
|
ipcom_parse_inet_init(&ctx, strptr);
|
|
if (ipcom_parse_num8(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8(&ctx))
|
|
return ipcom_inet_ctx_to_addr(&ctx, addrptr);
|
|
|
|
/* Try num8.num8.num16 */
|
|
ipcom_parse_inet_init(&ctx, strptr);
|
|
if (ipcom_parse_num8(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num8(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num16(&ctx))
|
|
return ipcom_inet_ctx_to_addr(&ctx, addrptr);
|
|
|
|
/* Try num8.num24 */
|
|
ipcom_parse_inet_init(&ctx, strptr);
|
|
if (ipcom_parse_num8(&ctx)
|
|
&& ipcom_parse_dot(&ctx)
|
|
&& ipcom_parse_num24(&ctx))
|
|
return ipcom_inet_ctx_to_addr(&ctx, addrptr);
|
|
|
|
/* Try num32 */
|
|
ipcom_parse_inet_init(&ctx, strptr);
|
|
if (ipcom_parse_num32(&ctx))
|
|
return ipcom_inet_ctx_to_addr(&ctx, addrptr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_colon
|
|
*===========================================================================
|
|
* Description: Parses a single dot (':')
|
|
* Parameters: ctx - parser context
|
|
* Returns: IP_FALSE - failed to parse a colon
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_colon(struct Ipcom_inet6_pton_ctx *ctx)
|
|
{
|
|
if (ctx->str[0] != ':')
|
|
return IP_FALSE;
|
|
++ctx->str;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_double_colon
|
|
*===========================================================================
|
|
* Description: Parses a double colon, update context to parse tail part
|
|
* if the call is successful.
|
|
* Parameters: ctx - parse context
|
|
* Returns: IP_FALSE - failed to parse double colon
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_double_colon(struct Ipcom_inet6_pton_ctx *ctx)
|
|
{
|
|
if (ctx->next_part == &ctx->next_tail_part)
|
|
/* More than one double colon */
|
|
return IP_FALSE;
|
|
|
|
ctx->next_part = &ctx->next_tail_part;
|
|
ctx->part = ctx->tail_part;
|
|
return (ipcom_parse_colon(ctx)
|
|
&& ipcom_parse_colon(ctx)
|
|
&& !ipcom_parse_colon(ctx));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_hex4
|
|
*===========================================================================
|
|
* Description: Parses a 16-bit hex string.
|
|
* Parameters: ctx - parse context
|
|
* Returns: IP_FALSE - failed to parse number or too big number
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_hex4(struct Ipcom_inet6_pton_ctx *ctx)
|
|
{
|
|
char *str = ctx->str;
|
|
unsigned hex4 = 0;
|
|
static const char *xdigits = "0123456789abcdef";
|
|
|
|
if (*ctx->next_part >= 8 || !ipcom_isxdigit(*str))
|
|
/* Too many hex4 entries or not a hex-digit */
|
|
return IP_FALSE;
|
|
|
|
do
|
|
{
|
|
hex4 <<= 4;
|
|
hex4 = (unsigned)(hex4 + ipcom_strchr(xdigits, ipcom_tolower(*str)) - xdigits);
|
|
if (hex4 > 0xffff)
|
|
/* Value too big */
|
|
return IP_FALSE;
|
|
} while (ipcom_isxdigit(*++str));
|
|
|
|
if (*str == '.')
|
|
/* Look like a part of an IPv4 address */
|
|
return IP_FALSE;
|
|
|
|
ctx->str = str;
|
|
|
|
ctx->part[*ctx->next_part] = (Ip_u16) hex4;
|
|
++(*ctx->next_part);
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_hexseq
|
|
*===========================================================================
|
|
* Description: Parses a sequence of hex4 elements
|
|
* Parameters: ctx - parse context
|
|
* Returns: IP_FALSE - failed to parse
|
|
* IP_TRUE - success
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_hexseq(struct Ipcom_inet6_pton_ctx *ctx)
|
|
{
|
|
/* <hexseq> ::= <hex4> *( ":" <hex4> ) */
|
|
if (!ipcom_parse_hex4(ctx))
|
|
return IP_FALSE;
|
|
|
|
for (;;)
|
|
{
|
|
struct Ipcom_inet6_pton_ctx rollback_point;
|
|
|
|
IPCOM_DEEP_CPY(&rollback_point, ctx);
|
|
if (!ipcom_parse_colon(ctx)
|
|
|| !ipcom_parse_hex4(ctx))
|
|
{
|
|
IPCOM_DEEP_CPY(ctx, &rollback_point);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_hexpart
|
|
*===========================================================================
|
|
* Description: Parses the hex + colon part of the IPv6 address.
|
|
* Parameters: ctx - parse context
|
|
* Returns: IP_FALSE - failed to parse
|
|
* IP_TRUE - success
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_hexpart(struct Ipcom_inet6_pton_ctx *ctx)
|
|
{
|
|
struct Ipcom_inet6_pton_ctx rollback_point;
|
|
Ip_bool success = IP_FALSE;
|
|
|
|
/*
|
|
* Try to parse this:
|
|
* <hexseq> | <hexseq> "::" [ <hexseq> ] | "::" [ <hexseq> ]
|
|
*/
|
|
IPCOM_DEEP_CPY(&rollback_point, ctx);
|
|
if (ipcom_parse_hexseq(ctx))
|
|
{
|
|
/*
|
|
* Success with one of <hexseq> | <hexseq> "::" [ <hexseq> ]
|
|
*/
|
|
success = IP_TRUE;
|
|
IPCOM_DEEP_CPY(&rollback_point, ctx);
|
|
}
|
|
|
|
if (ipcom_parse_double_colon(ctx))
|
|
{
|
|
/*
|
|
* Success with one of <hexseq> "::" [ <hexseq> ] | "::" [ <hexseq> ]
|
|
*/
|
|
success = IP_TRUE;
|
|
IPCOM_DEEP_CPY(&rollback_point, ctx);
|
|
if (ipcom_parse_hexseq(ctx))
|
|
/*
|
|
* Success with optional <hexseq> at end of expression.
|
|
*/
|
|
IPCOM_DEEP_CPY(&rollback_point, ctx);
|
|
}
|
|
|
|
IPCOM_DEEP_CPY(ctx, &rollback_point);
|
|
return success;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_inet6_ctx_to_addr
|
|
*===========================================================================
|
|
* Description: Combines the head and tail part of the IPv6 address
|
|
* and stores the result in "addrptr".
|
|
* Parameters: ctx - parse context
|
|
* addrptr - buffer where the IPv6 address should be stored
|
|
* Returns: 0 = parse error, not a valid IPv6 address
|
|
* 1 = success
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_inet6_ctx_to_addr(struct Ipcom_inet6_pton_ctx *ctx, void *addrptr)
|
|
{
|
|
Ip_u16 *addr = addrptr;
|
|
int i;
|
|
int num_parts;
|
|
|
|
if (!ipcom_is_valid_addr_end(*ctx->str))
|
|
return 0;
|
|
|
|
if ((ctx->part == ctx->head_part)
|
|
#ifdef IPCOM_USE_INET
|
|
&& (IP_FALSE == ctx->has_inaddr)
|
|
#endif
|
|
&& (ctx->next_head_part < 8))
|
|
/* no '::' && total length is not enough */
|
|
return 0;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (ctx->has_inaddr)
|
|
{
|
|
if (ctx->next_tail_part <= 6)
|
|
{
|
|
Ip_u16 *dst16 = &ctx->tail_part[ctx->next_tail_part];
|
|
ipcom_memcpy(dst16,
|
|
&ctx->inaddr,
|
|
sizeof(ctx->inaddr));
|
|
/*
|
|
* All data is stored in host endian up to this point, the
|
|
* IPv4 address is in network byte-order.
|
|
*/
|
|
dst16[0] = ip_ntohs(dst16[0]);
|
|
dst16[1] = ip_ntohs(dst16[1]);
|
|
}
|
|
ctx->next_tail_part += 2;
|
|
}
|
|
#endif
|
|
|
|
num_parts = ctx->next_head_part + ctx->next_tail_part;
|
|
if (num_parts > 8)
|
|
/* Too many parts */
|
|
return 0;
|
|
|
|
if (ctx->part == ctx->tail_part /* True if dubbel colon is present */
|
|
&& num_parts == 8)
|
|
{
|
|
/*
|
|
* We have a dubble colon, but the dubble colon represents
|
|
* zero or one 16-bit 0 field and RFC 5952 states
|
|
*
|
|
* 4.2.2. Handling One 16-Bit 0 Field
|
|
*
|
|
* The symbol "::" MUST NOT be used to shorten just one 16-bit
|
|
* 0 field. For example, the representation
|
|
* 2001:db8:0:1:1:1:1:1 is correct, but 2001:db8::1:1:1:1:1 is
|
|
* not correct.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
|
|
while (ctx->next_head_part + ctx->next_tail_part < 8)
|
|
ctx->head_part[ctx->next_head_part++] = 0;
|
|
|
|
for (i = 0; i < ctx->next_head_part; i++)
|
|
*addr++ = ip_htons(ctx->head_part[i]);
|
|
for (i = 0; i < ctx->next_tail_part; i++)
|
|
*addr++ = ip_htons(ctx->tail_part[i]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_inet_part
|
|
*===========================================================================
|
|
* Description: Parses an IPv4 address at the end of a IPv6 address
|
|
* Parameters: ctx - parse context
|
|
* Returns: IP_FALSE - parse failed
|
|
* IP_TRUE - success
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_STATIC Ip_bool
|
|
ipcom_parse_inet_part(struct Ipcom_inet6_pton_ctx *ctx)
|
|
{
|
|
if (ipcom_parse_dotted_quad(ctx->str, &ctx->inaddr))
|
|
{
|
|
/* IPv4 address was present at the end */
|
|
ctx->str += ipcom_strlen(ctx->str);
|
|
ctx->has_inaddr = IP_TRUE;
|
|
return IP_TRUE;
|
|
}
|
|
return IP_FALSE;
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_inet6_init
|
|
*===========================================================================
|
|
* Description: Initializes the inet6 parser.
|
|
* Parameters: ctx - parser context
|
|
* strptr - string to parse
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipcom_parse_inet6_init(struct Ipcom_inet6_pton_ctx *ctx, IP_CONST char *strptr)
|
|
{
|
|
ctx->str = (char *) strptr;
|
|
ctx->part = ctx->head_part;
|
|
ctx->next_part = &ctx->next_head_part;
|
|
ctx->next_head_part = 0;
|
|
ctx->next_tail_part = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_parse_inet6_addr
|
|
*===========================================================================
|
|
* Description: Tries to parse a string as an IPv6 address
|
|
* Parameters: strptr - pointer to string
|
|
* addrptr - pointer to where the binary representation should
|
|
* be stored.
|
|
* Returns: 0 = not a valid IPv6 address
|
|
* 1 = parse successful
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_parse_inet6_addr(IP_CONST char *strptr, void *addrptr)
|
|
{
|
|
struct Ipcom_inet6_pton_ctx ctx;
|
|
|
|
/*
|
|
* The IPv6 address format is described in RFC 2373.
|
|
*
|
|
* <inet6-addr> ::= <hexpart> [ [ ":" ] <inet4-addr> ] | "::" <inet4-addr>
|
|
* <hexpart> ::= <hexseq> | <hexseq> "::" [ <hexseq> ] | "::" [ <hexseq> ]
|
|
* <hexseq> ::= <hex4> *( ":" <hex4> )
|
|
* <hex4> ::= 1*4HEXDIGIT
|
|
*/
|
|
|
|
ipcom_parse_inet6_init(&ctx, strptr);
|
|
if (ipcom_parse_hexpart(&ctx))
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
int at_dubbel_colon = (ctx.next_part == &ctx.next_tail_part && ctx.next_tail_part == 0);
|
|
struct Ipcom_inet6_pton_ctx rollback_point;
|
|
|
|
ctx.has_inaddr = IP_FALSE;
|
|
/*
|
|
* The colon will be missing if the IPv4 address is preceded
|
|
* with a double colon.
|
|
*/
|
|
IPCOM_DEEP_CPY(&rollback_point, &ctx);
|
|
if (at_dubbel_colon || ipcom_parse_colon(&ctx))
|
|
{
|
|
/*
|
|
* The return value must not be checked since the IPv4 address
|
|
* is optional. The ipcom_inet6_ctx_to_addr() will fail if
|
|
* there are character that was not processed at the end.
|
|
*/
|
|
if (!ipcom_parse_inet_part(&ctx))
|
|
IPCOM_DEEP_CPY(&ctx, &rollback_point);
|
|
}
|
|
#endif
|
|
if (ipcom_inet6_ctx_to_addr(&ctx, addrptr))
|
|
return 1;
|
|
}
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
ipcom_parse_inet6_init(&ctx, strptr);
|
|
if (ipcom_parse_double_colon(&ctx)
|
|
&& ipcom_parse_inet_part(&ctx))
|
|
return ipcom_inet6_ctx_to_addr(&ctx, addrptr);
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
return 0;
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_inet_pton
|
|
*===========================================================================
|
|
* Description: Converts a string representation of a address to its binary
|
|
* form.
|
|
* Parameters: domain - The domain for the addresss (IP_AF_INET or
|
|
* IP_AF_INET6).
|
|
* strptr - A string representation of the address.
|
|
* addrptr - Points to the buffer that will receive the
|
|
* binary for of the address.
|
|
* Returns: 1 = success, 0 = the string was not a valid address
|
|
* <0 = error (ipcom_errno set)
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_inet_pton(int family, IP_CONST char *strptr, void *addrptr)
|
|
{
|
|
union Ip_in_addr_union addr;
|
|
int ret;
|
|
|
|
switch(family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
ret = ipcom_parse_dotted_quad(strptr, &addr);
|
|
ipcom_memcpy(addrptr, &addr, sizeof(addr.in));
|
|
return ret;
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
ret = ipcom_parse_inet6_addr(strptr, &addr);
|
|
ipcom_memcpy(addrptr, &addr, sizeof(addr.in6));
|
|
return ret;
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
case IP_AF_LINK:
|
|
{
|
|
struct Ip_sockaddr_dl *dl = (struct Ip_sockaddr_dl *) addrptr;
|
|
int str_index;
|
|
int data_index;
|
|
|
|
ipcom_memset(dl, 0, sizeof(struct Ip_sockaddr_dl));
|
|
for (data_index = 0, str_index = 0; strptr[str_index] != '\0'; data_index++)
|
|
{
|
|
int b;
|
|
if (ipcom_sscanf(&strptr[str_index], "%x", (unsigned*)&b) != 1)
|
|
break;
|
|
|
|
dl->sdl_data[data_index] = (char) b;
|
|
while (strptr[str_index++] != ':')
|
|
if (strptr[str_index] == '\0')
|
|
break;
|
|
}
|
|
|
|
dl->sdl_family = IP_AF_LINK;
|
|
dl->sdl_alen = (Ip_u8) data_index;
|
|
IPCOM_SA_LEN_SET(dl,(ip_offsetof(struct Ip_sockaddr_dl, sdl_data)
|
|
+ IP_MAX(sizeof(dl->sdl_data), dl->sdl_alen)));
|
|
return 1;
|
|
}
|
|
|
|
default:
|
|
return ipcom_errno_set(IP_ERRNO_EAFNOSUPPORT);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_inet_aton
|
|
*===========================================================================
|
|
* Description: Converts the Internet host address 'cp' from dotted quad
|
|
* notation into binary data and stores in in the structure that
|
|
* 'addr' points to.
|
|
* a.b.c.d Each of the four numeric parts specifies a
|
|
* byte of the address; the bytes are assigned in
|
|
* left-to-right order to produce the binary
|
|
* address.
|
|
* a.b.c Parts a and b specify the first two bytes of
|
|
* the binary address. Part c is interpreted as a
|
|
* 16-bit value that defines the rightmost two
|
|
* bytes of the binary address. This notation is
|
|
* suitable for specifying (out-moded) Class B
|
|
* network addresses.
|
|
* a.b Part a specifies the first byte of the
|
|
* binary address. Part b is interpreted as a
|
|
* 24-bit value that defines the rightmost three
|
|
* bytes of the binary address. This notation is
|
|
* suitable for specifying (outmoded) Class C
|
|
* network addresses.
|
|
* a The value a is interpreted as a 32-bit value
|
|
* that is stored directly into the binary address
|
|
* without any byte rearrangement.
|
|
* In all of the above forms, components of the dotted
|
|
* address can be specified in decimal, octal (with a
|
|
* leading 0), or hexadecimal, with a leading 0X).
|
|
* Addresses in any of these forms are collectively termed
|
|
* IPV4 numbers-and-dots notation. The form that uses
|
|
* exactly four decimal numbers is referred to as IPv4
|
|
* dotted-decimal notation (or sometimes: IPv4 dotted-quad
|
|
* notation).
|
|
* Parameters: cp - A text representation of an Internet address.
|
|
* addrptr - A pointer to where the binary address should
|
|
* be stored.
|
|
* Returns: >0 success, 0 fail
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_inet_aton(const char *cp, struct Ip_in_addr *addrptr)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
struct Ip_in_addr addr;
|
|
int ret;
|
|
|
|
ret = ipcom_parse_inet_addr(cp, &addr);
|
|
ipcom_memcpy(addrptr, &addr, sizeof(addr));
|
|
return ret;
|
|
#else
|
|
IPCOM_UNUSED_ARG(cp);
|
|
IPCOM_UNUSED_ARG(addrptr);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|