14 #include <libubox/utils.h>
18 static struct blob_buf b
;
19 static int reload_pipe
[2];
20 struct list_head leases
= LIST_HEAD_INIT(leases
);
21 struct list_head interfaces
= LIST_HEAD_INIT(interfaces
);
22 struct config config
= {.legacy
= false, .main_dhcpv4
= false,
23 .dhcp_cb
= NULL
, .dhcp_statefile
= NULL
,
24 .log_level
= LOG_INFO
};
30 IFACE_ATTR_DYNAMICDHCP
,
44 IFACE_ATTR_FILTER_CLASS
,
45 IFACE_ATTR_DHCPV4_FORCERECONF
,
46 IFACE_ATTR_DHCPV6_RAW
,
47 IFACE_ATTR_DHCPV6_ASSIGNALL
,
48 IFACE_ATTR_RA_DEFAULT
,
49 IFACE_ATTR_RA_MANAGEMENT
,
50 IFACE_ATTR_RA_OFFLINK
,
51 IFACE_ATTR_RA_PREFERENCE
,
52 IFACE_ATTR_RA_ADVROUTER
,
53 IFACE_ATTR_RA_MININTERVAL
,
54 IFACE_ATTR_RA_MAXINTERVAL
,
55 IFACE_ATTR_RA_LIFETIME
,
56 IFACE_ATTR_RA_USELEASETIME
,
57 IFACE_ATTR_RA_REACHABLETIME
,
58 IFACE_ATTR_RA_RETRANSTIME
,
59 IFACE_ATTR_RA_HOPLIMIT
,
62 IFACE_ATTR_PD_MANAGER
,
64 IFACE_ATTR_NDPROXY_ROUTING
,
65 IFACE_ATTR_NDPROXY_SLAVE
,
66 IFACE_ATTR_PREFIX_FILTER
,
70 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
71 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
72 [IFACE_ATTR_IFNAME
] = { .name
= "ifname", .type
= BLOBMSG_TYPE_STRING
},
73 [IFACE_ATTR_NETWORKID
] = { .name
= "networkid", .type
= BLOBMSG_TYPE_STRING
},
74 [IFACE_ATTR_DYNAMICDHCP
] = { .name
= "dynamicdhcp", .type
= BLOBMSG_TYPE_BOOL
},
75 [IFACE_ATTR_IGNORE
] = { .name
= "ignore", .type
= BLOBMSG_TYPE_BOOL
},
76 [IFACE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
77 [IFACE_ATTR_START
] = { .name
= "start", .type
= BLOBMSG_TYPE_INT32
},
78 [IFACE_ATTR_LIMIT
] = { .name
= "limit", .type
= BLOBMSG_TYPE_INT32
},
79 [IFACE_ATTR_MASTER
] = { .name
= "master", .type
= BLOBMSG_TYPE_BOOL
},
80 [IFACE_ATTR_UPSTREAM
] = { .name
= "upstream", .type
= BLOBMSG_TYPE_ARRAY
},
81 [IFACE_ATTR_RA
] = { .name
= "ra", .type
= BLOBMSG_TYPE_STRING
},
82 [IFACE_ATTR_DHCPV4
] = { .name
= "dhcpv4", .type
= BLOBMSG_TYPE_STRING
},
83 [IFACE_ATTR_DHCPV6
] = { .name
= "dhcpv6", .type
= BLOBMSG_TYPE_STRING
},
84 [IFACE_ATTR_NDP
] = { .name
= "ndp", .type
= BLOBMSG_TYPE_STRING
},
85 [IFACE_ATTR_ROUTER
] = { .name
= "router", .type
= BLOBMSG_TYPE_ARRAY
},
86 [IFACE_ATTR_DNS
] = { .name
= "dns", .type
= BLOBMSG_TYPE_ARRAY
},
87 [IFACE_ATTR_DOMAIN
] = { .name
= "domain", .type
= BLOBMSG_TYPE_ARRAY
},
88 [IFACE_ATTR_FILTER_CLASS
] = { .name
= "filter_class", .type
= BLOBMSG_TYPE_STRING
},
89 [IFACE_ATTR_DHCPV4_FORCERECONF
] = { .name
= "dhcpv4_forcereconf", .type
= BLOBMSG_TYPE_BOOL
},
90 [IFACE_ATTR_DHCPV6_RAW
] = { .name
= "dhcpv6_raw", .type
= BLOBMSG_TYPE_STRING
},
91 [IFACE_ATTR_DHCPV6_ASSIGNALL
] = { .name
="dhcpv6_assignall", .type
= BLOBMSG_TYPE_BOOL
},
92 [IFACE_ATTR_PD_MANAGER
] = { .name
= "pd_manager", .type
= BLOBMSG_TYPE_STRING
},
93 [IFACE_ATTR_PD_CER
] = { .name
= "pd_cer", .type
= BLOBMSG_TYPE_STRING
},
94 [IFACE_ATTR_RA_DEFAULT
] = { .name
= "ra_default", .type
= BLOBMSG_TYPE_INT32
},
95 [IFACE_ATTR_RA_MANAGEMENT
] = { .name
= "ra_management", .type
= BLOBMSG_TYPE_INT32
},
96 [IFACE_ATTR_RA_OFFLINK
] = { .name
= "ra_offlink", .type
= BLOBMSG_TYPE_BOOL
},
97 [IFACE_ATTR_RA_PREFERENCE
] = { .name
= "ra_preference", .type
= BLOBMSG_TYPE_STRING
},
98 [IFACE_ATTR_RA_ADVROUTER
] = { .name
= "ra_advrouter", .type
= BLOBMSG_TYPE_BOOL
},
99 [IFACE_ATTR_RA_MININTERVAL
] = { .name
= "ra_mininterval", .type
= BLOBMSG_TYPE_INT32
},
100 [IFACE_ATTR_RA_MAXINTERVAL
] = { .name
= "ra_maxinterval", .type
= BLOBMSG_TYPE_INT32
},
101 [IFACE_ATTR_RA_LIFETIME
] = { .name
= "ra_lifetime", .type
= BLOBMSG_TYPE_INT32
},
102 [IFACE_ATTR_RA_USELEASETIME
] = { .name
= "ra_useleasetime", .type
= BLOBMSG_TYPE_BOOL
},
103 [IFACE_ATTR_RA_REACHABLETIME
] = { .name
= "ra_reachabletime", .type
= BLOBMSG_TYPE_INT32
},
104 [IFACE_ATTR_RA_RETRANSTIME
] = { .name
= "ra_retranstime", .type
= BLOBMSG_TYPE_INT32
},
105 [IFACE_ATTR_RA_HOPLIMIT
] = { .name
= "ra_hoplimit", .type
= BLOBMSG_TYPE_INT32
},
106 [IFACE_ATTR_RA_MTU
] = { .name
= "ra_mtu", .type
= BLOBMSG_TYPE_INT32
},
107 [IFACE_ATTR_RA_DNS
] = { .name
= "ra_dns", .type
= BLOBMSG_TYPE_BOOL
},
108 [IFACE_ATTR_NDPROXY_ROUTING
] = { .name
= "ndproxy_routing", .type
= BLOBMSG_TYPE_BOOL
},
109 [IFACE_ATTR_NDPROXY_SLAVE
] = { .name
= "ndproxy_slave", .type
= BLOBMSG_TYPE_BOOL
},
110 [IFACE_ATTR_PREFIX_FILTER
] = { .name
= "prefix_filter", .type
= BLOBMSG_TYPE_STRING
},
113 static const struct uci_blob_param_info iface_attr_info
[IFACE_ATTR_MAX
] = {
114 [IFACE_ATTR_UPSTREAM
] = { .type
= BLOBMSG_TYPE_STRING
},
115 [IFACE_ATTR_DNS
] = { .type
= BLOBMSG_TYPE_STRING
},
116 [IFACE_ATTR_DOMAIN
] = { .type
= BLOBMSG_TYPE_STRING
},
119 const struct uci_blob_param_list interface_attr_list
= {
120 .n_params
= IFACE_ATTR_MAX
,
121 .params
= iface_attrs
,
122 .info
= iface_attr_info
,
130 LEASE_ATTR_LEASETIME
,
135 static const struct blobmsg_policy lease_attrs
[LEASE_ATTR_MAX
] = {
136 [LEASE_ATTR_IP
] = { .name
= "ip", .type
= BLOBMSG_TYPE_STRING
},
137 [LEASE_ATTR_MAC
] = { .name
= "mac", .type
= BLOBMSG_TYPE_STRING
},
138 [LEASE_ATTR_DUID
] = { .name
= "duid", .type
= BLOBMSG_TYPE_STRING
},
139 [LEASE_ATTR_HOSTID
] = { .name
= "hostid", .type
= BLOBMSG_TYPE_STRING
},
140 [LEASE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
141 [LEASE_ATTR_NAME
] = { .name
= "name", .type
= BLOBMSG_TYPE_STRING
},
144 const struct uci_blob_param_list lease_attr_list
= {
145 .n_params
= LEASE_ATTR_MAX
,
146 .params
= lease_attrs
,
151 ODHCPD_ATTR_MAINDHCP
,
152 ODHCPD_ATTR_LEASEFILE
,
153 ODHCPD_ATTR_LEASETRIGGER
,
154 ODHCPD_ATTR_LOGLEVEL
,
158 static const struct blobmsg_policy odhcpd_attrs
[ODHCPD_ATTR_MAX
] = {
159 [ODHCPD_ATTR_LEGACY
] = { .name
= "legacy", .type
= BLOBMSG_TYPE_BOOL
},
160 [ODHCPD_ATTR_MAINDHCP
] = { .name
= "maindhcp", .type
= BLOBMSG_TYPE_BOOL
},
161 [ODHCPD_ATTR_LEASEFILE
] = { .name
= "leasefile", .type
= BLOBMSG_TYPE_STRING
},
162 [ODHCPD_ATTR_LEASETRIGGER
] = { .name
= "leasetrigger", .type
= BLOBMSG_TYPE_STRING
},
163 [ODHCPD_ATTR_LOGLEVEL
] = { .name
= "loglevel", .type
= BLOBMSG_TYPE_INT32
},
166 const struct uci_blob_param_list odhcpd_attr_list
= {
167 .n_params
= ODHCPD_ATTR_MAX
,
168 .params
= odhcpd_attrs
,
171 static int mkdir_p(char *dir
, mode_t mask
)
173 char *l
= strrchr(dir
, '/');
181 if (mkdir_p(dir
, mask
))
186 ret
= mkdir(dir
, mask
);
187 if (ret
&& errno
== EEXIST
)
191 syslog(LOG_ERR
, "mkdir(%s, %d) failed: %m\n", dir
, mask
);
196 static void free_lease(struct lease
*l
)
205 static struct interface
* get_interface(const char *name
)
208 list_for_each_entry(c
, &interfaces
, head
)
209 if (!strcmp(c
->name
, name
))
214 static void set_interface_defaults(struct interface
*iface
)
216 iface
->learn_routes
= 1;
217 iface
->dhcpv4_leasetime
= 43200;
218 iface
->dhcpv6_assignall
= true;
219 iface
->ra_managed
= RA_MANAGED_MFLAG
;
220 iface
->ra_maxinterval
= 600;
221 iface
->ra_mininterval
= iface
->ra_maxinterval
/3;
222 iface
->ra_lifetime
= -1;
223 iface
->ra_dns
= true;
226 static void clean_interface(struct interface
*iface
)
230 free(iface
->upstream
);
231 free(iface
->dhcpv4_router
);
232 free(iface
->dhcpv4_dns
);
233 free(iface
->dhcpv6_raw
);
234 free(iface
->filter_class
);
235 memset(&iface
->ra
, 0, sizeof(*iface
) - offsetof(struct interface
, ra
));
236 set_interface_defaults(iface
);
239 static void close_interface(struct interface
*iface
)
241 if (iface
->head
.next
)
242 list_del(&iface
->head
);
244 router_setup_interface(iface
, false);
245 dhcpv6_setup_interface(iface
, false);
246 ndp_setup_interface(iface
, false);
247 #ifdef DHCPV4_SUPPORT
248 dhcpv4_setup_interface(iface
, false);
251 clean_interface(iface
);
258 static int parse_mode(const char *mode
)
260 if (!strcmp(mode
, "disabled"))
261 return MODE_DISABLED
;
262 else if (!strcmp(mode
, "server"))
264 else if (!strcmp(mode
, "relay"))
266 else if (!strcmp(mode
, "hybrid"))
272 static void set_config(struct uci_section
*s
)
274 struct blob_attr
*tb
[ODHCPD_ATTR_MAX
], *c
;
276 blob_buf_init(&b
, 0);
277 uci_to_blob(&b
, s
, &odhcpd_attr_list
);
278 blobmsg_parse(odhcpd_attrs
, ODHCPD_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
280 if ((c
= tb
[ODHCPD_ATTR_LEGACY
]))
281 config
.legacy
= blobmsg_get_bool(c
);
283 if ((c
= tb
[ODHCPD_ATTR_MAINDHCP
]))
284 config
.main_dhcpv4
= blobmsg_get_bool(c
);
286 if ((c
= tb
[ODHCPD_ATTR_LEASEFILE
])) {
287 free(config
.dhcp_statefile
);
288 config
.dhcp_statefile
= strdup(blobmsg_get_string(c
));
291 if ((c
= tb
[ODHCPD_ATTR_LEASETRIGGER
])) {
292 free(config
.dhcp_cb
);
293 config
.dhcp_cb
= strdup(blobmsg_get_string(c
));
296 if ((c
= tb
[ODHCPD_ATTR_LOGLEVEL
])) {
297 int log_level
= (blobmsg_get_u32(c
) & LOG_PRIMASK
);
299 if (config
.log_level
!= log_level
) {
300 config
.log_level
= log_level
;
301 setlogmask(LOG_UPTO(config
.log_level
));
306 static double parse_leasetime(struct blob_attr
*c
) {
307 char *val
= blobmsg_get_string(c
), *endptr
= NULL
;
308 double time
= strcmp(val
, "infinite") ? strtod(val
, &endptr
) : UINT32_MAX
;
310 if (time
&& endptr
&& endptr
[0]) {
311 if (endptr
[0] == 's')
313 else if (endptr
[0] == 'm')
315 else if (endptr
[0] == 'h')
317 else if (endptr
[0] == 'd')
319 else if (endptr
[0] == 'w')
320 time
*= 7 * 24 * 3600;
334 static int set_lease(struct uci_section
*s
)
336 struct blob_attr
*tb
[LEASE_ATTR_MAX
], *c
;
338 blob_buf_init(&b
, 0);
339 uci_to_blob(&b
, s
, &lease_attr_list
);
340 blobmsg_parse(lease_attrs
, LEASE_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
343 if ((c
= tb
[LEASE_ATTR_NAME
]))
344 hostlen
= blobmsg_data_len(c
);
346 struct lease
*lease
= calloc(1, sizeof(*lease
) + hostlen
);
351 memcpy(lease
->hostname
, blobmsg_get_string(c
), hostlen
);
352 if (!odhcpd_valid_hostname(lease
->hostname
))
356 if ((c
= tb
[LEASE_ATTR_IP
]))
357 if (inet_pton(AF_INET
, blobmsg_get_string(c
), &lease
->ipaddr
) < 0)
360 if ((c
= tb
[LEASE_ATTR_MAC
]))
361 if (!ether_aton_r(blobmsg_get_string(c
), &lease
->mac
))
364 if ((c
= tb
[LEASE_ATTR_DUID
])) {
365 size_t duidlen
= (blobmsg_data_len(c
) - 1) / 2;
366 lease
->duid
= malloc(duidlen
);
370 ssize_t len
= odhcpd_unhexlify(lease
->duid
,
371 duidlen
, blobmsg_get_string(c
));
376 lease
->duid_len
= len
;
379 if ((c
= tb
[LEASE_ATTR_HOSTID
])) {
381 lease
->hostid
= strtoul(blobmsg_get_string(c
), NULL
, 16);
386 if ((c
= tb
[LEASE_ATTR_LEASETIME
])) {
387 double time
= parse_leasetime(c
);
391 lease
->dhcpv4_leasetime
= time
;
394 list_add(&lease
->head
, &leases
);
404 int config_parse_interface(void *data
, size_t len
, const char *name
, bool overwrite
)
406 struct blob_attr
*tb
[IFACE_ATTR_MAX
], *c
;
407 bool get_addrs
= false;
409 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, data
, len
);
411 if (tb
[IFACE_ATTR_INTERFACE
])
412 name
= blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]);
417 struct interface
*iface
= get_interface(name
);
421 iface
= calloc_a(sizeof(*iface
), &iface_name
, strlen(name
) + 1);
425 iface
->name
= strcpy(iface_name
, name
);
427 set_interface_defaults(iface
);
429 list_add(&iface
->head
, &interfaces
);
430 get_addrs
= overwrite
= true;
433 const char *ifname
= NULL
;
435 if ((c
= tb
[IFACE_ATTR_IFNAME
]))
436 ifname
= blobmsg_get_string(c
);
437 else if ((c
= tb
[IFACE_ATTR_NETWORKID
]))
438 ifname
= blobmsg_get_string(c
);
442 if (overwrite
|| !iface
->ifname
)
443 ifname
= ubus_get_ifname(name
);
446 if (!iface
->ifname
&& !ifname
)
451 iface
->ifname
= strdup(ifname
);
456 if (!iface
->ifindex
&&
457 (iface
->ifindex
= if_nametoindex(iface
->ifname
)) <= 0)
462 ssize_t len
= netlink_get_interface_addrs(iface
->ifindex
,
463 true, &iface
->addr6
);
466 iface
->addr6_len
= len
;
468 len
= netlink_get_interface_addrs(iface
->ifindex
,
469 false, &iface
->addr4
);
471 iface
->addr4_len
= len
;
476 if ((c
= tb
[IFACE_ATTR_DYNAMICDHCP
]))
477 iface
->no_dynamic_dhcp
= !blobmsg_get_bool(c
);
479 if (overwrite
&& (c
= tb
[IFACE_ATTR_IGNORE
]))
480 iface
->ignore
= blobmsg_get_bool(c
);
482 if ((c
= tb
[IFACE_ATTR_LEASETIME
])) {
483 double time
= parse_leasetime(c
);
487 iface
->dhcpv4_leasetime
= time
;
490 if ((c
= tb
[IFACE_ATTR_START
])) {
491 iface
->dhcpv4_start
.s_addr
= htonl(blobmsg_get_u32(c
));
493 if (config
.main_dhcpv4
&& config
.legacy
)
494 iface
->dhcpv4
= MODE_SERVER
;
497 if ((c
= tb
[IFACE_ATTR_LIMIT
]))
498 iface
->dhcpv4_end
.s_addr
= htonl(
499 ntohl(iface
->dhcpv4_start
.s_addr
) + blobmsg_get_u32(c
));
501 if ((c
= tb
[IFACE_ATTR_MASTER
]))
502 iface
->master
= blobmsg_get_bool(c
);
504 if (overwrite
&& (c
= tb
[IFACE_ATTR_UPSTREAM
])) {
505 struct blob_attr
*cur
;
508 blobmsg_for_each_attr(cur
, c
, rem
) {
509 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
512 iface
->upstream
= realloc(iface
->upstream
,
513 iface
->upstream_len
+ blobmsg_data_len(cur
));
514 if (!iface
->upstream
)
517 memcpy(iface
->upstream
+ iface
->upstream_len
, blobmsg_get_string(cur
), blobmsg_data_len(cur
));
518 iface
->upstream_len
+= blobmsg_data_len(cur
);
523 if ((c
= tb
[IFACE_ATTR_RA
])) {
524 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
530 if ((c
= tb
[IFACE_ATTR_DHCPV4
])) {
531 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
532 if (config
.main_dhcpv4
)
533 iface
->dhcpv4
= mode
;
539 if ((c
= tb
[IFACE_ATTR_DHCPV6
])) {
540 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
541 iface
->dhcpv6
= mode
;
546 if ((c
= tb
[IFACE_ATTR_NDP
])) {
547 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
553 if ((c
= tb
[IFACE_ATTR_ROUTER
])) {
554 struct blob_attr
*cur
;
557 blobmsg_for_each_attr(cur
, c
, rem
) {
558 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
561 struct in_addr addr4
;
562 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
563 iface
->dhcpv4_router
= realloc(iface
->dhcpv4_router
,
564 (++iface
->dhcpv4_router_cnt
) * sizeof(*iface
->dhcpv4_router
));
565 if (!iface
->dhcpv4_router
)
568 iface
->dhcpv4_router
[iface
->dhcpv4_router_cnt
- 1] = addr4
;
574 if ((c
= tb
[IFACE_ATTR_DNS
])) {
575 struct blob_attr
*cur
;
578 iface
->always_rewrite_dns
= true;
579 blobmsg_for_each_attr(cur
, c
, rem
) {
580 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
583 struct in_addr addr4
;
584 struct in6_addr addr6
;
585 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
586 if (addr4
.s_addr
== INADDR_ANY
)
589 iface
->dhcpv4_dns
= realloc(iface
->dhcpv4_dns
,
590 (++iface
->dhcpv4_dns_cnt
) * sizeof(*iface
->dhcpv4_dns
));
591 if (!iface
->dhcpv4_dns
)
594 iface
->dhcpv4_dns
[iface
->dhcpv4_dns_cnt
- 1] = addr4
;
595 } else if (inet_pton(AF_INET6
, blobmsg_get_string(cur
), &addr6
) == 1) {
596 if (IN6_IS_ADDR_UNSPECIFIED(&addr6
))
599 iface
->dns
= realloc(iface
->dns
,
600 (++iface
->dns_cnt
) * sizeof(*iface
->dns
));
604 iface
->dns
[iface
->dns_cnt
- 1] = addr6
;
610 if ((c
= tb
[IFACE_ATTR_DOMAIN
])) {
611 struct blob_attr
*cur
;
614 blobmsg_for_each_attr(cur
, c
, rem
) {
615 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
619 char *domain
= blobmsg_get_string(cur
);
620 size_t domainlen
= strlen(domain
);
621 if (domainlen
> 0 && domain
[domainlen
- 1] == '.')
622 domain
[domainlen
- 1] = 0;
624 int len
= dn_comp(domain
, buf
, sizeof(buf
), NULL
, NULL
);
628 iface
->search
= realloc(iface
->search
, iface
->search_len
+ len
);
632 memcpy(&iface
->search
[iface
->search_len
], buf
, len
);
633 iface
->search_len
+= len
;
637 if ((c
= tb
[IFACE_ATTR_FILTER_CLASS
])) {
638 iface
->filter_class
= realloc(iface
->filter_class
, blobmsg_data_len(c
) + 1);
639 memcpy(iface
->filter_class
, blobmsg_get_string(c
), blobmsg_data_len(c
) + 1);
642 if ((c
= tb
[IFACE_ATTR_DHCPV4_FORCERECONF
]))
643 iface
->dhcpv4_forcereconf
= blobmsg_get_bool(c
);
645 if ((c
= tb
[IFACE_ATTR_DHCPV6_RAW
])) {
646 iface
->dhcpv6_raw_len
= blobmsg_data_len(c
) / 2;
647 iface
->dhcpv6_raw
= realloc(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
);
648 odhcpd_unhexlify(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
, blobmsg_get_string(c
));
651 if ((c
= tb
[IFACE_ATTR_DHCPV6_ASSIGNALL
]))
652 iface
->dhcpv6_assignall
= blobmsg_get_bool(c
);
654 if ((c
= tb
[IFACE_ATTR_RA_DEFAULT
]))
655 iface
->default_router
= blobmsg_get_u32(c
);
657 if ((c
= tb
[IFACE_ATTR_RA_MANAGEMENT
]))
658 iface
->ra_managed
= blobmsg_get_u32(c
);
660 if ((c
= tb
[IFACE_ATTR_RA_REACHABLETIME
])) {
661 uint32_t ra_reachabletime
= blobmsg_get_u32(c
);
662 if (ra_reachabletime
> 3600000)
665 iface
->ra_reachabletime
= ra_reachabletime
;
668 if ((c
= tb
[IFACE_ATTR_RA_RETRANSTIME
])) {
669 uint32_t ra_retranstime
= blobmsg_get_u32(c
);
670 if (ra_retranstime
> 60000)
673 iface
->ra_retranstime
= ra_retranstime
;
676 if ((c
= tb
[IFACE_ATTR_RA_HOPLIMIT
])) {
677 uint32_t ra_hoplimit
= blobmsg_get_u32(c
);
678 if (ra_hoplimit
> 255)
681 iface
->ra_hoplimit
= ra_hoplimit
;
684 if ((c
= tb
[IFACE_ATTR_RA_MTU
])) {
685 uint32_t ra_mtu
= blobmsg_get_u32(c
);
686 if (ra_mtu
< 1280 || ra_mtu
> 65535)
689 iface
->ra_mtu
= ra_mtu
;
692 if ((c
= tb
[IFACE_ATTR_RA_OFFLINK
]))
693 iface
->ra_not_onlink
= blobmsg_get_bool(c
);
695 if ((c
= tb
[IFACE_ATTR_RA_ADVROUTER
]))
696 iface
->ra_advrouter
= blobmsg_get_bool(c
);
698 if ((c
= tb
[IFACE_ATTR_RA_MININTERVAL
]))
699 iface
->ra_mininterval
= blobmsg_get_u32(c
);
701 if ((c
= tb
[IFACE_ATTR_RA_MAXINTERVAL
]))
702 iface
->ra_maxinterval
= blobmsg_get_u32(c
);
704 if ((c
= tb
[IFACE_ATTR_RA_LIFETIME
]))
705 iface
->ra_lifetime
= blobmsg_get_u32(c
);
707 if ((c
= tb
[IFACE_ATTR_RA_USELEASETIME
]))
708 iface
->ra_useleasetime
= blobmsg_get_bool(c
);
710 if ((c
= tb
[IFACE_ATTR_RA_DNS
]))
711 iface
->ra_dns
= blobmsg_get_bool(c
);
713 if ((c
= tb
[IFACE_ATTR_RA_PREFERENCE
])) {
714 const char *prio
= blobmsg_get_string(c
);
716 if (!strcmp(prio
, "high"))
717 iface
->route_preference
= 1;
718 else if (!strcmp(prio
, "low"))
719 iface
->route_preference
= -1;
720 else if (!strcmp(prio
, "medium") || !strcmp(prio
, "default"))
721 iface
->route_preference
= 0;
726 if ((c
= tb
[IFACE_ATTR_PD_MANAGER
]))
727 strncpy(iface
->dhcpv6_pd_manager
, blobmsg_get_string(c
),
728 sizeof(iface
->dhcpv6_pd_manager
) - 1);
730 if ((c
= tb
[IFACE_ATTR_PD_CER
]) &&
731 inet_pton(AF_INET6
, blobmsg_get_string(c
), &iface
->dhcpv6_pd_cer
) < 1)
734 if ((c
= tb
[IFACE_ATTR_NDPROXY_ROUTING
]))
735 iface
->learn_routes
= blobmsg_get_bool(c
);
737 if ((c
= tb
[IFACE_ATTR_NDPROXY_SLAVE
]))
738 iface
->external
= blobmsg_get_bool(c
);
740 if ((c
= tb
[IFACE_ATTR_PREFIX_FILTER
])) {
741 const char *str
= blobmsg_get_string(c
);
742 char *astr
= malloc(strlen(str
) + 1);
746 if (!astr
|| !strcpy(astr
, str
) ||
747 (delim
= strchr(astr
, '/')) == NULL
|| (*(delim
++) = 0) ||
748 sscanf(delim
, "%i", &l
) == 0 || l
> 128 ||
749 inet_pton(AF_INET6
, astr
, &iface
->pio_filter_addr
) == 0)
750 iface
->pio_filter_length
= 0;
752 iface
->pio_filter_length
= l
;
761 close_interface(iface
);
765 static int set_interface(struct uci_section
*s
)
767 blob_buf_init(&b
, 0);
768 uci_to_blob(&b
, s
, &interface_attr_list
);
770 return config_parse_interface(blob_data(b
.head
), blob_len(b
.head
), s
->e
.name
, true);
773 void odhcpd_reload(void)
775 struct uci_context
*uci
= uci_alloc_context();
777 while (!list_empty(&leases
))
778 free_lease(list_first_entry(&leases
, struct lease
, head
));
780 struct interface
*master
= NULL
, *i
, *n
;
785 list_for_each_entry(i
, &interfaces
, head
)
788 struct uci_package
*dhcp
= NULL
;
789 if (!uci_load(uci
, "dhcp", &dhcp
)) {
790 struct uci_element
*e
;
791 uci_foreach_element(&dhcp
->sections
, e
) {
792 struct uci_section
*s
= uci_to_section(e
);
793 if (!strcmp(s
->type
, "host"))
795 else if (!strcmp(s
->type
, "odhcpd"))
799 uci_foreach_element(&dhcp
->sections
, e
) {
800 struct uci_section
*s
= uci_to_section(e
);
801 if (!strcmp(s
->type
, "dhcp"))
806 if (config
.dhcp_statefile
) {
807 char *path
= strdup(config
.dhcp_statefile
);
809 mkdir_p(dirname(path
), 0755);
814 ubus_apply_network();
817 bool any_dhcpv6_slave
= false, any_ra_slave
= false, any_ndp_slave
= false;
820 list_for_each_entry(i
, &interfaces
, head
) {
824 if (i
->dhcpv6
== MODE_HYBRID
|| i
->dhcpv6
== MODE_RELAY
)
825 any_dhcpv6_slave
= true;
827 if (i
->ra
== MODE_HYBRID
|| i
->ra
== MODE_RELAY
)
830 if (i
->ndp
== MODE_HYBRID
|| i
->ndp
== MODE_RELAY
)
831 any_ndp_slave
= true;
834 /* Evaluate hybrid mode for master */
835 list_for_each_entry(i
, &interfaces
, head
) {
839 enum odhcpd_mode hybrid_mode
= MODE_DISABLED
;
841 if (!ubus_has_prefix(i
->name
, i
->ifname
))
842 hybrid_mode
= MODE_RELAY
;
845 if (i
->dhcpv6
== MODE_HYBRID
)
846 i
->dhcpv6
= hybrid_mode
;
848 if (i
->dhcpv6
== MODE_RELAY
&& !any_dhcpv6_slave
)
849 i
->dhcpv6
= MODE_DISABLED
;
851 if (i
->ra
== MODE_HYBRID
)
854 if (i
->ra
== MODE_RELAY
&& !any_ra_slave
)
855 i
->ra
= MODE_DISABLED
;
857 if (i
->ndp
== MODE_HYBRID
)
858 i
->ndp
= hybrid_mode
;
860 if (i
->ndp
== MODE_RELAY
&& !any_ndp_slave
)
861 i
->ndp
= MODE_DISABLED
;
863 if (i
->dhcpv6
== MODE_RELAY
|| i
->ra
== MODE_RELAY
|| i
->ndp
== MODE_RELAY
)
868 list_for_each_entry_safe(i
, n
, &interfaces
, head
) {
870 /* Resolve hybrid mode */
871 if (i
->dhcpv6
== MODE_HYBRID
)
872 i
->dhcpv6
= (master
&& master
->dhcpv6
== MODE_RELAY
) ?
873 MODE_RELAY
: MODE_SERVER
;
875 if (i
->ra
== MODE_HYBRID
)
876 i
->ra
= (master
&& master
->ra
== MODE_RELAY
) ?
877 MODE_RELAY
: MODE_SERVER
;
879 if (i
->ndp
== MODE_HYBRID
)
880 i
->ndp
= (master
&& master
->ndp
== MODE_RELAY
) ?
881 MODE_RELAY
: MODE_DISABLED
;
883 router_setup_interface(i
, !i
->ignore
|| i
->ra
!= MODE_DISABLED
);
884 dhcpv6_setup_interface(i
, !i
->ignore
|| i
->dhcpv6
!= MODE_DISABLED
);
885 ndp_setup_interface(i
, !i
->ignore
|| i
->ndp
!= MODE_DISABLED
);
886 #ifdef DHCPV4_SUPPORT
887 dhcpv4_setup_interface(i
, !i
->ignore
|| i
->dhcpv4
!= MODE_DISABLED
);
893 uci_unload(uci
, dhcp
);
894 uci_free_context(uci
);
897 static void handle_signal(int signal
)
901 if (signal
== SIGHUP
) {
902 if (write(reload_pipe
[1], b
, sizeof(b
)) < 0) {}
907 static void reload_cb(struct uloop_fd
*u
, _unused
unsigned int events
)
910 if (read(u
->fd
, b
, sizeof(b
)) < 0) {}
915 static struct uloop_fd reload_fd
= { .cb
= reload_cb
};
917 void odhcpd_run(void)
919 if (pipe2(reload_pipe
, O_NONBLOCK
| O_CLOEXEC
) < 0) {}
921 reload_fd
.fd
= reload_pipe
[0];
922 uloop_fd_add(&reload_fd
, ULOOP_READ
);
924 signal(SIGTERM
, handle_signal
);
925 signal(SIGINT
, handle_signal
);
926 signal(SIGHUP
, handle_signal
);
936 while (!list_empty(&interfaces
))
937 close_interface(list_first_entry(&interfaces
, struct interface
, head
));