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_dump_status(struct device
*dev
, struct blob_buf
*b
)
298 struct bridge_state
*bst
;
299 struct bridge_member
*bm
;
302 bst
= container_of(dev
, struct bridge_state
, dev
);
304 list
= blobmsg_open_array(b
, "bridge-members");
305 list_for_each_entry(bm
, &bst
->members
, list
) {
306 blobmsg_add_string(b
, NULL
, bm
->dev
.dev
->ifname
);
308 blobmsg_close_array(b
, list
);
312 bridge_create(const char *name
, struct uci_section
*s
)
314 static const struct device_type bridge_type
= {
317 .dump_status
= bridge_dump_status
,
319 struct bridge_state
*bst
;
322 dev
= get_device(name
, false);
326 bst
= calloc(1, sizeof(*bst
));
330 init_device(&bst
->dev
, &bridge_type
, name
);
332 bst
->set_state
= bst
->dev
.set_state
;
333 bst
->dev
.set_state
= bridge_set_state
;
335 bst
->dev
.hotplug_ops
= &bridge_ops
;
337 INIT_LIST_HEAD(&bst
->members
);
340 bridge_parse_config(bst
, s
);
346 interface_attach_bridge(struct interface
*iface
, struct uci_section
*s
)
349 char brname
[IFNAMSIZ
];
351 snprintf(brname
, IFNAMSIZ
- 1, "br-%s", iface
->name
);
352 brname
[IFNAMSIZ
- 1] = 0;
354 dev
= bridge_create(brname
, s
);
358 add_device_user(&iface
->main_dev
, dev
);