2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
22 #include "interface.h"
23 #include "interface-ip.h"
26 static struct avl_tree handlers
;
40 static const struct blobmsg_policy proto_ip_attributes
[__OPT_MAX
] = {
41 [OPT_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_ARRAY
},
42 [OPT_IP6ADDR
] = { .name
= "ip6addr", .type
= BLOBMSG_TYPE_ARRAY
},
43 [OPT_NETMASK
] = { .name
= "netmask", .type
= BLOBMSG_TYPE_STRING
},
44 [OPT_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
45 [OPT_GATEWAY
] = { .name
= "gateway", .type
= BLOBMSG_TYPE_STRING
},
46 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= BLOBMSG_TYPE_STRING
},
47 [OPT_DNS
] = { .name
= "dns", .type
= BLOBMSG_TYPE_ARRAY
},
48 [OPT_DNS_SEARCH
] = { .name
= "dns_search", .type
= BLOBMSG_TYPE_ARRAY
},
51 static const union config_param_info proto_ip_attr_info
[__OPT_MAX
] = {
52 [OPT_IPADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
53 [OPT_IP6ADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
54 [OPT_DNS
] = { .type
= BLOBMSG_TYPE_STRING
},
57 const struct config_param_list proto_ip_attr
= {
58 .n_params
= __OPT_MAX
,
59 .params
= proto_ip_attributes
,
60 .info
= proto_ip_attr_info
,
65 parse_netmask_string(const char *str
, bool v6
)
71 if (!strchr(str
, '.')) {
72 ret
= strtoul(str
, &err
, 0);
82 if (inet_aton(str
, &addr
) != 1)
85 return 32 - fls(~(ntohl(addr
.s_addr
)));
92 split_netmask(char *str
, unsigned int *netmask
, bool v6
)
94 char *delim
= strchr(str
, '/');
99 *netmask
= parse_netmask_string(delim
, v6
);
105 parse_ip_and_netmask(int af
, const char *str
, void *addr
, unsigned int *netmask
)
107 char *astr
= alloca(strlen(str
) + 1);
110 if (!split_netmask(astr
, netmask
, af
== AF_INET6
))
113 if (af
== AF_INET6
) {
121 return inet_pton(af
, astr
, addr
);
124 static struct device_addr
*
125 proto_parse_ip_addr_string(const char *str
, bool v6
, int mask
)
127 struct device_addr
*addr
;
128 int af
= v6
? AF_INET6
: AF_INET
;
130 addr
= calloc(1, sizeof(*addr
));
131 addr
->flags
= v6
? DEVADDR_INET6
: DEVADDR_INET4
;
133 if (!parse_ip_and_netmask(af
, str
, &addr
->addr
, &addr
->mask
)) {
141 parse_addr(struct interface
*iface
, const char *str
, bool v6
, int mask
,
142 bool ext
, uint32_t broadcast
)
144 struct device_addr
*addr
;
146 addr
= proto_parse_ip_addr_string(str
, v6
, mask
);
148 interface_add_error(iface
, "proto", "INVALID_ADDRESS", &str
, 1);
153 addr
->broadcast
= broadcast
;
156 addr
->flags
|= DEVADDR_EXTERNAL
;
158 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, &addr
->flags
);
163 parse_address_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
,
164 int netmask
, bool ext
, uint32_t broadcast
)
166 struct blob_attr
*cur
;
170 blobmsg_for_each_attr(cur
, attr
, rem
) {
171 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
175 if (!parse_addr(iface
, blobmsg_data(cur
), v6
, netmask
, ext
,
185 parse_gateway_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
)
187 struct device_route
*route
;
188 const char *str
= blobmsg_data(attr
);
189 int af
= v6
? AF_INET6
: AF_INET
;
191 route
= calloc(1, sizeof(*route
));
192 if (!inet_pton(af
, str
, &route
->nexthop
)) {
193 interface_add_error(iface
, "proto", "INVALID_GATEWAY", &str
, 1);
199 route
->flags
= (v6
? DEVADDR_INET6
: DEVADDR_INET4
);
200 vlist_add(&iface
->proto_ip
.route
, &route
->node
, &route
->flags
);
206 proto_apply_static_ip_settings(struct interface
*iface
, struct blob_attr
*attr
)
208 struct blob_attr
*tb
[__OPT_MAX
];
209 struct blob_attr
*cur
;
211 unsigned int netmask
= 32;
212 int n_v4
= 0, n_v6
= 0;
213 struct in_addr bcast
= {};
215 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
217 if ((cur
= tb
[OPT_NETMASK
])) {
218 netmask
= parse_netmask_string(blobmsg_data(cur
), false);
220 error
= "INVALID_NETMASK";
225 if ((cur
= tb
[OPT_BROADCAST
])) {
226 if (!inet_pton(AF_INET
, blobmsg_data(cur
), &bcast
)) {
227 error
= "INVALID_BROADCAST";
232 if ((cur
= tb
[OPT_IPADDR
]))
233 n_v4
= parse_address_option(iface
, cur
, false,
234 netmask
, false, bcast
.s_addr
);
236 if ((cur
= tb
[OPT_IP6ADDR
]))
237 n_v6
= parse_address_option(iface
, cur
, true,
240 if (!n_v4
&& !n_v6
) {
241 error
= "NO_ADDRESS";
245 if (n_v4
< 0 || n_v6
< 0)
248 if ((cur
= tb
[OPT_GATEWAY
])) {
249 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
253 if ((cur
= tb
[OPT_IP6GW
])) {
254 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
258 if ((cur
= tb
[OPT_DNS
]))
259 interface_add_dns_server_list(&iface
->proto_ip
, cur
);
261 if ((cur
= tb
[OPT_DNS_SEARCH
]))
262 interface_add_dns_search_list(&iface
->proto_ip
, cur
);
267 interface_add_error(iface
, "proto", error
, NULL
, 0);
273 proto_apply_ip_settings(struct interface
*iface
, struct blob_attr
*attr
, bool ext
)
275 struct blob_attr
*tb
[__OPT_MAX
];
276 struct blob_attr
*cur
;
278 int n_v4
= 0, n_v6
= 0;
279 struct in_addr bcast
= {};
281 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
283 if ((cur
= tb
[OPT_IPADDR
]))
284 n_v4
= parse_address_option(iface
, cur
, false,
285 32, ext
, bcast
.s_addr
);
287 if ((cur
= tb
[OPT_IP6ADDR
]))
288 n_v6
= parse_address_option(iface
, cur
, true,
291 if (!n_v4
&& !n_v6
) {
292 error
= "NO_ADDRESS";
296 if (n_v4
< 0 || n_v6
< 0)
299 if ((cur
= tb
[OPT_GATEWAY
])) {
300 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
304 if ((cur
= tb
[OPT_IP6GW
])) {
305 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
309 if ((cur
= tb
[OPT_DNS
]))
310 interface_add_dns_server_list(&iface
->proto_ip
, cur
);
312 if ((cur
= tb
[OPT_DNS_SEARCH
]))
313 interface_add_dns_search_list(&iface
->proto_ip
, cur
);
318 interface_add_error(iface
, "proto", error
, NULL
, 0);
323 void add_proto_handler(struct proto_handler
*p
)
326 avl_init(&handlers
, avl_strcmp
, false, NULL
);
331 p
->avl
.key
= p
->name
;
332 avl_insert(&handlers
, &p
->avl
);
336 default_proto_free(struct interface_proto_state
*proto
)
342 invalid_proto_handler(struct interface_proto_state
*proto
,
343 enum interface_proto_cmd cmd
, bool force
)
349 no_proto_handler(struct interface_proto_state
*proto
,
350 enum interface_proto_cmd cmd
, bool force
)
355 static struct interface_proto_state
*
356 default_proto_attach(const struct proto_handler
*h
,
357 struct interface
*iface
, struct blob_attr
*attr
)
359 struct interface_proto_state
*proto
;
361 proto
= calloc(1, sizeof(*proto
));
362 proto
->free
= default_proto_free
;
363 proto
->cb
= no_proto_handler
;
368 static const struct proto_handler no_proto
= {
370 .flags
= PROTO_FLAG_IMMEDIATE
,
371 .attach
= default_proto_attach
,
374 static const struct proto_handler
*
375 get_proto_handler(const char *name
)
377 struct proto_handler
*proto
;
379 if (!strcmp(name
, "none"))
385 return avl_find_element(&handlers
, name
, proto
, avl
);
389 proto_init_interface(struct interface
*iface
, struct blob_attr
*attr
)
391 const struct proto_handler
*proto
= iface
->proto_handler
;
392 struct interface_proto_state
*state
= NULL
;
397 state
= proto
->attach(proto
, iface
, attr
);
399 state
= no_proto
.attach(&no_proto
, iface
, attr
);
400 state
->cb
= invalid_proto_handler
;
403 state
->handler
= proto
;
404 interface_set_proto_state(iface
, state
);
408 proto_attach_interface(struct interface
*iface
, const char *proto_name
)
410 const struct proto_handler
*proto
= &no_proto
;
413 proto
= get_proto_handler(proto_name
);
415 interface_add_error(iface
, "proto", "INVALID_PROTO", NULL
, 0);
420 iface
->proto_handler
= proto
;
424 interface_proto_event(struct interface_proto_state
*proto
,
425 enum interface_proto_cmd cmd
, bool force
)
427 enum interface_proto_event ev
;
430 ret
= proto
->cb(proto
, cmd
, force
);
431 if (ret
|| !(proto
->handler
->flags
& PROTO_FLAG_IMMEDIATE
))
435 case PROTO_CMD_SETUP
:
438 case PROTO_CMD_TEARDOWN
:
444 proto
->proto_event(proto
, ev
);