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