Skip to content

Commit 1aaec67

Browse files
yoshfujiDavid S. Miller
authored and
David S. Miller
committed
[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>
1 parent 75bff8f commit 1aaec67

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

include/linux/inet.h

+2
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@
4646
#include <linux/types.h>
4747

4848
extern __be32 in_aton(const char *str);
49+
extern int in4_pton(const char *src, int srclen, u8 *dst, char delim, const char **end);
50+
extern int in6_pton(const char *src, int srclen, u8 *dst, char delim, const char **end);
4951
#endif
5052
#endif /* _LINUX_INET_H */

net/core/utils.c

+215
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Authors:
55
* net_random Alan Cox
66
* net_ratelimit Andy Kleen
7+
* in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
78
*
89
* Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
910
*
@@ -191,3 +192,217 @@ __be32 in_aton(const char *str)
191192
}
192193

193194
EXPORT_SYMBOL(in_aton);
195+
196+
#define IN6PTON_XDIGIT 0x00010000
197+
#define IN6PTON_DIGIT 0x00020000
198+
#define IN6PTON_COLON_MASK 0x00700000
199+
#define IN6PTON_COLON_1 0x00100000 /* single : requested */
200+
#define IN6PTON_COLON_2 0x00200000 /* second : requested */
201+
#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
202+
#define IN6PTON_DOT 0x00800000 /* . */
203+
#define IN6PTON_DELIM 0x10000000
204+
#define IN6PTON_NULL 0x20000000 /* first/tail */
205+
#define IN6PTON_UNKNOWN 0x40000000
206+
207+
static inline int digit2bin(char c, char delim)
208+
{
209+
if (c == delim || c == '\0')
210+
return IN6PTON_DELIM;
211+
if (c == '.')
212+
return IN6PTON_DOT;
213+
if (c >= '0' && c <= '9')
214+
return (IN6PTON_DIGIT | (c - '0'));
215+
return IN6PTON_UNKNOWN;
216+
}
217+
218+
static inline int xdigit2bin(char c, char delim)
219+
{
220+
if (c == delim || c == '\0')
221+
return IN6PTON_DELIM;
222+
if (c == ':')
223+
return IN6PTON_COLON_MASK;
224+
if (c == '.')
225+
return IN6PTON_DOT;
226+
if (c >= '0' && c <= '9')
227+
return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0'));
228+
if (c >= 'a' && c <= 'f')
229+
return (IN6PTON_XDIGIT | (c - 'a' + 10));
230+
if (c >= 'A' && c <= 'F')
231+
return (IN6PTON_XDIGIT | (c - 'A' + 10));
232+
return IN6PTON_UNKNOWN;
233+
}
234+
235+
int in4_pton(const char *src, int srclen,
236+
u8 *dst,
237+
char delim, const char **end)
238+
{
239+
const char *s;
240+
u8 *d;
241+
u8 dbuf[4];
242+
int ret = 0;
243+
int i;
244+
int w = 0;
245+
246+
if (srclen < 0)
247+
srclen = strlen(src);
248+
s = src;
249+
d = dbuf;
250+
i = 0;
251+
while(1) {
252+
int c;
253+
c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
254+
if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
255+
goto out;
256+
}
257+
if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
258+
if (w == 0)
259+
goto out;
260+
*d++ = w & 0xff;
261+
w = 0;
262+
i++;
263+
if (c & IN6PTON_DELIM) {
264+
if (i != 4)
265+
goto out;
266+
break;
267+
}
268+
goto cont;
269+
}
270+
w = (w * 10) + c;
271+
if ((w & 0xffff) > 255) {
272+
goto out;
273+
}
274+
cont:
275+
if (i >= 4)
276+
goto out;
277+
s++;
278+
srclen--;
279+
}
280+
ret = 1;
281+
memcpy(dst, dbuf, sizeof(dbuf));
282+
out:
283+
if (end)
284+
*end = s;
285+
return ret;
286+
}
287+
288+
EXPORT_SYMBOL(in4_pton);
289+
290+
int in6_pton(const char *src, int srclen,
291+
u8 *dst,
292+
char delim, const char **end)
293+
{
294+
const char *s, *tok = NULL;
295+
u8 *d, *dc = NULL;
296+
u8 dbuf[16];
297+
int ret = 0;
298+
int i;
299+
int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
300+
int w = 0;
301+
302+
memset(dbuf, 0, sizeof(dbuf));
303+
304+
s = src;
305+
d = dbuf;
306+
if (srclen < 0)
307+
srclen = strlen(src);
308+
309+
printf("srclen=%d\n", srclen);
310+
311+
while (1) {
312+
int c;
313+
314+
c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
315+
if (!(c & state))
316+
goto out;
317+
if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
318+
/* process one 16-bit word */
319+
if (!(state & IN6PTON_NULL)) {
320+
*d++ = (w >> 8) & 0xff;
321+
*d++ = w & 0xff;
322+
}
323+
w = 0;
324+
if (c & IN6PTON_DELIM) {
325+
/* We've processed last word */
326+
break;
327+
}
328+
/*
329+
* COLON_1 => XDIGIT
330+
* COLON_2 => XDIGIT|DELIM
331+
* COLON_1_2 => COLON_2
332+
*/
333+
switch (state & IN6PTON_COLON_MASK) {
334+
case IN6PTON_COLON_2:
335+
dc = d;
336+
state = IN6PTON_XDIGIT | IN6PTON_DELIM;
337+
if (dc - dbuf >= sizeof(dbuf))
338+
state |= IN6PTON_NULL;
339+
break;
340+
case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
341+
state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
342+
break;
343+
case IN6PTON_COLON_1:
344+
state = IN6PTON_XDIGIT;
345+
break;
346+
case IN6PTON_COLON_1_2:
347+
state = IN6PTON_COLON_2;
348+
break;
349+
default:
350+
state = 0;
351+
}
352+
tok = s + 1;
353+
goto cont;
354+
}
355+
356+
if (c & IN6PTON_DOT) {
357+
ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
358+
if (ret > 0) {
359+
d += 4;
360+
break;
361+
}
362+
goto out;
363+
}
364+
365+
w = (w << 4) | (0xff & c);
366+
state = IN6PTON_COLON_1 | IN6PTON_DELIM;
367+
if (!(w & 0xf000)) {
368+
state |= IN6PTON_XDIGIT;
369+
}
370+
if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
371+
state |= IN6PTON_COLON_1_2;
372+
state &= ~IN6PTON_DELIM;
373+
}
374+
if (d + 2 >= dbuf + sizeof(dbuf)) {
375+
state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
376+
}
377+
cont:
378+
if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
379+
d + 4 == dbuf + sizeof(dbuf)) {
380+
state |= IN6PTON_DOT;
381+
}
382+
if (d >= dbuf + sizeof(dbuf)) {
383+
state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
384+
}
385+
s++;
386+
srclen--;
387+
}
388+
389+
i = 15; d--;
390+
391+
if (dc) {
392+
while(d >= dc)
393+
dst[i--] = *d--;
394+
while(i >= dc - dbuf)
395+
dst[i--] = 0;
396+
while(i >= 0)
397+
dst[i--] = *d--;
398+
} else
399+
memcpy(dst, dbuf, sizeof(dbuf));
400+
401+
ret = 1;
402+
out:
403+
if (end)
404+
*end = s;
405+
return ret;
406+
}
407+
408+
EXPORT_SYMBOL(in6_pton);

0 commit comments

Comments
 (0)