summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bridge.c58
-rw-r--r--device.c34
-rw-r--r--device.h17
-rw-r--r--interface.c21
-rw-r--r--ubus.c6
5 files changed, 113 insertions, 23 deletions
diff --git a/bridge.c b/bridge.c
index 099dfe4..397ac97 100644
--- a/bridge.c
+++ b/bridge.c
@@ -122,6 +122,7 @@ struct bridge_member {
struct device_user dev;
uint16_t pvid;
bool present;
+ bool active;
char name[];
};
@@ -299,19 +300,21 @@ bridge_set_vlan_state(struct bridge_state *bst, struct bridge_vlan *vlan, bool a
}
static int
-bridge_disable_member(struct bridge_member *bm)
+bridge_disable_member(struct bridge_member *bm, bool keep_dev)
{
struct bridge_state *bst = bm->bst;
struct bridge_vlan *vlan;
- if (!bm->present)
+ if (!bm->present || !bm->active)
return 0;
+ bm->active = false;
vlist_for_each_element(&bst->dev.vlans, vlan, node)
bridge_set_member_vlan(bm, vlan, false);
system_bridge_delif(&bst->dev, bm->dev.dev);
- device_release(&bm->dev);
+ if (!keep_dev)
+ device_release(&bm->dev);
device_broadcast_event(&bst->dev, DEV_EVENT_TOPO_CHANGE);
@@ -356,6 +359,7 @@ bridge_enable_member(struct bridge_member *bm)
{
struct bridge_state *bst = bm->bst;
struct bridge_vlan *vlan;
+ struct device *dev;
int ret;
if (!bm->present)
@@ -375,12 +379,20 @@ bridge_enable_member(struct bridge_member *bm)
if (ret < 0)
goto error;
+ dev = bm->dev.dev;
+ if (dev->settings.auth && !dev->auth_status)
+ return -1;
+
+ if (bm->active)
+ return 0;
+
ret = system_bridge_addif(&bst->dev, bm->dev.dev);
if (ret < 0) {
D(DEVICE, "Bridge device %s could not be added\n", bm->dev.dev->ifname);
goto error;
}
+ bm->active = true;
if (bst->has_vlans) {
/* delete default VLAN 1 */
system_bridge_vlan(bm->dev.dev->ifname, 1, false, 0);
@@ -412,7 +424,7 @@ bridge_remove_member(struct bridge_member *bm)
return;
if (bst->dev.active)
- bridge_disable_member(bm);
+ bridge_disable_member(bm, false);
bm->present = false;
bm->bst->n_present--;
@@ -481,10 +493,11 @@ bridge_check_retry(struct bridge_state *bst)
}
static void
-bridge_member_cb(struct device_user *dev, enum device_event ev)
+bridge_member_cb(struct device_user *dep, enum device_event ev)
{
- struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
+ struct bridge_member *bm = container_of(dep, struct bridge_member, dev);
struct bridge_state *bst = bm->bst;
+ struct device *dev = dep->dev;
switch (ev) {
case DEV_EVENT_ADD:
@@ -495,19 +508,30 @@ bridge_member_cb(struct device_user *dev, enum device_event ev)
if (bst->n_present == 1)
device_set_present(&bst->dev, true);
- if (bst->dev.active && !bridge_enable_member(bm)) {
- /*
- * Adding a bridge member can overwrite the bridge mtu
- * in the kernel, apply the bridge settings in case the
- * bridge mtu is set
- */
- system_if_apply_settings(&bst->dev, &bst->dev.settings,
- DEV_OPT_MTU | DEV_OPT_MTU6);
- }
+ fallthrough;
+ case DEV_EVENT_AUTH_UP:
+ if (!bst->dev.active)
+ break;
+
+ if (bridge_enable_member(bm))
+ break;
+
+ /*
+ * Adding a bridge member can overwrite the bridge mtu
+ * in the kernel, apply the bridge settings in case the
+ * bridge mtu is set
+ */
+ system_if_apply_settings(&bst->dev, &bst->dev.settings,
+ DEV_OPT_MTU | DEV_OPT_MTU6);
+ break;
+ case DEV_EVENT_LINK_DOWN:
+ if (!dev->settings.auth)
+ break;
+ bridge_disable_member(bm, true);
break;
case DEV_EVENT_REMOVE:
- if (dev->hotplug) {
+ if (dep->hotplug) {
vlist_delete(&bst->members, &bm->node);
return;
}
@@ -529,7 +553,7 @@ bridge_set_down(struct bridge_state *bst)
bst->set_state(&bst->dev, false);
vlist_for_each_element(&bst->members, bm, node)
- bridge_disable_member(bm);
+ bridge_disable_member(bm, false);
bridge_disable_interface(bst);
diff --git a/device.c b/device.c
index 7f011b6..26254cc 100644
--- a/device.c
+++ b/device.c
@@ -59,6 +59,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
[DEV_ATTR_DROP_GRATUITOUS_ARP] = { .name = "drop_gratuitous_arp", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_DROP_UNSOLICITED_NA] = { .name = "drop_unsolicited_na", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_ARP_ACCEPT] = { .name = "arp_accept", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_AUTH] = { .name = "auth", .type = BLOBMSG_TYPE_BOOL },
};
const struct uci_blob_param_list device_attr_list = {
@@ -270,6 +271,7 @@ device_merge_settings(struct device *dev, struct device_settings *n)
s->drop_unsolicited_na : os->drop_unsolicited_na;
n->arp_accept = s->flags & DEV_OPT_ARP_ACCEPT ?
s->arp_accept : os->arp_accept;
+ n->auth = s->flags & DEV_OPT_AUTH ? s->auth : os->auth;
n->flags = s->flags | os->flags | os->valid_flags;
}
@@ -439,6 +441,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
s->flags |= DEV_OPT_ARP_ACCEPT;
}
+ if ((cur = tb[DEV_ATTR_AUTH])) {
+ s->auth = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_AUTH;
+ }
+
device_set_disabled(dev, disabled);
}
@@ -716,6 +723,28 @@ device_refresh_present(struct device *dev)
__device_set_present(dev, state);
}
+void
+device_set_auth_status(struct device *dev, bool value)
+{
+ if (dev->auth_status == value)
+ return;
+
+ dev->auth_status = value;
+ if (!dev->present)
+ return;
+
+ if (dev->auth_status) {
+ device_broadcast_event(dev, DEV_EVENT_AUTH_UP);
+ return;
+ }
+
+ device_broadcast_event(dev, DEV_EVENT_LINK_DOWN);
+ if (!dev->link_active)
+ return;
+
+ device_broadcast_event(dev, DEV_EVENT_LINK_UP);
+}
+
void device_set_present(struct device *dev, bool state)
{
if (dev->sys_present == state)
@@ -734,6 +763,8 @@ void device_set_link(struct device *dev, bool state)
netifd_log_message(L_NOTICE, "%s '%s' link is %s\n", dev->type->name, dev->ifname, state ? "up" : "down" );
dev->link_active = state;
+ if (!state)
+ dev->auth_status = false;
device_broadcast_event(dev, state ? DEV_EVENT_LINK_UP : DEV_EVENT_LINK_DOWN);
}
@@ -1091,6 +1122,7 @@ device_dump_status(struct blob_buf *b, struct device *dev)
blobmsg_add_u8(b, "up", !!dev->active);
blobmsg_add_u8(b, "carrier", !!dev->link_active);
+ blobmsg_add_u8(b, "auth_status", !!dev->auth_status);
if (dev->type->dump_info)
dev->type->dump_info(dev, b);
@@ -1157,6 +1189,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
blobmsg_add_u8(b, "drop_unsolicited_na", st.drop_unsolicited_na);
if (st.flags & DEV_OPT_ARP_ACCEPT)
blobmsg_add_u8(b, "arp_accept", st.arp_accept);
+ if (st.flags & DEV_OPT_AUTH)
+ blobmsg_add_u8(b, "auth", st.auth);
}
s = blobmsg_open_table(b, "statistics");
diff --git a/device.h b/device.h
index f6eaf27..ed07791 100644
--- a/device.h
+++ b/device.h
@@ -59,6 +59,7 @@ enum {
DEV_ATTR_DROP_GRATUITOUS_ARP,
DEV_ATTR_DROP_UNSOLICITED_NA,
DEV_ATTR_ARP_ACCEPT,
+ DEV_ATTR_AUTH,
__DEV_ATTR_MAX,
};
@@ -100,7 +101,7 @@ enum {
DEV_OPT_MLDVERSION = (1 << 8),
DEV_OPT_NEIGHREACHABLETIME = (1 << 9),
DEV_OPT_DEFAULT_MACADDR = (1 << 10),
- /* 1 bit hole */
+ DEV_OPT_AUTH = (1 << 11),
DEV_OPT_MTU6 = (1 << 12),
DEV_OPT_DADTRANSMITS = (1 << 13),
DEV_OPT_MULTICAST_TO_UNICAST = (1 << 14),
@@ -134,6 +135,7 @@ enum device_event {
DEV_EVENT_UP,
DEV_EVENT_DOWN,
+ DEV_EVENT_AUTH_UP,
DEV_EVENT_LINK_UP,
DEV_EVENT_LINK_DOWN,
@@ -192,6 +194,7 @@ struct device_settings {
bool drop_gratuitous_arp;
bool drop_unsolicited_na;
bool arp_accept;
+ bool auth;
};
/*
@@ -220,6 +223,7 @@ struct device {
int active;
/* DEV_EVENT_LINK_UP */
bool link_active;
+ bool auth_status;
bool external;
bool disabled;
@@ -324,6 +328,8 @@ struct device *get_vlan_device_chain(const char *ifname, bool create);
void alias_notify_device(const char *name, struct device *dev);
struct device *device_alias_get(const char *name);
+void device_set_auth_status(struct device *dev, bool value);
+
static inline void
device_set_deferred(struct device *dev, bool value)
{
@@ -338,6 +344,15 @@ device_set_disabled(struct device *dev, bool value)
device_refresh_present(dev);
}
+static inline bool
+device_link_active(struct device *dev)
+{
+ if (dev->settings.auth && !dev->auth_status)
+ return false;
+
+ return dev->link_active;
+}
+
bool device_check_ip6segmentrouting(void);
#endif
diff --git a/interface.c b/interface.c
index 2a8f604..a91246a 100644
--- a/interface.c
+++ b/interface.c
@@ -99,6 +99,17 @@ interface_error_flush(struct interface *iface)
}
}
+static bool
+interface_force_link(struct interface *iface)
+{
+ struct device *dev = iface->main_dev.dev;
+
+ if (dev && dev->settings.auth)
+ return false;
+
+ return iface->force_link;
+}
+
static void
interface_clear_errors(struct interface *iface)
{
@@ -344,7 +355,7 @@ __interface_set_up(struct interface *iface)
static void
interface_check_state(struct interface *iface)
{
- bool link_state = iface->link_state || iface->force_link;
+ bool link_state = iface->link_state || interface_force_link(iface);
switch (iface->state) {
case IFS_UP:
@@ -390,7 +401,8 @@ interface_set_link_state(struct interface *iface, bool new_state)
iface->link_state = new_state;
interface_check_state(iface);
- if (new_state && iface->force_link && iface->state == IFS_UP && !iface->link_up_event) {
+ if (new_state && interface_force_link(iface) &&
+ iface->state == IFS_UP && !iface->link_up_event) {
interface_event(iface, IFEV_LINK_UP);
iface->link_up_event = true;
}
@@ -424,11 +436,10 @@ interface_main_dev_cb(struct device_user *dep, enum device_event ev)
case DEV_EVENT_DOWN:
interface_set_enabled(iface, false);
break;
+ case DEV_EVENT_AUTH_UP:
case DEV_EVENT_LINK_UP:
- interface_set_link_state(iface, true);
- break;
case DEV_EVENT_LINK_DOWN:
- interface_set_link_state(iface, false);
+ interface_set_link_state(iface, device_link_active(dep->dev));
break;
case DEV_EVENT_TOPO_CHANGE:
interface_proto_event(iface->proto, PROTO_CMD_RENEW, false);
diff --git a/ubus.c b/ubus.c
index 9098c66..be15062 100644
--- a/ubus.c
+++ b/ubus.c
@@ -298,12 +298,14 @@ error:
enum {
DEV_STATE_NAME,
DEV_STATE_DEFER,
+ DEV_STATE_AUTH_STATUS,
__DEV_STATE_MAX,
};
static const struct blobmsg_policy dev_state_policy[__DEV_STATE_MAX] = {
[DEV_STATE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
[DEV_STATE_DEFER] = { .name = "defer", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_STATE_AUTH_STATUS] = { .name = "auth_status", .type = BLOBMSG_TYPE_BOOL },
};
static int
@@ -329,6 +331,10 @@ netifd_handle_set_state(struct ubus_context *ctx, struct ubus_object *obj,
if (cur)
device_set_deferred(dev, !!blobmsg_get_u8(cur));
+ cur = tb[DEV_STATE_AUTH_STATUS];
+ if (cur)
+ device_set_auth_status(dev, !!blobmsg_get_u8(cur));
+
return 0;
}