diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-04-15 00:04:49 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2011-04-15 00:04:49 +0200 |
commit | 389ea223853184930a21ceb6738ab5cea496723e (patch) | |
tree | 69f3fe7fb25099c03e084c7b5d771d53275e10c8 /proto-static.c | |
parent | 3e22e5b6bddce74aa7b3ca92ff0f089ac9b59ccb (diff) |
make creating a static proto state more flexible, add support for parsing gateways
Diffstat (limited to 'proto-static.c')
-rw-r--r-- | proto-static.c | 119 |
1 files changed, 76 insertions, 43 deletions
diff --git a/proto-static.c b/proto-static.c index 97b2b58..55e77d5 100644 --- a/proto-static.c +++ b/proto-static.c @@ -20,15 +20,29 @@ struct v6_addr { struct in6_addr addr; }; -struct static_proto_state { - struct interface_proto_state proto; - struct interface *iface; +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 v4_addr *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 static_proto_settings s; }; static int @@ -36,26 +50,28 @@ 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->n_v4; i++) { + for (i = 0; i < state->s.n_v4; i++) { if (ret) break; ret = system_add_address(dev, AF_INET, - &state->v4[i].addr, state->v4[i].prefix); + &ps->v4[i].addr, ps->v4[i].prefix); } - for (i = 0; i < state->n_v6; i++) { + for (i = 0; i < state->s.n_v6; i++) { if (ret) break; ret = system_add_address(dev, AF_INET6, - &state->v6[i].addr, state->v6[i].prefix); + &ps->v6[i].addr, ps->v6[i].prefix); } if (!ret) @@ -66,10 +82,10 @@ static_handler(struct interface_proto_state *proto, /* fall through */ case PROTO_CMD_TEARDOWN: - for (i = 0; i < state->n_v4; i++) - system_del_address(dev, AF_INET, &state->v4[i].addr); - for (i = 0; i < state->n_v6; i++) - system_del_address(dev, AF_INET6, &state->v6[i].addr); + 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; @@ -85,11 +101,11 @@ static_free(struct interface_proto_state *proto) } struct interface_proto_state * -static_create_state(struct interface *iface, struct v4_addr *v4, int n_v4, struct v6_addr *v6, int n_v6) +static_create_state(struct interface *iface, struct static_proto_settings *ps) { struct static_proto_state *state; - int v4_len = sizeof(struct v4_addr) * n_v4; - int v6_len = sizeof(struct v6_addr) * n_v6; + 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); @@ -97,19 +113,20 @@ static_create_state(struct interface *iface, struct v4_addr *v4, int n_v4, struc 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 (n_v4) { - state->n_v4 = n_v4; - state->v4 = next; - memcpy(state->v4, v4, sizeof(*v4) * n_v4); - next = state->v4 + n_v4; + 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 (n_v6) { - state->n_v6 = n_v6; - state->v6 = next; - memcpy(state->v6, v6, sizeof(*v6) * n_v6); + if (ps->n_v6) { + ps->v6 = next; + memcpy(next, ps->v6, sizeof(struct v6_addr) * ps->n_v6); } return &state->proto; @@ -182,6 +199,7 @@ enum { OPT_IP6ADDR, OPT_NETMASK, OPT_GATEWAY, + OPT_IP6GW, OPT_DNS, __OPT_MAX, }; @@ -191,6 +209,7 @@ static const struct uci_parse_option opts[__OPT_MAX] = { [OPT_IP6ADDR] = { .name = "ip6addr" }, [OPT_NETMASK] = { .name = "netmask", .type = UCI_TYPE_STRING }, [OPT_GATEWAY] = { .name = "gateway", .type = UCI_TYPE_STRING }, + [OPT_IP6GW] = { .name = "ip6gw", .type = UCI_TYPE_STRING }, [OPT_DNS] = { .name = "dns" }, }; @@ -200,14 +219,13 @@ static_attach(struct proto_handler *h, struct interface *iface, { struct uci_option *tb[__OPT_MAX]; struct uci_element *e; - struct v4_addr *v4 = NULL; - struct v6_addr *v6 = NULL; - int n_v4 = 0, n_v6 = 0; struct in_addr ina = {}; const char *error = NULL; int netmask = 32; int i; + struct static_proto_settings ps; + memset(&ps, 0, sizeof(ps)); uci_parse_section(s, opts, __OPT_MAX, tb); if (tb[OPT_NETMASK]) { @@ -221,16 +239,16 @@ static_attach(struct proto_handler *h, struct interface *iface, if (tb[OPT_IPADDR]) { if (tb[OPT_IPADDR]->type == UCI_TYPE_STRING) { - n_v4 = 1; - v4 = alloca(sizeof(*v4)); - if (!parse_v4(tb[OPT_IPADDR]->v.string, v4, netmask)) + 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; - n_v4 = count_list_entries(tb[OPT_IPADDR]); - v4 = alloca(sizeof(*v4) * n_v4); + 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, &v4[i++], netmask)) + if (!parse_v4(e->name, &ps.v4[i++], netmask)) goto invalid_addr; } } @@ -238,29 +256,44 @@ static_attach(struct proto_handler *h, struct interface *iface, if (tb[OPT_IP6ADDR]) { if (tb[OPT_IP6ADDR]->type == UCI_TYPE_STRING) { - n_v6 = 1; - v6 = alloca(sizeof(*v6)); - v6->prefix = netmask; - if (!parse_v6(tb[OPT_IP6ADDR]->v.string, v6, netmask)) + 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; - n_v6 = count_list_entries(tb[OPT_IP6ADDR]); - v6 = alloca(sizeof(*v6) * n_v6); + 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, &v6[i++], netmask)) + if (!parse_v6(e->name, &ps.v6[i++], netmask)) goto invalid_addr; } } } - - if (!n_v4 && !n_v6) { + if (!ps.n_v4 && !ps.n_v6) { error = "NO_ADDRESS"; goto error; } - return static_create_state(iface, v4, n_v4, v6, n_v6); + if (ps.n_v4 && tb[OPT_GATEWAY]) { + if (!inet_pton(AF_INET, tb[OPT_GATEWAY]->v.string, &ps.ipv4gw)) { + error = "INVALID_GATEWAY"; + goto error; + } + ps.flags |= STATIC_F_IPV4GW; + } + + if (ps.n_v6 && tb[OPT_IP6GW]) { + if (!inet_pton(AF_INET6, tb[OPT_IP6GW]->v.string, &ps.ipv6gw)) { + error = "INVALID_GATEWAY"; + goto error; + } + ps.flags |= STATIC_F_IPV6GW; + } + + return static_create_state(iface, &ps); invalid_addr: error = "INVALID_ADDRESS"; |