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>
23 #include "interface.h"
24 #include "interface-ip.h"
27 static struct avl_tree handlers
;
41 static const struct blobmsg_policy proto_ip_attributes
[__OPT_MAX
] = {
42 [OPT_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_ARRAY
},
43 [OPT_IP6ADDR
] = { .name
= "ip6addr", .type
= BLOBMSG_TYPE_ARRAY
},
44 [OPT_NETMASK
] = { .name
= "netmask", .type
= BLOBMSG_TYPE_STRING
},
45 [OPT_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
46 [OPT_GATEWAY
] = { .name
= "gateway", .type
= BLOBMSG_TYPE_STRING
},
47 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= BLOBMSG_TYPE_STRING
},
48 [OPT_IP6PREFIX
] = { .name
= "ip6prefix", .type
= BLOBMSG_TYPE_ARRAY
},
49 [OPT_IP6ASSIGN
] = { .name
= "ip6assign", .type
= BLOBMSG_TYPE_INT32
},
52 static const union config_param_info proto_ip_attr_info
[__OPT_MAX
] = {
53 [OPT_IPADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
54 [OPT_IP6ADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
55 [OPT_IP6PREFIX
] = { .type
= BLOBMSG_TYPE_STRING
},
58 const struct config_param_list proto_ip_attr
= {
59 .n_params
= __OPT_MAX
,
60 .params
= proto_ip_attributes
,
61 .info
= proto_ip_attr_info
,
72 static const struct blobmsg_policy proto_ip_addr
[__ADDR_MAX
] = {
73 [ADDR_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_STRING
},
74 [ADDR_MASK
] = { .name
= "mask", .type
= BLOBMSG_TYPE_STRING
},
75 [ADDR_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
76 [ADDR_PTP
] = { .name
= "ptp", .type
= BLOBMSG_TYPE_STRING
},
79 static struct device_addr
*
80 alloc_device_addr(bool v6
, bool ext
)
82 struct device_addr
*addr
;
84 addr
= calloc(1, sizeof(*addr
));
85 addr
->flags
= v6
? DEVADDR_INET6
: DEVADDR_INET4
;
87 addr
->flags
|= DEVADDR_EXTERNAL
;
93 parse_addr(struct interface
*iface
, const char *str
, bool v6
, int mask
,
94 bool ext
, uint32_t broadcast
)
96 struct device_addr
*addr
;
97 int af
= v6
? AF_INET6
: AF_INET
;
99 addr
= alloc_device_addr(v6
, ext
);
104 if (!parse_ip_and_netmask(af
, str
, &addr
->addr
, &addr
->mask
)) {
105 interface_add_error(iface
, "proto", "INVALID_ADDRESS", &str
, 1);
111 addr
->broadcast
= broadcast
;
113 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, &addr
->flags
);
118 parse_static_address_option(struct interface
*iface
, struct blob_attr
*attr
,
119 bool v6
, int netmask
, bool ext
, uint32_t broadcast
)
121 struct blob_attr
*cur
;
125 blobmsg_for_each_attr(cur
, attr
, rem
) {
126 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
130 if (!parse_addr(iface
, blobmsg_data(cur
), v6
, netmask
, ext
,
138 static struct device_addr
*
139 parse_address_item(struct blob_attr
*attr
, bool v6
, bool ext
)
141 struct device_addr
*addr
;
142 struct blob_attr
*tb
[__ADDR_MAX
];
143 struct blob_attr
*cur
;
145 if (blobmsg_type(attr
) != BLOBMSG_TYPE_TABLE
)
148 addr
= alloc_device_addr(v6
, ext
);
152 blobmsg_parse(proto_ip_addr
, __ADDR_MAX
, tb
, blobmsg_data(attr
), blobmsg_data_len(attr
));
154 addr
->mask
= v6
? 128 : 32;
155 if ((cur
= tb
[ADDR_MASK
])) {
156 unsigned int new_mask
;
158 new_mask
= parse_netmask_string(blobmsg_data(cur
), v6
);
159 if (new_mask
> addr
->mask
)
162 addr
->mask
= new_mask
;
165 cur
= tb
[ADDR_IPADDR
];
169 if (!inet_pton(v6
? AF_INET6
: AF_INET
, blobmsg_data(cur
), &addr
->addr
))
173 if ((cur
= tb
[ADDR_BROADCAST
]) &&
174 !inet_pton(AF_INET
, blobmsg_data(cur
), &addr
->broadcast
))
176 if ((cur
= tb
[ADDR_PTP
]) &&
177 !inet_pton(AF_INET
, blobmsg_data(cur
), &addr
->point_to_point
))
189 parse_address_list(struct interface
*iface
, struct blob_attr
*attr
, bool v6
,
192 struct device_addr
*addr
;
193 struct blob_attr
*cur
;
197 blobmsg_for_each_attr(cur
, attr
, rem
) {
198 addr
= parse_address_item(cur
, v6
, ext
);
203 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, &addr
->flags
);
210 parse_gateway_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
)
212 struct device_route
*route
;
213 const char *str
= blobmsg_data(attr
);
214 int af
= v6
? AF_INET6
: AF_INET
;
216 route
= calloc(1, sizeof(*route
));
217 if (!inet_pton(af
, str
, &route
->nexthop
)) {
218 interface_add_error(iface
, "proto", "INVALID_GATEWAY", &str
, 1);
224 route
->flags
= (v6
? DEVADDR_INET6
: DEVADDR_INET4
);
225 vlist_add(&iface
->proto_ip
.route
, &route
->node
, &route
->flags
);
231 parse_ip6assign_option(struct interface
*iface
, struct blob_attr
*attr
)
233 uint8_t oldval
= iface
->proto_ip
.assignment_length
;
234 uint8_t newval
= blobmsg_get_u32(attr
);
236 struct device_prefix
*prefix
;
237 list_for_each_entry(prefix
, &prefixes
, head
) {
238 if (oldval
&& oldval
!= newval
)
239 interface_ip_set_prefix_assignment(prefix
, iface
, 0);
241 if (newval
&& newval
<= 64)
242 interface_ip_set_prefix_assignment(prefix
, iface
, newval
);
245 iface
->proto_ip
.assignment_length
= newval
;
250 parse_prefix_option(struct interface
*iface
, const char *str
, size_t len
)
252 char buf
[128] = {0}, *saveptr
;
253 if (len
> sizeof(buf
))
256 memcpy(buf
, str
, len
);
257 char *addrstr
= strtok_r(buf
, "/", &saveptr
);
261 char *lengthstr
= strtok_r(NULL
, ",", &saveptr
);
265 char *prefstr
= strtok_r(NULL
, ",", &saveptr
);
266 char *validstr
= (!prefstr
) ? NULL
: strtok_r(NULL
, ",", &saveptr
);
268 uint32_t pref
= (!prefstr
) ? 0 : strtoul(prefstr
, NULL
, 10);
269 uint32_t valid
= (!validstr
) ? 0 : strtoul(validstr
, NULL
, 10);
271 uint8_t length
= strtoul(lengthstr
, NULL
, 10);
272 if (length
< 1 || length
> 64)
275 struct in6_addr addr
;
276 if (inet_pton(AF_INET6
, addrstr
, &addr
) < 1)
279 time_t now
= system_get_rtime();
280 time_t preferred_until
= 0;
281 if (prefstr
&& pref
!= 0xffffffffU
)
282 preferred_until
= pref
+ now
;
284 time_t valid_until
= 0;
285 if (validstr
&& valid
!= 0xffffffffU
)
286 valid_until
= valid
+ now
;
288 interface_ip_add_device_prefix(iface
, &addr
, length
,
289 valid_until
, preferred_until
);
294 parse_prefix_list(struct interface
*iface
, struct blob_attr
*attr
)
296 struct blob_attr
*cur
;
300 blobmsg_for_each_attr(cur
, attr
, rem
) {
301 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
305 if (!parse_prefix_option(iface
, blobmsg_data(cur
),
306 blobmsg_data_len(cur
)))
314 proto_apply_static_ip_settings(struct interface
*iface
, struct blob_attr
*attr
)
316 struct blob_attr
*tb
[__OPT_MAX
];
317 struct blob_attr
*cur
;
319 unsigned int netmask
= 32;
320 int n_v4
= 0, n_v6
= 0;
321 struct in_addr bcast
= {};
323 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
325 if ((cur
= tb
[OPT_NETMASK
])) {
326 netmask
= parse_netmask_string(blobmsg_data(cur
), false);
328 error
= "INVALID_NETMASK";
333 if ((cur
= tb
[OPT_BROADCAST
])) {
334 if (!inet_pton(AF_INET
, blobmsg_data(cur
), &bcast
)) {
335 error
= "INVALID_BROADCAST";
340 if ((cur
= tb
[OPT_IPADDR
]))
341 n_v4
= parse_static_address_option(iface
, cur
, false,
342 netmask
, false, bcast
.s_addr
);
344 if ((cur
= tb
[OPT_IP6ADDR
]))
345 n_v6
= parse_static_address_option(iface
, cur
, true,
348 if ((cur
= tb
[OPT_IP6PREFIX
]))
349 if (parse_prefix_list(iface
, cur
) < 0)
353 if (!n_v4 && !n_v6) {
354 error = "NO_ADDRESS";
359 if (n_v4
< 0 || n_v6
< 0)
362 if ((cur
= tb
[OPT_GATEWAY
])) {
363 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
367 if ((cur
= tb
[OPT_IP6GW
])) {
368 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
372 if ((cur
= tb
[OPT_IP6ASSIGN
]))
373 if (!parse_ip6assign_option(iface
, cur
))
379 interface_add_error(iface
, "proto", error
, NULL
, 0);
385 proto_apply_ip_settings(struct interface
*iface
, struct blob_attr
*attr
, bool ext
)
387 struct blob_attr
*tb
[__OPT_MAX
];
388 struct blob_attr
*cur
;
389 // const char *error;
390 int n_v4
= 0, n_v6
= 0;
392 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
394 if ((cur
= tb
[OPT_IPADDR
]))
395 n_v4
= parse_address_list(iface
, cur
, false, ext
);
397 if ((cur
= tb
[OPT_IP6ADDR
]))
398 n_v6
= parse_address_list(iface
, cur
, true, ext
);
400 if ((cur
= tb
[OPT_IP6PREFIX
]))
401 if (parse_prefix_list(iface
, cur
) < 0)
405 if (!n_v4 && !n_v6) {
406 error = "NO_ADDRESS";
411 if (n_v4
< 0 || n_v6
< 0)
414 if ((cur
= tb
[OPT_GATEWAY
])) {
415 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
419 if ((cur
= tb
[OPT_IP6GW
])) {
420 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
424 if ((cur
= tb
[OPT_IP6ASSIGN
]))
425 if (!parse_ip6assign_option(iface
, cur
))
432 interface_add_error(iface, "proto", error, NULL, 0);
438 void add_proto_handler(struct proto_handler
*p
)
441 avl_init(&handlers
, avl_strcmp
, false, NULL
);
446 p
->avl
.key
= p
->name
;
447 avl_insert(&handlers
, &p
->avl
);
451 default_proto_free(struct interface_proto_state
*proto
)
457 invalid_proto_handler(struct interface_proto_state
*proto
,
458 enum interface_proto_cmd cmd
, bool force
)
464 no_proto_handler(struct interface_proto_state
*proto
,
465 enum interface_proto_cmd cmd
, bool force
)
470 static struct interface_proto_state
*
471 default_proto_attach(const struct proto_handler
*h
,
472 struct interface
*iface
, struct blob_attr
*attr
)
474 struct interface_proto_state
*proto
;
476 proto
= calloc(1, sizeof(*proto
));
477 proto
->free
= default_proto_free
;
478 proto
->cb
= no_proto_handler
;
483 static const struct proto_handler no_proto
= {
485 .flags
= PROTO_FLAG_IMMEDIATE
,
486 .attach
= default_proto_attach
,
489 static const struct proto_handler
*
490 get_proto_handler(const char *name
)
492 struct proto_handler
*proto
;
494 if (!strcmp(name
, "none"))
500 return avl_find_element(&handlers
, name
, proto
, avl
);
504 proto_dump_handlers(struct blob_buf
*b
)
506 struct proto_handler
*p
;
509 avl_for_each_element(&handlers
, p
, avl
) {
510 c
= blobmsg_open_table(b
, p
->name
);
511 blobmsg_add_u8(b
, "no_device", !!(p
->flags
& PROTO_FLAG_NODEV
));
512 blobmsg_close_table(b
, c
);
517 proto_init_interface(struct interface
*iface
, struct blob_attr
*attr
)
519 const struct proto_handler
*proto
= iface
->proto_handler
;
520 struct interface_proto_state
*state
= NULL
;
525 state
= proto
->attach(proto
, iface
, attr
);
527 state
= no_proto
.attach(&no_proto
, iface
, attr
);
528 state
->cb
= invalid_proto_handler
;
531 state
->handler
= proto
;
532 interface_set_proto_state(iface
, state
);
536 proto_attach_interface(struct interface
*iface
, const char *proto_name
)
538 const struct proto_handler
*proto
= &no_proto
;
541 proto
= get_proto_handler(proto_name
);
543 interface_add_error(iface
, "proto", "INVALID_PROTO", NULL
, 0);
548 iface
->proto_handler
= proto
;
552 interface_proto_event(struct interface_proto_state
*proto
,
553 enum interface_proto_cmd cmd
, bool force
)
555 enum interface_proto_event ev
;
558 ret
= proto
->cb(proto
, cmd
, force
);
559 if (ret
|| !(proto
->handler
->flags
& PROTO_FLAG_IMMEDIATE
))
563 case PROTO_CMD_SETUP
:
566 case PROTO_CMD_TEARDOWN
:
572 proto
->proto_event(proto
, ev
);