14 device_state_cb set_state;
18 struct list_head members;
22 struct bridge_member {
23 struct list_head list;
24 struct bridge_state *bst;
25 struct device_user dev;
30 bridge_disable_member(struct bridge_member *bm)
32 struct bridge_state *bst = bm->bst;
37 system_bridge_delif(&bst->dev, bm->dev.dev);
38 release_device(bm->dev.dev);
44 bridge_enable_member(struct bridge_member *bm)
46 struct bridge_state *bst = bm->bst;
52 ret = claim_device(bm->dev.dev);
56 ret = system_bridge_addif(&bst->dev, bm->dev.dev);
69 bridge_member_cb(struct device_user *dev, enum device_event ev)
71 struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
72 struct bridge_state *bst = bm->bst;
82 bridge_enable_member(bm);
83 else if (bst->n_present == 1)
84 set_device_present(&bst->dev, true);
87 case DEV_EVENT_REMOVE:
92 bridge_disable_member(bm);
96 if (bst->n_present == 0)
97 set_device_present(&bst->dev, false);
106 bridge_set_down(struct bridge_state *bst)
108 struct bridge_member *bm;
110 bst->set_state(&bst->dev, false);
112 list_for_each_entry(bm, &bst->members, list)
113 bridge_disable_member(bm);
115 system_bridge_delbr(&bst->dev);
121 bridge_set_up(struct bridge_state *bst)
123 struct bridge_member *bm;
129 ret = system_bridge_addbr(&bst->dev);
133 list_for_each_entry(bm, &bst->members, list)
134 bridge_enable_member(bm);
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);
143 ret = bst->set_state(&bst->dev, true);
145 bridge_set_down(bst);
152 bridge_set_state(struct device *dev, bool up)
154 struct bridge_state *bst;
156 bst = container_of(dev, struct bridge_state, dev);
159 return bridge_set_up(bst);
161 return bridge_set_down(bst);
164 static struct bridge_member *
165 bridge_create_member(struct bridge_state *bst, struct device *dev)
167 struct bridge_member *bm;
169 bm = calloc(1, sizeof(*bm));
171 bm->dev.cb = bridge_member_cb;
172 add_device_user(&bm->dev, dev);
174 list_add(&bm->list, &bst->members);
177 bridge_enable_member(bm);
183 bridge_free_member(struct bridge_member *bm)
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);
193 device_remove_user(&bm->dev);
198 bridge_add_member(struct bridge_state *bst, const char *name)
202 dev = get_device(name, true);
206 bridge_create_member(bst, dev);
210 bridge_hotplug_add(struct device *dev, struct device *member)
212 struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
214 bridge_create_member(bst, member);
220 bridge_hotplug_del(struct device *dev, struct device *member)
222 struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
223 struct bridge_member *bm;
225 list_for_each_entry(bm, &bst->members, list) {
226 if (bm->dev.dev != member)
229 bridge_free_member(bm);
236 static const struct device_hotplug_ops bridge_ops = {
237 .add = bridge_hotplug_add,
238 .del = bridge_hotplug_del
242 bridge_parse_config(struct bridge_state *bst, struct uci_section *s)
244 struct uci_element *e;
245 struct uci_option *o;
246 char buf[IFNAMSIZ + 1];
250 o = uci_lookup_option(uci_ctx, s, "ifname");
254 if (o->type == UCI_TYPE_LIST) {
255 uci_foreach_element(&o->v.list, e)
256 bridge_add_member(bst, e->name);
266 end = strchr(p, ' ');
268 bridge_add_member(bst, p);
273 if (len <= IFNAMSIZ) {
276 bridge_add_member(bst, buf);
284 bridge_free(struct device *dev)
286 struct bridge_state *bst;
287 struct bridge_member *bm;
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);
298 bridge_dump_status(struct device *dev, struct blob_buf *b)
300 struct bridge_state *bst;
301 struct bridge_member *bm;
304 bst = container_of(dev, struct bridge_state, dev);
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);
310 blobmsg_close_array(b, list);
314 bridge_create(const char *name, struct uci_section *s)
316 static const struct device_type bridge_type = {
319 .dump_status = bridge_dump_status,
321 struct bridge_state *bst;
324 dev = get_device(name, false);
328 bst = calloc(1, sizeof(*bst));
332 init_device(&bst->dev, &bridge_type, name);
334 bst->set_state = bst->dev.set_state;
335 bst->dev.set_state = bridge_set_state;
337 bst->dev.hotplug_ops = &bridge_ops;
339 INIT_LIST_HEAD(&bst->members);
342 bridge_parse_config(bst, s);
348 interface_attach_bridge(struct interface *iface, struct uci_section *s)
351 char brname[IFNAMSIZ];
353 snprintf(brname, IFNAMSIZ - 1, "br-%s", iface->name);
354 brname[IFNAMSIZ - 1] = 0;
356 dev = bridge_create(brname, s);
360 add_device_user(&iface->main_dev, dev);