clean up variable names (llif -> dev)
[project/netifd.git] / bridge.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <assert.h>
5 #include <errno.h>
6
7 #include "netifd.h"
8 #include "device.h"
9 #include "interface.h"
10 #include "system.h"
11
12 struct bridge_state {
13         struct device dev;
14         device_state_cb set_state;
15
16         bool active;
17
18         struct list_head members;
19         int n_present;
20 };
21
22 struct bridge_member {
23         struct list_head list;
24         struct bridge_state *bst;
25         struct device_user dev;
26         bool present;
27 };
28
29 static int
30 bridge_disable_member(struct bridge_member *bm)
31 {
32         struct bridge_state *bst = bm->bst;
33
34         if (!bm->present)
35                 return 0;
36
37         system_bridge_delif(&bst->dev, bm->dev.dev);
38         release_device(bm->dev.dev);
39
40         return 0;
41 }
42
43 static int
44 bridge_enable_member(struct bridge_member *bm)
45 {
46         struct bridge_state *bst = bm->bst;
47         int ret;
48
49         if (!bm->present)
50                 return 0;
51
52         ret = claim_device(bm->dev.dev);
53         if (ret < 0)
54                 goto error;
55
56         ret = system_bridge_addif(&bst->dev, bm->dev.dev);
57         if (ret < 0)
58                 goto error;
59
60         return 0;
61
62 error:
63         bm->present = false;
64         bst->n_present--;
65         return ret;
66 }
67
68 static void
69 bridge_member_cb(struct device_user *dev, enum device_event ev)
70 {
71         struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
72         struct bridge_state *bst = bm->bst;
73
74         switch (ev) {
75         case DEV_EVENT_ADD:
76                 assert(!bm->present);
77
78                 bm->present = true;
79                 bst->n_present++;
80
81                 if (bst->dev.active)
82                         bridge_enable_member(bm);
83                 else if (bst->n_present == 1)
84                         set_device_present(&bst->dev, true);
85
86                 break;
87         case DEV_EVENT_REMOVE:
88                 if (!bm->present)
89                         return;
90
91                 if (bst->dev.active)
92                         bridge_disable_member(bm);
93
94                 bm->present = false;
95                 bm->bst->n_present--;
96                 if (bst->n_present == 0)
97                         set_device_present(&bst->dev, false);
98
99                 break;
100         default:
101                 return;
102         }
103 }
104
105 static int
106 bridge_set_down(struct bridge_state *bst)
107 {
108         struct bridge_member *bm;
109
110         bst->set_state(&bst->dev, false);
111
112         list_for_each_entry(bm, &bst->members, list)
113                 bridge_disable_member(bm);
114
115         system_bridge_delbr(&bst->dev);
116
117         return 0;
118 }
119
120 static int
121 bridge_set_up(struct bridge_state *bst)
122 {
123         struct bridge_member *bm;
124         int ret;
125
126         if (!bst->n_present)
127                 return -ENOENT;
128
129         ret = system_bridge_addbr(&bst->dev);
130         if (ret < 0)
131                 goto out;
132
133         list_for_each_entry(bm, &bst->members, list)
134                 bridge_enable_member(bm);
135
136         if (!bst->n_present) {
137                 /* initialization of all member interfaces failed */
138                 system_bridge_delbr(&bst->dev);
139                 set_device_present(&bst->dev, false);
140                 return -ENOENT;
141         }
142
143         ret = bst->set_state(&bst->dev, true);
144         if (ret < 0)
145                 bridge_set_down(bst);
146
147 out:
148         return ret;
149 }
150
151 static int
152 bridge_set_state(struct device *dev, bool up)
153 {
154         struct bridge_state *bst;
155
156         bst = container_of(dev, struct bridge_state, dev);
157
158         if (up)
159                 return bridge_set_up(bst);
160         else
161                 return bridge_set_down(bst);
162 }
163
164 static struct bridge_member *
165 bridge_create_member(struct bridge_state *bst, struct device *dev)
166 {
167         struct bridge_member *bm;
168
169         bm = calloc(1, sizeof(*bm));
170         bm->bst = bst;
171         bm->dev.cb = bridge_member_cb;
172         add_device_user(&bm->dev, dev);
173
174         list_add(&bm->list, &bst->members);
175
176         if (bst->dev.active)
177                 bridge_enable_member(bm);
178
179         return bm;
180 }
181
182 static void
183 bridge_free_member(struct bridge_member *bm)
184 {
185         if (bm->present) {
186                 bridge_member_cb(&bm->dev, DEV_EVENT_REMOVE);
187                 bm->bst->n_present--;
188                 if (bm->bst->dev.active)
189                         bridge_disable_member(bm);
190         }
191
192         list_del(&bm->list);
193         remove_device_user(&bm->dev);
194         free(bm);
195 }
196
197 static void
198 bridge_add_member(struct bridge_state *bst, const char *name)
199 {
200         struct device *dev;
201
202         dev = get_device(name, true);
203         if (!dev)
204                 return;
205
206         bridge_create_member(bst, dev);
207 }
208
209 static int
210 bridge_hotplug_add(struct device *dev, struct device *member)
211 {
212         struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
213
214         bridge_create_member(bst, member);
215
216         return 0;
217 }
218
219 static int
220 bridge_hotplug_del(struct device *dev, struct device *member)
221 {
222         struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
223         struct bridge_member *bm;
224
225         list_for_each_entry(bm, &bst->members, list) {
226                 if (bm->dev.dev != member)
227                         continue;
228
229                 bridge_free_member(bm);
230                 return 0;
231         }
232
233         return -ENOENT;
234 }
235
236 static const struct device_hotplug_ops bridge_ops = {
237         .add = bridge_hotplug_add,
238         .del = bridge_hotplug_del
239 };
240
241 static void
242 bridge_parse_config(struct bridge_state *bst, struct uci_section *s)
243 {
244         struct uci_element *e;
245         struct uci_option *o;
246         char buf[IFNAMSIZ + 1];
247         char *p, *end;
248         int len;
249
250         o = uci_lookup_option(uci_ctx, s, "ifname");
251         if (!o)
252                 return;
253
254         if (o->type == UCI_TYPE_LIST) {
255                 uci_foreach_element(&o->v.list, e)
256                         bridge_add_member(bst, e->name);
257         } else {
258                 p = o->v.string;
259                 do {
260                         if (!*p)
261                                 break;
262
263                         if (*p == ' ')
264                                 continue;
265
266                         end = strchr(p, ' ');
267                         if (!end) {
268                                 bridge_add_member(bst, p);
269                                 break;
270                         }
271
272                         len = end - p;
273                         if (len <= IFNAMSIZ) {
274                                 memcpy(buf, p, len);
275                                 buf[len] = 0;
276                                 bridge_add_member(bst, buf);
277                         }
278                         p = end;
279                 } while (p++);
280         }
281 }
282
283 static void
284 bridge_free(struct device *dev)
285 {
286         struct bridge_state *bst;
287         struct bridge_member *bm;
288
289         bst = container_of(dev, struct bridge_state, dev);
290         while (!list_empty(&bst->members)) {
291                 bm = list_first_entry(&bst->members, struct bridge_member, list);
292                 bridge_free_member(bm);
293         }
294         free(bst);
295 }
296
297 static void
298 bridge_dump_status(struct device *dev, struct blob_buf *b)
299 {
300         struct bridge_state *bst;
301         struct bridge_member *bm;
302         void *list;
303
304         bst = container_of(dev, struct bridge_state, dev);
305
306         list = blobmsg_open_array(b, "bridge-members");
307         list_for_each_entry(bm, &bst->members, list) {
308                 blobmsg_add_string(b, NULL, bm->dev.dev->ifname);
309         }
310         blobmsg_close_array(b, list);
311 }
312
313 struct device *
314 bridge_create(const char *name, struct uci_section *s)
315 {
316         static const struct device_type bridge_type = {
317                 .name = "Bridge",
318                 .free = bridge_free,
319                 .dump_status = bridge_dump_status,
320         };
321         struct bridge_state *bst;
322         struct device *dev;
323
324         dev = get_device(name, false);
325         if (dev)
326                 return NULL;
327
328         bst = calloc(1, sizeof(*bst));
329         if (!bst)
330                 return NULL;
331
332         init_device(&bst->dev, &bridge_type, name);
333
334         bst->set_state = bst->dev.set_state;
335         bst->dev.set_state = bridge_set_state;
336
337         bst->dev.hotplug_ops = &bridge_ops;
338
339         INIT_LIST_HEAD(&bst->members);
340
341         if (s)
342                 bridge_parse_config(bst, s);
343
344         return &bst->dev;
345 }
346
347 int
348 interface_attach_bridge(struct interface *iface, struct uci_section *s)
349 {
350         struct device *dev;
351         char brname[IFNAMSIZ];
352
353         snprintf(brname, IFNAMSIZ - 1, "br-%s", iface->name);
354         brname[IFNAMSIZ - 1] = 0;
355
356         dev = bridge_create(brname, s);
357         if (!dev)
358                 return -1;
359
360         add_device_user(&iface->main_dev, dev);
361         return 0;
362 }