12 static struct blob_buf b
;
13 static int reload_pipe
[2];
14 struct list_head leases
= LIST_HEAD_INIT(leases
);
15 struct list_head interfaces
= LIST_HEAD_INIT(interfaces
);
16 struct config config
= {false, NULL
, NULL
};
22 IFACE_ATTR_DYNAMICDHCP
,
36 IFACE_ATTR_FILTER_CLASS
,
37 IFACE_ATTR_DHCPV6_RAW
,
38 IFACE_ATTR_RA_DEFAULT
,
39 IFACE_ATTR_RA_MANAGEMENT
,
40 IFACE_ATTR_RA_OFFLINK
,
41 IFACE_ATTR_RA_PREFERENCE
,
42 IFACE_ATTR_RA_ADVROUTER
,
43 IFACE_ATTR_RA_MAXINTERVAL
,
44 IFACE_ATTR_PD_MANAGER
,
46 IFACE_ATTR_NDPROXY_ROUTING
,
47 IFACE_ATTR_NDPROXY_SLAVE
,
51 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
52 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
53 [IFACE_ATTR_IFNAME
] = { .name
= "ifname", .type
= BLOBMSG_TYPE_STRING
},
54 [IFACE_ATTR_NETWORKID
] = { .name
= "networkid", .type
= BLOBMSG_TYPE_STRING
},
55 [IFACE_ATTR_DYNAMICDHCP
] = { .name
= "dynamicdhcp", .type
= BLOBMSG_TYPE_BOOL
},
56 [IFACE_ATTR_IGNORE
] = { .name
= "ignore", .type
= BLOBMSG_TYPE_BOOL
},
57 [IFACE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
58 [IFACE_ATTR_START
] = { .name
= "start", .type
= BLOBMSG_TYPE_INT32
},
59 [IFACE_ATTR_LIMIT
] = { .name
= "limit", .type
= BLOBMSG_TYPE_INT32
},
60 [IFACE_ATTR_MASTER
] = { .name
= "master", .type
= BLOBMSG_TYPE_BOOL
},
61 [IFACE_ATTR_UPSTREAM
] = { .name
= "upstream", .type
= BLOBMSG_TYPE_ARRAY
},
62 [IFACE_ATTR_RA
] = { .name
= "ra", .type
= BLOBMSG_TYPE_STRING
},
63 [IFACE_ATTR_DHCPV4
] = { .name
= "dhcpv4", .type
= BLOBMSG_TYPE_STRING
},
64 [IFACE_ATTR_DHCPV6
] = { .name
= "dhcpv6", .type
= BLOBMSG_TYPE_STRING
},
65 [IFACE_ATTR_NDP
] = { .name
= "ndp", .type
= BLOBMSG_TYPE_STRING
},
66 [IFACE_ATTR_ROUTER
] = { .name
= "router", .type
= BLOBMSG_TYPE_ARRAY
},
67 [IFACE_ATTR_DNS
] = { .name
= "dns", .type
= BLOBMSG_TYPE_ARRAY
},
68 [IFACE_ATTR_DOMAIN
] = { .name
= "domain", .type
= BLOBMSG_TYPE_ARRAY
},
69 [IFACE_ATTR_FILTER_CLASS
] = { .name
= "filter_class", .type
= BLOBMSG_TYPE_STRING
},
70 [IFACE_ATTR_DHCPV6_RAW
] = { .name
= "dhcpv6_raw", .type
= BLOBMSG_TYPE_STRING
},
71 [IFACE_ATTR_PD_MANAGER
] = { .name
= "pd_manager", .type
= BLOBMSG_TYPE_STRING
},
72 [IFACE_ATTR_PD_CER
] = { .name
= "pd_cer", .type
= BLOBMSG_TYPE_STRING
},
73 [IFACE_ATTR_RA_DEFAULT
] = { .name
= "ra_default", .type
= BLOBMSG_TYPE_INT32
},
74 [IFACE_ATTR_RA_MANAGEMENT
] = { .name
= "ra_management", .type
= BLOBMSG_TYPE_INT32
},
75 [IFACE_ATTR_RA_OFFLINK
] = { .name
= "ra_offlink", .type
= BLOBMSG_TYPE_BOOL
},
76 [IFACE_ATTR_RA_PREFERENCE
] = { .name
= "ra_preference", .type
= BLOBMSG_TYPE_STRING
},
77 [IFACE_ATTR_RA_ADVROUTER
] = { .name
= "ra_advrouter", .type
= BLOBMSG_TYPE_BOOL
},
78 [IFACE_ATTR_RA_MAXINTERVAL
] = { .name
= "ra_maxinterval", .type
= BLOBMSG_TYPE_INT32
},
79 [IFACE_ATTR_NDPROXY_ROUTING
] = { .name
= "ndproxy_routing", .type
= BLOBMSG_TYPE_BOOL
},
80 [IFACE_ATTR_NDPROXY_SLAVE
] = { .name
= "ndproxy_slave", .type
= BLOBMSG_TYPE_BOOL
},
83 static const struct uci_blob_param_info iface_attr_info
[IFACE_ATTR_MAX
] = {
84 [IFACE_ATTR_UPSTREAM
] = { .type
= BLOBMSG_TYPE_STRING
},
85 [IFACE_ATTR_DNS
] = { .type
= BLOBMSG_TYPE_STRING
},
86 [IFACE_ATTR_DOMAIN
] = { .type
= BLOBMSG_TYPE_STRING
},
89 const struct uci_blob_param_list interface_attr_list
= {
90 .n_params
= IFACE_ATTR_MAX
,
91 .params
= iface_attrs
,
92 .info
= iface_attr_info
,
106 static const struct blobmsg_policy lease_attrs
[LEASE_ATTR_MAX
] = {
107 [LEASE_ATTR_IP
] = { .name
= "ip", .type
= BLOBMSG_TYPE_STRING
},
108 [LEASE_ATTR_MAC
] = { .name
= "mac", .type
= BLOBMSG_TYPE_STRING
},
109 [LEASE_ATTR_DUID
] = { .name
= "duid", .type
= BLOBMSG_TYPE_STRING
},
110 [LEASE_ATTR_HOSTID
] = { .name
= "hostid", .type
= BLOBMSG_TYPE_STRING
},
111 [LEASE_ATTR_NAME
] = { .name
= "name", .type
= BLOBMSG_TYPE_STRING
},
115 const struct uci_blob_param_list lease_attr_list
= {
116 .n_params
= LEASE_ATTR_MAX
,
117 .params
= lease_attrs
,
122 ODHCPD_ATTR_MAINDHCP
,
123 ODHCPD_ATTR_LEASEFILE
,
124 ODHCPD_ATTR_LEASETRIGGER
,
129 static const struct blobmsg_policy odhcpd_attrs
[LEASE_ATTR_MAX
] = {
130 [ODHCPD_ATTR_MAINDHCP
] = { .name
= "maindhcp", .type
= BLOBMSG_TYPE_BOOL
},
131 [ODHCPD_ATTR_LEASEFILE
] = { .name
= "leasefile", .type
= BLOBMSG_TYPE_STRING
},
132 [ODHCPD_ATTR_LEASETRIGGER
] = { .name
= "leasetrigger", .type
= BLOBMSG_TYPE_STRING
},
136 const struct uci_blob_param_list odhcpd_attr_list
= {
137 .n_params
= ODHCPD_ATTR_MAX
,
138 .params
= odhcpd_attrs
,
142 static struct interface
* get_interface(const char *name
)
145 list_for_each_entry(c
, &interfaces
, head
)
146 if (!strcmp(c
->name
, name
))
152 static void clean_interface(struct interface
*iface
)
156 free(iface
->upstream
);
157 free(iface
->dhcpv4_router
);
158 free(iface
->dhcpv4_dns
);
159 free(iface
->dhcpv6_raw
);
160 free(iface
->filter_class
);
161 memset(&iface
->ra
, 0, sizeof(*iface
) - offsetof(struct interface
, ra
));
165 static void close_interface(struct interface
*iface
)
167 if (iface
->head
.next
)
168 list_del(&iface
->head
);
170 setup_router_interface(iface
, false);
171 setup_dhcpv6_interface(iface
, false);
172 setup_ndp_interface(iface
, false);
173 setup_dhcpv4_interface(iface
, false);
175 clean_interface(iface
);
180 static int parse_mode(const char *mode
)
182 if (!strcmp(mode
, "disabled")) {
183 return RELAYD_DISABLED
;
184 } else if (!strcmp(mode
, "server")) {
185 return RELAYD_SERVER
;
186 } else if (!strcmp(mode
, "relay")) {
188 } else if (!strcmp(mode
, "hybrid")) {
189 return RELAYD_HYBRID
;
196 static void set_config(struct uci_section
*s
)
198 struct blob_attr
*tb
[ODHCPD_ATTR_MAX
], *c
;
200 blob_buf_init(&b
, 0);
201 uci_to_blob(&b
, s
, &odhcpd_attr_list
);
202 blobmsg_parse(odhcpd_attrs
, ODHCPD_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
204 if ((c
= tb
[ODHCPD_ATTR_MAINDHCP
]))
205 config
.legacy
= blobmsg_get_bool(c
);
207 if ((c
= tb
[ODHCPD_ATTR_LEASEFILE
])) {
208 free(config
.dhcp_statefile
);
209 config
.dhcp_statefile
= strdup(blobmsg_get_string(c
));
212 if ((c
= tb
[ODHCPD_ATTR_LEASETRIGGER
])) {
213 free(config
.dhcp_cb
);
214 config
.dhcp_cb
= strdup(blobmsg_get_string(c
));
219 static int set_lease(struct uci_section
*s
)
221 struct blob_attr
*tb
[LEASE_ATTR_MAX
], *c
;
223 blob_buf_init(&b
, 0);
224 uci_to_blob(&b
, s
, &lease_attr_list
);
225 blobmsg_parse(lease_attrs
, LEASE_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
228 if ((c
= tb
[LEASE_ATTR_NAME
]))
229 hostlen
= blobmsg_data_len(c
);
231 struct lease
*lease
= calloc(1, sizeof(*lease
) + hostlen
);
236 memcpy(lease
->hostname
, blobmsg_get_string(c
), hostlen
);
238 if ((c
= tb
[LEASE_ATTR_IP
]))
239 if (inet_pton(AF_INET
, blobmsg_get_string(c
), &lease
->ipaddr
) < 0)
242 if ((c
= tb
[LEASE_ATTR_MAC
]))
243 if (!ether_aton_r(blobmsg_get_string(c
), &lease
->mac
))
246 if ((c
= tb
[LEASE_ATTR_DUID
])) {
247 size_t duidlen
= (blobmsg_data_len(c
) - 1) / 2;
248 lease
->duid
= malloc(duidlen
);
252 ssize_t len
= odhcpd_unhexlify(lease
->duid
,
253 duidlen
, blobmsg_get_string(c
));
258 lease
->duid_len
= len
;
261 if ((c
= tb
[LEASE_ATTR_HOSTID
])) {
263 lease
->hostid
= strtoul(blobmsg_get_string(c
), NULL
, 16);
268 list_add(&lease
->head
, &leases
);
280 int config_parse_interface(void *data
, size_t len
, const char *name
, bool overwrite
)
282 struct blob_attr
*tb
[IFACE_ATTR_MAX
], *c
;
283 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, data
, len
);
285 if (tb
[IFACE_ATTR_INTERFACE
])
286 name
= blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]);
291 struct interface
*iface
= get_interface(name
);
293 iface
= calloc(1, sizeof(*iface
));
297 strncpy(iface
->name
, name
, sizeof(iface
->name
) - 1);
298 list_add(&iface
->head
, &interfaces
);
302 const char *ifname
= NULL
;
304 if (overwrite
|| !iface
->ifname
[0])
305 ifname
= ubus_get_ifname(name
);
309 if ((c
= tb
[IFACE_ATTR_IFNAME
]))
310 ifname
= blobmsg_get_string(c
);
311 else if ((c
= tb
[IFACE_ATTR_NETWORKID
]))
312 ifname
= blobmsg_get_string(c
);
315 if (!iface
->ifname
[0] && !ifname
)
319 strncpy(iface
->ifname
, ifname
, sizeof(iface
->ifname
) - 1);
321 if ((iface
->ifindex
= if_nametoindex(iface
->ifname
)) <= 0)
326 if ((c
= tb
[IFACE_ATTR_DYNAMICDHCP
]))
327 iface
->no_dynamic_dhcp
= !blobmsg_get_bool(c
);
329 if (overwrite
&& (c
= tb
[IFACE_ATTR_IGNORE
]))
330 iface
->ignore
= blobmsg_get_bool(c
);
332 if ((c
= tb
[IFACE_ATTR_LEASETIME
])) {
333 char *val
= blobmsg_get_string(c
), *endptr
;
334 double time
= strtod(val
, &endptr
);
335 if (time
&& endptr
[0]) {
336 if (endptr
[0] == 's')
338 else if (endptr
[0] == 'm')
340 else if (endptr
[0] == 'h')
342 else if (endptr
[0] == 'd')
344 else if (endptr
[0] == 'w')
345 time
*= 7 * 24 * 3600;
351 iface
->dhcpv4_leasetime
= time
;
354 if ((c
= tb
[IFACE_ATTR_START
])) {
355 iface
->dhcpv4_start
.s_addr
= htonl(blobmsg_get_u32(c
));
358 iface
->dhcpv4
= RELAYD_SERVER
;
361 if ((c
= tb
[IFACE_ATTR_LIMIT
]))
362 iface
->dhcpv4_end
.s_addr
= htonl(
363 ntohl(iface
->dhcpv4_start
.s_addr
) + blobmsg_get_u32(c
));
365 if ((c
= tb
[IFACE_ATTR_MASTER
]))
366 iface
->master
= blobmsg_get_bool(c
);
368 if (overwrite
&& (c
= tb
[IFACE_ATTR_UPSTREAM
])) {
369 struct blob_attr
*cur
;
372 blobmsg_for_each_attr(cur
, c
, rem
) {
373 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, NULL
))
376 iface
->upstream
= realloc(iface
->upstream
,
377 iface
->upstream_len
+ blobmsg_data_len(cur
));
378 if (!iface
->upstream
)
381 memcpy(iface
->upstream
+ iface
->upstream_len
, blobmsg_get_string(cur
), blobmsg_data_len(cur
));
382 iface
->upstream_len
+= blobmsg_data_len(cur
);
387 if ((c
= tb
[IFACE_ATTR_RA
])) {
388 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
394 if ((c
= tb
[IFACE_ATTR_DHCPV4
])) {
395 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
396 iface
->dhcpv4
= mode
;
401 if ((c
= tb
[IFACE_ATTR_DHCPV6
])) {
402 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
403 iface
->dhcpv6
= mode
;
408 if ((c
= tb
[IFACE_ATTR_NDP
])) {
409 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0)
415 if ((c
= tb
[IFACE_ATTR_ROUTER
])) {
416 struct blob_attr
*cur
;
419 blobmsg_for_each_attr(cur
, c
, rem
) {
420 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, NULL
))
423 struct in_addr addr4
;
424 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
425 iface
->dhcpv4_router
= realloc(iface
->dhcpv4_router
,
426 (++iface
->dhcpv4_router_cnt
) * sizeof(*iface
->dhcpv4_router
));
427 if (!iface
->dhcpv4_router
)
430 iface
->dhcpv4_router
[iface
->dhcpv4_router_cnt
- 1] = addr4
;
437 if ((c
= tb
[IFACE_ATTR_DNS
])) {
438 struct blob_attr
*cur
;
441 iface
->always_rewrite_dns
= true;
442 blobmsg_for_each_attr(cur
, c
, rem
) {
443 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, NULL
))
446 struct in_addr addr4
;
447 struct in6_addr addr6
;
448 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
449 iface
->dhcpv4_dns
= realloc(iface
->dhcpv4_dns
,
450 (++iface
->dhcpv4_dns_cnt
) * sizeof(*iface
->dhcpv4_dns
));
451 if (!iface
->dhcpv4_dns
)
454 iface
->dhcpv4_dns
[iface
->dhcpv4_dns_cnt
- 1] = addr4
;
455 } else if (inet_pton(AF_INET6
, blobmsg_get_string(cur
), &addr6
) == 1) {
456 iface
->dns
= realloc(iface
->dns
,
457 (++iface
->dns_cnt
) * sizeof(*iface
->dns
));
461 iface
->dns
[iface
->dns_cnt
- 1] = addr6
;
468 if ((c
= tb
[IFACE_ATTR_DOMAIN
])) {
469 struct blob_attr
*cur
;
472 blobmsg_for_each_attr(cur
, c
, rem
) {
473 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, NULL
))
477 char *domain
= blobmsg_get_string(cur
);
478 size_t domainlen
= strlen(domain
);
479 if (domainlen
> 0 && domain
[domainlen
- 1] == '.')
480 domain
[domainlen
- 1] = 0;
482 int len
= dn_comp(domain
, buf
, sizeof(buf
), NULL
, NULL
);
486 iface
->search
= realloc(iface
->search
, iface
->search_len
+ len
);
490 memcpy(&iface
->search
[iface
->search_len
], buf
, len
);
491 iface
->search_len
+= len
;
495 if ((c
= tb
[IFACE_ATTR_FILTER_CLASS
])) {
496 iface
->filter_class
= realloc(iface
->filter_class
, blobmsg_data_len(c
) + 1);
497 memcpy(iface
->filter_class
, blobmsg_get_string(c
), blobmsg_data_len(c
) + 1);
500 if ((c
= tb
[IFACE_ATTR_DHCPV6_RAW
])) {
501 iface
->dhcpv6_raw_len
= blobmsg_data_len(c
) / 2;
502 iface
->dhcpv6_raw
= realloc(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
);
503 odhcpd_unhexlify(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
, blobmsg_get_string(c
));
506 if ((c
= tb
[IFACE_ATTR_RA_DEFAULT
]))
507 iface
->default_router
= blobmsg_get_u32(c
);
509 if ((c
= tb
[IFACE_ATTR_RA_MANAGEMENT
]))
510 iface
->managed
= blobmsg_get_u32(c
);
514 if ((c
= tb
[IFACE_ATTR_RA_OFFLINK
]))
515 iface
->ra_not_onlink
= blobmsg_get_bool(c
);
517 if ((c
= tb
[IFACE_ATTR_RA_ADVROUTER
]))
518 iface
->ra_advrouter
= blobmsg_get_bool(c
);
520 if ((c
= tb
[IFACE_ATTR_RA_MAXINTERVAL
]))
521 iface
->ra_maxinterval
= blobmsg_get_u32(c
);
523 if ((c
= tb
[IFACE_ATTR_RA_PREFERENCE
])) {
524 const char *prio
= blobmsg_get_string(c
);
526 if (!strcmp(prio
, "high"))
527 iface
->route_preference
= 1;
528 else if (!strcmp(prio
, "low"))
529 iface
->route_preference
= -1;
530 else if (!strcmp(prio
, "medium") || !strcmp(prio
, "default"))
531 iface
->route_preference
= 0;
536 if ((c
= tb
[IFACE_ATTR_PD_MANAGER
]))
537 strncpy(iface
->dhcpv6_pd_manager
, blobmsg_get_string(c
),
538 sizeof(iface
->dhcpv6_pd_manager
) - 1);
540 if ((c
= tb
[IFACE_ATTR_PD_CER
]) &&
541 inet_pton(AF_INET6
, blobmsg_get_string(c
), &iface
->dhcpv6_pd_cer
) < 1)
544 if ((c
= tb
[IFACE_ATTR_NDPROXY_ROUTING
]))
545 iface
->learn_routes
= blobmsg_get_bool(c
);
547 iface
->learn_routes
= true;
549 if ((c
= tb
[IFACE_ATTR_NDPROXY_SLAVE
]))
550 iface
->external
= blobmsg_get_bool(c
);
555 close_interface(iface
);
559 static int set_interface(struct uci_section
*s
)
561 blob_buf_init(&b
, 0);
562 uci_to_blob(&b
, s
, &interface_attr_list
);
563 return config_parse_interface(blob_data(b
.head
), blob_len(b
.head
), s
->e
.name
, true);
567 void odhcpd_reload(void)
569 struct uci_context
*uci
= uci_alloc_context();
570 while (!list_empty(&leases
)) {
571 struct lease
*l
= list_first_entry(&leases
, struct lease
, head
);
577 struct interface
*master
= NULL
, *i
, *n
;
582 list_for_each_entry(i
, &interfaces
, head
)
585 struct uci_package
*dhcp
= NULL
;
586 if (!uci_load(uci
, "dhcp", &dhcp
)) {
587 struct uci_element
*e
;
588 uci_foreach_element(&dhcp
->sections
, e
) {
589 struct uci_section
*s
= uci_to_section(e
);
590 if (!strcmp(s
->type
, "host"))
592 else if (!strcmp(s
->type
, "odhcpd"))
596 uci_foreach_element(&dhcp
->sections
, e
) {
597 struct uci_section
*s
= uci_to_section(e
);
598 if (!strcmp(s
->type
, "dhcp"))
605 ubus_apply_network();
608 bool any_dhcpv6_slave
= false, any_ra_slave
= false, any_ndp_slave
= false;
611 list_for_each_entry(i
, &interfaces
, head
) {
615 if (i
->dhcpv6
== RELAYD_HYBRID
|| i
->dhcpv6
== RELAYD_RELAY
)
616 any_dhcpv6_slave
= true;
618 if (i
->ra
== RELAYD_HYBRID
|| i
->ra
== RELAYD_RELAY
)
621 if (i
->ndp
== RELAYD_HYBRID
|| i
->ndp
== RELAYD_RELAY
)
622 any_ndp_slave
= true;
625 // Evaluate hybrid mode for master
626 list_for_each_entry(i
, &interfaces
, head
) {
630 enum odhcpd_mode hybrid_mode
= RELAYD_DISABLED
;
632 if (!ubus_has_prefix(i
->name
, i
->ifname
))
633 hybrid_mode
= RELAYD_RELAY
;
636 if (i
->dhcpv6
== RELAYD_HYBRID
)
637 i
->dhcpv6
= hybrid_mode
;
639 if (i
->dhcpv6
== RELAYD_RELAY
&& !any_dhcpv6_slave
)
640 i
->dhcpv6
= RELAYD_DISABLED
;
642 if (i
->ra
== RELAYD_HYBRID
)
645 if (i
->ra
== RELAYD_RELAY
&& !any_ra_slave
)
646 i
->ra
= RELAYD_DISABLED
;
648 if (i
->ndp
== RELAYD_HYBRID
)
649 i
->ndp
= hybrid_mode
;
651 if (i
->ndp
== RELAYD_RELAY
&& !any_ndp_slave
)
652 i
->ndp
= RELAYD_DISABLED
;
654 if (i
->dhcpv6
== RELAYD_RELAY
|| i
->ra
== RELAYD_RELAY
|| i
->ndp
== RELAYD_RELAY
)
659 list_for_each_entry_safe(i
, n
, &interfaces
, head
) {
661 // Resolve hybrid mode
662 if (i
->dhcpv6
== RELAYD_HYBRID
)
663 i
->dhcpv6
= (master
&& master
->dhcpv6
== RELAYD_RELAY
) ?
664 RELAYD_RELAY
: RELAYD_SERVER
;
666 if (i
->ra
== RELAYD_HYBRID
)
667 i
->ra
= (master
&& master
->ra
== RELAYD_RELAY
) ?
668 RELAYD_RELAY
: RELAYD_SERVER
;
670 if (i
->ndp
== RELAYD_HYBRID
)
671 i
->ndp
= (master
&& master
->ndp
== RELAYD_RELAY
) ?
672 RELAYD_RELAY
: RELAYD_DISABLED
;
674 setup_router_interface(i
, true);
675 setup_dhcpv6_interface(i
, true);
676 setup_ndp_interface(i
, true);
677 setup_dhcpv4_interface(i
, true);
683 uci_unload(uci
, dhcp
);
684 uci_free_context(uci
);
688 static void handle_signal(int signal
)
692 if (signal
== SIGHUP
) {
693 if (write(reload_pipe
[1], b
, sizeof(b
)) < 0) {}
700 static void reload_cb(struct uloop_fd
*u
, _unused
unsigned int events
)
703 if (read(u
->fd
, b
, sizeof(b
)) < 0) {}
707 static struct uloop_fd reload_fd
= { .cb
= reload_cb
};
709 void odhcpd_run(void)
711 if (pipe2(reload_pipe
, O_NONBLOCK
| O_CLOEXEC
) < 0) {}
712 reload_fd
.fd
= reload_pipe
[0];
713 uloop_fd_add(&reload_fd
, ULOOP_READ
);
715 signal(SIGTERM
, handle_signal
);
716 signal(SIGINT
, handle_signal
);
717 signal(SIGHUP
, handle_signal
);
727 while (!list_empty(&interfaces
))
728 close_interface(list_first_entry(&interfaces
, struct interface
, head
));