remove code duplication
[project/netifd.git] / config.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #include "netifd.h"
6 #include "interface.h"
7 #include "proto.h"
8
9 struct uci_context *uci_ctx;
10 static struct uci_package *uci_network;
11 bool config_init = false;
12 static struct blob_buf b;
13
14
15 static void uci_attr_to_blob(struct blob_buf *b, const char *str,
16                              const char *name, enum blobmsg_type type)
17 {
18         char *err;
19         int intval;
20
21         switch (type) {
22         case BLOBMSG_TYPE_STRING:
23                 blobmsg_add_string(b, name, str);
24                 break;
25         case BLOBMSG_TYPE_BOOL:
26                 if (!strcmp(str, "true") || !strcmp(str, "1"))
27                         intval = 1;
28                 else if (!strcmp(str, "false") || !strcmp(str, "0"))
29                         intval = 0;
30                 else
31                         return;
32
33                 blobmsg_add_u8(b, name, intval);
34                 break;
35         case BLOBMSG_TYPE_INT32:
36                 intval = strtol(str, &err, 0);
37                 if (*err)
38                         return;
39
40                 blobmsg_add_u32(b, name, intval);
41                 break;
42         default:
43                 break;
44         }
45 }
46
47 static void uci_array_to_blob(struct blob_buf *b, struct uci_option *o,
48                               enum blobmsg_type type)
49 {
50         struct uci_element *e;
51         char *str, *next, *word;
52
53         if (o->type == UCI_TYPE_LIST) {
54                 uci_foreach_element(&o->v.list, e) {
55                         uci_attr_to_blob(b, e->name, NULL, type);
56                 }
57                 return;
58         }
59
60         str = strdup(o->v.string);
61         next = str;
62
63         while ((word = strsep(&next, " \t")) != NULL) {
64                 if (!*word)
65                         continue;
66
67                 uci_attr_to_blob(b, word, NULL, type);
68         }
69
70         free(str);
71 }
72
73 static void __uci_to_blob(struct blob_buf *b, struct uci_section *s,
74                           const struct config_param_list *p)
75 {
76         const struct blobmsg_policy *attr = NULL;
77         struct uci_element *e;
78         struct uci_option *o;
79         void *array;
80         int i;
81
82         uci_foreach_element(&s->options, e) {
83                 for (i = 0; i < p->n_params; i++) {
84                         attr = &p->params[i];
85                         if (!strcmp(attr->name, e->name))
86                                 break;
87                 }
88
89                 if (i == p->n_params)
90                         continue;
91
92                 o = uci_to_option(e);
93
94                 if (attr->type == BLOBMSG_TYPE_ARRAY) {
95                         if (!p->info)
96                                 continue;
97
98                         array = blobmsg_open_array(b, attr->name);
99                         uci_array_to_blob(b, o, p->info[i].type);
100                         blobmsg_close_array(b, array);
101                         continue;
102                 }
103
104                 if (o->type == UCI_TYPE_LIST)
105                         continue;
106
107                 uci_attr_to_blob(b, o->v.string, attr->name, attr->type);
108         }
109 }
110
111 static void uci_to_blob(struct blob_buf *b, struct uci_section *s,
112                         const struct config_param_list *p)
113 {
114         int i;
115
116         __uci_to_blob(b, s, p);
117         for (i = 0; i < p->n_next; i++)
118                 uci_to_blob(b, s, p->next[i]);
119 }
120
121 static int
122 config_parse_bridge_interface(struct uci_section *s)
123 {
124         char *name;
125
126         name = alloca(strlen(s->e.name) + 4);
127         sprintf(name, "br-%s", s->e.name);
128         blobmsg_add_string(&b, "name", name);
129
130         uci_to_blob(&b, s, bridge_device_type.config_params);
131         if (!bridge_device_type.create(b.head)) {
132                 DPRINTF("Failed to create bridge for interface '%s'\n", s->e.name);
133                 return -EINVAL;
134         }
135
136         blob_buf_init(&b, 0);
137         blobmsg_add_string(&b, "ifname", name);
138         return 0;
139 }
140
141 static void
142 config_parse_interface(struct uci_section *s)
143 {
144         struct interface *iface;
145         const char *type;
146
147         DPRINTF("Create interface '%s'\n", s->e.name);
148
149         blob_buf_init(&b, 0);
150
151         type = uci_lookup_option_string(uci_ctx, s, "type");
152         if (type && !strcmp(type, "bridge"))
153                 if (config_parse_bridge_interface(s))
154                         return;
155
156         uci_to_blob(&b, s, &interface_attr_list);
157         iface = interface_alloc(s->e.name, b.head);
158         if (!iface)
159                 return;
160
161         blob_buf_init(&b, 0);
162         if (iface->proto_handler && iface->proto_handler->config_params)
163                 uci_to_blob(&b, s, iface->proto_handler->config_params);
164
165         proto_init_interface(iface, b.head);
166 }
167
168 void
169 config_init_devices(void)
170 {
171         struct uci_element *e;
172
173         uci_foreach_element(&uci_network->sections, e) {
174                 struct uci_section *s = uci_to_section(e);
175                 const struct device_type *devtype;
176                 const char *type;
177
178                 if (strcmp(s->type, "device") != 0)
179                         continue;
180
181                 blob_buf_init(&b, 0);
182                 type = uci_lookup_option_string(uci_ctx, s, "type");
183                 if (type && !strcmp(type, "bridge"))
184                         devtype = &bridge_device_type;
185                 else
186                         devtype = &simple_device_type;
187
188                 uci_to_blob(&b, s, devtype->config_params);
189                 devtype->create(b.head);
190         }
191 }
192
193 void
194 config_init_interfaces(const char *name)
195 {
196         struct uci_context *ctx;
197         struct uci_package *p = NULL;
198         struct uci_element *e;
199
200         ctx = uci_alloc_context();
201         uci_ctx = ctx;
202
203         uci_set_confdir(ctx, "./config");
204
205         if (uci_load(ctx, "network", &p)) {
206                 fprintf(stderr, "Failed to load network config\n");
207                 return;
208         }
209
210         uci_network = p;
211         config_init = true;
212
213         config_init_devices();
214
215         uci_foreach_element(&p->sections, e) {
216                 struct uci_section *s = uci_to_section(e);
217
218                 if (name && strcmp(s->e.name, name) != 0)
219                         continue;
220
221                 if (!strcmp(s->type, "interface"))
222                         config_parse_interface(s);
223         }
224         device_free_unused(NULL);
225         config_init = false;
226
227         interface_start_pending();
228 }