diff options
| author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-06-25 23:54:55 +0900 | 
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 15:18:01 -0700 | 
| commit | 1aaec67f9335a17856dfacdd3e5cc6f4c18faeec (patch) | |
| tree | 87801e3cb66fc7103dc2c0008246b055fda39deb | |
| parent | 75bff8f023e02b045a8f68f36fa7da98dca124b8 (diff) | |
| download | olio-linux-3.10-1aaec67f9335a17856dfacdd3e5cc6f4c18faeec.tar.xz olio-linux-3.10-1aaec67f9335a17856dfacdd3e5cc6f4c18faeec.zip  | |
[NET]: Add common helper functions to convert IPv6/IPv4 address string to network address structure.
These helpers can be used in netfilter, cifs etc.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
| -rw-r--r-- | include/linux/inet.h | 2 | ||||
| -rw-r--r-- | net/core/utils.c | 215 | 
2 files changed, 217 insertions, 0 deletions
diff --git a/include/linux/inet.h b/include/linux/inet.h index 6c5587af118..b7c6da7d6d3 100644 --- a/include/linux/inet.h +++ b/include/linux/inet.h @@ -46,5 +46,7 @@  #include <linux/types.h>  extern __be32 in_aton(const char *str); +extern int in4_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); +extern int in6_pton(const char *src, int srclen, u8 *dst, char delim, const char **end);  #endif  #endif	/* _LINUX_INET_H */ diff --git a/net/core/utils.c b/net/core/utils.c index e31c90e0559..5a06e8a72c1 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -4,6 +4,7 @@   *	Authors:   *	net_random Alan Cox   *	net_ratelimit Andy Kleen + *	in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project   *   *	Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>   * @@ -191,3 +192,217 @@ __be32 in_aton(const char *str)  }  EXPORT_SYMBOL(in_aton); + +#define IN6PTON_XDIGIT		0x00010000 +#define IN6PTON_DIGIT		0x00020000 +#define IN6PTON_COLON_MASK	0x00700000 +#define IN6PTON_COLON_1		0x00100000	/* single : requested */ +#define IN6PTON_COLON_2		0x00200000	/* second : requested */ +#define IN6PTON_COLON_1_2	0x00400000	/* :: requested */ +#define IN6PTON_DOT		0x00800000	/* . */ +#define IN6PTON_DELIM		0x10000000 +#define IN6PTON_NULL		0x20000000	/* first/tail */ +#define IN6PTON_UNKNOWN		0x40000000 + +static inline int digit2bin(char c, char delim) +{ +	if (c == delim || c == '\0') +		return IN6PTON_DELIM; +	if (c == '.') +		return IN6PTON_DOT; +	if (c >= '0' && c <= '9') +		return (IN6PTON_DIGIT | (c - '0')); +	return IN6PTON_UNKNOWN; +} + +static inline int xdigit2bin(char c, char delim) +{ +	if (c == delim || c == '\0') +		return IN6PTON_DELIM; +	if (c == ':') +		return IN6PTON_COLON_MASK; +	if (c == '.') +		return IN6PTON_DOT; +	if (c >= '0' && c <= '9') +		return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0')); +	if (c >= 'a' && c <= 'f') +		return (IN6PTON_XDIGIT | (c - 'a' + 10)); +	if (c >= 'A' && c <= 'F') +		return (IN6PTON_XDIGIT | (c - 'A' + 10)); +	return IN6PTON_UNKNOWN; +} + +int in4_pton(const char *src, int srclen, +	     u8 *dst, +	     char delim, const char **end) +{ +	const char *s; +	u8 *d; +	u8 dbuf[4]; +	int ret = 0; +	int i; +	int w = 0; + +	if (srclen < 0) +		srclen = strlen(src); +	s = src; +	d = dbuf; +	i = 0; +	while(1) { +		int c; +		c = xdigit2bin(srclen > 0 ? *s : '\0', delim); +		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) { +			goto out; +		} +		if (c & (IN6PTON_DOT | IN6PTON_DELIM)) { +			if (w == 0) +				goto out; +			*d++ = w & 0xff; +			w = 0; +			i++; +			if (c & IN6PTON_DELIM) { +				if (i != 4) +					goto out; +				break; +			} +			goto cont; +		} +		w = (w * 10) + c; +		if ((w & 0xffff) > 255) { +			goto out; +		} +cont: +		if (i >= 4) +			goto out; +		s++; +		srclen--; +	} +	ret = 1; +	memcpy(dst, dbuf, sizeof(dbuf)); +out: +	if (end) +		*end = s; +	return ret; +} + +EXPORT_SYMBOL(in4_pton); + +int in6_pton(const char *src, int srclen, +	     u8 *dst, +	     char delim, const char **end) +{ +	const char *s, *tok = NULL; +	u8 *d, *dc = NULL; +	u8 dbuf[16]; +	int ret = 0; +	int i; +	int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL; +	int w = 0; + +	memset(dbuf, 0, sizeof(dbuf)); + +	s = src; +	d = dbuf; +	if (srclen < 0) +		srclen = strlen(src); + +	printf("srclen=%d\n", srclen); + +	while (1) { +		int c; + +		c = xdigit2bin(srclen > 0 ? *s : '\0', delim); +		if (!(c & state)) +			goto out; +		if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { +			/* process one 16-bit word */ +			if (!(state & IN6PTON_NULL)) { +				*d++ = (w >> 8) & 0xff; +				*d++ = w & 0xff; +			} +			w = 0; +			if (c & IN6PTON_DELIM) { +				/* We've processed last word */ +				break; +			} +			/* +			 * COLON_1 => XDIGIT +			 * COLON_2 => XDIGIT|DELIM +			 * COLON_1_2 => COLON_2 +			 */ +			switch (state & IN6PTON_COLON_MASK) { +			case IN6PTON_COLON_2: +				dc = d; +				state = IN6PTON_XDIGIT | IN6PTON_DELIM; +				if (dc - dbuf >= sizeof(dbuf)) +					state |= IN6PTON_NULL; +				break; +			case IN6PTON_COLON_1|IN6PTON_COLON_1_2: +				state = IN6PTON_XDIGIT | IN6PTON_COLON_2; +				break; +			case IN6PTON_COLON_1: +				state = IN6PTON_XDIGIT; +				break; +			case IN6PTON_COLON_1_2: +				state = IN6PTON_COLON_2; +				break; +			default: +				state = 0; +			} +			tok = s + 1; +			goto cont; +		} + +		if (c & IN6PTON_DOT) { +			ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s); +			if (ret > 0) { +				d += 4; +				break; +			} +			goto out; +		} + +		w = (w << 4) | (0xff & c); +		state = IN6PTON_COLON_1 | IN6PTON_DELIM; +		if (!(w & 0xf000)) { +			state |= IN6PTON_XDIGIT; +		} +		if (!dc && d + 2 < dbuf + sizeof(dbuf)) { +			state |= IN6PTON_COLON_1_2; +			state &= ~IN6PTON_DELIM; +		} +		if (d + 2 >= dbuf + sizeof(dbuf)) { +			state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2); +		} +cont: +		if ((dc && d + 4 < dbuf + sizeof(dbuf)) || +		    d + 4 == dbuf + sizeof(dbuf)) { +			state |= IN6PTON_DOT; +		} +		if (d >= dbuf + sizeof(dbuf)) { +			state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK); +		} +		s++; +		srclen--; +	} + +	i = 15; d--; + +	if (dc) { +		while(d >= dc) +			dst[i--] = *d--; +		while(i >= dc - dbuf) +			dst[i--] = 0; +		while(i >= 0) +			dst[i--] = *d--; +	} else +		memcpy(dst, dbuf, sizeof(dbuf)); + +	ret = 1; +out: +	if (end) +		*end = s; +	return ret; +} + +EXPORT_SYMBOL(in6_pton);  |