X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=interface.c;h=65bc37d07154d64fbf010c7150d213fd0e65845f;hp=b2c8bafcd80ef40822355121a883af011e7e5ab8;hb=c9dadceeba2faa311e4a086f1c6a5eb0d5577c9f;hpb=9cd56141e80ea7d19350584d382d303f884d0aa5 diff --git a/interface.c b/interface.c index b2c8baf..65bc37d 100644 --- a/interface.c +++ b/interface.c @@ -43,6 +43,7 @@ enum { IFACE_ATTR_IP6TABLE, IFACE_ATTR_IP6CLASS, IFACE_ATTR_DELEGATE, + IFACE_ATTR_FORCE_LINK, IFACE_ATTR_MAX }; @@ -62,6 +63,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_IP6TABLE] = { .name = "ip6table", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_IP6CLASS] = { .name = "ip6class", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_DELEGATE] = { .name = "delegate", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_FORCE_LINK] = { .name = "force_link", .type = BLOBMSG_TYPE_BOOL }, }; static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = { @@ -207,6 +209,9 @@ mark_interface_down(struct interface *iface) { enum interface_state state = iface->state; + if (state == IFS_DOWN) + return; + iface->state = IFS_DOWN; if (state == IFS_UP) interface_event(iface, IFEV_DOWN); @@ -219,42 +224,120 @@ mark_interface_down(struct interface *iface) void __interface_set_down(struct interface *iface, bool force) { - if (iface->state == IFS_DOWN || - iface->state == IFS_TEARDOWN) + enum interface_state state = iface->state; + switch (state) { + case IFS_UP: + case IFS_SETUP: + iface->state = IFS_TEARDOWN; + if (state == IFS_UP) + interface_event(iface, IFEV_DOWN); + + interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force); + if (force) + interface_flush_state(iface); + + if (iface->dynamic) + vlist_delete(&interfaces, &iface->node); + break; + + case IFS_DOWN: + if (iface->main_dev.dev) + device_release(&iface->main_dev); + case IFS_TEARDOWN: + default: + break; + } +} + +static int +__interface_set_up(struct interface *iface) +{ + int ret; + + netifd_log_message(L_NOTICE, "Interface '%s' is setting up now\n", iface->name); + + iface->state = IFS_SETUP; + ret = interface_proto_event(iface->proto, PROTO_CMD_SETUP, false); + if (ret) + mark_interface_down(iface); + + return ret; +} + +static void +interface_check_state(struct interface *iface) +{ + bool link_state = iface->link_state || iface->force_link; + + switch (iface->state) { + case IFS_UP: + if (!iface->enabled || !link_state) { + mark_interface_down(iface); + interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false); + } + break; + case IFS_DOWN: + if (iface->autostart && iface->enabled && link_state && !config_init) + __interface_set_up(iface); + break; + default: + break; + } +} + +static void +interface_set_enabled(struct interface *iface, bool new_state) +{ + if (iface->enabled == new_state) return; - if (iface->state == IFS_UP) - interface_event(iface, IFEV_DOWN); - iface->state = IFS_TEARDOWN; - interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force); - if (force) - interface_flush_state(iface); + netifd_log_message(L_NOTICE, "Interface '%s' is %s\n", iface->name, new_state ? "enabled" : "disabled"); + iface->enabled = new_state; + interface_check_state(iface); +} + +static void +interface_set_link_state(struct interface *iface, bool new_state) +{ + if (iface->link_state == new_state) + return; - if (iface->dynamic) - vlist_delete(&interfaces, &iface->node); + netifd_log_message(L_NOTICE, "Interface '%s' has link connectivity %s\n", iface->name, new_state ? "" : "loss"); + iface->link_state = new_state; + interface_check_state(iface); } static void interface_cb(struct device_user *dep, enum device_event ev) { struct interface *iface; - bool new_state; + bool new_state = false; iface = container_of(dep, struct interface, main_dev); switch (ev) { case DEV_EVENT_ADD: new_state = true; - break; case DEV_EVENT_REMOVE: - new_state = false; + interface_set_available(iface, new_state); + if (!new_state && dep->dev->external) + interface_set_main_dev(iface, NULL); break; - default: + case DEV_EVENT_UP: + new_state = true; + case DEV_EVENT_DOWN: + interface_set_enabled(iface, new_state); + break; + case DEV_EVENT_LINK_UP: + new_state = true; + case DEV_EVENT_LINK_DOWN: + interface_set_link_state(iface, new_state); + break; + case DEV_EVENT_TOPO_CHANGE: + interface_proto_event(iface->proto, PROTO_CMD_RENEW, false); return; + default: + break; } - - interface_set_available(iface, new_state); - if (!new_state && dep->dev->external) - interface_set_main_dev(iface, NULL); } void @@ -498,6 +581,9 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve return; } + if (!iface->l3_dev.dev) + interface_set_l3_dev(iface, iface->main_dev.dev); + interface_ip_set_enabled(&iface->config_ip, true); system_flush_routes(); iface->state = IFS_UP; @@ -513,6 +599,8 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve mark_interface_down(iface); if (iface->main_dev.dev) device_release(&iface->main_dev); + if (iface->l3_dev.dev) + device_remove_user(&iface->l3_dev); interface_handle_config_change(iface); break; case IFPEV_LINK_LOST: @@ -523,6 +611,8 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve mark_interface_down(iface); iface->state = IFS_SETUP; break; + default: + return; } interface_write_resolv_conf(); @@ -573,6 +663,7 @@ interface_alloc(const char *name, struct blob_attr *config) proto_attach_interface(iface, proto_name); iface->autostart = blobmsg_get_bool_default(tb[IFACE_ATTR_AUTO], true); + iface->force_link = blobmsg_get_bool_default(tb[IFACE_ATTR_FORCE_LINK], false); iface->proto_ip.no_defaultroute = !blobmsg_get_bool_default(tb[IFACE_ATTR_DEFAULTROUTE], true); iface->proto_ip.no_dns = @@ -684,18 +775,16 @@ interface_set_l3_dev(struct interface *iface, struct device *dev) void interface_set_main_dev(struct interface *iface, struct device *dev) { - bool set_l3 = (iface->main_dev.dev == iface->l3_dev.dev); bool claimed = iface->l3_dev.claimed; if (iface->main_dev.dev == dev) return; - if (set_l3) - interface_set_l3_dev(iface, dev); - device_add_user(&iface->main_dev, dev); - if (!dev) + if (!dev) { + interface_set_link_state(iface, false); return; + } if (claimed) device_claim(&iface->l3_dev); @@ -718,7 +807,7 @@ interface_remove_link(struct interface *iface, struct device *dev) if (dev != iface->main_dev.dev) return UBUS_STATUS_INVALID_ARGUMENT; - device_remove_user(&iface->main_dev); + interface_set_main_dev(iface, NULL); return 0; } @@ -764,7 +853,7 @@ interface_handle_link(struct interface *iface, const char *name, bool add) if (iface->device_config) device_set_config(dev, &simple_device_type, iface->config); - system_if_apply_settings(dev, &dev->settings); + system_if_apply_settings(dev, &dev->settings, dev->settings.flags); ret = interface_add_link(iface, dev); } else { ret = interface_remove_link(iface, dev); @@ -794,18 +883,13 @@ interface_set_up(struct interface *iface) if (iface->main_dev.dev) { ret = device_claim(&iface->main_dev); - if (ret) - return ret; - } - - iface->state = IFS_SETUP; - ret = interface_proto_event(iface->proto, PROTO_CMD_SETUP, false); - if (ret) { - mark_interface_down(iface); - return ret; + if (!ret) + interface_check_state(iface); } + else + ret = __interface_set_up(iface); - return 0; + return ret; } int @@ -906,6 +990,7 @@ interface_change_config(struct interface *if_old, struct interface *if_new) if_old->ifname = if_new->ifname; if_old->parent_ifname = if_new->parent_ifname; if_old->proto_handler = if_new->proto_handler; + if_old->force_link = if_new->force_link; if_old->proto_ip.no_dns = if_new->proto_ip.no_dns; interface_replace_dns(&if_old->config_ip, &if_new->config_ip); @@ -934,6 +1019,7 @@ interface_change_config(struct interface *if_old, struct interface *if_new) } interface_write_resolv_conf(); + interface_check_state(if_old); out: if_new->config = NULL;