IFACE_ATTR_IP6TABLE,
IFACE_ATTR_IP6CLASS,
IFACE_ATTR_DELEGATE,
+ IFACE_ATTR_FORCE_LINK,
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] = {
void
__interface_set_down(struct interface *iface, bool force)
{
- switch (iface->state) {
+ enum interface_state state = iface->state;
+ switch (state) {
case IFS_UP:
- interface_event(iface, IFEV_DOWN);
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);
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 || !iface->link_state) {
+ if (!iface->enabled || !link_state) {
mark_interface_down(iface);
interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false);
}
break;
case IFS_DOWN:
- if (iface->enabled && iface->link_state && !config_init)
+ if (iface->autostart && iface->enabled && link_state && !config_init)
__interface_set_up(iface);
break;
default:
new_state = true;
case DEV_EVENT_REMOVE:
interface_set_available(iface, new_state);
- if (!new_state && dep->dev->external)
+ if (!new_state && dep->dev && dep->dev->external)
interface_set_main_dev(iface, NULL);
break;
case DEV_EVENT_UP:
break;
case DEV_EVENT_LINK_UP:
new_state = true;
- case DEV_EVENT_LINK_DOWN:
+ 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_clear_errors(iface);
interface_set_proto_state(iface, NULL);
- if (iface->main_dev.dev)
- interface_set_main_dev(iface, NULL);
+ interface_set_main_dev(iface, NULL);
+ interface_set_l3_dev(iface, NULL);
}
static void
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;
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:
mark_interface_down(iface);
iface->state = IFS_SETUP;
break;
+ default:
+ return;
}
interface_write_resolv_conf();
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 =
void interface_set_dynamic(struct interface *iface)
{
iface->dynamic = true;
+ iface->autostart = true;
iface->node.version = -1; // Don't delete on reload
}
device_add_user(&iface->l3_dev, dev);
if (dev) {
- if (claimed)
- device_claim(&iface->l3_dev);
+ if (claimed) {
+ if (device_claim(&iface->l3_dev) < 0)
+ return;
+ }
interface_ip_set_enabled(&iface->config_ip, enabled);
}
}
void
interface_set_main_dev(struct interface *iface, struct device *dev)
{
- bool set_l3 = (!dev || 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);
-
+ interface_set_available(iface, false);
device_add_user(&iface->main_dev, dev);
if (!dev) {
interface_set_link_state(iface, false);
return;
}
- if (claimed)
- device_claim(&iface->l3_dev);
+ if (claimed) {
+ if (device_claim(&iface->l3_dev) < 0)
+ return;
+ }
if (!iface->l3_dev.dev)
interface_set_l3_dev(iface, 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;
}
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);
}
interface_write_resolv_conf();
+ if (if_old->main_dev.dev)
+ interface_check_state(if_old);
out:
if_new->config = NULL;