use false instead of 0 for a bool variable
[project/netifd.git] / proto-static.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7
8 #include "netifd.h"
9 #include "interface.h"
10 #include "interface-ip.h"
11 #include "proto.h"
12 #include "system.h"
13
14 enum {
15 OPT_IPADDR,
16 OPT_IP6ADDR,
17 OPT_NETMASK,
18 OPT_GATEWAY,
19 OPT_IP6GW,
20 __OPT_MAX,
21 };
22
23 static const struct blobmsg_policy static_attrs[__OPT_MAX] = {
24 [OPT_IPADDR] = { .name = "ipaddr", .type = BLOBMSG_TYPE_ARRAY },
25 [OPT_IP6ADDR] = { .name = "ip6addr", .type = BLOBMSG_TYPE_ARRAY },
26 [OPT_NETMASK] = { .name = "netmask", .type = BLOBMSG_TYPE_STRING },
27 [OPT_GATEWAY] = { .name = "gateway", .type = BLOBMSG_TYPE_STRING },
28 [OPT_IP6GW] = { .name = "ip6gw", .type = BLOBMSG_TYPE_STRING },
29 };
30
31 static const union config_param_info static_attr_info[__OPT_MAX] = {
32 [OPT_IPADDR] = { .type = BLOBMSG_TYPE_STRING },
33 [OPT_IP6ADDR] = { .type = BLOBMSG_TYPE_STRING },
34 };
35
36 static const struct config_param_list static_attr_list = {
37 .n_params = __OPT_MAX,
38 .params = static_attrs,
39 .info = static_attr_info,
40 };
41
42 struct static_proto_state {
43 struct interface_proto_state proto;
44
45 struct blob_attr *config;
46 };
47
48 static bool
49 split_netmask(char *str, unsigned int *netmask)
50 {
51 char *delim, *err = NULL;
52
53 delim = strchr(str, '/');
54 if (delim) {
55 *(delim++) = 0;
56
57 *netmask = strtoul(delim, &err, 10);
58 if (err && *err)
59 return false;
60 }
61 return true;
62 }
63
64 static int
65 parse_ip_and_netmask(int af, const char *str, void *addr, unsigned int *netmask)
66 {
67 char *astr = alloca(strlen(str) + 1);
68
69 strcpy(astr, str);
70 if (!split_netmask(astr, netmask))
71 return 0;
72
73 if (af == AF_INET6) {
74 if (*netmask > 128)
75 return 0;
76 } else {
77 if (*netmask > 32)
78 return 0;
79 }
80
81 return inet_pton(af, str, addr);
82 }
83
84 static bool
85 parse_addr(struct interface_proto_state *state, const char *str, bool v6, int mask)
86 {
87 struct device_addr *addr;
88 int af = v6 ? AF_INET6 : AF_INET;
89
90 addr = calloc(1, sizeof(*addr));
91 addr->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
92 addr->mask = mask;
93 if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) {
94 interface_add_error(state->iface, "proto-static", "INVALID_ADDRESS", &str, 1);
95 free(addr);
96 return false;
97 }
98 vlist_add(&state->iface->proto_addr, &addr->node);
99 return true;
100 }
101
102 static int
103 parse_address_option(struct interface_proto_state *state, struct blob_attr *attr, bool v6, int netmask)
104 {
105 struct blob_attr *cur;
106 int n_addr = 0;
107 int rem;
108
109 blobmsg_for_each_attr(cur, attr, rem) {
110 n_addr++;
111 if (!parse_addr(state, blobmsg_data(cur), v6, netmask))
112 return -1;
113 }
114
115 return n_addr;
116 }
117
118 static bool
119 parse_gateway_option(struct interface_proto_state *state, struct blob_attr *attr, bool v6)
120 {
121 struct device_route *route;
122 const char *str = blobmsg_data(attr);
123 int af = v6 ? AF_INET6 : AF_INET;
124
125 route = calloc(1, sizeof(*route));
126 if (!inet_pton(af, str, &route->nexthop)) {
127 interface_add_error(state->iface, "proto-static",
128 "INVALID_GATEWAY", &str, 1);
129 free(route);
130 return false;
131 }
132 route->mask = 0;
133 route->flags = DEVADDR_DEVICE | (v6 ? DEVADDR_INET6 : DEVADDR_INET4);
134 vlist_add(&state->iface->proto_route, &route->node);
135
136 return true;
137 }
138
139 int
140 proto_apply_static_settings(struct interface_proto_state *state, struct blob_attr *attr)
141 {
142 struct blob_attr *tb[__OPT_MAX];
143 struct in_addr ina;
144 const char *error;
145 int netmask = 32;
146 int n_v4 = 0, n_v6 = 0;
147
148 blobmsg_parse(static_attrs, __OPT_MAX, tb, blob_data(attr), blob_len(attr));
149
150 if (tb[OPT_NETMASK]) {
151 if (!inet_aton(blobmsg_data(tb[OPT_NETMASK]), &ina)) {
152 error = "INVALID_NETMASK";
153 goto error;
154 }
155
156 netmask = 32 - fls(~(ntohl(ina.s_addr)));
157 }
158
159 if (tb[OPT_IPADDR])
160 n_v4 = parse_address_option(state, tb[OPT_IPADDR], false, netmask);
161
162 if (tb[OPT_IP6ADDR])
163 n_v6 = parse_address_option(state, tb[OPT_IP6ADDR], true, netmask);
164
165 if (!n_v4 && !n_v6) {
166 error = "NO_ADDRESS";
167 goto error;
168 }
169
170 if (n_v4 < 0 || n_v6 < 0)
171 goto out;
172
173 if (n_v4 && tb[OPT_GATEWAY]) {
174 if (!parse_gateway_option(state, tb[OPT_GATEWAY], false))
175 goto out;
176 }
177
178 if (n_v6 && tb[OPT_IP6GW]) {
179 if (!parse_gateway_option(state, tb[OPT_IP6GW], true))
180 goto out;
181 }
182
183 return 0;
184
185 error:
186 interface_add_error(state->iface, "proto-static", error, NULL, 0);
187 out:
188 return -1;
189 }
190
191 static bool
192 static_proto_setup(struct static_proto_state *state)
193 {
194 return proto_apply_static_settings(&state->proto, state->config) == 0;
195 }
196
197 static int
198 static_handler(struct interface_proto_state *proto,
199 enum interface_proto_cmd cmd, bool force)
200 {
201 struct static_proto_state *state;
202 int ret = 0;
203
204 state = container_of(proto, struct static_proto_state, proto);
205
206 switch (cmd) {
207 case PROTO_CMD_SETUP:
208 if (!static_proto_setup(state))
209 return -1;
210
211 break;
212 case PROTO_CMD_TEARDOWN:
213 break;
214 }
215 return ret;
216 }
217
218 static void
219 static_free(struct interface_proto_state *proto)
220 {
221 struct static_proto_state *state;
222
223 state = container_of(proto, struct static_proto_state, proto);
224 free(state->config);
225 free(state);
226 }
227
228 struct interface_proto_state *
229 static_attach(const struct proto_handler *h, struct interface *iface,
230 struct blob_attr *attr)
231 {
232 struct static_proto_state *state;
233
234 state = calloc(1, sizeof(*state));
235 if (!state)
236 return NULL;
237
238 state->config = malloc(blob_pad_len(attr));
239 if (!state->config)
240 goto error;
241
242 memcpy(state->config, attr, blob_pad_len(attr));
243 state->proto.free = static_free;
244 state->proto.cb = static_handler;
245
246 return &state->proto;
247
248 error:
249 free(state);
250 return NULL;
251 }
252
253 static struct proto_handler static_proto = {
254 .name = "static",
255 .flags = PROTO_FLAG_IMMEDIATE,
256 .config_params = &static_attr_list,
257 .attach = static_attach,
258 };
259
260 static void __init
261 static_proto_init(void)
262 {
263 add_proto_handler(&static_proto);
264 }