netifd: fix a typo in vlandev hotplug support
[project/netifd.git] / device.c
index 70cb6a7b86b469c95567c03607ad4f44cc38fab7..4243c18bebe508a19a3734b09967139ea059cd22 100644 (file)
--- a/device.c
+++ b/device.c
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <net/ethernet.h>
-
-#ifdef linux
-#include <netinet/ether.h>
-#endif
 
 #include <libubox/list.h>
 
@@ -41,6 +36,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
        [DEV_ATTR_TXQUEUELEN] = { .name = "txqueuelen", .type = BLOBMSG_TYPE_INT32 },
        [DEV_ATTR_ENABLED] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_IPV6] = { .name = "ipv6", .type = BLOBMSG_TYPE_BOOL },
+       [DEV_ATTR_IP6SEGMENTROUTING] = { .name = "ip6segmentrouting", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_PROMISC] = { .name = "promisc", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_RPFILTER] = { .name = "rpfilter", .type = BLOBMSG_TYPE_STRING },
        [DEV_ATTR_ACCEPTLOCAL] = { .name = "acceptlocal", .type = BLOBMSG_TYPE_BOOL },
@@ -109,6 +105,31 @@ void device_unlock(void)
                device_free_unused(NULL);
 }
 
+static int device_vlan_len(struct kvlist *kv, const void *data)
+{
+       return sizeof(unsigned int);
+}
+
+void device_vlan_update(bool done)
+{
+       struct device *dev;
+
+       avl_for_each_element(&devices, dev, avl) {
+               if (!dev->vlans.update)
+                       continue;
+
+               if (!done) {
+                       if (dev->vlan_aliases.get_len)
+                               kvlist_free(&dev->vlan_aliases);
+                       else
+                               kvlist_init(&dev->vlan_aliases, device_vlan_len);
+                       vlist_update(&dev->vlans);
+               } else {
+                       vlist_flush(&dev->vlans);
+               }
+       }
+}
+
 static int set_device_state(struct device *dev, bool state)
 {
        if (state) {
@@ -118,10 +139,17 @@ static int set_device_state(struct device *dev, bool state)
                if (!dev->ifindex)
                        return -1;
 
+               system_if_get_settings(dev, &dev->orig_settings);
+               /* Only keep orig settings based on what needs to be set */
+               dev->orig_settings.valid_flags = dev->orig_settings.flags;
+               dev->orig_settings.flags &= dev->settings.flags;
+               system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
+
                system_if_up(dev);
-       }
-       else
+       } else {
                system_if_down(dev);
+               system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
+       }
 
        return 0;
 }
@@ -200,9 +228,10 @@ device_merge_settings(struct device *dev, struct device_settings *n)
        n->txqueuelen = s->flags & DEV_OPT_TXQUEUELEN ?
                s->txqueuelen : os->txqueuelen;
        memcpy(n->macaddr,
-               (s->flags & DEV_OPT_MACADDR ? s->macaddr : os->macaddr),
+               (s->flags & (DEV_OPT_MACADDR|DEV_OPT_DEFAULT_MACADDR) ? s->macaddr : os->macaddr),
                sizeof(n->macaddr));
        n->ipv6 = s->flags & DEV_OPT_IPV6 ? s->ipv6 : os->ipv6;
+       n->ip6segmentrouting = s->flags & DEV_OPT_IP6SEGMENTROUTING ? s->ip6segmentrouting : os->ip6segmentrouting;
        n->promisc = s->flags & DEV_OPT_PROMISC ? s->promisc : os->promisc;
        n->rpfilter = s->flags & DEV_OPT_RPFILTER ? s->rpfilter : os->rpfilter;
        n->acceptlocal = s->flags & DEV_OPT_ACCEPTLOCAL ? s->acceptlocal : os->acceptlocal;
@@ -272,6 +301,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
                s->flags |= DEV_OPT_IPV6;
        }
 
+       if ((cur = tb[DEV_ATTR_IP6SEGMENTROUTING])) {
+               s->ip6segmentrouting = blobmsg_get_bool(cur);
+               s->flags |= DEV_OPT_IP6SEGMENTROUTING;
+       }
+
        if ((cur = tb[DEV_ATTR_PROMISC])) {
                s->promisc = blobmsg_get_bool(cur);
                s->flags |= DEV_OPT_PROMISC;
@@ -398,6 +432,21 @@ void device_broadcast_event(struct device *dev, enum device_event ev)
        safe_list_for_each(&dev->users, device_broadcast_cb, &dev_ev);
 }
 
+static void
+device_fill_default_settings(struct device *dev)
+{
+       struct device_settings *s = &dev->settings;
+       struct ether_addr *ea;
+
+       if (!(s->flags & DEV_OPT_MACADDR)) {
+               ea = config_get_default_macaddr(dev->ifname);
+               if (ea) {
+                       memcpy(s->macaddr, ea, 6);
+                       s->flags |= DEV_OPT_DEFAULT_MACADDR;
+               }
+       }
+}
+
 int device_claim(struct device_user *dep)
 {
        struct device *dev = dep->dev;
@@ -415,6 +464,7 @@ int device_claim(struct device_user *dep)
                return 0;
 
        device_broadcast_event(dev, DEV_EVENT_SETUP);
+       device_fill_default_settings(dev);
        if (dev->external) {
                /* Get ifindex for external claimed devices so a valid   */
                /* ifindex is in place avoiding possible race conditions */
@@ -557,13 +607,14 @@ device_get(const char *name, int create)
 {
        struct device *dev;
 
-       if (strchr(name, '.'))
+       dev = avl_find_element(&devices, name, dev, avl);
+
+       if (!dev && strchr(name, '.'))
                return get_vlan_device_chain(name, create);
 
        if (name[0] == '@')
                return device_alias_get(name + 1);
 
-       dev = avl_find_element(&devices, name, dev, avl);
        if (dev) {
                if (create > 1 && !dev->external) {
                        system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
@@ -800,6 +851,18 @@ device_init_pending(void)
        }
 }
 
+bool
+device_check_ip6segmentrouting(void)
+{
+       struct device *dev;
+       bool ip6segmentrouting = false;
+
+       avl_for_each_element(&devices, dev, avl)
+               ip6segmentrouting |= dev->settings.ip6segmentrouting;
+
+       return ip6segmentrouting;
+}
+
 static enum dev_change_type
 device_set_config(struct device *dev, struct device_type *type,
                  struct blob_attr *attr)
@@ -1009,6 +1072,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
                        blobmsg_add_u32(b, "txqueuelen", st.txqueuelen);
                if (st.flags & DEV_OPT_IPV6)
                        blobmsg_add_u8(b, "ipv6", st.ipv6);
+               if (st.flags & DEV_OPT_IP6SEGMENTROUTING)
+                       blobmsg_add_u8(b, "ip6segmentrouting", st.ip6segmentrouting);
                if (st.flags & DEV_OPT_PROMISC)
                        blobmsg_add_u8(b, "promisc", st.promisc);
                if (st.flags & DEV_OPT_RPFILTER)