diff options
-rw-r--r-- | config/network | 5 | ||||
-rw-r--r-- | device.c | 6 | ||||
-rw-r--r-- | interface.c | 5 | ||||
-rw-r--r-- | interface.h | 3 | ||||
-rw-r--r-- | ubus.c | 48 |
5 files changed, 51 insertions, 16 deletions
diff --git a/config/network b/config/network index 9b16bba..5514b0b 100644 --- a/config/network +++ b/config/network @@ -42,6 +42,11 @@ config interface wan option username foo option password bar +config interface wlan + option proto static + option ipaddr 192.168.2.1 + option netmask 255.255.255.0 + config interface test option ifname @test option proto static @@ -179,8 +179,7 @@ alias_notify_device(const char *name, struct device *dev) alias->cleanup = !dev; if (dev) { if (dev != alias->dep.dev) { - if (alias->dep.dev) - device_remove_user(&alias->dep); + device_remove_user(&alias->dep); strcpy(alias->dev.ifname, dev->ifname); device_add_user(&alias->dep, dev); } @@ -396,6 +395,9 @@ void device_remove_user(struct device_user *dep) { struct device *dev = dep->dev; + if (!dep->dev) + return; + if (dep->claimed) device_release(dep); diff --git a/interface.c b/interface.c index f03a7b0..8e42f21 100644 --- a/interface.c +++ b/interface.c @@ -122,7 +122,7 @@ __interface_set_up(struct interface *iface) return 0; } -static void +void __interface_set_down(struct interface *iface, bool force) { interface_clear_errors(iface); @@ -194,7 +194,7 @@ interface_claim_device(struct interface *iface) { struct device *dev; - if (iface->proto_handler && + if (iface->ifname && iface->proto_handler && !(iface->proto_handler->flags & PROTO_FLAG_NODEV)) { dev = device_get(iface->ifname, true); if (dev) @@ -208,6 +208,7 @@ interface_cleanup(struct interface *iface) { struct interface_user *dep, *tmp; + iface->hotplug_dev = false; list_for_each_entry_safe(dep, tmp, &iface->users, list) interface_remove_user(dep); diff --git a/interface.h b/interface.h index 7f84060..91cffca 100644 --- a/interface.h +++ b/interface.h @@ -62,6 +62,7 @@ struct interface { /* 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; @@ -98,6 +99,8 @@ void interface_set_proto_state(struct interface *iface, struct interface_proto_s void interface_set_available(struct interface *iface, bool new_state); int interface_set_up(struct interface *iface); int interface_set_down(struct interface *iface); +void __interface_set_down(struct interface *iface, bool force); + void interface_add_user(struct interface_user *dep, struct interface *iface); void interface_remove_user(struct interface_user *dep); @@ -236,6 +236,7 @@ netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { struct interface *iface; + struct device *dev; iface = container_of(obj, struct interface, ubus); @@ -251,8 +252,9 @@ netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj, blobmsg_add_string(&b, "l3_device", iface->l3_dev->dev->ifname); } - if (!(iface->proto_handler->flags & PROTO_FLAG_NODEV)) - blobmsg_add_string(&b, "device", iface->main_dev.dev->ifname); + dev = iface->main_dev.dev; + if (dev && !(iface->proto_handler->flags & PROTO_FLAG_NODEV)) + blobmsg_add_string(&b, "device", dev->ifname); if (!list_is_empty(&iface->errors)) netifd_add_interface_errors(&b, iface); @@ -268,9 +270,10 @@ netifd_iface_handle_device(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { struct interface *iface; - struct device *dev, *main_dev; + struct device *dev, *main_dev = NULL; struct blob_attr *tb[__DEV_MAX]; bool add = !strncmp(method, "add", 3); + const char *devname; int ret; iface = container_of(obj, struct interface, ubus); @@ -280,17 +283,39 @@ netifd_iface_handle_device(struct ubus_context *ctx, struct ubus_object *obj, if (!tb[DEV_NAME]) return UBUS_STATUS_INVALID_ARGUMENT; - main_dev = iface->main_dev.dev; - if (!main_dev) - return UBUS_STATUS_NOT_FOUND; + 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 (!main_dev->hotplug_ops) - return UBUS_STATUS_NOT_SUPPORTED; + if (iface->hotplug_dev) { + if (iface->main_dev.dev) { + interface_set_available(iface, false); + device_remove_user(&iface->main_dev); + } + } else + main_dev = iface->main_dev.dev; dev = device_get(blobmsg_data(tb[DEV_NAME]), add); if (!dev) return UBUS_STATUS_NOT_FOUND; + if (!main_dev) { + if (add) { + device_add_user(&iface->main_dev, dev); + iface->hotplug_dev = true; + } + ret = 0; + goto out; + } + + if (!main_dev->hotplug_ops) { + ret = UBUS_STATUS_NOT_SUPPORTED; + goto out; + } + if (main_dev != dev) { if (add) ret = main_dev->hotplug_ops->add(main_dev, dev); @@ -302,6 +327,7 @@ netifd_iface_handle_device(struct ubus_context *ctx, struct ubus_object *obj, ret = UBUS_STATUS_INVALID_ARGUMENT; } +out: if (add) device_free_unused(dev); @@ -353,10 +379,8 @@ static struct ubus_method iface_object_methods[] = { { .name = "up", .handler = netifd_handle_up }, { .name = "down", .handler = netifd_handle_down }, { .name = "status", .handler = netifd_handle_status }, - { .name = "add_device", .handler = netifd_iface_handle_device, - .policy = dev_policy, .n_policy = __DEV_MAX }, - { .name = "remove_device", .handler = netifd_iface_handle_device, - .policy = dev_policy, .n_policy = __DEV_MAX }, + UBUS_METHOD("add_device", netifd_iface_handle_device, dev_policy ), + UBUS_METHOD("remove_device", netifd_iface_handle_device, dev_policy ), { .name = "notify_proto", .handler = netifd_iface_notify_proto }, { .name = "remove", .handler = netifd_iface_remove } }; |