chiark / gitweb /
networkd: split out vlan and macvlan handling
[elogind.git] / src / network / sd-network.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7   Copyright 2014 Tom Gundersen
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <sys/inotify.h>
27 #include <sys/poll.h>
28 #include <net/if.h>
29
30 #include "util.h"
31 #include "macro.h"
32 #include "strv.h"
33 #include "fileio.h"
34 #include "sd-network.h"
35 #include "network-internal.h"
36 #include "dhcp-lease-internal.h"
37
38 static int link_get_flags(unsigned index, unsigned *flags) {
39         _cleanup_free_ char *s = NULL, *p = NULL;
40         int r;
41
42         assert(index);
43         assert(flags);
44
45         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
46                 return -ENOMEM;
47
48         r = parse_env_file(p, NEWLINE, "FLAGS", &s, NULL);
49         if (r == -ENOENT)
50                 return -ENODATA;
51         else if (r < 0)
52                 return r;
53         else if (!s)
54                 return -EIO;
55
56         return safe_atou(s, flags);
57 }
58
59 _public_ int sd_network_link_is_loopback(unsigned index) {
60         unsigned flags;
61         int r;
62
63         r = link_get_flags(index, &flags);
64         if (r < 0)
65                 return 0;
66
67         return flags & IFF_LOOPBACK;
68 }
69
70 _public_ int sd_network_get_link_state(unsigned index, char **state) {
71         _cleanup_free_ char *s = NULL, *p = NULL;
72         int r;
73
74         assert_return(index, -EINVAL);
75         assert_return(state, -EINVAL);
76
77         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
78                 return -ENOMEM;
79
80         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
81         if (r == -ENOENT)
82                 return -ENODATA;
83         else if (r < 0)
84                 return r;
85         else if (!s)
86                 return -EIO;
87
88         if (streq(s, "unmanaged"))
89                 return -EUNATCH;
90         else if (streq(s, "initializing"))
91                 return -EBUSY;
92
93         *state = s;
94         s = NULL;
95
96         return 0;
97 }
98
99 _public_ int sd_network_get_operational_state(char **state) {
100         _cleanup_free_ char *s = NULL;
101         int r;
102
103         assert_return(state, -EINVAL);
104
105         r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
106                            &s, NULL);
107         if (r == -ENOENT)
108                 return -ENODATA;
109         else if (r < 0)
110                 return r;
111         else if (!s)
112                 return -EIO;
113
114         *state = s;
115         s = NULL;
116
117         return 0;
118 }
119
120 _public_ int sd_network_get_link_operational_state(unsigned index, char **state) {
121         _cleanup_free_ char *s = NULL, *p = NULL;
122         int r;
123
124         assert_return(index, -EINVAL);
125         assert_return(state, -EINVAL);
126
127         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
128                 return -ENOMEM;
129
130         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
131         if (r == -ENOENT)
132                 return -ENODATA;
133         else if (r < 0)
134                 return r;
135         else if (!s)
136                 return -EIO;
137
138         *state = s;
139         s = NULL;
140
141         return 0;
142 }
143
144 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
145         _cleanup_free_ char *p = NULL, *s = NULL;
146         sd_dhcp_lease *lease = NULL;
147         int r;
148
149         assert_return(index, -EINVAL);
150         assert_return(ret, -EINVAL);
151
152         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
153                 return -ENOMEM;
154
155         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
156
157         if (r < 0)
158                 return r;
159         else if (!s)
160                 return -EIO;
161
162         r = dhcp_lease_load(s, &lease);
163         if (r < 0)
164                 return r;
165
166         *ret = lease;
167
168         return 0;
169 }
170
171 static int network_get_in_addr(const char *key, unsigned index, struct in_addr **addr, size_t *addr_size) {
172         _cleanup_free_ char *p = NULL, *s = NULL;
173         int r;
174
175         assert_return(index, -EINVAL);
176         assert_return(addr, -EINVAL);
177         assert_return(addr_size, -EINVAL);
178
179         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
180                 return -ENOMEM;
181
182         r = parse_env_file(p, NEWLINE, key, &s, NULL);
183         if (r < 0)
184                 return r;
185         else if (!s)
186                 return -EIO;
187
188         return deserialize_in_addrs(addr, addr_size, s);
189 }
190
191 _public_ int sd_network_get_dns(unsigned index, struct in_addr **addr, size_t *addr_size) {
192         return network_get_in_addr("DNS", index, addr, addr_size);
193 }
194
195 _public_ int sd_network_get_ntp(unsigned index, struct in_addr **addr, size_t *addr_size) {
196         return network_get_in_addr("NTP", index, addr, addr_size);
197 }
198
199 static int network_get_in6_addr(const char *key, unsigned index, struct in6_addr **addr, size_t *addr_size) {
200         _cleanup_free_ char *p = NULL, *s = NULL;
201         int r;
202
203         assert_return(index, -EINVAL);
204         assert_return(addr, -EINVAL);
205         assert_return(addr_size, -EINVAL);
206
207         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
208                 return -ENOMEM;
209
210         r = parse_env_file(p, NEWLINE, key, &s, NULL);
211         if (r < 0)
212                 return r;
213         else if (!s)
214                 return -EIO;
215
216         return deserialize_in6_addrs(addr, addr_size, s);
217 }
218
219 _public_ int sd_network_get_dns6(unsigned index, struct in6_addr **addr, size_t *addr_size) {
220         return network_get_in6_addr("DNS", index, addr, addr_size);
221 }
222
223 _public_ int sd_network_get_ntp6(unsigned index, struct in6_addr **addr, size_t *addr_size) {
224         return network_get_in6_addr("NTP", index, addr, addr_size);
225 }
226
227 static int network_get_boolean(const char *key, unsigned index) {
228         _cleanup_free_ char *p = NULL, *s = NULL;
229         int r;
230
231         assert_return(index, -EINVAL);
232
233         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
234                 return -ENOMEM;
235
236         r = parse_env_file(p, NEWLINE, key, &s, NULL);
237         if (r < 0)
238                 return r;
239         else if (!s)
240                 return -EIO;
241
242         return parse_boolean(s);
243 }
244
245 _public_ int sd_network_dhcp_use_dns(unsigned index) {
246         return network_get_boolean("DHCP_USE_DNS", index);
247 }
248
249 _public_ int sd_network_dhcp_use_ntp(unsigned index) {
250         return network_get_boolean("DHCP_USE_NTP", index);
251 }
252
253 _public_ int sd_network_get_ifindices(unsigned **indices) {
254         _cleanup_closedir_ DIR *d;
255         int r = 0;
256         unsigned n = 0;
257         _cleanup_free_ uid_t *l = NULL;
258
259         d = opendir("/run/systemd/netif/links/");
260         if (!d)
261                 return -errno;
262
263         for (;;) {
264                 struct dirent *de;
265                 int k;
266                 unsigned index;
267
268                 errno = 0;
269                 de = readdir(d);
270                 if (!de && errno != 0)
271                         return -errno;
272
273                 if (!de)
274                         break;
275
276                 dirent_ensure_type(d, de);
277
278                 if (!dirent_is_file(de))
279                         continue;
280
281                 k = safe_atou(de->d_name, &index);
282                 if (k < 0)
283                         continue;
284
285                 if (indices) {
286                         if ((unsigned) r >= n) {
287                                 unsigned *t;
288
289                                 n = MAX(16, 2*r);
290                                 t = realloc(l, sizeof(unsigned) * n);
291                                 if (!t)
292                                         return -ENOMEM;
293
294                                 l = t;
295                         }
296
297                         assert((unsigned) r < n);
298                         l[r++] = index;
299                 } else
300                         r++;
301         }
302
303         if (indices) {
304                 *indices = l;
305                 l = NULL;
306         }
307
308         return r;
309 }
310
311 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
312         return (int) (unsigned long) m - 1;
313 }
314
315 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
316         return (sd_network_monitor*) (unsigned long) (fd + 1);
317 }
318
319 _public_ int sd_network_monitor_new(const char *category, sd_network_monitor **m) {
320         int fd, k;
321         bool good = false;
322
323         assert_return(m, -EINVAL);
324
325         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
326         if (fd < 0)
327                 return -errno;
328
329         if (!category || streq(category, "links")) {
330                 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
331                 if (k < 0) {
332                         safe_close(fd);
333                         return -errno;
334                 }
335
336                 good = true;
337         }
338
339         if (!category || streq(category, "leases")) {
340                 k = inotify_add_watch(fd, "/run/systemd/netif/leases/", IN_MOVED_TO|IN_DELETE);
341                 if (k < 0) {
342                         safe_close(fd);
343                         return -errno;
344                 }
345
346                 good = true;
347         }
348
349         if (!good) {
350                 close_nointr(fd);
351                 return -EINVAL;
352         }
353
354         *m = FD_TO_MONITOR(fd);
355         return 0;
356 }
357
358 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
359         int fd;
360
361         assert_return(m, NULL);
362
363         fd = MONITOR_TO_FD(m);
364         close_nointr(fd);
365
366         return NULL;
367 }
368
369 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
370
371         assert_return(m, -EINVAL);
372
373         return flush_fd(MONITOR_TO_FD(m));
374 }
375
376 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
377
378         assert_return(m, -EINVAL);
379
380         return MONITOR_TO_FD(m);
381 }
382
383 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
384
385         assert_return(m, -EINVAL);
386
387         /* For now we will only return POLLIN here, since we don't
388          * need anything else ever for inotify.  However, let's have
389          * this API to keep our options open should we later on need
390          * it. */
391         return POLLIN;
392 }
393
394 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
395
396         assert_return(m, -EINVAL);
397         assert_return(timeout_usec, -EINVAL);
398
399         /* For now we will only return (uint64_t) -1, since we don't
400          * need any timeout. However, let's have this API to keep our
401          * options open should we later on need it. */
402         *timeout_usec = (uint64_t) -1;
403         return 0;
404 }