2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
4 * Copyright (C) 2012 Steven Barth <steven@midlink.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
20 #include <arpa/inet.h>
21 #include <netinet/in.h>
25 #include "interface.h"
26 #include "interface-ip.h"
29 static struct avl_tree handlers
;
44 static const struct blobmsg_policy proto_ip_attributes
[__OPT_MAX
] = {
45 [OPT_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_ARRAY
},
46 [OPT_IP6ADDR
] = { .name
= "ip6addr", .type
= BLOBMSG_TYPE_ARRAY
},
47 [OPT_NETMASK
] = { .name
= "netmask", .type
= BLOBMSG_TYPE_STRING
},
48 [OPT_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
49 [OPT_PTPADDR
] = { .name
= "ptpaddr", .type
= BLOBMSG_TYPE_STRING
},
50 [OPT_GATEWAY
] = { .name
= "gateway", .type
= BLOBMSG_TYPE_STRING
},
51 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= BLOBMSG_TYPE_STRING
},
52 [OPT_IP6PREFIX
] = { .name
= "ip6prefix", .type
= BLOBMSG_TYPE_ARRAY
},
53 [OPT_IP6DEPRECATED
] = { .name
= "ip6deprecated", .type
= BLOBMSG_TYPE_BOOL
},
56 static const struct uci_blob_param_info proto_ip_attr_info
[__OPT_MAX
] = {
57 [OPT_IPADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
58 [OPT_IP6ADDR
] = { .type
= BLOBMSG_TYPE_STRING
},
59 [OPT_IP6PREFIX
] = { .type
= BLOBMSG_TYPE_STRING
},
62 static const char * const proto_ip_validate
[__OPT_MAX
] = {
63 [OPT_IPADDR
] = "ip4addr",
64 [OPT_IP6ADDR
] = "ip6addr",
65 [OPT_NETMASK
] = "netmask",
66 [OPT_BROADCAST
] = "ipaddr",
67 [OPT_PTPADDR
] = "ip4addr",
68 [OPT_GATEWAY
] = "ip4addr",
69 [OPT_IP6GW
] = "ip6addr",
70 [OPT_IP6PREFIX
] = "ip6addr",
73 const struct uci_blob_param_list proto_ip_attr
= {
74 .n_params
= __OPT_MAX
,
75 .params
= proto_ip_attributes
,
76 .validate
= proto_ip_validate
,
77 .info
= proto_ip_attr_info
,
92 static const struct blobmsg_policy proto_ip_addr
[__ADDR_MAX
] = {
93 [ADDR_IPADDR
] = { .name
= "ipaddr", .type
= BLOBMSG_TYPE_STRING
},
94 [ADDR_MASK
] = { .name
= "mask", .type
= BLOBMSG_TYPE_STRING
},
95 [ADDR_BROADCAST
] = { .name
= "broadcast", .type
= BLOBMSG_TYPE_STRING
},
96 [ADDR_PTP
] = { .name
= "ptp", .type
= BLOBMSG_TYPE_STRING
},
97 [ADDR_PREFERRED
] = { .name
= "preferred", .type
= BLOBMSG_TYPE_INT32
},
98 [ADDR_VALID
] = { .name
= "valid", .type
= BLOBMSG_TYPE_INT32
},
99 [ADDR_OFFLINK
] = { .name
= "offlink", .type
= BLOBMSG_TYPE_BOOL
},
100 [ADDR_CLASS
] = { .name
= "class", .type
= BLOBMSG_TYPE_STRING
},
103 static struct device_addr
*
104 alloc_device_addr(bool v6
, bool ext
)
106 struct device_addr
*addr
;
108 addr
= calloc(1, sizeof(*addr
));
112 addr
->flags
= v6
? DEVADDR_INET6
: DEVADDR_INET4
;
114 addr
->flags
|= DEVADDR_EXTERNAL
;
119 static struct device_addr
*
120 parse_addr(const char *str
, bool v6
, int mask
, bool ext
, uint32_t broadcast
,
121 uint32_t ptp
, bool deprecated
)
123 struct device_addr
*addr
;
124 int af
= v6
? AF_INET6
: AF_INET
;
126 addr
= alloc_device_addr(v6
, ext
);
131 if (!parse_ip_and_netmask(af
, str
, &addr
->addr
, &addr
->mask
))
134 if (v6
&& IN6_IS_ADDR_MULTICAST(&addr
->addr
.in6
))
138 addr
->broadcast
= broadcast
;
141 addr
->point_to_point
= ptp
;
144 addr
->preferred_until
= system_get_rtime();
155 parse_static_address_option(struct interface
*iface
, struct blob_attr
*attr
,
156 bool v6
, int netmask
, bool ext
, uint32_t broadcast
,
157 uint32_t ptp
, bool deprecated
)
159 struct blob_attr
*cur
;
160 struct device_addr
*addr
;
165 blobmsg_for_each_attr(cur
, attr
, rem
) {
166 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
169 str
= blobmsg_data(cur
);
170 addr
= parse_addr(str
, v6
, netmask
, ext
, broadcast
, ptp
, deprecated
);
172 interface_add_error(iface
, "proto", "INVALID_ADDRESS", &str
, 1);
175 addr
->index
= n_addr
;
177 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, addr
);
183 static struct device_addr
*
184 parse_address_item(struct blob_attr
*attr
, bool v6
, bool ext
)
186 struct device_addr
*addr
;
187 struct blob_attr
*tb
[__ADDR_MAX
];
188 struct blob_attr
*cur
;
190 if (blobmsg_type(attr
) != BLOBMSG_TYPE_TABLE
)
193 addr
= alloc_device_addr(v6
, ext
);
197 blobmsg_parse(proto_ip_addr
, __ADDR_MAX
, tb
, blobmsg_data(attr
), blobmsg_data_len(attr
));
199 addr
->mask
= v6
? 128 : 32;
200 if ((cur
= tb
[ADDR_MASK
])) {
201 unsigned int new_mask
;
203 new_mask
= parse_netmask_string(blobmsg_data(cur
), v6
);
204 if (new_mask
> addr
->mask
)
207 addr
->mask
= new_mask
;
210 cur
= tb
[ADDR_IPADDR
];
214 if (!inet_pton(v6
? AF_INET6
: AF_INET
, blobmsg_data(cur
), &addr
->addr
))
217 if ((cur
= tb
[ADDR_OFFLINK
]) && blobmsg_get_bool(cur
))
218 addr
->flags
|= DEVADDR_OFFLINK
;
221 if ((cur
= tb
[ADDR_BROADCAST
]) &&
222 !inet_pton(AF_INET
, blobmsg_data(cur
), &addr
->broadcast
))
224 if ((cur
= tb
[ADDR_PTP
]) &&
225 !inet_pton(AF_INET
, blobmsg_data(cur
), &addr
->point_to_point
))
228 time_t now
= system_get_rtime();
229 if ((cur
= tb
[ADDR_PREFERRED
])) {
230 int64_t preferred
= blobmsg_get_u32(cur
);
231 int64_t preferred_until
= preferred
+ (int64_t)now
;
232 if (preferred_until
<= LONG_MAX
&& preferred
!= 0xffffffffLL
)
233 addr
->preferred_until
= preferred_until
;
236 if ((cur
= tb
[ADDR_VALID
])) {
237 int64_t valid
= blobmsg_get_u32(cur
);
238 int64_t valid_until
= valid
+ (int64_t)now
;
239 if (valid_until
<= LONG_MAX
&& valid
!= 0xffffffffLL
)
240 addr
->valid_until
= valid_until
;
244 if (addr
->valid_until
) {
245 if (!addr
->preferred_until
)
246 addr
->preferred_until
= addr
->valid_until
;
247 else if (addr
->preferred_until
> addr
->valid_until
)
251 if ((cur
= tb
[ADDR_CLASS
]))
252 addr
->pclass
= strdup(blobmsg_get_string(cur
));
263 parse_address_list(struct interface
*iface
, struct blob_attr
*attr
, bool v6
,
266 struct device_addr
*addr
;
267 struct blob_attr
*cur
;
271 blobmsg_for_each_attr(cur
, attr
, rem
) {
272 addr
= parse_address_item(cur
, v6
, ext
);
276 addr
->index
= n_addr
;
278 vlist_add(&iface
->proto_ip
.addr
, &addr
->node
, addr
);
285 parse_gateway_option(struct interface
*iface
, struct blob_attr
*attr
, bool v6
)
287 struct device_route
*route
;
288 const char *str
= blobmsg_data(attr
);
289 int af
= v6
? AF_INET6
: AF_INET
;
291 route
= calloc(1, sizeof(*route
));
295 if (!inet_pton(af
, str
, &route
->nexthop
)) {
296 interface_add_error(iface
, "proto", "INVALID_GATEWAY", &str
, 1);
302 route
->flags
= (v6
? DEVADDR_INET6
: DEVADDR_INET4
);
303 route
->metric
= iface
->metric
;
305 unsigned int table
= (v6
) ? iface
->ip6table
: iface
->ip4table
;
307 route
->table
= table
;
308 route
->flags
|= DEVROUTE_SRCTABLE
;
311 vlist_add(&iface
->proto_ip
.route
, &route
->node
, route
);
317 parse_prefix_option(struct interface
*iface
, const char *str
, size_t len
)
319 char buf
[128] = {0}, *saveptr
;
320 if (len
>= sizeof(buf
))
323 memcpy(buf
, str
, len
);
324 char *addrstr
= strtok_r(buf
, "/", &saveptr
);
328 char *lengthstr
= strtok_r(NULL
, ",", &saveptr
);
332 char *prefstr
= strtok_r(NULL
, ",", &saveptr
);
333 char *validstr
= (!prefstr
) ? NULL
: strtok_r(NULL
, ",", &saveptr
);
334 char *addstr
= (!validstr
) ? NULL
: strtok_r(NULL
, ",", &saveptr
);
335 const char *pclass
= NULL
;
337 int64_t pref
= (!prefstr
) ? 0 : strtoul(prefstr
, NULL
, 10);
338 int64_t valid
= (!validstr
) ? 0 : strtoul(validstr
, NULL
, 10);
340 uint8_t length
= strtoul(lengthstr
, NULL
, 10), excl_length
= 0;
341 if (length
< 1 || length
> 64)
344 struct in6_addr addr
, excluded
, *excludedp
= NULL
;
345 if (inet_pton(AF_INET6
, addrstr
, &addr
) < 1)
348 for (; addstr
; addstr
= strtok_r(NULL
, ",", &saveptr
)) {
349 char *key
= NULL
, *val
= NULL
, *addsaveptr
;
350 if (!(key
= strtok_r(addstr
, "=", &addsaveptr
)) ||
351 !(val
= strtok_r(NULL
, ",", &addsaveptr
)))
354 if (!strcmp(key
, "excluded")) {
355 char *sep
= strchr(val
, '/');
360 excl_length
= atoi(sep
+ 1);
362 if (inet_pton(AF_INET6
, val
, &excluded
) < 1)
365 excludedp
= &excluded
;
366 } else if (!strcmp(key
, "class")) {
375 int64_t now
= system_get_rtime();
376 time_t preferred_until
= 0;
377 if (prefstr
&& pref
!= 0xffffffffLL
&& pref
+ now
<= LONG_MAX
)
378 preferred_until
= pref
+ now
;
380 time_t valid_until
= 0;
381 if (validstr
&& valid
!= 0xffffffffLL
&& valid
+ now
<= LONG_MAX
)
382 valid_until
= valid
+ now
;
384 interface_ip_add_device_prefix(iface
, &addr
, length
,
385 valid_until
, preferred_until
,
386 excludedp
, excl_length
, pclass
);
391 parse_prefix_list(struct interface
*iface
, struct blob_attr
*attr
)
393 struct blob_attr
*cur
;
397 blobmsg_for_each_attr(cur
, attr
, rem
) {
398 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
402 if (!parse_prefix_option(iface
, blobmsg_data(cur
),
403 blobmsg_data_len(cur
)))
411 proto_apply_static_ip_settings(struct interface
*iface
, struct blob_attr
*attr
)
413 struct blob_attr
*tb
[__OPT_MAX
];
414 struct blob_attr
*cur
;
416 unsigned int netmask
= 32;
418 int n_v4
= 0, n_v6
= 0;
419 struct in_addr bcast
= {}, ptp
= {};
421 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
423 if ((cur
= tb
[OPT_NETMASK
])) {
424 netmask
= parse_netmask_string(blobmsg_data(cur
), false);
426 error
= "INVALID_NETMASK";
431 if ((cur
= tb
[OPT_BROADCAST
])) {
432 if (!inet_pton(AF_INET
, blobmsg_data(cur
), &bcast
)) {
433 error
= "INVALID_BROADCAST";
438 if ((cur
= tb
[OPT_PTPADDR
])) {
439 if (!inet_pton(AF_INET
, blobmsg_data(cur
), &ptp
)) {
440 error
= "INVALID_PTPADDR";
445 ip6deprecated
= blobmsg_get_bool_default(tb
[OPT_IP6DEPRECATED
], false);
447 if ((cur
= tb
[OPT_IPADDR
]))
448 n_v4
= parse_static_address_option(iface
, cur
, false,
449 netmask
, false, bcast
.s_addr
, ptp
.s_addr
, false);
451 if ((cur
= tb
[OPT_IP6ADDR
]))
452 n_v6
= parse_static_address_option(iface
, cur
, true,
453 128, false, 0, 0, ip6deprecated
);
455 if ((cur
= tb
[OPT_IP6PREFIX
]))
456 if (parse_prefix_list(iface
, cur
) < 0)
459 if (n_v4
< 0 || n_v6
< 0)
462 if ((cur
= tb
[OPT_GATEWAY
])) {
463 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
467 if ((cur
= tb
[OPT_IP6GW
])) {
468 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
475 interface_add_error(iface
, "proto", error
, NULL
, 0);
481 proto_apply_ip_settings(struct interface
*iface
, struct blob_attr
*attr
, bool ext
)
483 struct blob_attr
*tb
[__OPT_MAX
];
484 struct blob_attr
*cur
;
485 int n_v4
= 0, n_v6
= 0;
487 blobmsg_parse(proto_ip_attributes
, __OPT_MAX
, tb
, blob_data(attr
), blob_len(attr
));
489 if ((cur
= tb
[OPT_IPADDR
]))
490 n_v4
= parse_address_list(iface
, cur
, false, ext
);
492 if ((cur
= tb
[OPT_IP6ADDR
]))
493 n_v6
= parse_address_list(iface
, cur
, true, ext
);
495 if ((cur
= tb
[OPT_IP6PREFIX
]))
496 if (parse_prefix_list(iface
, cur
) < 0)
499 if (n_v4
< 0 || n_v6
< 0)
502 if ((cur
= tb
[OPT_GATEWAY
])) {
503 if (n_v4
&& !parse_gateway_option(iface
, cur
, false))
507 if ((cur
= tb
[OPT_IP6GW
])) {
508 if (n_v6
&& !parse_gateway_option(iface
, cur
, true))
518 void add_proto_handler(struct proto_handler
*p
)
521 avl_init(&handlers
, avl_strcmp
, false, NULL
);
526 p
->avl
.key
= p
->name
;
527 avl_insert(&handlers
, &p
->avl
);
531 default_proto_free(struct interface_proto_state
*proto
)
537 invalid_proto_handler(struct interface_proto_state
*proto
,
538 enum interface_proto_cmd cmd
, bool force
)
544 no_proto_handler(struct interface_proto_state
*proto
,
545 enum interface_proto_cmd cmd
, bool force
)
550 static struct interface_proto_state
*
551 default_proto_attach(const struct proto_handler
*h
,
552 struct interface
*iface
, struct blob_attr
*attr
)
554 struct interface_proto_state
*proto
;
556 proto
= calloc(1, sizeof(*proto
));
560 proto
->free
= default_proto_free
;
561 proto
->cb
= no_proto_handler
;
566 static const struct proto_handler no_proto
= {
568 .flags
= PROTO_FLAG_IMMEDIATE
,
569 .attach
= default_proto_attach
,
572 static const struct proto_handler
*
573 get_proto_handler(const char *name
)
575 struct proto_handler
*proto
;
577 if (!strcmp(name
, "none"))
583 return avl_find_element(&handlers
, name
, proto
, avl
);
587 proto_dump_handlers(struct blob_buf
*b
)
589 struct proto_handler
*p
;
592 avl_for_each_element(&handlers
, p
, avl
) {
595 c
= blobmsg_open_table(b
, p
->name
);
596 if (p
->config_params
&& p
->config_params
->validate
) {
599 v
= blobmsg_open_table(b
, "validate");
600 for (i
= 0; i
< p
->config_params
->n_params
; i
++)
601 blobmsg_add_string(b
, p
->config_params
->params
[i
].name
, uci_get_validate_string(p
->config_params
, i
));
602 blobmsg_close_table(b
, v
);
604 blobmsg_add_u8(b
, "immediate", !!(p
->flags
& PROTO_FLAG_IMMEDIATE
));
605 blobmsg_add_u8(b
, "no_device", !!(p
->flags
& PROTO_FLAG_NODEV
));
606 blobmsg_add_u8(b
, "init_available", !!(p
->flags
& PROTO_FLAG_INIT_AVAILABLE
));
607 blobmsg_add_u8(b
, "renew_available", !!(p
->flags
& PROTO_FLAG_RENEW_AVAILABLE
));
608 blobmsg_add_u8(b
, "force_link_default", !!(p
->flags
& PROTO_FLAG_FORCE_LINK_DEFAULT
));
609 blobmsg_add_u8(b
, "last_error", !!(p
->flags
& PROTO_FLAG_LASTERROR
));
610 blobmsg_add_u8(b
, "teardown_on_l3_link_down", !!(p
->flags
& PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN
));
611 blobmsg_add_u8(b
, "no_task", !!(p
->flags
& PROTO_FLAG_NO_TASK
));
612 blobmsg_close_table(b
, c
);
617 proto_init_interface(struct interface
*iface
, struct blob_attr
*attr
)
619 const struct proto_handler
*proto
= iface
->proto_handler
;
620 struct interface_proto_state
*state
= NULL
;
625 state
= proto
->attach(proto
, iface
, attr
);
627 state
= no_proto
.attach(&no_proto
, iface
, attr
);
628 state
->cb
= invalid_proto_handler
;
631 state
->handler
= proto
;
632 interface_set_proto_state(iface
, state
);
636 proto_attach_interface(struct interface
*iface
, const char *proto_name
)
638 const struct proto_handler
*proto
= &no_proto
;
639 const char *error
= NULL
;
642 proto
= get_proto_handler(proto_name
);
644 error
= "INVALID_PROTO";
649 iface
->proto_handler
= proto
;
652 interface_add_error(iface
, "proto", error
, NULL
, 0);
656 interface_proto_event(struct interface_proto_state
*proto
,
657 enum interface_proto_cmd cmd
, bool force
)
659 enum interface_proto_event ev
;
662 ret
= proto
->cb(proto
, cmd
, force
);
663 if (ret
|| !(proto
->handler
->flags
& PROTO_FLAG_IMMEDIATE
))
667 case PROTO_CMD_SETUP
:
670 case PROTO_CMD_TEARDOWN
:
673 case PROTO_CMD_RENEW
:
679 proto
->proto_event(proto
, ev
);