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
;
38 static const struct blobmsg_policy proto_ip_attributes
[__OPT_MAX
] = {
39 [OPT_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_ARRAY
},
40 [OPT_IP6ADDR
] = { .name
= "ip6addr", .type
= BLOBMSG_TYPE_ARRAY
},
41 [OPT_NETMASK
] = { .name
= "netmask", .type
= BLOBMSG_TYPE_STRING
},
42 [OPT_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
43 [OPT_GATEWAY
] = { .name
= "gateway", .type
= BLOBMSG_TYPE_STRING
},
44 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= BLOBMSG_TYPE_STRING
},
47 static const union config_param_info proto_ip_attr_info
[__OPT_MAX
] = {
48 [OPT_IPADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
49 [OPT_IP6ADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
52 const struct config_param_list proto_ip_attr
= {
53 .n_params
= __OPT_MAX
,
54 .params
= proto_ip_attributes
,
55 .info
= proto_ip_attr_info
,
66 static const struct blobmsg_policy proto_ip_addr
[__ADDR_MAX
] = {
67 [ADDR_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_STRING
},
68 [ADDR_MASK
] = { .name
= "mask", .type
= BLOBMSG_TYPE_STRING
},
69 [ADDR_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
70 [ADDR_PTP
] = { .name
= "ptp", .type
= BLOBMSG_TYPE_STRING
},
73 static struct device_addr
*
74 alloc_device_addr(bool v6
, bool ext
)
76 struct device_addr
*addr
;
78 addr
= calloc(1, sizeof(*addr
));
79 addr
->flags
= v6
? DEVADDR_INET6
: DEVADDR_INET4
;
81 addr
->flags
|= DEVADDR_EXTERNAL
;
87 parse_addr(struct interface
*iface
, const char *str
, bool v6
, int mask
,
88 bool ext
, uint32_t broadcast
)
90 struct device_addr
*addr
;
91 int af
= v6
? AF_INET6
: AF_INET
;
93 addr
= alloc_device_addr(v6
, ext
);
98 if (!parse_ip_and_netmask(af
, str
, &addr
->addr
, &addr
->mask
)) {
99 interface_add_error(iface
, "proto", "INVALID_ADDRESS", &str
, 1);
105 addr
->broadcast
= broadcast
;
107 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, &addr
->flags
);
112 parse_static_address_option(struct interface
*iface
, struct blob_attr
*attr
,
113 bool v6
, int netmask
, bool ext
, uint32_t broadcast
)
115 struct blob_attr
*cur
;
119 blobmsg_for_each_attr(cur
, attr
, rem
) {
120 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
124 if (!parse_addr(iface
, blobmsg_data(cur
), v6
, netmask
, ext
,
132 static struct device_addr
*
133 parse_address_item(struct blob_attr
*attr
, bool v6
, bool ext
)
135 struct device_addr
*addr
;
136 struct blob_attr
*tb
[__ADDR_MAX
];
137 struct blob_attr
*cur
;
139 if (blobmsg_type(attr
) != BLOBMSG_TYPE_TABLE
)
142 addr
= alloc_device_addr(v6
, ext
);
146 blobmsg_parse(proto_ip_addr
, __ADDR_MAX
, tb
, blobmsg_data(attr
), blobmsg_data_len(attr
));
148 addr
->mask
= v6
? 128 : 32;
149 if ((cur
= tb
[ADDR_MASK
])) {
150 unsigned int new_mask
;
152 new_mask
= parse_netmask_string(blobmsg_data(cur
), v6
);
153 if (new_mask
> addr
->mask
)
156 addr
->mask
= new_mask
;
159 cur
= tb
[ADDR_IPADDR
];
163 if (!inet_pton(v6
? AF_INET6
: AF_INET
, blobmsg_data(cur
), &addr
->addr
))
167 if ((cur
= tb
[ADDR_BROADCAST
]) &&
168 !inet_pton(AF_INET
, blobmsg_data(cur
), &addr
->broadcast
))
170 if ((cur
= tb
[ADDR_PTP
]) &&
171 !inet_pton(AF_INET
, blobmsg_data(cur
), &addr
->point_to_point
))
183 parse_address_list(struct interface
*iface
, struct blob_attr
*attr
, bool v6
,
186 struct device_addr
*addr
;
187 struct blob_attr
*cur
;
191 blobmsg_for_each_attr(cur
, attr
, rem
) {
192 addr
= parse_address_item(cur
, v6
, ext
);
197 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, &addr
->flags
);
204 parse_gateway_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
)
206 struct device_route
*route
;
207 const char *str
= blobmsg_data(attr
);
208 int af
= v6
? AF_INET6
: AF_INET
;
210 route
= calloc(1, sizeof(*route
));
211 if (!inet_pton(af
, str
, &route
->nexthop
)) {
212 interface_add_error(iface
, "proto", "INVALID_GATEWAY", &str
, 1);
218 route
->flags
= (v6
? DEVADDR_INET6
: DEVADDR_INET4
);
219 vlist_add(&iface
->proto_ip
.route
, &route
->node
, &route
->flags
);
225 proto_apply_static_ip_settings(struct interface
*iface
, struct blob_attr
*attr
)
227 struct blob_attr
*tb
[__OPT_MAX
];
228 struct blob_attr
*cur
;
230 unsigned int netmask
= 32;
231 int n_v4
= 0, n_v6
= 0;
232 struct in_addr bcast
= {};
234 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
236 if ((cur
= tb
[OPT_NETMASK
])) {
237 netmask
= parse_netmask_string(blobmsg_data(cur
), false);
239 error
= "INVALID_NETMASK";
244 if ((cur
= tb
[OPT_BROADCAST
])) {
245 if (!inet_pton(AF_INET
, blobmsg_data(cur
), &bcast
)) {
246 error
= "INVALID_BROADCAST";
251 if ((cur
= tb
[OPT_IPADDR
]))
252 n_v4
= parse_static_address_option(iface
, cur
, false,
253 netmask
, false, bcast
.s_addr
);
255 if ((cur
= tb
[OPT_IP6ADDR
]))
256 n_v6
= parse_static_address_option(iface
, cur
, true,
259 if (!n_v4
&& !n_v6
) {
260 error
= "NO_ADDRESS";
264 if (n_v4
< 0 || n_v6
< 0)
267 if ((cur
= tb
[OPT_GATEWAY
])) {
268 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
272 if ((cur
= tb
[OPT_IP6GW
])) {
273 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
280 interface_add_error(iface
, "proto", error
, NULL
, 0);
286 proto_apply_ip_settings(struct interface
*iface
, struct blob_attr
*attr
, bool ext
)
288 struct blob_attr
*tb
[__OPT_MAX
];
289 struct blob_attr
*cur
;
291 int n_v4
= 0, n_v6
= 0;
293 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
295 if ((cur
= tb
[OPT_IPADDR
]))
296 n_v4
= parse_address_list(iface
, cur
, false, ext
);
298 if ((cur
= tb
[OPT_IP6ADDR
]))
299 n_v6
= parse_address_list(iface
, cur
, true, ext
);
301 if (!n_v4
&& !n_v6
) {
302 error
= "NO_ADDRESS";
306 if (n_v4
< 0 || n_v6
< 0)
309 if ((cur
= tb
[OPT_GATEWAY
])) {
310 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
314 if ((cur
= tb
[OPT_IP6GW
])) {
315 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
322 interface_add_error(iface
, "proto", error
, NULL
, 0);
327 void add_proto_handler(struct proto_handler
*p
)
330 avl_init(&handlers
, avl_strcmp
, false, NULL
);
335 p
->avl
.key
= p
->name
;
336 avl_insert(&handlers
, &p
->avl
);
340 default_proto_free(struct interface_proto_state
*proto
)
346 invalid_proto_handler(struct interface_proto_state
*proto
,
347 enum interface_proto_cmd cmd
, bool force
)
353 no_proto_handler(struct interface_proto_state
*proto
,
354 enum interface_proto_cmd cmd
, bool force
)
359 static struct interface_proto_state
*
360 default_proto_attach(const struct proto_handler
*h
,
361 struct interface
*iface
, struct blob_attr
*attr
)
363 struct interface_proto_state
*proto
;
365 proto
= calloc(1, sizeof(*proto
));
366 proto
->free
= default_proto_free
;
367 proto
->cb
= no_proto_handler
;
372 static const struct proto_handler no_proto
= {
374 .flags
= PROTO_FLAG_IMMEDIATE
,
375 .attach
= default_proto_attach
,
378 static const struct proto_handler
*
379 get_proto_handler(const char *name
)
381 struct proto_handler
*proto
;
383 if (!strcmp(name
, "none"))
389 return avl_find_element(&handlers
, name
, proto
, avl
);
393 proto_dump_handlers(struct blob_buf
*b
)
395 struct proto_handler
*p
;
398 avl_for_each_element(&handlers
, p
, avl
) {
399 c
= blobmsg_open_table(b
, p
->name
);
400 blobmsg_add_u8(b
, "no_device", !!(p
->flags
& PROTO_FLAG_NODEV
));
401 blobmsg_close_table(b
, c
);
406 proto_init_interface(struct interface
*iface
, struct blob_attr
*attr
)
408 const struct proto_handler
*proto
= iface
->proto_handler
;
409 struct interface_proto_state
*state
= NULL
;
414 state
= proto
->attach(proto
, iface
, attr
);
416 state
= no_proto
.attach(&no_proto
, iface
, attr
);
417 state
->cb
= invalid_proto_handler
;
420 state
->handler
= proto
;
421 interface_set_proto_state(iface
, state
);
425 proto_attach_interface(struct interface
*iface
, const char *proto_name
)
427 const struct proto_handler
*proto
= &no_proto
;
430 proto
= get_proto_handler(proto_name
);
432 interface_add_error(iface
, "proto", "INVALID_PROTO", NULL
, 0);
437 iface
->proto_handler
= proto
;
441 interface_proto_event(struct interface_proto_state
*proto
,
442 enum interface_proto_cmd cmd
, bool force
)
444 enum interface_proto_event ev
;
447 ret
= proto
->cb(proto
, cmd
, force
);
448 if (ret
|| !(proto
->handler
->flags
& PROTO_FLAG_IMMEDIATE
))
452 case PROTO_CMD_SETUP
:
455 case PROTO_CMD_TEARDOWN
:
461 proto
->proto_event(proto
, ev
);