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 remove_device_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
);