x86: Don't enter the monitor for invalid opcode
[akaros.git] / user / iplib / parseip.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9 #include <stdlib.h>
10
11 #include <iplib/iplib.h>
12 #include <parlib/parlib.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <unistd.h>
16
17 static int isascii(int c)
18 {
19         return ((c >= 0) && (c <= 128));
20 }
21 static int isalnum(int c)
22 {
23         return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
24                 (c >= '0' && c <= '9'));
25 }
26 static int isdigit(int c)
27 {
28         return ((c >= '0' && c <= '9'));
29 }
30 static int isxdigit(int c)
31 {
32         return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ||
33                 (c >= '0' && c <= '9'));
34 }
35
36 char *v4parseip(uint8_t *to, char *from)
37 {
38         int i;
39         char *p;
40
41         p = from;
42         for (i = 0; i < 4 && *p; i++) {
43                 to[i] = strtoul(p, &p, 0);
44                 if (*p == '.')
45                         p++;
46         }
47         switch (CLASS(to)) {
48         case 0: /* class A - 1 uchar net */
49         case 1:
50                 if (i == 3) {
51                         to[3] = to[2];
52                         to[2] = to[1];
53                         to[1] = 0;
54                 } else if (i == 2) {
55                         to[3] = to[1];
56                         to[1] = 0;
57                 }
58                 break;
59         case 2: /* class B - 2 uchar net */
60                 if (i == 3) {
61                         to[3] = to[2];
62                         to[2] = 0;
63                 }
64                 break;
65         }
66         return p;
67 }
68
69 static int ipcharok(int c)
70 {
71         return c == '.' || c == ':' || isascii(c) && isxdigit(c);
72 }
73
74 static int delimchar(int c)
75 {
76         if (c == '\0')
77                 return 1;
78         if (c == '.' || c == ':' || isascii(c) && isalnum(c))
79                 return 0;
80         return 1;
81 }
82
83 /*
84  * `from' may contain an address followed by other characters,
85  * at least in /boot, so we permit whitespace (and more) after the address.
86  * we do ensure that "delete" cannot be parsed as "de::".
87  *
88  * some callers don't check the return value for errors, so
89  * set `to' to something distinctive in the case of a parse error.
90  */
91 int64_t parseip(uint8_t *to, char *from)
92 {
93         int i, elipsis = 0, v4 = 1;
94         uint32_t x;
95         char *p, *op;
96
97         memset(to, 0, IPaddrlen);
98         p = from;
99         for (i = 0; i < IPaddrlen && ipcharok(*p); i += 2) {
100                 op = p;
101                 x = strtoul(p, &p, 16);
102                 if (*p == '.' || (*p == 0 && i == 0)) { /* ends with v4? */
103                         p = v4parseip(to + i, op);
104                         i += 4;
105                         break;
106                 }
107                 /* v6: at most 4 hex digits, followed by colon or delim */
108                 if (x != (uint16_t)x || *p != ':' && !delimchar(*p)) {
109                         memset(to, 0, IPaddrlen);
110                         return -1; /* parse error */
111                 }
112                 to[i] = x >> 8;
113                 to[i + 1] = x;
114                 if (*p == ':') {
115                         v4 = 0;
116                         if (*++p == ':') { /* :: is elided zero short(s) */
117                                 if (elipsis) {
118                                         memset(to, 0, IPaddrlen);
119                                         return -1; /* second :: */
120                                 }
121                                 elipsis = i + 2;
122                                 p++;
123                         }
124                 } else if (p == op) /* strtoul made no progress? */
125                         break;
126         }
127         if (p == from || !delimchar(*p)) {
128                 memset(to, 0, IPaddrlen);
129                 return -1; /* parse error */
130         }
131         if (i < IPaddrlen) {
132                 memmove(&to[elipsis + IPaddrlen - i], &to[elipsis], i - elipsis);
133                 memset(&to[elipsis], 0, IPaddrlen - i);
134         }
135         if (v4) {
136                 to[10] = to[11] = 0xff;
137                 return nhgetl(to + IPv4off);
138         } else
139                 return 6;
140 }
141
142 /*
143  *  hack to allow ip v4 masks to be entered in the old
144  *  style
145  */
146 int64_t parseipmask(uint8_t *to, char *from)
147 {
148         int i, w;
149         int64_t x;
150         uint8_t *p;
151
152         if (*from == '/') {
153                 /* as a number of prefix bits */
154                 i = atoi(from + 1);
155                 if (i < 0)
156                         i = 0;
157                 if (i > 128)
158                         i = 128;
159                 w = i;
160                 memset(to, 0, IPaddrlen);
161                 for (p = to; i >= 8; i -= 8)
162                         *p++ = 0xff;
163                 if (i > 0)
164                         *p = ~((1 << (8 - i)) - 1);
165                 x = nhgetl(to + IPv4off);
166                 /*
167                  * identify as ipv6 if the mask is inexpressible as a v4 mask
168                  * (because it has too few mask bits).  Arguably, we could
169                  * always return 6 here.
170                  */
171                 if (w < 8 * (IPaddrlen - IPv4addrlen))
172                         return 6;
173         } else {
174                 /* as a straight v4 bit mask */
175                 x = parseip(to, from);
176                 if (x != -1)
177                         x = (uint32_t)nhgetl(to + IPv4off);
178                 if (memcmp(to, v4prefix, IPv4off) == 0)
179                         memset(to, 0xff, IPv4off);
180         }
181         return x;
182 }
183
184 /*
185  *  parse a v4 ip address/mask in cidr format
186  */
187 char *v4parsecidr(uint8_t *addr, uint8_t *mask, char *from)
188 {
189         int i;
190         char *p;
191         uint8_t *a;
192
193         p = v4parseip(addr, from);
194
195         if (*p == '/') {
196                 /* as a number of prefix bits */
197                 i = strtoul(p + 1, &p, 0);
198                 /* We might have been passed a v6 mask - the signal for that will be
199                  * having more than 32 bits. */
200                 if (i >= 32)
201                         i -= 128 - 32;
202                 memset(mask, 0, IPv4addrlen);
203                 for (a = mask; i >= 8; i -= 8)
204                         *a++ = 0xff;
205                 if (i > 0)
206                         *a = ~((1 << (8 - i)) - 1);
207         } else
208                 memcpy(mask, defmask(addr), IPv4addrlen);
209         return p;
210 }