summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface.c130
-rw-r--r--interface.h2
-rw-r--r--proto-shell.c1
3 files changed, 103 insertions, 30 deletions
diff --git a/interface.c b/interface.c
index 9c208a2..4b381a4 100644
--- a/interface.c
+++ b/interface.c
@@ -200,6 +200,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);
@@ -212,42 +215,112 @@ mark_interface_down(struct interface *iface)
void
__interface_set_down(struct interface *iface, bool force)
{
- if (iface->state == IFS_DOWN ||
- iface->state == IFS_TEARDOWN)
+ switch (iface->state) {
+ case IFS_UP:
+ interface_event(iface, IFEV_DOWN);
+ case IFS_SETUP:
+ iface->state = IFS_TEARDOWN;
+ 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)
+{
+ switch (iface->state) {
+ case IFS_UP:
+ if (!iface->enabled || !iface->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)
+ __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);
+}
- if (iface->dynamic)
- vlist_delete(&interfaces, &iface->node);
+static void
+interface_set_link_state(struct interface *iface, bool new_state)
+{
+ if (iface->link_state == new_state)
+ return;
+
+ 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;
+ 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;
default:
- return;
+ break;
}
-
- interface_set_available(iface, new_state);
- if (!new_state && dep->dev->external)
- interface_set_main_dev(iface, NULL);
}
void
@@ -684,7 +757,7 @@ 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 set_l3 = (!dev || iface->main_dev.dev == iface->l3_dev.dev);
bool claimed = iface->l3_dev.claimed;
if (iface->main_dev.dev == dev)
@@ -694,8 +767,10 @@ interface_set_main_dev(struct interface *iface, struct device *dev)
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);
@@ -794,18 +869,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
diff --git a/interface.h b/interface.h
index 4b7de59..1004bdd 100644
--- a/interface.h
+++ b/interface.h
@@ -95,6 +95,8 @@ struct interface {
bool autostart;
bool config_autostart;
bool device_config;
+ bool enabled;
+ bool link_state;
bool dynamic;
time_t start_time;
diff --git a/proto-shell.c b/proto-shell.c
index 6bbfe10..27fe265 100644
--- a/proto-shell.c
+++ b/proto-shell.c
@@ -158,6 +158,7 @@ proto_shell_handler(struct interface_proto_state *proto,
action = "setup";
state->last_error = -1;
proto_shell_clear_host_dep(state);
+ state->sm = S_SETUP;
} else {
if (state->sm == S_TEARDOWN)
return 0;