#include "interface.h"
#include "system.h"
+enum {
+ BRIDGE_ATTR_IFNAME,
+ BRIDGE_ATTR_STP,
+ __BRIDGE_ATTR_MAX
+};
+
+static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = {
+ [BRIDGE_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY },
+ [BRIDGE_ATTR_STP] = { "stp", BLOBMSG_TYPE_BOOL },
+};
+
+static const union config_param_info bridge_attr_info[__BRIDGE_ATTR_MAX] = {
+ [BRIDGE_ATTR_IFNAME] = { .type = BLOBMSG_TYPE_STRING },
+};
+
+static const struct config_param_list bridge_attr_list = {
+ .n_params = __BRIDGE_ATTR_MAX,
+ .params = bridge_attrs,
+ .info = bridge_attr_info,
+
+ .n_next = 1,
+ .next = { &device_attr_list },
+};
+
+static struct device *bridge_create(struct blob_attr *attr);
+static void bridge_free(struct device *dev);
+static void bridge_dump_status(struct device *dev, struct blob_buf *b);
+
+const struct device_type bridge_device_type = {
+ .name = "Bridge",
+ .config_params = &bridge_attr_list,
+
+ .create = bridge_create,
+ .free = bridge_free,
+ .dump_status = bridge_dump_status,
+};
+
struct bridge_state {
struct device dev;
device_state_cb set_state;
.del = bridge_hotplug_del
};
-static void
-bridge_parse_config(struct bridge_state *bst, struct uci_section *s)
-{
- struct uci_element *e;
- struct uci_option *o;
- char buf[IFNAMSIZ + 1];
- char *p, *end;
- int len;
-
- o = uci_lookup_option(uci_ctx, s, "ifname");
- if (!o)
- return;
-
- if (o->type == UCI_TYPE_LIST) {
- uci_foreach_element(&o->v.list, e)
- bridge_add_member(bst, e->name);
- } else {
- p = o->v.string;
- do {
- if (!*p)
- break;
-
- if (*p == ' ')
- continue;
-
- end = strchr(p, ' ');
- if (!end) {
- bridge_add_member(bst, p);
- break;
- }
-
- len = end - p;
- if (len <= IFNAMSIZ) {
- memcpy(buf, p, len);
- buf[len] = 0;
- bridge_add_member(bst, buf);
- }
- p = end;
- } while (p++);
- }
-}
-
static void
bridge_free(struct device *dev)
{
blobmsg_close_array(b, list);
}
-struct device *
-bridge_create(const char *name, struct uci_section *s)
+static struct device *
+bridge_create(struct blob_attr *attr)
{
- static const struct device_type bridge_type = {
- .name = "Bridge",
- .free = bridge_free,
- .dump_status = bridge_dump_status,
- };
+ struct blob_attr *tb_dev[__DEV_ATTR_MAX];
+ struct blob_attr *tb_br[__BRIDGE_ATTR_MAX];
+ struct blob_attr *cur;
struct bridge_state *bst;
- struct device *dev;
+ struct device *dev = NULL;
+ const char *name;
+ int rem;
- dev = device_get(name, false);
- if (dev)
+ blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev,
+ blob_data(attr), blob_len(attr));
+ blobmsg_parse(bridge_attrs, __BRIDGE_ATTR_MAX, tb_br,
+ blob_data(attr), blob_len(attr));
+
+ if (!tb_dev[DEV_ATTR_NAME])
+ return NULL;
+
+ if (!tb_br[BRIDGE_ATTR_IFNAME])
return NULL;
+ name = blobmsg_data(tb_dev[DEV_ATTR_NAME]);
+
bst = calloc(1, sizeof(*bst));
if (!bst)
return NULL;
- device_init(&bst->dev, &bridge_type, name);
+ dev = &bst->dev;
+ device_init(dev, &bridge_device_type, name);
+ device_init_settings(dev, tb_dev);
- bst->set_state = bst->dev.set_state;
- bst->dev.set_state = bridge_set_state;
+ bst->set_state = dev->set_state;
+ dev->set_state = bridge_set_state;
- bst->dev.hotplug_ops = &bridge_ops;
+ dev->hotplug_ops = &bridge_ops;
INIT_LIST_HEAD(&bst->members);
- if (s)
- bridge_parse_config(bst, s);
+ blobmsg_for_each_attr(cur, tb_br[BRIDGE_ATTR_IFNAME], rem) {
+ bridge_add_member(bst, blobmsg_data(cur));
+ }
- return &bst->dev;
+ return dev;
}
-int
-interface_attach_bridge(struct interface *iface, struct uci_section *s)
-{
- struct device *dev;
- char brname[IFNAMSIZ];
-
- snprintf(brname, IFNAMSIZ - 1, "br-%s", iface->name);
- brname[IFNAMSIZ - 1] = 0;
- dev = bridge_create(brname, s);
- if (!dev)
- return -1;
-
- device_add_user(&iface->main_dev, dev);
- return 0;
-}
uci_to_blob(b, s, p->next[i]);
}
+static int
+config_parse_bridge_interface(struct uci_section *s)
+{
+ char *name;
+
+ name = alloca(strlen(s->e.name) + 4);
+ sprintf(name, "br-%s", s->e.name);
+ blobmsg_add_string(&b, "name", name);
+
+ uci_to_blob(&b, s, bridge_device_type.config_params);
+ if (!bridge_device_type.create(b.head)) {
+ DPRINTF("Failed to create bridge for interface '%s'\n", s->e.name);
+ return -EINVAL;
+ }
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "ifname", name);
+ return 0;
+}
+
static void
config_parse_interface(struct uci_section *s)
{
+ const char *type;
DPRINTF("Create interface '%s'\n", s->e.name);
blob_buf_init(&b, 0);
+
+ type = uci_lookup_option_string(uci_ctx, s, "type");
+ if (type && !strcmp(type, "bridge"))
+ if (config_parse_bridge_interface(s))
+ return;
+
uci_to_blob(&b, s, &interface_attr_list);
interface_alloc(s->e.name, s, b.head);
}
uci_foreach_element(&uci_network->sections, e) {
struct uci_section *s = uci_to_section(e);
+ const struct device_type *devtype;
+ const char *type;
if (strcmp(s->type, "device") != 0)
continue;
blob_buf_init(&b, 0);
- uci_to_blob(&b, s, &device_attr_list);
- device_create(b.head, s);
+ type = uci_lookup_option_string(uci_ctx, s, "type");
+ if (type && !strcmp(type, "bridge"))
+ devtype = &bridge_device_type;
+ else
+ devtype = &simple_device_type;
+
+ uci_to_blob(&b, s, devtype->config_params);
+ devtype->create(b.head);
}
}
static struct avl_tree devices;
-enum {
- DEV_ATTR_NAME,
- DEV_ATTR_TYPE,
- DEV_ATTR_MTU,
- DEV_ATTR_MACADDR,
- DEV_ATTR_TXQUEUELEN,
- __DEV_ATTR_MAX,
-};
-
static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
- [DEV_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
[DEV_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING },
+ [DEV_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
+ [DEV_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY },
[DEV_ATTR_MTU] = { "mtu", BLOBMSG_TYPE_INT32 },
[DEV_ATTR_MACADDR] = { "macaddr", BLOBMSG_TYPE_STRING },
[DEV_ATTR_TXQUEUELEN] = { "txqueuelen", BLOBMSG_TYPE_INT32 },
.params = dev_attrs,
};
-static void
+static struct device *
+simple_device_create(struct blob_attr *attr)
+{
+ struct blob_attr *tb[__DEV_ATTR_MAX];
+ struct device *dev = NULL;
+ const char *name;
+
+ blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, blob_data(attr), blob_len(attr));
+ if (!tb[DEV_ATTR_NAME])
+ return NULL;
+
+ name = blobmsg_data(tb[DEV_ATTR_NAME]);
+ if (!name)
+ return NULL;
+
+ dev = device_get(name, true);
+ if (!dev)
+ return NULL;
+
+ device_init_settings(dev, tb);
+
+ return dev;
+}
+
+static void simple_device_free(struct device *dev)
+{
+ device_cleanup(dev);
+ free(dev);
+}
+
+const struct device_type simple_device_type = {
+ .name = "Network device",
+ .config_params = &device_attr_list,
+
+ .create = simple_device_create,
+ .check_state = system_if_check,
+ .free = simple_device_free,
+};
+
+void
device_init_settings(struct device *dev, struct blob_attr **tb)
{
struct blob_attr *cur;
}
}
-struct device *
-device_create(struct blob_attr *attr, struct uci_section *s)
-{
- struct blob_attr *tb[__DEV_ATTR_MAX];
- struct blob_attr *cur;
- struct device *dev = NULL;
- const char *name;
-
- blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, blob_data(attr), blob_len(attr));
- if (!tb[DEV_ATTR_NAME])
- return NULL;
-
- name = blobmsg_data(tb[DEV_ATTR_NAME]);
- if ((cur = tb[DEV_ATTR_TYPE])) {
- if (!strcmp(blobmsg_data(cur), "bridge"))
- dev = bridge_create(name, s);
- } else {
- dev = device_get(name, true);
- }
-
- if (!dev)
- return NULL;
-
- device_init_settings(dev, tb);
-
- return dev;
-}
-
-
static void __init dev_init(void)
{
avl_init(&devices, avl_strcmp, false, NULL);
}
-static void free_simple_device(struct device *dev)
-{
- device_cleanup(dev);
- free(dev);
-}
-
static void device_broadcast_event(struct device *dev, enum device_event ev)
{
struct device_user *dep, *tmp;
struct device *device_get(const char *name, bool create)
{
- static const struct device_type simple_type = {
- .name = "Device",
- .check_state = system_if_check,
- .free = free_simple_device,
- };
struct device *dev;
-
if (strchr(name, '.'))
return get_vlan_device_chain(name, create);
return NULL;
dev = calloc(1, sizeof(*dev));
- device_init(dev, &simple_type, name);
+ device_init(dev, &simple_device_type, name);
return dev;
}
typedef int (*device_state_cb)(struct device *, bool up);
+enum {
+ DEV_ATTR_TYPE,
+ DEV_ATTR_NAME,
+ DEV_ATTR_IFNAME,
+ DEV_ATTR_MTU,
+ DEV_ATTR_MACADDR,
+ DEV_ATTR_TXQUEUELEN,
+ __DEV_ATTR_MAX,
+};
+
struct device_type {
+ struct list_head list;
const char *name;
+ const struct config_param_list *config_params;
+
+ struct device *(*create)(struct blob_attr *attr);
void (*dump_status)(struct device *, struct blob_buf *buf);
int (*check_state)(struct device *);
void (*free)(struct device *);
};
extern const struct config_param_list device_attr_list;
+extern const struct device_type simple_device_type;
+extern const struct device_type bridge_device_type;
-struct device *device_create(struct blob_attr *attr, struct uci_section *s);
+void device_init_settings(struct device *dev, struct blob_attr **tb);
void device_init_virtual(struct device *dev, const struct device_type *type, const char *name);
int device_init(struct device *iface, const struct device_type *type, const char *ifname);
void device_free_all(void);
struct device *get_vlan_device_chain(const char *ifname, bool create);
-struct device *bridge_create(const char *name, struct uci_section *s);
#endif
static LIST_HEAD(interfaces);
enum {
- IFACE_ATTR_TYPE,
IFACE_ATTR_IFNAME,
IFACE_ATTR_PROTO,
IFACE_ATTR_AUTO,
};
static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
- [IFACE_ATTR_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_ARRAY },
[IFACE_ATTR_AUTO] = { .name = "auto", .type = BLOBMSG_TYPE_BOOL },
blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb,
blob_data(attr), blob_len(attr));
- if ((cur = tb[IFACE_ATTR_TYPE])) {
- if (!strcmp(blobmsg_data(cur), "bridge"))
- interface_attach_bridge(iface, s);
- }
-
if ((cur = tb[IFACE_ATTR_IFNAME])) {
dev = device_get(blobmsg_data(cur), true);
if (dev)
void interface_add_error(struct interface *iface, const char *subsystem,
const char *code, const char **data, int n_data);
-int interface_attach_bridge(struct interface *iface, struct uci_section *s);
-
int interface_add_address(struct interface *iface, struct device_addr *addr);
void interface_del_address(struct interface *iface, struct device_addr *addr);
void interface_del_ctx_addr(struct interface *iface, void *ctx);