diff options
-rw-r--r-- | bridge.c | 58 | ||||
-rw-r--r-- | device.c | 34 | ||||
-rw-r--r-- | device.h | 17 | ||||
-rw-r--r-- | interface.c | 21 | ||||
-rw-r--r-- | ubus.c | 6 |
5 files changed, 113 insertions, 23 deletions
@@ -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); @@ -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"); @@ -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); @@ -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; } |