6 #include <netinet/in.h>
10 #include "interface-ip.h"
13 static struct avl_tree handlers
;
26 static const struct blobmsg_policy proto_ip_attributes
[__OPT_MAX
] = {
27 [OPT_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_ARRAY
},
28 [OPT_IP6ADDR
] = { .name
= "ip6addr", .type
= BLOBMSG_TYPE_ARRAY
},
29 [OPT_NETMASK
] = { .name
= "netmask", .type
= BLOBMSG_TYPE_STRING
},
30 [OPT_GATEWAY
] = { .name
= "gateway", .type
= BLOBMSG_TYPE_STRING
},
31 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= BLOBMSG_TYPE_STRING
},
32 [OPT_DNS
] = { .name
= "dns", .type
= BLOBMSG_TYPE_ARRAY
},
33 [OPT_DNS_SEARCH
] = { .name
= "dns_search", .type
= BLOBMSG_TYPE_ARRAY
},
36 static const union config_param_info proto_ip_attr_info
[__OPT_MAX
] = {
37 [OPT_IPADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
38 [OPT_IP6ADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
39 [OPT_DNS
] = { .type
= BLOBMSG_TYPE_STRING
},
42 const struct config_param_list proto_ip_attr
= {
43 .n_params
= __OPT_MAX
,
44 .params
= proto_ip_attributes
,
45 .info
= proto_ip_attr_info
,
50 parse_netmask_string(const char *str
, bool v6
)
56 if (!strchr(str
, '.')) {
57 ret
= strtoul(str
, &err
, 0);
67 if (inet_aton(str
, &addr
) != 1)
70 return 32 - fls(~(ntohl(addr
.s_addr
)));
77 split_netmask(char *str
, unsigned int *netmask
, bool v6
)
79 char *delim
= strchr(str
, '/');
84 *netmask
= parse_netmask_string(delim
, v6
);
90 parse_ip_and_netmask(int af
, const char *str
, void *addr
, unsigned int *netmask
)
92 char *astr
= alloca(strlen(str
) + 1);
95 if (!split_netmask(astr
, netmask
, af
== AF_INET6
))
106 return inet_pton(af
, astr
, addr
);
110 proto_parse_ip_addr_string(const char *str
, bool v6
, int mask
)
112 struct device_addr
*addr
;
113 int af
= v6
? AF_INET6
: AF_INET
;
115 addr
= calloc(1, sizeof(*addr
));
116 addr
->flags
= v6
? DEVADDR_INET6
: DEVADDR_INET4
;
118 if (!parse_ip_and_netmask(af
, str
, &addr
->addr
, &addr
->mask
)) {
126 parse_addr(struct interface
*iface
, const char *str
, bool v6
, int mask
, bool ext
)
128 struct device_addr
*addr
;
130 addr
= proto_parse_ip_addr_string(str
, v6
, mask
);
132 interface_add_error(iface
, "proto", "INVALID_ADDRESS", &str
, 1);
137 addr
->flags
|= DEVADDR_EXTERNAL
;
139 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
);
144 parse_address_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
, int netmask
, bool ext
)
146 struct blob_attr
*cur
;
150 blobmsg_for_each_attr(cur
, attr
, rem
) {
151 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
155 if (!parse_addr(iface
, blobmsg_data(cur
), v6
, netmask
, ext
))
164 parse_gateway_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
)
166 struct device_route
*route
;
167 const char *str
= blobmsg_data(attr
);
168 int af
= v6
? AF_INET6
: AF_INET
;
170 route
= calloc(1, sizeof(*route
));
171 if (!inet_pton(af
, str
, &route
->nexthop
)) {
172 interface_add_error(iface
, "proto", "INVALID_GATEWAY", &str
, 1);
178 route
->flags
= DEVADDR_DEVICE
| (v6
? DEVADDR_INET6
: DEVADDR_INET4
);
179 vlist_add(&iface
->proto_ip
.route
, &route
->node
);
185 proto_apply_ip_settings(struct interface
*iface
, struct blob_attr
*attr
, bool ext
)
187 struct blob_attr
*tb
[__OPT_MAX
];
189 unsigned int netmask
= 32;
190 int n_v4
= 0, n_v6
= 0;
192 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
194 if (tb
[OPT_NETMASK
]) {
195 netmask
= parse_netmask_string(blobmsg_data(tb
[OPT_NETMASK
]), false);
197 error
= "INVALID_NETMASK";
203 n_v4
= parse_address_option(iface
, tb
[OPT_IPADDR
], false, netmask
, ext
);
206 n_v6
= parse_address_option(iface
, tb
[OPT_IP6ADDR
], true, netmask
, ext
);
208 if (!n_v4
&& !n_v6
) {
209 error
= "NO_ADDRESS";
213 if (n_v4
< 0 || n_v6
< 0)
216 if (n_v4
&& tb
[OPT_GATEWAY
]) {
217 if (!parse_gateway_option(iface
, tb
[OPT_GATEWAY
], false))
221 if (n_v6
&& tb
[OPT_IP6GW
]) {
222 if (!parse_gateway_option(iface
, tb
[OPT_IP6GW
], true))
227 interface_add_dns_server_list(&iface
->proto_ip
, tb
[OPT_DNS
]);
229 if (tb
[OPT_DNS_SEARCH
])
230 interface_add_dns_search_list(&iface
->proto_ip
, tb
[OPT_DNS_SEARCH
]);
235 interface_add_error(iface
, "proto", error
, NULL
, 0);
240 void add_proto_handler(struct proto_handler
*p
)
243 avl_init(&handlers
, avl_strcmp
, false, NULL
);
248 p
->avl
.key
= p
->name
;
249 avl_insert(&handlers
, &p
->avl
);
253 default_proto_free(struct interface_proto_state
*proto
)
259 invalid_proto_handler(struct interface_proto_state
*proto
,
260 enum interface_proto_cmd cmd
, bool force
)
266 no_proto_handler(struct interface_proto_state
*proto
,
267 enum interface_proto_cmd cmd
, bool force
)
272 static struct interface_proto_state
*
273 default_proto_attach(const struct proto_handler
*h
,
274 struct interface
*iface
, struct blob_attr
*attr
)
276 struct interface_proto_state
*proto
;
278 proto
= calloc(1, sizeof(*proto
));
279 proto
->free
= default_proto_free
;
280 proto
->cb
= no_proto_handler
;
285 static const struct proto_handler no_proto
= {
287 .flags
= PROTO_FLAG_IMMEDIATE
,
288 .attach
= default_proto_attach
,
291 static const struct proto_handler
*
292 get_proto_handler(const char *name
)
294 struct proto_handler
*proto
;
296 if (!strcmp(name
, "none"))
302 return avl_find_element(&handlers
, name
, proto
, avl
);
306 proto_init_interface(struct interface
*iface
, struct blob_attr
*attr
)
308 const struct proto_handler
*proto
= iface
->proto_handler
;
309 struct interface_proto_state
*state
= NULL
;
314 state
= proto
->attach(proto
, iface
, attr
);
316 state
= no_proto
.attach(&no_proto
, iface
, attr
);
317 state
->cb
= invalid_proto_handler
;
320 state
->handler
= proto
;
321 interface_set_proto_state(iface
, state
);
325 proto_attach_interface(struct interface
*iface
, const char *proto_name
)
327 const struct proto_handler
*proto
= &no_proto
;
330 proto
= get_proto_handler(proto_name
);
332 interface_add_error(iface
, "proto", "INVALID_PROTO", NULL
, 0);
337 iface
->proto_handler
= proto
;
341 interface_proto_event(struct interface_proto_state
*proto
,
342 enum interface_proto_cmd cmd
, bool force
)
344 enum interface_proto_event ev
;
347 ret
= proto
->cb(proto
, cmd
, force
);
348 if (ret
|| !(proto
->handler
->flags
& PROTO_FLAG_IMMEDIATE
))
352 case PROTO_CMD_SETUP
:
355 case PROTO_CMD_TEARDOWN
:
361 proto
->proto_event(proto
, ev
);