diff options
-rw-r--r-- | config.c | 2 | ||||
-rw-r--r-- | config/network | 3 | ||||
-rw-r--r-- | interface.c | 11 | ||||
-rw-r--r-- | interface.h | 4 | ||||
-rw-r--r-- | proto.c | 67 | ||||
-rw-r--r-- | proto.h | 10 |
6 files changed, 83 insertions, 14 deletions
@@ -34,7 +34,7 @@ config_parse_interface(struct uci_section *s) DPRINTF("Create interface '%s'\n", s->e.name); - iface = alloc_interface(s->e.name); + iface = alloc_interface(s->e.name, s); if (!iface) return; diff --git a/config/network b/config/network index 0a02e89..1f803a0 100644 --- a/config/network +++ b/config/network @@ -21,6 +21,9 @@ config interface lan option ipaddr 192.168.1.1 option netmask 255.255.255.0 +config interface dummy + option ifname eth0.4 + option proto none config interface lan2 option ifname eth0.3 diff --git a/interface.c b/interface.c index 06a36ed..ef176f6 100644 --- a/interface.c +++ b/interface.c @@ -175,7 +175,7 @@ void interface_set_proto_state(struct interface *iface, struct interface_proto_s } struct interface * -alloc_interface(const char *name) +alloc_interface(const char *name, struct uci_section *s) { struct interface *iface; @@ -184,19 +184,14 @@ alloc_interface(const char *name) return iface; iface = calloc(1, sizeof(*iface)); - - interface_set_proto_state(iface, get_default_proto()); - if (!iface->proto) { - free(iface); - return NULL; - } - iface->main_dev.cb = interface_cb; iface->l3_iface = &iface->main_dev; strncpy(iface->name, name, sizeof(iface->name) - 1); list_add(&iface->list, &interfaces); INIT_LIST_HEAD(&iface->errors); + proto_attach_interface(iface, s); + netifd_ubus_add_interface(iface); return iface; diff --git a/interface.h b/interface.h index 92bae5a..e3b5ff7 100644 --- a/interface.h +++ b/interface.h @@ -55,9 +55,11 @@ struct interface { }; struct interface *get_interface(const char *name); -struct interface *alloc_interface(const char *name); +struct interface *alloc_interface(const char *name, struct uci_section *s); void free_interface(struct interface *iface); +void interface_set_proto_state(struct interface *iface, struct interface_proto_state *state); + int set_interface_up(struct interface *iface); int set_interface_down(struct interface *iface); @@ -6,6 +6,20 @@ #include "interface.h" #include "proto.h" +static struct avl_tree handlers; + +void add_proto_handler(struct proto_handler *p) +{ + if (!handlers.comp) + avl_init(&handlers, avl_strcmp, false, NULL); + + if (p->avl.key) + return; + + p->avl.key = p->name; + avl_insert(&handlers, &p->avl); +} + static void default_proto_free(struct interface_proto_state *proto) { @@ -13,24 +27,71 @@ default_proto_free(struct interface_proto_state *proto) } static int -default_proto_handler(struct interface_proto_state *proto, +invalid_proto_handler(struct interface_proto_state *proto, + enum interface_proto_cmd cmd, bool force) +{ + return -1; +} + +static int +no_proto_handler(struct interface_proto_state *proto, enum interface_proto_cmd cmd, bool force) { return 0; } -struct interface_proto_state *get_default_proto(void) +static struct interface_proto_state *get_default_proto(void) { struct interface_proto_state *proto; proto = calloc(1, sizeof(*proto)); - proto->handler = default_proto_handler; proto->free = default_proto_free; proto->flags = PROTO_FLAG_IMMEDIATE; return proto; } +void proto_attach_interface(struct interface *iface, struct uci_section *s) +{ + struct interface_proto_state *state = NULL; + struct proto_handler *proto = NULL; + const char *proto_name; + const char *error = NULL; + + proto_name = uci_lookup_option_string(uci_ctx, s, "proto"); + if (!proto_name) { + error = "NO_PROTO"; + goto error; + } + + if (!strcmp(proto_name, "none")) { + state = get_default_proto(); + state->handler = no_proto_handler; + goto out; + } + + if (handlers.comp) + proto = avl_find_element(&handlers, proto_name, proto, avl); + + if (!proto) { + error = "INVALID_PROTO"; + goto error; + } + + state = proto->attach(proto, iface); + +error: + if (error) { + interface_add_error(iface, "proto", error, NULL, 0); + state = get_default_proto(); + state->handler = invalid_proto_handler; + } + +out: + interface_set_proto_state(iface, state); +} + + int interface_proto_event(struct interface_proto_state *proto, enum interface_proto_cmd cmd, bool force) { @@ -29,7 +29,15 @@ struct interface_proto_state { void (*free)(struct interface_proto_state *); }; -struct interface_proto_state *get_default_proto(void); +struct proto_handler { + struct avl_node avl; + + const char *name; + struct interface_proto_state * (*attach)(struct proto_handler *h, struct interface *); +}; + +void add_proto_handler(struct proto_handler *p); +void proto_attach_interface(struct interface *iface, struct uci_section *s); int interface_proto_event(struct interface_proto_state *proto, enum interface_proto_cmd cmd, bool force); |