be10379d55590f0fd124760fe4becaea56c4a9f1
[project/netifd.git] / config.c
1 /*
2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #define _GNU_SOURCE
15 #include <string.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18
19 #include <uci.h>
20
21 #include "netifd.h"
22 #include "interface.h"
23 #include "interface-ip.h"
24 #include "iprule.h"
25 #include "proto.h"
26 #include "wireless.h"
27 #include "config.h"
28
29 bool config_init = false;
30
31 static struct uci_context *uci_ctx;
32 static struct uci_package *uci_network;
33 static struct uci_package *uci_wireless;
34 static struct blob_buf b;
35
36 static int
37 config_section_idx(struct uci_section *s)
38 {
39 struct uci_element *e;
40 int idx = 0;
41
42 uci_foreach_element(&uci_wireless->sections, e) {
43 struct uci_section *cur = uci_to_section(e);
44
45 if (s == cur)
46 return idx;
47
48 if (!strcmp(cur->type, s->type))
49 idx++;
50 }
51
52 return -1;
53 }
54
55 static int
56 config_parse_bridge_interface(struct uci_section *s, struct device_type *devtype)
57 {
58 char *name;
59
60 name = alloca(strlen(s->e.name) + strlen(devtype->name_prefix) + 2);
61 sprintf(name, "%s-%s", devtype->name_prefix, s->e.name);
62 blobmsg_add_string(&b, "name", name);
63
64 uci_to_blob(&b, s, devtype->config_params);
65 if (!device_create(name, devtype, b.head)) {
66 D(INTERFACE, "Failed to create '%s' device for interface '%s'\n",
67 devtype->name, s->e.name);
68 }
69
70 blob_buf_init(&b, 0);
71 blobmsg_add_string(&b, "ifname", name);
72 return 0;
73 }
74
75 static void
76 config_parse_interface(struct uci_section *s, bool alias)
77 {
78 struct interface *iface;
79 const char *type = NULL, *disabled;
80 struct blob_attr *config;
81 bool bridge = false;
82 struct device_type *devtype = NULL;
83
84 disabled = uci_lookup_option_string(uci_ctx, s, "disabled");
85 if (disabled && !strcmp(disabled, "1"))
86 return;
87
88 blob_buf_init(&b, 0);
89
90 if (!alias)
91 type = uci_lookup_option_string(uci_ctx, s, "type");
92
93 if (type)
94 devtype = device_type_get(type);
95
96 if (devtype && devtype->bridge_capability) {
97 if (config_parse_bridge_interface(s, devtype))
98 return;
99
100 bridge = true;
101 }
102
103 uci_to_blob(&b, s, &interface_attr_list);
104
105 iface = interface_alloc(s->e.name, b.head, false);
106 if (!iface)
107 return;
108
109 if (iface->proto_handler && iface->proto_handler->config_params)
110 uci_to_blob(&b, s, iface->proto_handler->config_params);
111
112 if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params))
113 iface->device_config = true;
114
115 config = blob_memdup(b.head);
116 if (!config)
117 goto error;
118
119 if (alias) {
120 if (!interface_add_alias(iface, config))
121 goto error_free_config;
122 } else {
123 if (!interface_add(iface, config))
124 goto error_free_config;
125 }
126 return;
127
128 error_free_config:
129 free(config);
130 error:
131 free(iface);
132 }
133
134 static void
135 config_parse_route(struct uci_section *s, bool v6)
136 {
137 void *route;
138
139 blob_buf_init(&b, 0);
140 route = blobmsg_open_array(&b, "route");
141 uci_to_blob(&b, s, &route_attr_list);
142 blobmsg_close_array(&b, route);
143 interface_ip_add_route(NULL, blob_data(b.head), v6);
144 }
145
146 static void
147 config_parse_rule(struct uci_section *s, bool v6)
148 {
149 void *rule;
150
151 blob_buf_init(&b, 0);
152 rule = blobmsg_open_array(&b, "rule");
153 uci_to_blob(&b, s, &rule_attr_list);
154 blobmsg_close_array(&b, rule);
155 iprule_add(blob_data(b.head), v6);
156 }
157
158 static void
159 config_init_devices(void)
160 {
161 struct uci_element *e;
162
163 uci_foreach_element(&uci_network->sections, e) {
164 const struct uci_blob_param_list *params = NULL;
165 struct uci_section *s = uci_to_section(e);
166 struct device_type *devtype = NULL;
167 struct device *dev;
168 const char *type, *name;
169
170 if (strcmp(s->type, "device") != 0)
171 continue;
172
173 name = uci_lookup_option_string(uci_ctx, s, "name");
174 if (!name)
175 continue;
176
177 type = uci_lookup_option_string(uci_ctx, s, "type");
178 if (type)
179 devtype = device_type_get(type);
180
181 if (devtype)
182 params = devtype->config_params;
183 if (!params)
184 params = simple_device_type.config_params;
185
186 blob_buf_init(&b, 0);
187 uci_to_blob(&b, s, params);
188 if (devtype) {
189 dev = device_create(name, devtype, b.head);
190 if (!dev)
191 continue;
192 } else {
193 dev = device_get(name, 1);
194 if (!dev)
195 continue;
196
197 dev->current_config = true;
198 device_apply_config(dev, dev->type, b.head);
199 }
200 dev->default_config = false;
201 }
202 }
203
204 static struct uci_package *
205 config_init_package(const char *config)
206 {
207 struct uci_context *ctx = uci_ctx;
208 struct uci_package *p = NULL;
209
210 if (!ctx) {
211 ctx = uci_alloc_context();
212 uci_ctx = ctx;
213
214 ctx->flags &= ~UCI_FLAG_STRICT;
215 if (config_path)
216 uci_set_confdir(ctx, config_path);
217
218 #ifdef DUMMY_MODE
219 uci_set_savedir(ctx, "./tmp");
220 #endif
221 } else {
222 p = uci_lookup_package(ctx, config);
223 if (p)
224 uci_unload(ctx, p);
225 }
226
227 if (uci_load(ctx, config, &p))
228 return NULL;
229
230 return p;
231 }
232
233 static void
234 config_init_interfaces(void)
235 {
236 struct uci_element *e;
237
238 uci_foreach_element(&uci_network->sections, e) {
239 struct uci_section *s = uci_to_section(e);
240
241 if (!strcmp(s->type, "interface"))
242 config_parse_interface(s, false);
243 }
244
245 uci_foreach_element(&uci_network->sections, e) {
246 struct uci_section *s = uci_to_section(e);
247
248 if (!strcmp(s->type, "alias"))
249 config_parse_interface(s, true);
250 }
251 }
252
253 static void
254 config_init_routes(void)
255 {
256 struct interface *iface;
257 struct uci_element *e;
258
259 vlist_for_each_element(&interfaces, iface, node)
260 interface_ip_update_start(&iface->config_ip);
261
262 uci_foreach_element(&uci_network->sections, e) {
263 struct uci_section *s = uci_to_section(e);
264
265 if (!strcmp(s->type, "route"))
266 config_parse_route(s, false);
267 else if (!strcmp(s->type, "route6"))
268 config_parse_route(s, true);
269 }
270
271 vlist_for_each_element(&interfaces, iface, node)
272 interface_ip_update_complete(&iface->config_ip);
273 }
274
275 static void
276 config_init_rules(void)
277 {
278 struct uci_element *e;
279
280 iprule_update_start();
281
282 uci_foreach_element(&uci_network->sections, e) {
283 struct uci_section *s = uci_to_section(e);
284
285 if (!strcmp(s->type, "rule"))
286 config_parse_rule(s, false);
287 else if (!strcmp(s->type, "rule6"))
288 config_parse_rule(s, true);
289 }
290
291 iprule_update_complete();
292 }
293
294 static void
295 config_init_globals(void)
296 {
297 struct uci_section *globals = uci_lookup_section(
298 uci_ctx, uci_network, "globals");
299 if (!globals)
300 return;
301
302 const char *ula_prefix = uci_lookup_option_string(
303 uci_ctx, globals, "ula_prefix");
304 interface_ip_set_ula_prefix(ula_prefix);
305 }
306
307 static void
308 config_parse_wireless_device(struct uci_section *s)
309 {
310 struct wireless_driver *drv;
311 const char *driver_name;
312
313 driver_name = uci_lookup_option_string(uci_ctx, s, "type");
314 if (!driver_name)
315 return;
316
317 drv = avl_find_element(&wireless_drivers, driver_name, drv, node);
318 if (!drv)
319 return;
320
321 blob_buf_init(&b, 0);
322 uci_to_blob(&b, s, drv->device.config);
323 wireless_device_create(drv, s->e.name, b.head);
324 }
325
326 static void
327 config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
328 {
329 char *name;
330
331 name = alloca(strlen(s->type) + 16);
332 sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
333
334 blob_buf_init(&b, 0);
335 uci_to_blob(&b, s, wdev->drv->interface.config);
336 wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
337 }
338
339 static void
340 config_init_wireless(void)
341 {
342 struct wireless_device *wdev;
343 struct uci_element *e;
344 const char *dev_name;
345
346 if (!uci_wireless) {
347 DPRINTF("No wireless configuration found\n");
348 return;
349 }
350
351 vlist_update(&wireless_devices);
352
353 uci_foreach_element(&uci_wireless->sections, e) {
354 struct uci_section *s = uci_to_section(e);
355 if (strcmp(s->type, "wifi-device") != 0)
356 continue;
357
358 config_parse_wireless_device(s);
359 }
360
361 vlist_flush(&wireless_devices);
362
363 vlist_for_each_element(&wireless_devices, wdev, node) {
364 wdev->vif_idx = 0;
365 vlist_update(&wdev->interfaces);
366 }
367
368 uci_foreach_element(&uci_wireless->sections, e) {
369 struct uci_section *s = uci_to_section(e);
370
371 if (strcmp(s->type, "wifi-iface") != 0)
372 continue;
373
374 dev_name = uci_lookup_option_string(uci_ctx, s, "device");
375 if (!dev_name)
376 continue;
377
378 wdev = vlist_find(&wireless_devices, dev_name, wdev, node);
379 if (!wdev) {
380 DPRINTF("device %s not found!\n", dev_name);
381 continue;
382 }
383
384 config_parse_wireless_interface(wdev, s);
385 }
386
387 vlist_for_each_element(&wireless_devices, wdev, node)
388 vlist_flush(&wdev->interfaces);
389 }
390
391 int
392 config_init_all(void)
393 {
394 int ret = 0;
395 char *err;
396
397 uci_network = config_init_package("network");
398 if (!uci_network) {
399 uci_get_errorstr(uci_ctx, &err, NULL);
400 netifd_log_message(L_CRIT, "Failed to load network config (%s)\n", err);
401 free(err);
402 return -1;
403 }
404
405 uci_wireless = config_init_package("wireless");
406 if (!uci_wireless && uci_ctx->err != UCI_ERR_NOTFOUND) {
407 uci_get_errorstr(uci_ctx, &err, NULL);
408 netifd_log_message(L_CRIT, "Failed to load wireless config (%s)\n", err);
409 free(err);
410 ret = -1;
411 }
412
413 vlist_update(&interfaces);
414 config_init = true;
415 device_lock();
416
417 device_reset_config();
418 config_init_devices();
419 config_init_interfaces();
420 config_init_routes();
421 config_init_rules();
422 config_init_globals();
423 config_init_wireless();
424
425 config_init = false;
426 device_unlock();
427
428 device_reset_old();
429 device_init_pending();
430 vlist_flush(&interfaces);
431 device_free_unused(NULL);
432 interface_refresh_assignments(false);
433 interface_start_pending();
434 wireless_start_pending();
435
436 return ret;
437 }