bool present;
};
+static void bridge_free_member(struct bridge_member *bm);
+
static int
bridge_disable_member(struct bridge_member *bm)
{
if (bst->n_present == 0)
device_set_present(&bst->dev, false);
+ if (dev->hotplug)
+ bridge_free_member(bm);
break;
default:
return;
}
static struct bridge_member *
-bridge_create_member(struct bridge_state *bst, struct device *dev)
+bridge_create_member(struct bridge_state *bst, struct device *dev, bool hotplug)
{
struct bridge_member *bm;
bm->bst = bst;
bm->dev.cb = bridge_member_cb;
device_add_user(&bm->dev, dev);
+ bm->dev.hotplug = hotplug;
list_add_tail(&bm->list, &bst->members);
if (!dev)
return;
- bridge_create_member(bst, dev);
+ bridge_create_member(bst, dev, false);
}
static int
{
struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
- bridge_create_member(bst, member);
+ bridge_create_member(bst, member, true);
return 0;
}
uci_network = p;
config_init = true;
+ device_lock();
device_reset_config();
config_init_devices();
if (!strcmp(s->type, "interface"))
config_parse_interface(s);
}
+
config_init = false;
+ device_unlock();
device_reset_old();
device_init_pending();
.params = dev_attrs,
};
+static int __devlock = 0;
+
+void device_lock(void)
+{
+ __devlock++;
+}
+
+void device_unlock(void)
+{
+ __devlock--;
+ if (!__devlock)
+ device_free_unused(NULL);
+}
+
static struct device *
simple_device_create(const char *name, struct blob_attr *attr)
{
{
struct alias_device *alias;
+ device_lock();
+
alias = avl_find_element(&aliases, name, alias, avl);
if (!alias)
return;
if (!dev && alias->dep.dev && !alias->dep.dev->active)
device_remove_user(&alias->dep);
+
+ device_unlock();
}
static int set_device_state(struct device *dev, bool state)
if (!dep->dev)
return;
+ dep->hotplug = false;
if (dep->claimed)
device_release(dep);
struct list_head list;
bool claimed;
+ bool hotplug;
+
struct device *dev;
void (*cb)(struct device_user *, enum device_event);
};
extern const struct device_type simple_device_type;
extern const struct device_type bridge_device_type;
+void device_lock(void);
+void device_unlock(void);
+
struct device *device_create(const char *name, const struct device_type *type,
struct blob_attr *config);
void device_init_settings(struct device *dev, struct blob_attr **tb);
}
static void
-mark_interface_down(struct interface *iface)
+interface_flush_state(struct interface *iface)
{
interface_clear_dns(iface);
vlist_flush_all(&iface->proto_addr);
vlist_flush_all(&iface->proto_route);
if (iface->main_dev.dev)
device_release(&iface->main_dev);
+}
+
+static void
+mark_interface_down(struct interface *iface)
+{
+ interface_flush_state(iface);
iface->state = IFS_DOWN;
}
iface->state = IFS_TEARDOWN;
interface_event(iface, IFEV_DOWN);
interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force);
+ if (force)
+ interface_flush_state(iface);
}
static void
{
struct interface_user *dep, *tmp;
- iface->hotplug_dev = false;
list_for_each_entry_safe(dep, tmp, &iface->users, list)
interface_remove_user(dep);
/* main interface that the interface is bound to */
struct device_user main_dev;
- bool hotplug_dev;
/* interface that layer 3 communication will go through */
struct device_user *l3_dev;
return UBUS_STATUS_INVALID_ARGUMENT;
devname = blobmsg_data(tb[DEV_NAME]);
- dev = iface->main_dev.dev;
- if (iface->hotplug_dev && dev && !add) {
- if (strcmp(dev->ifname, devname) != 0)
- return UBUS_STATUS_INVALID_ARGUMENT;
- }
- if (iface->hotplug_dev) {
- if (iface->main_dev.dev) {
+ device_lock();
+
+ if (iface->main_dev.hotplug) {
+ dev = iface->main_dev.dev;
+
+ if (dev) {
+ if (!add && strcmp(dev->ifname, devname) != 0) {
+ ret = UBUS_STATUS_INVALID_ARGUMENT;
+ goto out;
+ }
+
interface_set_available(iface, false);
device_remove_user(&iface->main_dev);
}
main_dev = iface->main_dev.dev;
dev = device_get(blobmsg_data(tb[DEV_NAME]), add);
- if (!dev)
- return UBUS_STATUS_NOT_FOUND;
+ if (!dev && (main_dev || add)) {
+ ret = UBUS_STATUS_NOT_FOUND;
+ goto out;
+ }
if (!main_dev) {
if (add) {
device_add_user(&iface->main_dev, dev);
- iface->hotplug_dev = true;
+ iface->main_dev.hotplug = true;
}
ret = 0;
goto out;
}
out:
- if (add)
- device_free_unused(dev);
+ device_unlock();
return ret;
}