Merge branch 'e1000-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[pandora-kernel.git] / net / core / utils.c
1 /*
2  *      Generic address resultion entity
3  *
4  *      Authors:
5  *      net_random Alan Cox
6  *      net_ratelimit Andi Kleen
7  *      in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
8  *
9  *      Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
10  *
11  *      This program is free software; you can redistribute it and/or
12  *      modify it under the terms of the GNU General Public License
13  *      as published by the Free Software Foundation; either version
14  *      2 of the License, or (at your option) any later version.
15  */
16
17 #include <linux/module.h>
18 #include <linux/jiffies.h>
19 #include <linux/kernel.h>
20 #include <linux/inet.h>
21 #include <linux/mm.h>
22 #include <linux/net.h>
23 #include <linux/string.h>
24 #include <linux/types.h>
25 #include <linux/random.h>
26 #include <linux/percpu.h>
27 #include <linux/init.h>
28
29 #include <asm/byteorder.h>
30 #include <asm/system.h>
31 #include <asm/uaccess.h>
32
33 int net_msg_cost __read_mostly = 5*HZ;
34 int net_msg_burst __read_mostly = 10;
35 int net_msg_warn __read_mostly = 1;
36 EXPORT_SYMBOL(net_msg_warn);
37
38 /*
39  * All net warning printk()s should be guarded by this function.
40  */
41 int net_ratelimit(void)
42 {
43         return __printk_ratelimit(net_msg_cost, net_msg_burst);
44 }
45 EXPORT_SYMBOL(net_ratelimit);
46
47 /*
48  * Convert an ASCII string to binary IP.
49  * This is outside of net/ipv4/ because various code that uses IP addresses
50  * is otherwise not dependent on the TCP/IP stack.
51  */
52
53 __be32 in_aton(const char *str)
54 {
55         unsigned long l;
56         unsigned int val;
57         int i;
58
59         l = 0;
60         for (i = 0; i < 4; i++)
61         {
62                 l <<= 8;
63                 if (*str != '\0')
64                 {
65                         val = 0;
66                         while (*str != '\0' && *str != '.' && *str != '\n')
67                         {
68                                 val *= 10;
69                                 val += *str - '0';
70                                 str++;
71                         }
72                         l |= val;
73                         if (*str != '\0')
74                                 str++;
75                 }
76         }
77         return(htonl(l));
78 }
79
80 EXPORT_SYMBOL(in_aton);
81
82 #define IN6PTON_XDIGIT          0x00010000
83 #define IN6PTON_DIGIT           0x00020000
84 #define IN6PTON_COLON_MASK      0x00700000
85 #define IN6PTON_COLON_1         0x00100000      /* single : requested */
86 #define IN6PTON_COLON_2         0x00200000      /* second : requested */
87 #define IN6PTON_COLON_1_2       0x00400000      /* :: requested */
88 #define IN6PTON_DOT             0x00800000      /* . */
89 #define IN6PTON_DELIM           0x10000000
90 #define IN6PTON_NULL            0x20000000      /* first/tail */
91 #define IN6PTON_UNKNOWN         0x40000000
92
93 static inline int digit2bin(char c, int delim)
94 {
95         if (c == delim || c == '\0')
96                 return IN6PTON_DELIM;
97         if (c == '.')
98                 return IN6PTON_DOT;
99         if (c >= '0' && c <= '9')
100                 return (IN6PTON_DIGIT | (c - '0'));
101         return IN6PTON_UNKNOWN;
102 }
103
104 static inline int xdigit2bin(char c, int delim)
105 {
106         if (c == delim || c == '\0')
107                 return IN6PTON_DELIM;
108         if (c == ':')
109                 return IN6PTON_COLON_MASK;
110         if (c == '.')
111                 return IN6PTON_DOT;
112         if (c >= '0' && c <= '9')
113                 return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0'));
114         if (c >= 'a' && c <= 'f')
115                 return (IN6PTON_XDIGIT | (c - 'a' + 10));
116         if (c >= 'A' && c <= 'F')
117                 return (IN6PTON_XDIGIT | (c - 'A' + 10));
118         if (delim == -1)
119                 return IN6PTON_DELIM;
120         return IN6PTON_UNKNOWN;
121 }
122
123 int in4_pton(const char *src, int srclen,
124              u8 *dst,
125              int delim, const char **end)
126 {
127         const char *s;
128         u8 *d;
129         u8 dbuf[4];
130         int ret = 0;
131         int i;
132         int w = 0;
133
134         if (srclen < 0)
135                 srclen = strlen(src);
136         s = src;
137         d = dbuf;
138         i = 0;
139         while(1) {
140                 int c;
141                 c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
142                 if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
143                         goto out;
144                 }
145                 if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
146                         if (w == 0)
147                                 goto out;
148                         *d++ = w & 0xff;
149                         w = 0;
150                         i++;
151                         if (c & IN6PTON_DELIM) {
152                                 if (i != 4)
153                                         goto out;
154                                 break;
155                         }
156                         goto cont;
157                 }
158                 w = (w * 10) + c;
159                 if ((w & 0xffff) > 255) {
160                         goto out;
161                 }
162 cont:
163                 if (i >= 4)
164                         goto out;
165                 s++;
166                 srclen--;
167         }
168         ret = 1;
169         memcpy(dst, dbuf, sizeof(dbuf));
170 out:
171         if (end)
172                 *end = s;
173         return ret;
174 }
175
176 EXPORT_SYMBOL(in4_pton);
177
178 int in6_pton(const char *src, int srclen,
179              u8 *dst,
180              int delim, const char **end)
181 {
182         const char *s, *tok = NULL;
183         u8 *d, *dc = NULL;
184         u8 dbuf[16];
185         int ret = 0;
186         int i;
187         int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
188         int w = 0;
189
190         memset(dbuf, 0, sizeof(dbuf));
191
192         s = src;
193         d = dbuf;
194         if (srclen < 0)
195                 srclen = strlen(src);
196
197         while (1) {
198                 int c;
199
200                 c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
201                 if (!(c & state))
202                         goto out;
203                 if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
204                         /* process one 16-bit word */
205                         if (!(state & IN6PTON_NULL)) {
206                                 *d++ = (w >> 8) & 0xff;
207                                 *d++ = w & 0xff;
208                         }
209                         w = 0;
210                         if (c & IN6PTON_DELIM) {
211                                 /* We've processed last word */
212                                 break;
213                         }
214                         /*
215                          * COLON_1 => XDIGIT
216                          * COLON_2 => XDIGIT|DELIM
217                          * COLON_1_2 => COLON_2
218                          */
219                         switch (state & IN6PTON_COLON_MASK) {
220                         case IN6PTON_COLON_2:
221                                 dc = d;
222                                 state = IN6PTON_XDIGIT | IN6PTON_DELIM;
223                                 if (dc - dbuf >= sizeof(dbuf))
224                                         state |= IN6PTON_NULL;
225                                 break;
226                         case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
227                                 state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
228                                 break;
229                         case IN6PTON_COLON_1:
230                                 state = IN6PTON_XDIGIT;
231                                 break;
232                         case IN6PTON_COLON_1_2:
233                                 state = IN6PTON_COLON_2;
234                                 break;
235                         default:
236                                 state = 0;
237                         }
238                         tok = s + 1;
239                         goto cont;
240                 }
241
242                 if (c & IN6PTON_DOT) {
243                         ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
244                         if (ret > 0) {
245                                 d += 4;
246                                 break;
247                         }
248                         goto out;
249                 }
250
251                 w = (w << 4) | (0xff & c);
252                 state = IN6PTON_COLON_1 | IN6PTON_DELIM;
253                 if (!(w & 0xf000)) {
254                         state |= IN6PTON_XDIGIT;
255                 }
256                 if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
257                         state |= IN6PTON_COLON_1_2;
258                         state &= ~IN6PTON_DELIM;
259                 }
260                 if (d + 2 >= dbuf + sizeof(dbuf)) {
261                         state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
262                 }
263 cont:
264                 if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
265                     d + 4 == dbuf + sizeof(dbuf)) {
266                         state |= IN6PTON_DOT;
267                 }
268                 if (d >= dbuf + sizeof(dbuf)) {
269                         state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
270                 }
271                 s++;
272                 srclen--;
273         }
274
275         i = 15; d--;
276
277         if (dc) {
278                 while(d >= dc)
279                         dst[i--] = *d--;
280                 while(i >= dc - dbuf)
281                         dst[i--] = 0;
282                 while(i >= 0)
283                         dst[i--] = *d--;
284         } else
285                 memcpy(dst, dbuf, sizeof(dbuf));
286
287         ret = 1;
288 out:
289         if (end)
290                 *end = s;
291         return ret;
292 }
293
294 EXPORT_SYMBOL(in6_pton);