config: parse default mac address from board.json
[project/netifd.git] / device.c
index ad470c929793b0ca4a8f3215cc85fdd2f014b53b..73cc4bfebd17253dced948a1b985f9d8928878e1 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>
 
@@ -57,6 +52,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
        [DEV_ATTR_UNICAST_FLOOD] = { .name ="unicast_flood", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_SENDREDIRECTS] = { .name = "sendredirects", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_NEIGHLOCKTIME] = { .name = "neighlocktime", .type = BLOBMSG_TYPE_INT32 },
+       [DEV_ATTR_ISOLATE] = { .name = "isolate", .type = BLOBMSG_TYPE_BOOL },
 };
 
 const struct uci_blob_param_list device_attr_list = {
@@ -108,6 +104,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) {
@@ -117,10 +138,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;
 }
@@ -199,7 +227,7 @@ 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->promisc = s->flags & DEV_OPT_PROMISC ? s->promisc : os->promisc;
@@ -362,6 +390,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
                s->flags |= DEV_OPT_SENDREDIRECTS;
        }
 
+       if ((cur = tb[DEV_ATTR_ISOLATE])) {
+               s->isolate = blobmsg_get_bool(cur);
+               s->flags |= DEV_OPT_ISOLATE;
+       }
+
        device_set_disabled(dev, disabled);
 }
 
@@ -392,6 +425,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;
@@ -409,6 +457,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 */
@@ -464,7 +513,7 @@ int device_check_state(struct device *dev)
        return dev->type->check_state(dev);
 }
 
-void device_init_virtual(struct device *dev, struct device_type *type, const char *name)
+int device_init_virtual(struct device *dev, struct device_type *type, const char *name)
 {
        assert(dev);
        assert(type);
@@ -474,18 +523,27 @@ void device_init_virtual(struct device *dev, struct device_type *type, const cha
        INIT_SAFE_LIST(&dev->aliases);
        dev->type = type;
 
-       if (name)
-               device_set_ifname(dev, name);
+       if (name) {
+               int ret;
+
+               ret = device_set_ifname(dev, name);
+               if (ret < 0)
+                       return ret;
+       }
 
        if (!dev->set_state)
                dev->set_state = set_device_state;
+
+       return 0;
 }
 
 int device_init(struct device *dev, struct device_type *type, const char *ifname)
 {
        int ret;
 
-       device_init_virtual(dev, type, ifname);
+       ret = device_init_virtual(dev, type, ifname);
+       if (ret < 0)
+               return ret;
 
        dev->avl.key = dev->ifname;
 
@@ -494,7 +552,6 @@ int device_init(struct device *dev, struct device_type *type, const char *ifname
                return ret;
 
        system_if_clear_state(dev);
-       device_check_state(dev);
 
        return 0;
 }
@@ -514,10 +571,19 @@ device_create_default(const char *name, bool external)
 
        dev->external = external;
        dev->set_state = simple_device_set_state;
-       device_init(dev, &simple_device_type, name);
+
+       if (device_init(dev, &simple_device_type, name) < 0) {
+               device_cleanup(dev);
+               free(dev);
+               return NULL;
+       }
+
        dev->default_config = true;
        if (external)
                system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
+
+       device_check_state(dev);
+
        return dev;
 }
 
@@ -534,13 +600,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);
@@ -642,10 +709,13 @@ int device_set_ifname(struct device *dev, const char *name)
        if (!strcmp(dev->ifname, name))
                return 0;
 
+       if (strlen(name) > sizeof(dev->ifname) - 1)
+               return -1;
+
        if (dev->avl.key)
                avl_delete(&devices, &dev->avl);
 
-       strncpy(dev->ifname, name, IFNAMSIZ);
+       strcpy(dev->ifname, name);
 
        if (dev->avl.key)
                ret = avl_insert(&devices, &dev->avl);
@@ -709,7 +779,7 @@ void device_add_user(struct device_user *dep, struct device *dev)
        __device_add_user(dep, dev);
 }
 
-void
+static void
 device_free(struct device *dev)
 {
        __devlock++;
@@ -770,6 +840,7 @@ device_init_pending(void)
 
                dev->type->config_init(dev);
                dev->config_pending = false;
+               device_check_state(dev);
        }
 }
 
@@ -932,6 +1003,8 @@ device_create(const char *name, struct device_type *type,
                dev->config_pending = false;
        }
 
+       device_check_state(dev);
+
        return dev;
 }