1/* The following code has been extracted from the kenrel sources, if there is
2 * any problem, blame for mangling it. --pablo */
3
4/*
5 *	Generic address resultion entity
6 *
7 *	Authors:
8 *	net_random Alan Cox
9 *	net_ratelimit Andi Kleen
10 *	in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
11 *
12 *	Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
13 *
14 *	This program is free software; you can redistribute it and/or
15 *	modify it under the terms of the GNU General Public License
16 *	as published by the Free Software Foundation; either version
17 *	2 of the License, or (at your option) any later version.
18 */
19
20/*
21 * lib/hexdump.c
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License version 2 as
25 * published by the Free Software Foundation. See README and COPYING for
26 * more details.
27 */
28
29#include <stdint.h>
30#include <ctype.h>
31#include <string.h>	/* for memcpy */
32
33#include "helper.h"
34
35static int hex_to_bin(char ch)
36{
37	if ((ch >= '0') && (ch <= '9'))
38		return ch - '0';
39	ch = tolower(ch);
40	if ((ch >= 'a') && (ch <= 'f'))
41		return ch - 'a' + 10;
42	return -1;
43}
44
45#define IN6PTON_XDIGIT		0x00010000
46#define IN6PTON_DIGIT		0x00020000
47#define IN6PTON_COLON_MASK	0x00700000
48#define IN6PTON_COLON_1		0x00100000	/* single : requested */
49#define IN6PTON_COLON_2		0x00200000	/* second : requested */
50#define IN6PTON_COLON_1_2	0x00400000	/* :: requested */
51#define IN6PTON_DOT		0x00800000	/* . */
52#define IN6PTON_DELIM		0x10000000
53#define IN6PTON_NULL		0x20000000	/* first/tail */
54#define IN6PTON_UNKNOWN		0x40000000
55
56static inline int xdigit2bin(char c, int delim)
57{
58	int val;
59
60	if (c == delim || c == '\0')
61		return IN6PTON_DELIM;
62	if (c == ':')
63		return IN6PTON_COLON_MASK;
64	if (c == '.')
65		return IN6PTON_DOT;
66
67	val = hex_to_bin(c);
68	if (val >= 0)
69		return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
70
71	if (delim == -1)
72		return IN6PTON_DELIM;
73	return IN6PTON_UNKNOWN;
74}
75
76int in4_pton(const char *src, int srclen,
77	     uint8_t *dst,
78	     int delim, const char **end)
79{
80	const char *s;
81	uint8_t *d;
82	uint8_t dbuf[4];
83	int ret = 0;
84	int i;
85	int w = 0;
86
87	if (srclen < 0)
88		srclen = strlen(src);
89	s = src;
90	d = dbuf;
91	i = 0;
92	while(1) {
93		int c;
94		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
95		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
96			goto out;
97		}
98		if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
99			if (w == 0)
100				goto out;
101			*d++ = w & 0xff;
102			w = 0;
103			i++;
104			if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
105				if (i != 4)
106					goto out;
107				break;
108			}
109			goto cont;
110		}
111		w = (w * 10) + c;
112		if ((w & 0xffff) > 255) {
113			goto out;
114		}
115cont:
116		if (i >= 4)
117			goto out;
118		s++;
119		srclen--;
120	}
121	ret = 1;
122	memcpy(dst, dbuf, sizeof(dbuf));
123out:
124	if (end)
125		*end = s;
126	return ret;
127}
128
129int in6_pton(const char *src, int srclen,
130	     uint8_t *dst,
131	     int delim, const char **end)
132{
133	const char *s, *tok = NULL;
134	uint8_t *d, *dc = NULL;
135	uint8_t dbuf[16];
136	int ret = 0;
137	int i;
138	int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
139	int w = 0;
140
141	memset(dbuf, 0, sizeof(dbuf));
142
143	s = src;
144	d = dbuf;
145	if (srclen < 0)
146		srclen = strlen(src);
147
148	while (1) {
149		int c;
150
151		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
152		if (!(c & state))
153			goto out;
154		if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
155			/* process one 16-bit word */
156			if (!(state & IN6PTON_NULL)) {
157				*d++ = (w >> 8) & 0xff;
158				*d++ = w & 0xff;
159			}
160			w = 0;
161			if (c & IN6PTON_DELIM) {
162				/* We've processed last word */
163				break;
164			}
165			/*
166			 * COLON_1 => XDIGIT
167			 * COLON_2 => XDIGIT|DELIM
168			 * COLON_1_2 => COLON_2
169			 */
170			switch (state & IN6PTON_COLON_MASK) {
171			case IN6PTON_COLON_2:
172				dc = d;
173				state = IN6PTON_XDIGIT | IN6PTON_DELIM;
174				if (dc - dbuf >= (int)sizeof(dbuf))
175					state |= IN6PTON_NULL;
176				break;
177			case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
178				state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
179				break;
180			case IN6PTON_COLON_1:
181				state = IN6PTON_XDIGIT;
182				break;
183			case IN6PTON_COLON_1_2:
184				state = IN6PTON_COLON_2;
185				break;
186			default:
187				state = 0;
188			}
189			tok = s + 1;
190			goto cont;
191		}
192
193		if (c & IN6PTON_DOT) {
194			ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
195			if (ret > 0) {
196				d += 4;
197				break;
198			}
199			goto out;
200		}
201
202		w = (w << 4) | (0xff & c);
203		state = IN6PTON_COLON_1 | IN6PTON_DELIM;
204		if (!(w & 0xf000)) {
205			state |= IN6PTON_XDIGIT;
206		}
207		if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
208			state |= IN6PTON_COLON_1_2;
209			state &= ~IN6PTON_DELIM;
210		}
211		if (d + 2 >= dbuf + sizeof(dbuf)) {
212			state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
213		}
214cont:
215		if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
216		    d + 4 == dbuf + sizeof(dbuf)) {
217			state |= IN6PTON_DOT;
218		}
219		if (d >= dbuf + sizeof(dbuf)) {
220			state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
221		}
222		s++;
223		srclen--;
224	}
225
226	i = 15; d--;
227
228	if (dc) {
229		while(d >= dc)
230			dst[i--] = *d--;
231		while(i >= dc - dbuf)
232			dst[i--] = 0;
233		while(i >= 0)
234			dst[i--] = *d--;
235	} else
236		memcpy(dst, dbuf, sizeof(dbuf));
237
238	ret = 1;
239out:
240	if (end)
241		*end = s;
242	return ret;
243}
244