diff options
Diffstat (limited to 'net/core/utils.c')
-rw-r--r-- | net/core/utils.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/net/core/utils.c b/net/core/utils.c index e31c90e05594..5a06e8a72c17 100644 --- a/net/core/utils.c +++ b/net/core/utils.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Authors: | 4 | * Authors: |
5 | * net_random Alan Cox | 5 | * net_random Alan Cox |
6 | * net_ratelimit Andy Kleen | 6 | * net_ratelimit Andy Kleen |
7 | * in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project | ||
7 | * | 8 | * |
8 | * Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | 9 | * Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
9 | * | 10 | * |
@@ -191,3 +192,217 @@ __be32 in_aton(const char *str) | |||
191 | } | 192 | } |
192 | 193 | ||
193 | EXPORT_SYMBOL(in_aton); | 194 | 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); | ||