#include <sys/types.h>
#include <sys/socket.h>
-#include <net/ethernet.h>
-
-#ifdef linux
-#include <netinet/ether.h>
-#endif
#include <libubox/list.h>
[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 = {
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) {
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;
}
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;
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);
}
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;
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 */
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);
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;
return ret;
system_if_clear_state(dev);
- device_check_state(dev);
return 0;
}
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;
}
{
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);
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);
__device_add_user(dep, dev);
}
-void
+static void
device_free(struct device *dev)
{
__devlock++;
dev->type->config_init(dev);
dev->config_pending = false;
+ device_check_state(dev);
}
}
dev->config_pending = false;
}
+ device_check_state(dev);
+
return dev;
}