move address handling to common code
authorFelix Fietkau <nbd@openwrt.org>
Mon, 2 May 2011 19:32:37 +0000 (21:32 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 2 May 2011 19:32:37 +0000 (21:32 +0200)
CMakeLists.txt
interface-ip.c [new file with mode: 0644]
interface.c
interface.h
proto-static.c

index 212377e..bb65a4b 100644 (file)
@@ -9,5 +9,5 @@ IF(DEBUG)
   ADD_DEFINITIONS(-DDEBUG -O0)
 ENDIF()
 
-ADD_EXECUTABLE(netifd main.c interface.c proto.c proto-static.c config.c device.c bridge.c vlan.c ubus.c system-dummy.c)
+ADD_EXECUTABLE(netifd main.c interface.c interface-ip.c proto.c proto-static.c config.c device.c bridge.c vlan.c ubus.c system-dummy.c)
 TARGET_LINK_LIBRARIES(netifd ubox ubus uci)
diff --git a/interface-ip.c b/interface-ip.c
new file mode 100644 (file)
index 0000000..20df281
--- /dev/null
@@ -0,0 +1,48 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "netifd.h"
+#include "device.h"
+#include "interface.h"
+#include "proto.h"
+#include "ubus.h"
+#include "system.h"
+
+int interface_add_address(struct interface *iface, struct interface_addr *addr)
+{
+       int family;
+
+       if (addr->flags & IFADDR_INET6)
+               family = AF_INET6;
+       else
+               family = AF_INET;
+
+       list_add(&addr->list, &iface->address);
+       return system_add_address(iface->l3_iface->dev, family, &addr->addr.in, addr->mask);
+}
+
+void interface_del_address(struct interface *iface, struct interface_addr *addr)
+{
+       int family;
+
+       if (addr->flags & IFADDR_INET6)
+               family = AF_INET6;
+       else
+               family = AF_INET;
+
+       list_del(&addr->list);
+       system_del_address(iface->l3_iface->dev, family, &addr->addr.in);
+}
+
+void interface_del_ctx_addr(struct interface *iface, void *ctx)
+{
+       struct interface_addr *addr, *tmp;
+
+       list_for_each_entry_safe(addr, tmp, &iface->address, list) {
+               if (addr->ctx != ctx)
+                       continue;
+
+               interface_del_address(iface, addr);
+       }
+}
index 0576166..88cf682 100644 (file)
@@ -189,6 +189,8 @@ alloc_interface(const char *name, struct uci_section *s)
        strncpy(iface->name, name, sizeof(iface->name) - 1);
        list_add(&iface->list, &interfaces);
        INIT_LIST_HEAD(&iface->errors);
+       INIT_LIST_HEAD(&iface->address);
+       INIT_LIST_HEAD(&iface->routes);
 
        proto_attach_interface(iface, s);
 
index e3b5ff7..e19d61d 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __NETIFD_INTERFACE_H
 #define __NETIFD_INTERFACE_H
 
+#include <netinet/in.h>
 #include "device.h"
 
 struct interface;
@@ -26,6 +27,42 @@ struct interface_error {
        const char *data[];
 };
 
+enum interface_addr_flags {
+       /* address family for routes and addresses */
+       IFADDR_INET4    = (0 << 0),
+       IFADDR_INET6    = (1 << 0),
+       IFADDR_FAMILY   = IFADDR_INET4 | IFADDR_INET6,
+
+       /* device route (no gateway) */
+       IFADDR_DEVICE   = (1 << 1),
+};
+
+union if_addr {
+       struct in_addr in;
+       struct in6_addr in6;
+};
+
+struct interface_addr {
+       struct list_head list;
+       void *ctx;
+
+       enum interface_addr_flags flags;
+
+       unsigned int mask;
+       union if_addr addr;
+};
+
+struct interface_route {
+       struct list_head list;
+       void *ctx;
+
+       enum interface_addr_flags flags;
+
+       unsigned int mask;
+       union if_addr addr;
+       union if_addr nexthop;
+};
+
 /*
  * interface configuration
  */
@@ -48,6 +85,8 @@ struct interface {
        /* primary protocol state */
        struct interface_proto_state *proto;
 
+       struct list_head address, routes;
+
        /* errors/warnings while trying to bring up the interface */
        struct list_head errors;
 
@@ -71,6 +110,10 @@ void interface_add_error(struct interface *iface, const char *subsystem,
 
 int interface_attach_bridge(struct interface *iface, struct uci_section *s);
 
+int interface_add_address(struct interface *iface, struct interface_addr *addr);
+void interface_del_address(struct interface *iface, struct interface_addr *addr);
+void interface_del_ctx_addr(struct interface *iface, void *ctx);
+
 void start_pending_interfaces(void);
 
 #endif
index e57b63f..3a36ec0 100644 (file)
 #include "proto.h"
 #include "system.h"
 
-struct v4_addr {
-       unsigned int prefix;
-       struct in_addr addr;
-};
-
-struct v6_addr {
-       unsigned int prefix;
-       struct in6_addr addr;
-};
-
-enum static_proto_flags {
-       STATIC_F_IPV4GW         = (1 << 0),
-       STATIC_F_IPV6GW         = (1 << 1),
-};
-
-struct static_proto_settings {
-       uint32_t flags;
-
-       int n_v4;
-       struct v4_addr *v4;
-
-       int n_v6;
-       struct v6_addr *v6;
-
-       struct in_addr ipv4gw;
-       struct in6_addr ipv6gw;
-};
-
 struct static_proto_state {
-    struct interface_proto_state proto;
-       struct interface *iface;
+       struct interface_proto_state proto;
 
-       struct static_proto_settings s;
+       struct uci_section *section;
+       struct interface *iface;
 };
 
-static int
-static_handler(struct interface_proto_state *proto,
-              enum interface_proto_cmd cmd, bool force)
-{
-       struct static_proto_state *state;
-       struct static_proto_settings *ps;
-       struct device *dev;
-       int ret = 0;
-       int i;
-
-       state = container_of(proto, struct static_proto_state, proto);
-       ps = &state->s;
-       dev = state->iface->main_dev.dev;
-
-       switch (cmd) {
-       case PROTO_CMD_SETUP:
-               for (i = 0; i < state->s.n_v4; i++) {
-                       if (ret)
-                               break;
-                       ret = system_add_address(dev, AF_INET,
-                               &ps->v4[i].addr, ps->v4[i].prefix);
-               }
-               for (i = 0; i < state->s.n_v6; i++) {
-                       if (ret)
-                               break;
-                       ret = system_add_address(dev, AF_INET6,
-                               &ps->v6[i].addr, ps->v6[i].prefix);
-               }
-
-               if (!ret)
-                       return 0;
-
-               interface_add_error(state->iface, "proto-static",
-                       "SET_ADDRESS_FAILED", NULL, 0);
-               /* fall through */
-
-       case PROTO_CMD_TEARDOWN:
-               for (i = 0; i < ps->n_v4; i++)
-                       system_del_address(dev, AF_INET, &ps->v4[i].addr);
-               for (i = 0; i < ps->n_v6; i++)
-                       system_del_address(dev, AF_INET6, &ps->v6[i].addr);
-               break;
-       }
-       return ret;
-}
-
-static void
-static_free(struct interface_proto_state *proto)
-{
-       struct static_proto_state *state;
-
-       state = container_of(proto, struct static_proto_state, proto);
-       free(state);
-}
-
-struct interface_proto_state *
-static_create_state(struct interface *iface, struct static_proto_settings *ps)
-{
-       struct static_proto_state *state;
-       int v4_len = sizeof(struct v4_addr) * ps->n_v4;
-       int v6_len = sizeof(struct v6_addr) * ps->n_v6;
-       void *next;
-
-       state = calloc(1, sizeof(*state) + v4_len + v6_len);
-       state->iface = iface;
-       state->proto.free = static_free;
-       state->proto.handler = static_handler;
-       state->proto.flags = PROTO_FLAG_IMMEDIATE;
-       memcpy(&state->s, ps, sizeof(state->s));
-
-       next = (void *) (state + 1);
-
-       if (ps->n_v4) {
-               ps->v4 = next;
-               memcpy(next, ps->v4, sizeof(struct v4_addr) * ps->n_v4);
-
-               next = ps->v4 + ps->n_v4;
-       }
-
-       if (ps->n_v6) {
-               ps->v6 = next;
-               memcpy(next, ps->v6, sizeof(struct v6_addr) * ps->n_v6);
-       }
-
-       return &state->proto;
-}
-
 static bool
 split_netmask(char *str, unsigned int *netmask)
 {
@@ -168,30 +53,44 @@ parse_ip_and_netmask(int af, const char *str, void *addr, unsigned int *netmask)
        return inet_pton(af, str, addr);
 }
 
-static int
-parse_v4(const char *str, struct v4_addr *v4, int netmask)
-{
-       v4->prefix = netmask;
-       return parse_ip_and_netmask(AF_INET, str, &v4->addr, &v4->prefix);
-}
-
-static int
-parse_v6(const char *str, struct v6_addr *v6, int netmask)
+static bool
+parse_addr(struct static_proto_state *state, const char *str, bool v6, int mask)
 {
-       v6->prefix = netmask;
-       return parse_ip_and_netmask(AF_INET6, str, &v6->addr, &v6->prefix);
+       struct interface_addr *addr;
+       int af = v6 ? AF_INET6 : AF_INET;
+
+       addr = calloc(1, sizeof(*addr));
+       addr->flags = v6 ? IFADDR_INET6 : IFADDR_INET4;
+       addr->ctx = state;
+       addr->mask = mask;
+       if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) {
+               interface_add_error(state->iface, "proto-static", "INVALID_ADDRESS", &str, 1);
+               free(addr);
+               return false;
+       }
+       interface_add_address(state->iface, addr);
+       return true;
 }
 
 static int
-count_list_entries(struct uci_option *o)
+parse_address_option(struct static_proto_state *state, struct uci_option *o, bool v6, int netmask)
 {
        struct uci_element *e;
-       int n = 0;
+       int n_addr = 0;
 
-       uci_foreach_element(&o->v.list, e)
-               n++;
+       if (o->type == UCI_TYPE_STRING) {
+               n_addr++;
+               if (!parse_addr(state, o->v.string, v6, netmask))
+                       return -1;
+       } else {
+               uci_foreach_element(&o->v.list, e) {
+                       n_addr++;
+                       if (!parse_addr(state, e->name, v6, netmask))
+                               return -1;
+               }
+       }
 
-       return n;
+       return n_addr;
 }
 
 enum {
@@ -211,20 +110,16 @@ static const struct uci_parse_option opts[__OPT_MAX] = {
        [OPT_IP6GW] = { .name = "ip6gw", .type = UCI_TYPE_STRING },
 };
 
-struct interface_proto_state *
-static_attach(struct proto_handler *h, struct interface *iface,
-             struct uci_section *s)
+static bool
+static_proto_setup(struct static_proto_state *state)
 {
        struct uci_option *tb[__OPT_MAX];
-       struct uci_element *e;
-       struct in_addr ina = {};
-       const char *error = NULL;
+       struct in_addr ina;
+       const char *error;
        int netmask = 32;
-       int i;
-       struct static_proto_settings ps;
+       int n_v4 = 0, n_v6 = 0;
 
-       memset(&ps, 0, sizeof(ps));
-       uci_parse_section(s, opts, __OPT_MAX, tb);
+       uci_parse_section(state->section, opts, __OPT_MAX, tb);
 
        if (tb[OPT_NETMASK]) {
                if (!inet_aton(tb[OPT_NETMASK]->v.string, &ina)) {
@@ -235,46 +130,21 @@ static_attach(struct proto_handler *h, struct interface *iface,
                netmask = 32 - fls(~(ntohl(ina.s_addr)));
        }
 
-       if (tb[OPT_IPADDR]) {
-               if (tb[OPT_IPADDR]->type == UCI_TYPE_STRING) {
-                       ps.n_v4 = 1;
-                       ps.v4 = alloca(sizeof(struct v4_addr));
-                       if (!parse_v4(tb[OPT_IPADDR]->v.string, ps.v4, netmask))
-                               goto invalid_addr;
-               } else {
-                       i = 0;
-                       ps.n_v4 = count_list_entries(tb[OPT_IPADDR]);
-                       ps.v4 = alloca(sizeof(struct v4_addr) * ps.n_v4);
-                       uci_foreach_element(&tb[OPT_IPADDR]->v.list, e) {
-                               if (!parse_v4(e->name, &ps.v4[i++], netmask))
-                                       goto invalid_addr;
-                       }
-               }
-       }
+       if (tb[OPT_IPADDR])
+               n_v4 = parse_address_option(state, tb[OPT_IPADDR], false, netmask);
 
-       if (tb[OPT_IP6ADDR]) {
-               if (tb[OPT_IP6ADDR]->type == UCI_TYPE_STRING) {
-                       ps.n_v6 = 1;
-                       ps.v6 = alloca(sizeof(struct v6_addr));
-                       ps.v6->prefix = netmask;
-                       if (!parse_v6(tb[OPT_IP6ADDR]->v.string, ps.v6, netmask))
-                               goto invalid_addr;
-               } else {
-                       i = 0;
-                       ps.n_v6 = count_list_entries(tb[OPT_IP6ADDR]);
-                       ps.v6 = alloca(sizeof(struct v6_addr) * ps.n_v6);
-                       uci_foreach_element(&tb[OPT_IP6ADDR]->v.list, e) {
-                               if (!parse_v6(e->name, &ps.v6[i++], netmask))
-                                       goto invalid_addr;
-                       }
-               }
-       }
+       if (tb[OPT_IP6ADDR])
+               n_v6 = parse_address_option(state, tb[OPT_IP6ADDR], true, netmask);
 
-       if (!ps.n_v4 && !ps.n_v6) {
+       if (!n_v4 && !n_v6) {
                error = "NO_ADDRESS";
                goto error;
        }
 
+       if (n_v4 < 0 || n_v6 < 0)
+               goto out;
+
+#if 0
        if (ps.n_v4 && tb[OPT_GATEWAY]) {
                if (!inet_pton(AF_INET, tb[OPT_GATEWAY]->v.string, &ps.ipv4gw)) {
                        error = "INVALID_GATEWAY";
@@ -290,15 +160,61 @@ static_attach(struct proto_handler *h, struct interface *iface,
                }
                ps.flags |= STATIC_F_IPV6GW;
        }
+#endif
 
-       return static_create_state(iface, &ps);
-
-invalid_addr:
-       error = "INVALID_ADDRESS";
+       return true;
 
 error:
-       interface_add_error(iface, "proto-static", error, NULL, 0);
-       return NULL;
+       interface_add_error(state->iface, "proto-static", error, NULL, 0);
+out:
+       return false;
+}
+
+static int
+static_handler(struct interface_proto_state *proto,
+              enum interface_proto_cmd cmd, bool force)
+{
+       struct static_proto_state *state;
+       int ret = 0;
+
+       state = container_of(proto, struct static_proto_state, proto);
+
+       switch (cmd) {
+       case PROTO_CMD_SETUP:
+               if (static_proto_setup(state))
+                       break;
+
+               /* fall through */
+       case PROTO_CMD_TEARDOWN:
+               interface_del_ctx_addr(state->iface, state);
+               break;
+       }
+       return ret;
+}
+
+static void
+static_free(struct interface_proto_state *proto)
+{
+       struct static_proto_state *state;
+
+       state = container_of(proto, struct static_proto_state, proto);
+       free(state);
+}
+
+struct interface_proto_state *
+static_attach(struct proto_handler *h, struct interface *iface,
+             struct uci_section *s)
+{
+       struct static_proto_state *state;
+
+       state = calloc(1, sizeof(*state));
+       state->iface = iface;
+       state->section = s;
+       state->proto.free = static_free;
+       state->proto.handler = static_handler;
+       state->proto.flags = PROTO_FLAG_IMMEDIATE;
+
+       return &state->proto;
 }
 
 static struct proto_handler static_proto = {