12 device_state_cb set_state;
16 struct list_head members;
20 struct bridge_member {
21 struct list_head list;
22 struct bridge_state *bst;
23 struct device_user dev;
28 bridge_disable_member(struct bridge_member *bm)
30 struct bridge_state *bst = bm->bst;
35 system_bridge_delif(&bst->dev, bm->dev.dev);
36 release_device(bm->dev.dev);
42 bridge_enable_member(struct bridge_member *bm)
44 struct bridge_state *bst = bm->bst;
50 ret = claim_device(bm->dev.dev);
54 ret = system_bridge_addif(&bst->dev, bm->dev.dev);
67 bridge_member_cb(struct device_user *dev, enum device_event ev)
69 struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
70 struct bridge_state *bst = bm->bst;
80 bridge_enable_member(bm);
81 else if (bst->n_present == 1)
82 set_device_present(&bst->dev, true);
85 case DEV_EVENT_REMOVE:
90 bridge_disable_member(bm);
94 if (bst->n_present == 0)
95 set_device_present(&bst->dev, false);
104 bridge_set_down(struct bridge_state *bst)
106 struct bridge_member *bm;
108 bst->set_state(&bst->dev, false);
110 list_for_each_entry(bm, &bst->members, list)
111 bridge_disable_member(bm);
113 system_bridge_delbr(&bst->dev);
119 bridge_set_up(struct bridge_state *bst)
121 struct bridge_member *bm;
127 ret = system_bridge_addbr(&bst->dev);
131 list_for_each_entry(bm, &bst->members, list)
132 bridge_enable_member(bm);
134 if (!bst->n_present) {
135 /* initialization of all member interfaces failed */
136 system_bridge_delbr(&bst->dev);
137 set_device_present(&bst->dev, false);
141 ret = bst->set_state(&bst->dev, true);
143 bridge_set_down(bst);
150 bridge_set_state(struct device *dev, bool up)
152 struct bridge_state *bst;
154 bst = container_of(dev, struct bridge_state, dev);
157 return bridge_set_up(bst);
159 return bridge_set_down(bst);
162 static struct bridge_member *
163 bridge_create_member(struct bridge_state *bst, struct device *dev)
165 struct bridge_member *bm;
167 bm = calloc(1, sizeof(*bm));
169 bm->dev.cb = bridge_member_cb;
170 add_device_user(&bm->dev, dev);
172 list_add(&bm->list, &bst->members);
175 bridge_enable_member(bm);
181 bridge_free_member(struct bridge_member *bm)
184 bridge_member_cb(&bm->dev, DEV_EVENT_REMOVE);
185 bm->bst->n_present--;
186 if (bm->bst->dev.active)
187 bridge_disable_member(bm);
191 remove_device_user(&bm->dev);
196 bridge_add_member(struct bridge_state *bst, const char *name)
200 dev = get_device(name, true);
204 bridge_create_member(bst, dev);
208 bridge_hotplug_add(struct device *dev, struct device *member)
210 struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
212 bridge_create_member(bst, member);
218 bridge_hotplug_del(struct device *dev, struct device *member)
220 struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
221 struct bridge_member *bm;
223 list_for_each_entry(bm, &bst->members, list) {
224 if (bm->dev.dev != member)
227 bridge_free_member(bm);
234 static const struct device_hotplug_ops bridge_ops = {
235 .add = bridge_hotplug_add,
236 .del = bridge_hotplug_del
240 bridge_parse_config(struct bridge_state *bst, struct uci_section *s)
242 struct uci_element *e;
243 struct uci_option *o;
244 char buf[IFNAMSIZ + 1];
248 o = uci_lookup_option(uci_ctx, s, "ifname");
252 if (o->type == UCI_TYPE_LIST) {
253 uci_foreach_element(&o->v.list, e)
254 bridge_add_member(bst, e->name);
264 end = strchr(p, ' ');
266 bridge_add_member(bst, p);
271 if (len <= IFNAMSIZ) {
274 bridge_add_member(bst, buf);
282 bridge_free(struct device *dev)
284 struct bridge_state *bst;
285 struct bridge_member *bm;
287 bst = container_of(dev, struct bridge_state, dev);
288 while (!list_empty(&bst->members)) {
289 bm = list_first_entry(&bst->members, struct bridge_member, list);
290 bridge_free_member(bm);
296 bridge_create(const char *name, struct uci_section *s)
298 static const struct device_type bridge_type = {
302 struct bridge_state *bst;
305 dev = get_device(name, false);
309 bst = calloc(1, sizeof(*bst));
313 init_device(&bst->dev, &bridge_type, name);
315 bst->set_state = bst->dev.set_state;
316 bst->dev.set_state = bridge_set_state;
318 bst->dev.hotplug_ops = &bridge_ops;
320 INIT_LIST_HEAD(&bst->members);
323 bridge_parse_config(bst, s);
329 interface_attach_bridge(struct interface *iface, struct uci_section *s)
332 char brname[IFNAMSIZ];
334 snprintf(brname, IFNAMSIZ - 1, "br-%s", iface->name);
335 brname[IFNAMSIZ - 1] = 0;
337 dev = bridge_create(brname, s);
341 add_device_user(&iface->main_dev, dev);