tizen 2.4 release
[external/busybox.git] / networking / libiproute / utils.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  *
5  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6  *
7  * Changes:
8  *
9  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
10  */
11
12 #include "libbb.h"
13 #include "utils.h"
14 #include "inet_common.h"
15
16 unsigned get_unsigned(char *arg, const char *errmsg)
17 {
18         unsigned long res;
19         char *ptr;
20
21         if (*arg) {
22                 res = strtoul(arg, &ptr, 0);
23 //FIXME: "" will be accepted too, is it correct?!
24                 if (!*ptr && res <= UINT_MAX) {
25                         return res;
26                 }
27         }
28         invarg(arg, errmsg); /* does not return */
29 }
30
31 uint32_t get_u32(char *arg, const char *errmsg)
32 {
33         unsigned long res;
34         char *ptr;
35
36         if (*arg) {
37                 res = strtoul(arg, &ptr, 0);
38 //FIXME: "" will be accepted too, is it correct?!
39                 if (!*ptr && res <= 0xFFFFFFFFUL) {
40                         return res;
41                 }
42         }
43         invarg(arg, errmsg); /* does not return */
44 }
45
46 uint16_t get_u16(char *arg, const char *errmsg)
47 {
48         unsigned long res;
49         char *ptr;
50
51         if (*arg) {
52                 res = strtoul(arg, &ptr, 0);
53 //FIXME: "" will be accepted too, is it correct?!
54                 if (!*ptr && res <= 0xFFFF) {
55                         return res;
56                 }
57         }
58         invarg(arg, errmsg); /* does not return */
59 }
60
61 int get_addr_1(inet_prefix *addr, char *name, int family)
62 {
63         memset(addr, 0, sizeof(*addr));
64
65         if (strcmp(name, "default") == 0
66          || strcmp(name, "all") == 0
67          || strcmp(name, "any") == 0
68         ) {
69                 addr->family = family;
70                 addr->bytelen = (family == AF_INET6 ? 16 : 4);
71                 addr->bitlen = -1;
72                 return 0;
73         }
74
75         if (strchr(name, ':')) {
76                 addr->family = AF_INET6;
77                 if (family != AF_UNSPEC && family != AF_INET6)
78                         return -1;
79                 if (inet_pton(AF_INET6, name, addr->data) <= 0)
80                         return -1;
81                 addr->bytelen = 16;
82                 addr->bitlen = -1;
83                 return 0;
84         }
85
86         if (family != AF_UNSPEC && family != AF_INET)
87                 return -1;
88
89         /* Try to parse it as IPv4 */
90         addr->family = AF_INET;
91 #if 0 /* Doesn't handle e.g. "10.10", for example, "ip r l root 10.10/16" */
92         if (inet_pton(AF_INET, name, addr->data) <= 0)
93                 return -1;
94 #else
95         {
96                 unsigned i = 0;
97                 unsigned n = 0;
98                 const char *cp = name - 1;
99                 while (*++cp) {
100                         if ((unsigned char)(*cp - '0') <= 9) {
101                                 n = 10 * n + (unsigned char)(*cp - '0');
102                                 if (n >= 256)
103                                         return -1;
104                                 ((uint8_t*)addr->data)[i] = n;
105                                 continue;
106                         }
107                         if (*cp == '.' && ++i <= 3) {
108                                 n = 0;
109                                 continue;
110                         }
111                         return -1;
112                 }
113         }
114 #endif
115         addr->bytelen = 4;
116         addr->bitlen = -1;
117
118         return 0;
119 }
120
121 static void get_prefix_1(inet_prefix *dst, char *arg, int family)
122 {
123         char *slash;
124
125         memset(dst, 0, sizeof(*dst));
126
127         if (strcmp(arg, "default") == 0
128          || strcmp(arg, "all") == 0
129          || strcmp(arg, "any") == 0
130         ) {
131                 dst->family = family;
132                 /*dst->bytelen = 0; - done by memset */
133                 /*dst->bitlen = 0;*/
134                 return;
135         }
136
137         slash = strchr(arg, '/');
138         if (slash)
139                 *slash = '\0';
140
141         if (get_addr_1(dst, arg, family) == 0) {
142                 dst->bitlen = (dst->family == AF_INET6) ? 128 : 32;
143                 if (slash) {
144                         unsigned plen;
145                         inet_prefix netmask_pfx;
146
147                         netmask_pfx.family = AF_UNSPEC;
148                         plen = bb_strtou(slash + 1, NULL, 0);
149                         if ((errno || plen > dst->bitlen)
150                          && get_addr_1(&netmask_pfx, slash + 1, family) != 0
151                         ) {
152                                 goto bad;
153                         }
154                         if (netmask_pfx.family == AF_INET) {
155                                 /* fill in prefix length of dotted quad */
156                                 uint32_t mask = ntohl(netmask_pfx.data[0]);
157                                 uint32_t host = ~mask;
158
159                                 /* a valid netmask must be 2^n - 1 */
160                                 if (host & (host + 1))
161                                         goto bad;
162
163                                 for (plen = 0; mask; mask <<= 1)
164                                         ++plen;
165                                 if (plen > dst->bitlen)
166                                         goto bad;
167                                 /* dst->flags |= PREFIXLEN_SPECIFIED; */
168                         }
169                         dst->bitlen = plen;
170                 }
171         }
172
173         if (slash)
174                 *slash = '/';
175         return;
176  bad:
177         bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg);
178 }
179
180 int get_addr(inet_prefix *dst, char *arg, int family)
181 {
182         if (family == AF_PACKET) {
183                 bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address");
184         }
185         if (get_addr_1(dst, arg, family)) {
186                 bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg);
187         }
188         return 0;
189 }
190
191 void get_prefix(inet_prefix *dst, char *arg, int family)
192 {
193         if (family == AF_PACKET) {
194                 bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix");
195         }
196         get_prefix_1(dst, arg, family);
197 }
198
199 uint32_t get_addr32(char *name)
200 {
201         inet_prefix addr;
202
203         if (get_addr_1(&addr, name, AF_INET)) {
204                 bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name);
205         }
206         return addr.data[0];
207 }
208
209 void incomplete_command(void)
210 {
211         bb_error_msg_and_die("command line is not complete, try option \"help\"");
212 }
213
214 void invarg(const char *arg, const char *opt)
215 {
216         bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt);
217 }
218
219 void duparg(const char *key, const char *arg)
220 {
221         bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg);
222 }
223
224 void duparg2(const char *key, const char *arg)
225 {
226         bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg);
227 }
228
229 int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
230 {
231         const uint32_t *a1 = a->data;
232         const uint32_t *a2 = b->data;
233         int words = bits >> 5;
234
235         bits &= 0x1f;
236
237         if (words)
238                 if (memcmp(a1, a2, words << 2))
239                         return -1;
240
241         if (bits) {
242                 uint32_t w1, w2;
243                 uint32_t mask;
244
245                 w1 = a1[words];
246                 w2 = a2[words];
247
248                 mask = htonl((0xffffffff) << (0x20 - bits));
249
250                 if ((w1 ^ w2) & mask)
251                         return 1;
252         }
253
254         return 0;
255 }
256
257 const char *rt_addr_n2a(int af,
258                 void *addr, char *buf, int buflen)
259 {
260         switch (af) {
261         case AF_INET:
262         case AF_INET6:
263                 return inet_ntop(af, addr, buf, buflen);
264         default:
265                 return "???";
266         }
267 }
268
269 #ifdef RESOLVE_HOSTNAMES
270 const char *format_host(int af, int len, void *addr, char *buf, int buflen)
271 {
272         if (resolve_hosts) {
273                 struct hostent *h_ent;
274
275                 if (len <= 0) {
276                         switch (af) {
277                         case AF_INET:
278                                 len = 4;
279                                 break;
280                         case AF_INET6:
281                                 len = 16;
282                                 break;
283                         default:;
284                         }
285                 }
286                 if (len > 0) {
287                         h_ent = gethostbyaddr(addr, len, af);
288                         if (h_ent != NULL) {
289                                 safe_strncpy(buf, h_ent->h_name, buflen);
290                                 return buf;
291                         }
292                 }
293         }
294         return rt_addr_n2a(af, addr, buf, buflen);
295 }
296 #endif