VMM: SMP guest (XCC)
[akaros.git] / user / iplib / readipifc.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 #include <dirent.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 static uint8_t loopbacknet[IPaddrlen] = {
23         0, 0, 0, 0,
24         0, 0, 0, 0,
25         0, 0, 0xff, 0xff,
26         127, 0, 0, 0
27 };
28 static uint8_t loopbackmask[IPaddrlen] = {
29         0xff, 0xff, 0xff, 0xff,
30         0xff, 0xff, 0xff, 0xff,
31         0xff, 0xff, 0xff, 0xff,
32         0xff, 0, 0, 0
33 };
34
35 #define NFIELD 200
36 #define nelem(x) (sizeof(x) / sizeof(x[0]))
37 static struct ipifc **_readoldipifc(char *buf, struct ipifc **l, int index)
38 {
39         char *f[NFIELD];
40         int i, n;
41         struct ipifc *ifc;
42         struct iplifc *lifc, **ll;
43
44         /* allocate new interface */
45         *l = ifc = calloc(sizeof(struct ipifc), 1);
46         if (ifc == NULL)
47                 return l;
48         l = &ifc->next;
49         ifc->index = index;
50
51         n = tokenize(buf, f, NFIELD);
52         if (n < 2)
53                 return l;
54
55         strncpy(ifc->dev, f[0], sizeof ifc->dev);
56         ifc->dev[sizeof(ifc->dev) - 1] = 0;
57         ifc->mtu = strtoul(f[1], NULL, 10);
58
59         ll = &ifc->lifc;
60         for (i = 2; n - i >= 7; i += 7) {
61                 /* allocate new local address */
62                 *ll = lifc = calloc(sizeof(struct iplifc), 1);
63                 ll = &lifc->next;
64
65                 parseip(lifc->ip, f[i]);
66                 parseipmask(lifc->mask, f[i + 1]);
67                 parseip(lifc->net, f[i + 2]);
68                 ifc->pktin = strtoul(f[i + 3], NULL, 10);
69                 ifc->pktout = strtoul(f[i + 4], NULL, 10);
70                 ifc->errin = strtoul(f[i + 5], NULL, 10);
71                 ifc->errout = strtoul(f[i + 6], NULL, 10);
72         }
73         return l;
74 }
75
76 static char *findfield(char *name, char **f, int n)
77 {
78         int i;
79
80         for (i = 0; i < n - 1; i++)
81                 if (strcmp(f[i], name) == 0)
82                         return f[i + 1];
83         return "";
84 }
85
86 static struct ipifc **_readipifc(char *file, struct ipifc **l, int index)
87 {
88         int i, n, fd, lines;
89         char buf[4 * 1024];
90         char *line[32];
91         char *f[64];
92         struct ipifc *ifc, **l0;
93         struct iplifc *lifc, **ll;
94
95         /* read the file */
96         fd = open(file, O_RDONLY);
97         if (fd < 0)
98                 return l;
99         n = 0;
100         while ((i = read(fd, buf + n, sizeof(buf) - 1 - n)) > 0 &&
101                n < sizeof(buf) - 1)
102                 n += i;
103         buf[n] = 0;
104         close(fd);
105
106         if (strncmp(buf, "device", 6) != 0)
107                 return _readoldipifc(buf, l, index);
108         /* ignore ifcs with no associated device */
109         if (strncmp(buf + 6, "  ", 2) == 0)
110                 return l;
111         /* allocate new interface */
112         *l = ifc = calloc(sizeof(struct ipifc), 1);
113         if (ifc == NULL)
114                 return l;
115         l0 = l;
116         l = &ifc->next;
117         ifc->index = index;
118
119         lines = getfields(buf, line, nelem(line), 1, "\n");
120
121         /* pick off device specific info(first line) */
122         n = tokenize(line[0], f, nelem(f));
123         if (n % 2 != 0)
124                 goto lose;
125         strncpy(ifc->dev, findfield("device", f, n), sizeof(ifc->dev));
126         ifc->dev[sizeof(ifc->dev) - 1] = 0;
127         if (ifc->dev[0] == 0) {
128         lose:
129                 free(ifc);
130                 *l0 = NULL;
131                 return l;
132         }
133         ifc->mtu = strtoul(findfield("maxtu", f, n), NULL, 10);
134         ifc->sendra6 = atoi(findfield("sendra", f, n));
135         ifc->recvra6 = atoi(findfield("recvra", f, n));
136         ifc->rp.mflag = atoi(findfield("mflag", f, n));
137         ifc->rp.oflag = atoi(findfield("oflag", f, n));
138         ifc->rp.maxraint = atoi(findfield("maxraint", f, n));
139         ifc->rp.minraint = atoi(findfield("minraint", f, n));
140         ifc->rp.linkmtu = atoi(findfield("linkmtu", f, n));
141         ifc->rp.reachtime = atoi(findfield("reachtime", f, n));
142         ifc->rp.rxmitra = atoi(findfield("rxmitra", f, n));
143         ifc->rp.ttl = atoi(findfield("ttl", f, n));
144         ifc->rp.routerlt = atoi(findfield("routerlt", f, n));
145         ifc->pktin = strtoul(findfield("pktin", f, n), NULL, 10);
146         ifc->pktout = strtoul(findfield("pktout", f, n), NULL, 10);
147         ifc->errin = strtoul(findfield("errin", f, n), NULL, 10);
148         ifc->errout = strtoul(findfield("errout", f, n), NULL, 10);
149
150         /* now read the addresses */
151         ll = &ifc->lifc;
152         for (i = 1; i < lines; i++) {
153                 n = tokenize(line[i], f, nelem(f));
154                 if (n < 5)
155                         break;
156
157                 /* allocate new local address */
158                 *ll = lifc = calloc(sizeof(struct iplifc), 1);
159                 ll = &lifc->next;
160
161                 parseip(lifc->ip, f[0]);
162                 parseipmask(lifc->mask, f[1]);
163                 parseip(lifc->net, f[2]);
164
165                 lifc->validlt = strtoul(f[3], NULL, 10);
166                 lifc->preflt = strtoul(f[4], NULL, 10);
167         }
168
169         return l;
170 }
171
172 void free_ipifc(struct ipifc *ifc)
173 {
174         struct ipifc *next;
175         struct iplifc *lnext, *lifc;
176
177         if (ifc == NULL)
178                 return;
179         for (; ifc; ifc = next) {
180                 next = ifc->next;
181                 for (lifc = ifc->lifc; lifc; lifc = lnext) {
182                         lnext = lifc->next;
183                         free(lifc);
184                 }
185                 free(ifc);
186         }
187 }
188
189 /* This will free @ifc when passed in.  Some old Plan 9 programs might rely on
190  * it still (like our ping, netstat, ipconfig).  It usually ends up be a
191  * thread-unsafe disaster. */
192 struct ipifc *readipifc(char *net, struct ipifc *ifc, int index)
193 {
194         int fd, i, n;
195         struct dir *dir;
196         char directory[128];
197         char buf[128];
198         struct ipifc **l;
199
200         free_ipifc(ifc);
201
202         l = &ifc;
203         ifc = NULL;
204
205         if (net == 0)
206                 net = "/net";
207         snprintf(directory, sizeof(directory), "%s/ipifc", net);
208
209         if (index >= 0) {
210                 snprintf(buf, sizeof(buf), "%s/%d/status", directory, index);
211                 _readipifc(buf, l, index);
212         } else {
213                 DIR *d;
214                 struct dirent *de;
215                 d = opendir(directory);
216                 if (!d)
217                         return NULL;
218
219                 while (de = readdir(d)) {
220                         if (strcmp(de->d_name, "clone") == 0)
221                                 continue;
222                         if (strcmp(de->d_name, "stats") == 0)
223                                 continue;
224                         snprintf(buf, sizeof(buf), "%s/%s/status", directory, de->d_name);
225                         l = _readipifc(buf, l, atoi(de->d_name));
226                 }
227                 closedir(d);
228         }
229
230         return ifc;
231 }
232
233 /* Gets the local interface that isn't the friggin' loopback address.  When
234  * you're done, free_ipifc(ifc).  Returns 0 on failure. */
235 struct iplifc *get_first_noloop_iplifc(char *net, struct ipifc **ifc)
236 {
237         struct ipifc *nifc;
238         struct iplifc *lifc;
239         uint8_t mynet[IPaddrlen];
240
241         *ifc = readipifc(net, NULL, -1);
242         for (nifc = *ifc; nifc; nifc = nifc->next) {
243                 for (lifc = nifc->lifc; lifc; lifc = lifc->next) {
244                         maskip(lifc->ip, loopbackmask, mynet);
245                         if (ipcmp(mynet, loopbacknet) == 0)
246                                 continue;
247                         if (ipcmp(lifc->ip, IPnoaddr) != 0)
248                                 return lifc;
249                 }
250         }
251         free_ipifc(*ifc);
252         return 0;
253 }