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