14 #include <libubox/utils.h>
15 #include <libubox/avl.h>
16 #include <libubox/avl-cmp.h>
17 #include <libubox/list.h>
18 #include <libubox/vlist.h>
22 static struct blob_buf b
;
23 static int reload_pipe
[2] = { -1, -1 };
25 static int lease_cmp(const void *k1
, const void *k2
, void *ptr
);
26 static void lease_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
27 struct vlist_node
*node_old
);
29 struct vlist_tree leases
= VLIST_TREE_INIT(leases
, lease_cmp
, lease_update
, true, false);
30 AVL_TREE(interfaces
, avl_strcmp
, false, NULL
);
31 struct config config
= {.legacy
= false, .main_dhcpv4
= false,
32 .dhcp_cb
= NULL
, .dhcp_statefile
= NULL
, .dhcp_hostsfile
= NULL
,
33 .log_level
= LOG_WARNING
};
35 #define START_DEFAULT 100
36 #define LIMIT_DEFAULT 150
38 #define HOSTID_LEN_MIN 12
39 #define HOSTID_LEN_MAX 64
40 #define HOSTID_LEN_DEFAULT HOSTID_LEN_MIN
42 #define PD_MIN_LEN_MAX (64-2) // must delegate at least 2 bits of prefix
44 #define OAF_DHCPV6 (OAF_DHCPV6_NA | OAF_DHCPV6_PD)
50 IFACE_ATTR_DYNAMICDHCP
,
62 IFACE_ATTR_DNS_SERVICE
,
64 IFACE_ATTR_FILTER_CLASS
,
65 IFACE_ATTR_DHCPV4_FORCERECONF
,
66 IFACE_ATTR_DHCPV6_RAW
,
67 IFACE_ATTR_DHCPV6_ASSIGNALL
,
69 IFACE_ATTR_DHCPV6_PD_MIN_LEN
,
71 IFACE_ATTR_DHCPV6_HOSTID_LEN
,
72 IFACE_ATTR_RA_DEFAULT
,
73 IFACE_ATTR_RA_MANAGEMENT
,
76 IFACE_ATTR_RA_OFFLINK
,
77 IFACE_ATTR_RA_PREFERENCE
,
78 IFACE_ATTR_RA_ADVROUTER
,
79 IFACE_ATTR_RA_MININTERVAL
,
80 IFACE_ATTR_RA_MAXINTERVAL
,
81 IFACE_ATTR_RA_LIFETIME
,
82 IFACE_ATTR_RA_USELEASETIME
,
83 IFACE_ATTR_RA_REACHABLETIME
,
84 IFACE_ATTR_RA_RETRANSTIME
,
85 IFACE_ATTR_RA_HOPLIMIT
,
89 IFACE_ATTR_PD_MANAGER
,
91 IFACE_ATTR_NDPROXY_ROUTING
,
92 IFACE_ATTR_NDPROXY_SLAVE
,
93 IFACE_ATTR_PREFIX_FILTER
,
94 IFACE_ATTR_PREFERRED_LIFETIME
,
99 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
100 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
101 [IFACE_ATTR_IFNAME
] = { .name
= "ifname", .type
= BLOBMSG_TYPE_STRING
},
102 [IFACE_ATTR_NETWORKID
] = { .name
= "networkid", .type
= BLOBMSG_TYPE_STRING
},
103 [IFACE_ATTR_DYNAMICDHCP
] = { .name
= "dynamicdhcp", .type
= BLOBMSG_TYPE_BOOL
},
104 [IFACE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
105 [IFACE_ATTR_START
] = { .name
= "start", .type
= BLOBMSG_TYPE_INT32
},
106 [IFACE_ATTR_LIMIT
] = { .name
= "limit", .type
= BLOBMSG_TYPE_INT32
},
107 [IFACE_ATTR_MASTER
] = { .name
= "master", .type
= BLOBMSG_TYPE_BOOL
},
108 [IFACE_ATTR_UPSTREAM
] = { .name
= "upstream", .type
= BLOBMSG_TYPE_ARRAY
},
109 [IFACE_ATTR_RA
] = { .name
= "ra", .type
= BLOBMSG_TYPE_STRING
},
110 [IFACE_ATTR_DHCPV4
] = { .name
= "dhcpv4", .type
= BLOBMSG_TYPE_STRING
},
111 [IFACE_ATTR_DHCPV6
] = { .name
= "dhcpv6", .type
= BLOBMSG_TYPE_STRING
},
112 [IFACE_ATTR_NDP
] = { .name
= "ndp", .type
= BLOBMSG_TYPE_STRING
},
113 [IFACE_ATTR_ROUTER
] = { .name
= "router", .type
= BLOBMSG_TYPE_ARRAY
},
114 [IFACE_ATTR_DNS
] = { .name
= "dns", .type
= BLOBMSG_TYPE_ARRAY
},
115 [IFACE_ATTR_DNS_SERVICE
] = { .name
= "dns_service", .type
= BLOBMSG_TYPE_BOOL
},
116 [IFACE_ATTR_DOMAIN
] = { .name
= "domain", .type
= BLOBMSG_TYPE_ARRAY
},
117 [IFACE_ATTR_FILTER_CLASS
] = { .name
= "filter_class", .type
= BLOBMSG_TYPE_STRING
},
118 [IFACE_ATTR_DHCPV4_FORCERECONF
] = { .name
= "dhcpv4_forcereconf", .type
= BLOBMSG_TYPE_BOOL
},
119 [IFACE_ATTR_DHCPV6_RAW
] = { .name
= "dhcpv6_raw", .type
= BLOBMSG_TYPE_STRING
},
120 [IFACE_ATTR_DHCPV6_ASSIGNALL
] = { .name
="dhcpv6_assignall", .type
= BLOBMSG_TYPE_BOOL
},
121 [IFACE_ATTR_DHCPV6_PD
] = { .name
= "dhcpv6_pd", .type
= BLOBMSG_TYPE_BOOL
},
122 [IFACE_ATTR_DHCPV6_PD_MIN_LEN
] = { .name
= "dhcpv6_pd_min_len", .type
= BLOBMSG_TYPE_INT32
},
123 [IFACE_ATTR_DHCPV6_NA
] = { .name
= "dhcpv6_na", .type
= BLOBMSG_TYPE_BOOL
},
124 [IFACE_ATTR_DHCPV6_HOSTID_LEN
] = { .name
= "dhcpv6_hostidlength", .type
= BLOBMSG_TYPE_INT32
},
125 [IFACE_ATTR_PD_MANAGER
] = { .name
= "pd_manager", .type
= BLOBMSG_TYPE_STRING
},
126 [IFACE_ATTR_PD_CER
] = { .name
= "pd_cer", .type
= BLOBMSG_TYPE_STRING
},
127 [IFACE_ATTR_RA_DEFAULT
] = { .name
= "ra_default", .type
= BLOBMSG_TYPE_INT32
},
128 [IFACE_ATTR_RA_MANAGEMENT
] = { .name
= "ra_management", .type
= BLOBMSG_TYPE_INT32
},
129 [IFACE_ATTR_RA_FLAGS
] = { .name
= "ra_flags", . type
= BLOBMSG_TYPE_ARRAY
},
130 [IFACE_ATTR_RA_SLAAC
] = { .name
= "ra_slaac", .type
= BLOBMSG_TYPE_BOOL
},
131 [IFACE_ATTR_RA_OFFLINK
] = { .name
= "ra_offlink", .type
= BLOBMSG_TYPE_BOOL
},
132 [IFACE_ATTR_RA_PREFERENCE
] = { .name
= "ra_preference", .type
= BLOBMSG_TYPE_STRING
},
133 [IFACE_ATTR_RA_ADVROUTER
] = { .name
= "ra_advrouter", .type
= BLOBMSG_TYPE_BOOL
},
134 [IFACE_ATTR_RA_MININTERVAL
] = { .name
= "ra_mininterval", .type
= BLOBMSG_TYPE_INT32
},
135 [IFACE_ATTR_RA_MAXINTERVAL
] = { .name
= "ra_maxinterval", .type
= BLOBMSG_TYPE_INT32
},
136 [IFACE_ATTR_RA_LIFETIME
] = { .name
= "ra_lifetime", .type
= BLOBMSG_TYPE_INT32
},
137 [IFACE_ATTR_RA_USELEASETIME
] = { .name
= "ra_useleasetime", .type
= BLOBMSG_TYPE_BOOL
},
138 [IFACE_ATTR_RA_REACHABLETIME
] = { .name
= "ra_reachabletime", .type
= BLOBMSG_TYPE_INT32
},
139 [IFACE_ATTR_RA_RETRANSTIME
] = { .name
= "ra_retranstime", .type
= BLOBMSG_TYPE_INT32
},
140 [IFACE_ATTR_RA_HOPLIMIT
] = { .name
= "ra_hoplimit", .type
= BLOBMSG_TYPE_INT32
},
141 [IFACE_ATTR_RA_MTU
] = { .name
= "ra_mtu", .type
= BLOBMSG_TYPE_INT32
},
142 [IFACE_ATTR_RA_DNS
] = { .name
= "ra_dns", .type
= BLOBMSG_TYPE_BOOL
},
143 [IFACE_ATTR_RA_PREF64
] = { .name
= "ra_pref64", .type
= BLOBMSG_TYPE_STRING
},
144 [IFACE_ATTR_NDPROXY_ROUTING
] = { .name
= "ndproxy_routing", .type
= BLOBMSG_TYPE_BOOL
},
145 [IFACE_ATTR_NDPROXY_SLAVE
] = { .name
= "ndproxy_slave", .type
= BLOBMSG_TYPE_BOOL
},
146 [IFACE_ATTR_PREFIX_FILTER
] = { .name
= "prefix_filter", .type
= BLOBMSG_TYPE_STRING
},
147 [IFACE_ATTR_PREFERRED_LIFETIME
] = { .name
= "preferred_lifetime", .type
= BLOBMSG_TYPE_STRING
},
148 [IFACE_ATTR_NTP
] = { .name
= "ntp", .type
= BLOBMSG_TYPE_ARRAY
},
151 static const struct uci_blob_param_info iface_attr_info
[IFACE_ATTR_MAX
] = {
152 [IFACE_ATTR_UPSTREAM
] = { .type
= BLOBMSG_TYPE_STRING
},
153 [IFACE_ATTR_DNS
] = { .type
= BLOBMSG_TYPE_STRING
},
154 [IFACE_ATTR_DOMAIN
] = { .type
= BLOBMSG_TYPE_STRING
},
157 const struct uci_blob_param_list interface_attr_list
= {
158 .n_params
= IFACE_ATTR_MAX
,
159 .params
= iface_attrs
,
160 .info
= iface_attr_info
,
163 const struct blobmsg_policy lease_attrs
[LEASE_ATTR_MAX
] = {
164 [LEASE_ATTR_IP
] = { .name
= "ip", .type
= BLOBMSG_TYPE_STRING
},
165 [LEASE_ATTR_MAC
] = { .name
= "mac", .type
= BLOBMSG_TYPE_STRING
},
166 [LEASE_ATTR_DUID
] = { .name
= "duid", .type
= BLOBMSG_TYPE_STRING
},
167 [LEASE_ATTR_HOSTID
] = { .name
= "hostid", .type
= BLOBMSG_TYPE_STRING
},
168 [LEASE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
169 [LEASE_ATTR_NAME
] = { .name
= "name", .type
= BLOBMSG_TYPE_STRING
},
172 const struct uci_blob_param_list lease_attr_list
= {
173 .n_params
= LEASE_ATTR_MAX
,
174 .params
= lease_attrs
,
179 ODHCPD_ATTR_MAINDHCP
,
180 ODHCPD_ATTR_LEASEFILE
,
181 ODHCPD_ATTR_LEASETRIGGER
,
182 ODHCPD_ATTR_LOGLEVEL
,
183 ODHCPD_ATTR_HOSTSFILE
,
187 static const struct blobmsg_policy odhcpd_attrs
[ODHCPD_ATTR_MAX
] = {
188 [ODHCPD_ATTR_LEGACY
] = { .name
= "legacy", .type
= BLOBMSG_TYPE_BOOL
},
189 [ODHCPD_ATTR_MAINDHCP
] = { .name
= "maindhcp", .type
= BLOBMSG_TYPE_BOOL
},
190 [ODHCPD_ATTR_LEASEFILE
] = { .name
= "leasefile", .type
= BLOBMSG_TYPE_STRING
},
191 [ODHCPD_ATTR_LEASETRIGGER
] = { .name
= "leasetrigger", .type
= BLOBMSG_TYPE_STRING
},
192 [ODHCPD_ATTR_LOGLEVEL
] = { .name
= "loglevel", .type
= BLOBMSG_TYPE_INT32
},
193 [ODHCPD_ATTR_HOSTSFILE
] = { .name
= "hostsfile", .type
= BLOBMSG_TYPE_STRING
},
196 const struct uci_blob_param_list odhcpd_attr_list
= {
197 .n_params
= ODHCPD_ATTR_MAX
,
198 .params
= odhcpd_attrs
,
201 static const struct { const char *name
; uint8_t flag
; } ra_flags
[] = {
202 { .name
= "managed-config", .flag
= ND_RA_FLAG_MANAGED
},
203 { .name
= "other-config", .flag
= ND_RA_FLAG_OTHER
},
204 { .name
= "home-agent", .flag
= ND_RA_FLAG_HOME_AGENT
},
205 { .name
= "none", . flag
= 0 },
209 static void set_interface_defaults(struct interface
*iface
)
211 iface
->ignore
= true;
212 iface
->dhcpv4
= MODE_DISABLED
;
213 iface
->dhcpv6
= MODE_DISABLED
;
214 iface
->ra
= MODE_DISABLED
;
215 iface
->ndp
= MODE_DISABLED
;
216 iface
->learn_routes
= 1;
217 iface
->dhcp_leasetime
= 43200;
218 iface
->preferred_lifetime
= 43200;
219 iface
->dhcpv4_start
.s_addr
= htonl(START_DEFAULT
);
220 iface
->dhcpv4_end
.s_addr
= htonl(START_DEFAULT
+ LIMIT_DEFAULT
- 1);
221 iface
->dhcpv6_assignall
= true;
222 iface
->dhcpv6_pd
= true;
223 iface
->dhcpv6_pd_min_len
= 0;
224 iface
->dhcpv6_na
= true;
225 iface
->dhcpv6_hostid_len
= HOSTID_LEN_DEFAULT
;
226 iface
->dns_service
= true;
227 iface
->ra_flags
= ND_RA_FLAG_OTHER
;
228 iface
->ra_slaac
= true;
229 iface
->ra_maxinterval
= 600;
230 iface
->ra_mininterval
= iface
->ra_maxinterval
/3;
231 iface
->ra_lifetime
= -1;
232 iface
->ra_dns
= true;
235 static void clean_interface(struct interface
*iface
)
239 free(iface
->upstream
);
240 free(iface
->dhcpv4_router
);
241 free(iface
->dhcpv4_dns
);
242 free(iface
->dhcpv6_raw
);
243 free(iface
->filter_class
);
244 free(iface
->dhcpv4_ntp
);
245 free(iface
->dhcpv6_ntp
);
246 free(iface
->dhcpv6_sntp
);
247 memset(&iface
->ra
, 0, sizeof(*iface
) - offsetof(struct interface
, ra
));
248 set_interface_defaults(iface
);
251 static void close_interface(struct interface
*iface
)
253 avl_delete(&interfaces
, &iface
->avl
);
255 router_setup_interface(iface
, false);
256 dhcpv6_setup_interface(iface
, false);
257 ndp_setup_interface(iface
, false);
258 #ifdef DHCPV4_SUPPORT
259 dhcpv4_setup_interface(iface
, false);
262 clean_interface(iface
);
265 free(iface
->invalid_addr6
);
270 static int parse_mode(const char *mode
)
272 if (!strcmp(mode
, "disabled"))
273 return MODE_DISABLED
;
274 else if (!strcmp(mode
, "server"))
276 else if (!strcmp(mode
, "relay"))
278 else if (!strcmp(mode
, "hybrid"))
284 static int parse_ra_flags(uint8_t *flags
, struct blob_attr
*attr
)
286 struct blob_attr
*cur
;
289 blobmsg_for_each_attr(cur
, attr
, rem
) {
292 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
295 if (!blobmsg_check_attr(cur
, false))
298 for (i
= 0; ra_flags
[i
].name
; i
++) {
299 if (!strcmp(ra_flags
[i
].name
, blobmsg_get_string(cur
))) {
300 *flags
|= ra_flags
[i
].flag
;
305 if (!ra_flags
[i
].name
)
312 static void set_config(struct uci_section
*s
)
314 struct blob_attr
*tb
[ODHCPD_ATTR_MAX
], *c
;
316 blob_buf_init(&b
, 0);
317 uci_to_blob(&b
, s
, &odhcpd_attr_list
);
318 blobmsg_parse(odhcpd_attrs
, ODHCPD_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
320 if ((c
= tb
[ODHCPD_ATTR_LEGACY
]))
321 config
.legacy
= blobmsg_get_bool(c
);
323 if ((c
= tb
[ODHCPD_ATTR_MAINDHCP
]))
324 config
.main_dhcpv4
= blobmsg_get_bool(c
);
326 if ((c
= tb
[ODHCPD_ATTR_LEASEFILE
])) {
327 free(config
.dhcp_statefile
);
328 config
.dhcp_statefile
= strdup(blobmsg_get_string(c
));
331 if ((c
= tb
[ODHCPD_ATTR_HOSTSFILE
])) {
332 free(config
.dhcp_hostsfile
);
333 config
.dhcp_hostsfile
= strdup(blobmsg_get_string(c
));
336 if ((c
= tb
[ODHCPD_ATTR_LEASETRIGGER
])) {
337 free(config
.dhcp_cb
);
338 config
.dhcp_cb
= strdup(blobmsg_get_string(c
));
341 if ((c
= tb
[ODHCPD_ATTR_LOGLEVEL
])) {
342 int log_level
= (blobmsg_get_u32(c
) & LOG_PRIMASK
);
344 if (config
.log_level
!= log_level
) {
345 config
.log_level
= log_level
;
346 setlogmask(LOG_UPTO(config
.log_level
));
351 static double parse_leasetime(struct blob_attr
*c
) {
352 char *val
= blobmsg_get_string(c
), *endptr
= NULL
;
353 double time
= strcmp(val
, "infinite") ? strtod(val
, &endptr
) : UINT32_MAX
;
355 if (time
&& endptr
&& endptr
[0]) {
356 if (endptr
[0] == 's')
358 else if (endptr
[0] == 'm')
360 else if (endptr
[0] == 'h')
362 else if (endptr
[0] == 'd')
364 else if (endptr
[0] == 'w')
365 time
*= 7 * 24 * 3600;
379 static void free_lease(struct lease
*l
)
386 int set_lease_from_blobmsg(struct blob_attr
*ba
)
388 struct blob_attr
*tb
[LEASE_ATTR_MAX
], *c
;
393 blobmsg_parse(lease_attrs
, LEASE_ATTR_MAX
, tb
, blob_data(ba
), blob_len(ba
));
395 if ((c
= tb
[LEASE_ATTR_DUID
]))
396 duidlen
= (blobmsg_data_len(c
) - 1) / 2;
398 l
= calloc_a(sizeof(*l
), &duid
, duidlen
);
402 if ((c
= tb
[LEASE_ATTR_MAC
]))
403 if (!ether_aton_r(blobmsg_get_string(c
), &l
->mac
))
406 if ((c
= tb
[LEASE_ATTR_DUID
])) {
410 len
= odhcpd_unhexlify(l
->duid
, duidlen
, blobmsg_get_string(c
));
418 if ((c
= tb
[LEASE_ATTR_NAME
])) {
419 l
->hostname
= strdup(blobmsg_get_string(c
));
420 if (!l
->hostname
|| !odhcpd_valid_hostname(l
->hostname
))
424 if ((c
= tb
[LEASE_ATTR_IP
]))
425 if (inet_pton(AF_INET
, blobmsg_get_string(c
), &l
->ipaddr
) < 0)
428 if ((c
= tb
[LEASE_ATTR_HOSTID
])) {
430 l
->hostid
= strtoull(blobmsg_get_string(c
), NULL
, 16);
434 uint32_t i4a
= ntohl(l
->ipaddr
) & 0xff;
435 l
->hostid
= ((i4a
/ 100) << 8) | (((i4a
% 100) / 10) << 4) | (i4a
% 10);
438 if ((c
= tb
[LEASE_ATTR_LEASETIME
])) {
439 double time
= parse_leasetime(c
);
446 INIT_LIST_HEAD(&l
->assignments
);
447 vlist_add(&leases
, &l
->node
, l
);
457 static int set_lease_from_uci(struct uci_section
*s
)
459 blob_buf_init(&b
, 0);
460 uci_to_blob(&b
, s
, &lease_attr_list
);
462 return set_lease_from_blobmsg(b
.head
);
465 /* Parse NTP Options for DHCPv6 Address */
466 static int parse_ntp_options(uint16_t *dhcpv6_ntp_len
, struct in6_addr addr6
, uint8_t **dhcpv6_ntp
)
468 uint16_t sub_opt
= 0, sub_len
= htons(IPV6_ADDR_LEN
);
469 uint16_t ntp_len
= IPV6_ADDR_LEN
+ 4;
470 uint8_t *ntp
= *dhcpv6_ntp
;
471 size_t pos
= *dhcpv6_ntp_len
;
473 ntp
= realloc(ntp
, pos
+ ntp_len
);
479 if (IN6_IS_ADDR_MULTICAST(&addr6
))
480 sub_opt
= htons(NTP_SUBOPTION_MC_ADDR
);
482 sub_opt
= htons(NTP_SUBOPTION_SRV_ADDR
);
484 memcpy(ntp
+ pos
, &sub_opt
, sizeof(sub_opt
));
485 pos
+= sizeof(sub_opt
);
486 memcpy(ntp
+ pos
, &sub_len
, sizeof(sub_len
));
487 pos
+= sizeof(sub_len
);
488 memcpy(ntp
+ pos
, &addr6
, IPV6_ADDR_LEN
);
490 *dhcpv6_ntp_len
+= ntp_len
;
495 /* Parse NTP Options for FQDN */
496 static int parse_ntp_fqdn(uint16_t *dhcpv6_ntp_len
, char *fqdn
, uint8_t **dhcpv6_ntp
)
498 size_t fqdn_len
= strlen(fqdn
);
499 uint16_t sub_opt
= 0, sub_len
= 0, ntp_len
= 0;
500 uint8_t *ntp
= *dhcpv6_ntp
;
501 size_t pos
= *dhcpv6_ntp_len
;
502 uint8_t buf
[256] = {0};
504 if (fqdn_len
> 0 && fqdn
[fqdn_len
- 1] == '.')
505 fqdn
[fqdn_len
- 1] = 0;
507 int len
= dn_comp(fqdn
, buf
, sizeof(buf
), NULL
, NULL
);
513 ntp
= realloc(ntp
, pos
+ ntp_len
);
519 sub_opt
= htons(NTP_SUBOPTION_SRV_FQDN
);
520 sub_len
= htons(len
);
522 memcpy(ntp
+ pos
, &sub_opt
, sizeof(sub_opt
));
523 pos
+= sizeof(sub_opt
);
524 memcpy(ntp
+ pos
, &sub_len
, sizeof(sub_len
));
525 pos
+= sizeof(sub_len
);
526 memcpy(ntp
+ pos
, buf
, len
);
528 *dhcpv6_ntp_len
+= ntp_len
;
533 int config_parse_interface(void *data
, size_t len
, const char *name
, bool overwrite
)
535 struct odhcpd_ipaddr
*addrs
= NULL
;
536 struct interface
*iface
;
537 struct blob_attr
*tb
[IFACE_ATTR_MAX
], *c
;
539 bool get_addrs
= false;
541 const char *ifname
= NULL
;
543 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, data
, len
);
545 if (tb
[IFACE_ATTR_INTERFACE
])
546 name
= blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]);
551 iface
= avl_find_element(&interfaces
, name
, iface
, avl
);
555 iface
= calloc_a(sizeof(*iface
), &new_name
, strlen(name
) + 1);
559 iface
->name
= strcpy(new_name
, name
);
560 iface
->avl
.key
= iface
->name
;
561 iface
->router_event
.uloop
.fd
= -1;
562 iface
->dhcpv6_event
.uloop
.fd
= -1;
563 iface
->ndp_event
.uloop
.fd
= -1;
564 iface
->ndp_ping_fd
= -1;
565 iface
->dhcpv4_event
.uloop
.fd
= -1;
566 INIT_LIST_HEAD(&iface
->ia_assignments
);
567 INIT_LIST_HEAD(&iface
->dhcpv4_assignments
);
568 INIT_LIST_HEAD(&iface
->dhcpv4_fr_ips
);
570 set_interface_defaults(iface
);
572 avl_insert(&interfaces
, &iface
->avl
);
573 get_addrs
= overwrite
= true;
577 if ((c
= tb
[IFACE_ATTR_IFNAME
]))
578 ifname
= blobmsg_get_string(c
);
579 else if ((c
= tb
[IFACE_ATTR_NETWORKID
]))
580 ifname
= blobmsg_get_string(c
);
584 if (overwrite
|| !iface
->ifname
)
585 ifname
= ubus_get_ifname(name
);
588 if (!iface
->ifname
&& !ifname
)
593 iface
->ifname
= strdup(ifname
);
598 if (!iface
->ifindex
&&
599 (iface
->ifindex
= if_nametoindex(iface
->ifname
)) <= 0)
602 if ((iface
->ifflags
= odhcpd_get_flags(iface
)) < 0)
607 addrs_len
= netlink_get_interface_addrs(iface
->ifindex
,
608 true, &iface
->addr6
);
611 iface
->addr6_len
= addrs_len
;
613 addrs_len
= netlink_get_interface_addrs(iface
->ifindex
,
614 false, &iface
->addr4
);
616 iface
->addr4_len
= addrs_len
;
619 addrs_len
= netlink_get_interface_linklocal(iface
->ifindex
, &addrs
);
621 for (ssize_t i
= 0; i
< addrs_len
; i
++) {
622 struct odhcpd_ipaddr
*addr
= &addrs
[i
];
624 if (!addr
->tentative
) {
625 iface
->have_link_local
= true;
633 if ((c
= tb
[IFACE_ATTR_DYNAMICDHCP
]))
634 iface
->no_dynamic_dhcp
= !blobmsg_get_bool(c
);
636 if ((c
= tb
[IFACE_ATTR_LEASETIME
])) {
637 double time
= parse_leasetime(c
);
640 iface
->dhcp_leasetime
= time
;
642 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
643 iface_attrs
[IFACE_ATTR_LEASETIME
].name
, iface
->name
);
647 if ((c
= tb
[IFACE_ATTR_PREFERRED_LIFETIME
])) {
648 double time
= parse_leasetime(c
);
651 iface
->preferred_lifetime
= time
;
653 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
654 iface_attrs
[IFACE_ATTR_PREFERRED_LIFETIME
].name
, iface
->name
);
658 if ((c
= tb
[IFACE_ATTR_START
])) {
659 iface
->dhcpv4_start
.s_addr
= htonl(blobmsg_get_u32(c
));
660 iface
->dhcpv4_end
.s_addr
= htonl(ntohl(iface
->dhcpv4_start
.s_addr
) +
663 if (config
.main_dhcpv4
&& config
.legacy
)
664 iface
->dhcpv4
= MODE_SERVER
;
667 if ((c
= tb
[IFACE_ATTR_LIMIT
]))
668 iface
->dhcpv4_end
.s_addr
= htonl(ntohl(iface
->dhcpv4_start
.s_addr
) +
669 blobmsg_get_u32(c
) - 1);
671 if ((c
= tb
[IFACE_ATTR_MASTER
]))
672 iface
->master
= blobmsg_get_bool(c
);
674 if (overwrite
&& (c
= tb
[IFACE_ATTR_UPSTREAM
])) {
675 struct blob_attr
*cur
;
678 blobmsg_for_each_attr(cur
, c
, rem
) {
679 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
682 iface
->upstream
= realloc(iface
->upstream
,
683 iface
->upstream_len
+ blobmsg_data_len(cur
));
684 if (!iface
->upstream
)
687 memcpy(iface
->upstream
+ iface
->upstream_len
, blobmsg_get_string(cur
), blobmsg_data_len(cur
));
688 iface
->upstream_len
+= blobmsg_data_len(cur
);
692 if ((c
= tb
[IFACE_ATTR_RA
])) {
693 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
696 if (iface
->ra
!= MODE_DISABLED
)
697 iface
->ignore
= false;
699 syslog(LOG_ERR
, "Invalid %s mode configured for interface '%s'",
700 iface_attrs
[IFACE_ATTR_RA
].name
, iface
->name
);
703 if ((c
= tb
[IFACE_ATTR_DHCPV4
])) {
704 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
705 if (config
.main_dhcpv4
) {
706 iface
->dhcpv4
= mode
;
708 if (iface
->dhcpv4
!= MODE_DISABLED
)
709 iface
->ignore
= false;
712 syslog(LOG_ERR
, "Invalid %s mode configured for interface %s",
713 iface_attrs
[IFACE_ATTR_DHCPV4
].name
, iface
->name
);
716 if ((c
= tb
[IFACE_ATTR_DHCPV6
])) {
717 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
718 iface
->dhcpv6
= mode
;
720 if (iface
->dhcpv6
!= MODE_DISABLED
)
721 iface
->ignore
= false;
723 syslog(LOG_ERR
, "Invalid %s mode configured for interface '%s'",
724 iface_attrs
[IFACE_ATTR_DHCPV6
].name
, iface
->name
);
727 if ((c
= tb
[IFACE_ATTR_NDP
])) {
728 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
731 if (iface
->ndp
!= MODE_DISABLED
)
732 iface
->ignore
= false;
734 syslog(LOG_ERR
, "Invalid %s mode configured for interface '%s'",
735 iface_attrs
[IFACE_ATTR_NDP
].name
, iface
->name
);
738 if ((c
= tb
[IFACE_ATTR_ROUTER
])) {
739 struct blob_attr
*cur
;
742 blobmsg_for_each_attr(cur
, c
, rem
) {
743 struct in_addr addr4
;
745 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
748 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
749 iface
->dhcpv4_router
= realloc(iface
->dhcpv4_router
,
750 (++iface
->dhcpv4_router_cnt
) * sizeof(*iface
->dhcpv4_router
));
751 if (!iface
->dhcpv4_router
)
754 iface
->dhcpv4_router
[iface
->dhcpv4_router_cnt
- 1] = addr4
;
756 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
757 iface_attrs
[IFACE_ATTR_ROUTER
].name
, iface
->name
);
761 if ((c
= tb
[IFACE_ATTR_DNS
])) {
762 struct blob_attr
*cur
;
765 iface
->always_rewrite_dns
= true;
766 blobmsg_for_each_attr(cur
, c
, rem
) {
767 struct in_addr addr4
;
768 struct in6_addr addr6
;
770 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
773 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
774 if (addr4
.s_addr
== INADDR_ANY
) {
775 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
776 iface_attrs
[IFACE_ATTR_DNS
].name
, iface
->name
);
781 iface
->dhcpv4_dns
= realloc(iface
->dhcpv4_dns
,
782 (++iface
->dhcpv4_dns_cnt
) * sizeof(*iface
->dhcpv4_dns
));
783 if (!iface
->dhcpv4_dns
)
786 iface
->dhcpv4_dns
[iface
->dhcpv4_dns_cnt
- 1] = addr4
;
787 } else if (inet_pton(AF_INET6
, blobmsg_get_string(cur
), &addr6
) == 1) {
788 if (IN6_IS_ADDR_UNSPECIFIED(&addr6
)) {
789 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
790 iface_attrs
[IFACE_ATTR_DNS
].name
, iface
->name
);
795 iface
->dns
= realloc(iface
->dns
,
796 (++iface
->dns_cnt
) * sizeof(*iface
->dns
));
800 iface
->dns
[iface
->dns_cnt
- 1] = addr6
;
802 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
803 iface_attrs
[IFACE_ATTR_DNS
].name
, iface
->name
);
807 if ((c
= tb
[IFACE_ATTR_DNS_SERVICE
]))
808 iface
->dns_service
= blobmsg_get_bool(c
);
810 if ((c
= tb
[IFACE_ATTR_DOMAIN
])) {
811 struct blob_attr
*cur
;
814 blobmsg_for_each_attr(cur
, c
, rem
) {
816 char *domain
= blobmsg_get_string(cur
);
817 size_t domainlen
= strlen(domain
);
820 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
823 domain
= blobmsg_get_string(cur
);
824 domainlen
= strlen(domain
);
826 if (domainlen
> 0 && domain
[domainlen
- 1] == '.')
827 domain
[domainlen
- 1] = 0;
829 len
= dn_comp(domain
, buf
, sizeof(buf
), NULL
, NULL
);
831 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
832 iface_attrs
[IFACE_ATTR_DOMAIN
].name
, iface
->name
);
837 iface
->search
= realloc(iface
->search
, iface
->search_len
+ len
);
841 memcpy(&iface
->search
[iface
->search_len
], buf
, len
);
842 iface
->search_len
+= len
;
846 if ((c
= tb
[IFACE_ATTR_FILTER_CLASS
])) {
847 iface
->filter_class
= realloc(iface
->filter_class
, blobmsg_data_len(c
) + 1);
848 memcpy(iface
->filter_class
, blobmsg_get_string(c
), blobmsg_data_len(c
) + 1);
851 if ((c
= tb
[IFACE_ATTR_DHCPV4_FORCERECONF
]))
852 iface
->dhcpv4_forcereconf
= blobmsg_get_bool(c
);
854 if ((c
= tb
[IFACE_ATTR_DHCPV6_RAW
])) {
855 iface
->dhcpv6_raw_len
= blobmsg_data_len(c
) / 2;
856 iface
->dhcpv6_raw
= realloc(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
);
857 odhcpd_unhexlify(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
, blobmsg_get_string(c
));
860 if ((c
= tb
[IFACE_ATTR_DHCPV6_ASSIGNALL
]))
861 iface
->dhcpv6_assignall
= blobmsg_get_bool(c
);
863 if ((c
= tb
[IFACE_ATTR_DHCPV6_PD
]))
864 iface
->dhcpv6_pd
= blobmsg_get_bool(c
);
866 if ((c
= tb
[IFACE_ATTR_DHCPV6_PD_MIN_LEN
])) {
867 uint32_t pd_min_len
= blobmsg_get_u32(c
);
868 if (pd_min_len
!= 0 && pd_min_len
<= PD_MIN_LEN_MAX
)
869 iface
->dhcpv6_pd_min_len
= pd_min_len
;
871 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
872 iface_attrs
[IFACE_ATTR_DHCPV6_PD_MIN_LEN
].name
, iface
->name
);
875 if ((c
= tb
[IFACE_ATTR_DHCPV6_NA
]))
876 iface
->dhcpv6_na
= blobmsg_get_bool(c
);
878 if ((c
= tb
[IFACE_ATTR_DHCPV6_HOSTID_LEN
])) {
879 uint32_t hostid_len
= blobmsg_get_u32(c
);
881 if (hostid_len
>= HOSTID_LEN_MIN
&& hostid_len
<= HOSTID_LEN_MAX
)
882 iface
->dhcpv6_hostid_len
= hostid_len
;
884 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
885 iface_attrs
[IFACE_ATTR_DHCPV6_HOSTID_LEN
].name
, iface
->name
);
889 if ((c
= tb
[IFACE_ATTR_RA_DEFAULT
]))
890 iface
->default_router
= blobmsg_get_u32(c
);
892 if (!tb
[IFACE_ATTR_RA_FLAGS
] && !tb
[IFACE_ATTR_RA_SLAAC
] &&
893 (c
= tb
[IFACE_ATTR_RA_MANAGEMENT
])) {
894 switch (blobmsg_get_u32(c
)) {
896 iface
->ra_flags
= ND_RA_FLAG_OTHER
;
897 iface
->ra_slaac
= true;
900 iface
->ra_flags
= ND_RA_FLAG_OTHER
|ND_RA_FLAG_MANAGED
;
901 iface
->ra_slaac
= true;
904 iface
->ra_flags
= ND_RA_FLAG_OTHER
|ND_RA_FLAG_MANAGED
;
905 iface
->ra_slaac
= false;
912 if ((c
= tb
[IFACE_ATTR_RA_FLAGS
])) {
915 if (parse_ra_flags(&iface
->ra_flags
, c
) < 0)
916 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
917 iface_attrs
[IFACE_ATTR_RA_FLAGS
].name
, iface
->name
);
920 if ((c
= tb
[IFACE_ATTR_RA_REACHABLETIME
])) {
921 uint32_t ra_reachabletime
= blobmsg_get_u32(c
);
923 if (ra_reachabletime
<= 3600000)
924 iface
->ra_reachabletime
= ra_reachabletime
;
926 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
927 iface_attrs
[IFACE_ATTR_RA_REACHABLETIME
].name
, iface
->name
);
930 if ((c
= tb
[IFACE_ATTR_RA_RETRANSTIME
])) {
931 uint32_t ra_retranstime
= blobmsg_get_u32(c
);
933 if (ra_retranstime
<= 60000)
934 iface
->ra_retranstime
= ra_retranstime
;
936 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
937 iface_attrs
[IFACE_ATTR_RA_RETRANSTIME
].name
, iface
->name
);
940 if ((c
= tb
[IFACE_ATTR_RA_HOPLIMIT
])) {
941 uint32_t ra_hoplimit
= blobmsg_get_u32(c
);
943 if (ra_hoplimit
<= 255)
944 iface
->ra_hoplimit
= ra_hoplimit
;
946 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
947 iface_attrs
[IFACE_ATTR_RA_HOPLIMIT
].name
, iface
->name
);
950 if ((c
= tb
[IFACE_ATTR_RA_MTU
])) {
951 uint32_t ra_mtu
= blobmsg_get_u32(c
);
953 if (ra_mtu
>= 1280 || ra_mtu
<= 65535)
954 iface
->ra_mtu
= ra_mtu
;
956 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
957 iface_attrs
[IFACE_ATTR_RA_MTU
].name
, iface
->name
);
960 if ((c
= tb
[IFACE_ATTR_RA_SLAAC
]))
961 iface
->ra_slaac
= blobmsg_get_bool(c
);
963 if ((c
= tb
[IFACE_ATTR_RA_OFFLINK
]))
964 iface
->ra_not_onlink
= blobmsg_get_bool(c
);
966 if ((c
= tb
[IFACE_ATTR_RA_ADVROUTER
]))
967 iface
->ra_advrouter
= blobmsg_get_bool(c
);
969 if ((c
= tb
[IFACE_ATTR_RA_MININTERVAL
]))
970 iface
->ra_mininterval
= blobmsg_get_u32(c
);
972 if ((c
= tb
[IFACE_ATTR_RA_MAXINTERVAL
]))
973 iface
->ra_maxinterval
= blobmsg_get_u32(c
);
975 if ((c
= tb
[IFACE_ATTR_RA_LIFETIME
]))
976 iface
->ra_lifetime
= blobmsg_get_u32(c
);
978 if ((c
= tb
[IFACE_ATTR_RA_USELEASETIME
]))
979 iface
->ra_useleasetime
= blobmsg_get_bool(c
);
981 if ((c
= tb
[IFACE_ATTR_RA_DNS
]))
982 iface
->ra_dns
= blobmsg_get_bool(c
);
984 if ((c
= tb
[IFACE_ATTR_RA_PREF64
])) {
985 const char *str
= blobmsg_get_string(c
);
986 char *astr
= malloc(strlen(str
) + 1);
990 if (!astr
|| !strcpy(astr
, str
) ||
991 (delim
= strchr(astr
, '/')) == NULL
|| (*(delim
++) = 0) ||
992 sscanf(delim
, "%i", &l
) == 0 || l
> 128 ||
993 inet_pton(AF_INET6
, astr
, &iface
->pref64_addr
) == 0)
994 iface
->pref64_length
= 0;
996 iface
->pref64_length
= l
;
1002 if ((c
= tb
[IFACE_ATTR_RA_PREFERENCE
])) {
1003 const char *prio
= blobmsg_get_string(c
);
1005 if (!strcmp(prio
, "high"))
1006 iface
->route_preference
= 1;
1007 else if (!strcmp(prio
, "low"))
1008 iface
->route_preference
= -1;
1009 else if (!strcmp(prio
, "medium") || !strcmp(prio
, "default"))
1010 iface
->route_preference
= 0;
1012 syslog(LOG_ERR
, "Invalid %s mode configured for interface '%s'",
1013 iface_attrs
[IFACE_ATTR_RA_PREFERENCE
].name
, iface
->name
);
1016 if ((c
= tb
[IFACE_ATTR_PD_MANAGER
]))
1017 strncpy(iface
->dhcpv6_pd_manager
, blobmsg_get_string(c
),
1018 sizeof(iface
->dhcpv6_pd_manager
) - 1);
1020 if ((c
= tb
[IFACE_ATTR_PD_CER
]) &&
1021 inet_pton(AF_INET6
, blobmsg_get_string(c
), &iface
->dhcpv6_pd_cer
) < 1)
1022 syslog(LOG_ERR
, "Invalid %s value configured for interface '%s'",
1023 iface_attrs
[IFACE_ATTR_PD_CER
].name
, iface
->name
);
1025 if ((c
= tb
[IFACE_ATTR_NDPROXY_ROUTING
]))
1026 iface
->learn_routes
= blobmsg_get_bool(c
);
1028 if ((c
= tb
[IFACE_ATTR_NDPROXY_SLAVE
]))
1029 iface
->external
= blobmsg_get_bool(c
);
1031 if ((c
= tb
[IFACE_ATTR_PREFIX_FILTER
])) {
1032 const char *str
= blobmsg_get_string(c
);
1033 char *astr
= malloc(strlen(str
) + 1);
1037 if (!astr
|| !strcpy(astr
, str
) ||
1038 (delim
= strchr(astr
, '/')) == NULL
|| (*(delim
++) = 0) ||
1039 sscanf(delim
, "%i", &l
) == 0 || l
> 128 ||
1040 inet_pton(AF_INET6
, astr
, &iface
->pio_filter_addr
) == 0)
1041 iface
->pio_filter_length
= 0;
1043 iface
->pio_filter_length
= l
;
1049 if (overwrite
&& (c
= tb
[IFACE_ATTR_NTP
])) {
1050 struct blob_attr
*cur
;
1053 blobmsg_for_each_attr(cur
, c
, rem
) {
1054 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
1057 char *str
= blobmsg_get_string(cur
);
1058 struct in_addr addr4
;
1059 struct in6_addr addr6
;
1061 if (inet_pton(AF_INET
, str
, &addr4
) == 1) {
1062 if (addr4
.s_addr
== INADDR_ANY
)
1065 iface
->dhcpv4_ntp
= realloc(iface
->dhcpv4_ntp
,
1066 (++iface
->dhcpv4_ntp_cnt
) * sizeof(*iface
->dhcpv4_ntp
));
1067 if (!iface
->dhcpv4_ntp
)
1070 iface
->dhcpv4_ntp
[iface
->dhcpv4_ntp_cnt
- 1] = addr4
;
1071 } else if (inet_pton(AF_INET6
, str
, &addr6
) == 1) {
1072 if (IN6_IS_ADDR_UNSPECIFIED(&addr6
))
1075 iface
->dhcpv6_sntp
= realloc(iface
->dhcpv6_sntp
,
1076 (++iface
->dhcpv6_sntp_cnt
) * sizeof(*iface
->dhcpv6_sntp
));
1077 if (!iface
->dhcpv6_sntp
)
1080 iface
->dhcpv6_sntp
[iface
->dhcpv6_sntp_cnt
- 1] = addr6
;
1082 if (!parse_ntp_options(&iface
->dhcpv6_ntp_len
, addr6
, &iface
->dhcpv6_ntp
))
1083 iface
->dhcpv6_ntp_cnt
++;
1085 if (!parse_ntp_fqdn(&iface
->dhcpv6_ntp_len
, str
, &iface
->dhcpv6_ntp
))
1086 iface
->dhcpv6_ntp_cnt
++;
1094 close_interface(iface
);
1098 static int set_interface(struct uci_section
*s
)
1100 blob_buf_init(&b
, 0);
1101 uci_to_blob(&b
, s
, &interface_attr_list
);
1103 return config_parse_interface(blob_data(b
.head
), blob_len(b
.head
), s
->e
.name
, true);
1106 static void lease_delete_assignments(struct lease
*l
, bool v6
)
1108 struct dhcp_assignment
*a
, *tmp
;
1109 unsigned int flag
= v6
? OAF_DHCPV6
: OAF_DHCPV4
;
1111 list_for_each_entry_safe(a
, tmp
, &l
->assignments
, lease_list
) {
1112 if (a
->flags
& flag
)
1117 static void lease_update_assignments(struct lease
*l
)
1119 struct dhcp_assignment
*a
;
1121 list_for_each_entry(a
, &l
->assignments
, lease_list
) {
1127 a
->hostname
= strdup(l
->hostname
);
1129 a
->leasetime
= l
->leasetime
;
1133 static int lease_cmp(const void *k1
, const void *k2
, _unused
void *ptr
)
1135 const struct lease
*l1
= k1
, *l2
= k2
;
1138 if (l1
->duid_len
!= l2
->duid_len
)
1139 return l1
->duid_len
- l2
->duid_len
;
1141 if (l1
->duid_len
&& l2
->duid_len
)
1142 cmp
= memcmp(l1
->duid
, l2
->duid
, l1
->duid_len
);
1147 return memcmp(l1
->mac
.ether_addr_octet
, l2
->mac
.ether_addr_octet
,
1148 sizeof(l1
->mac
.ether_addr_octet
));
1151 static void lease_change_config(struct lease
*l_old
, struct lease
*l_new
)
1153 bool update
= false;
1155 if ((!!l_new
->hostname
!= !!l_old
->hostname
) ||
1156 (l_new
->hostname
&& strcmp(l_new
->hostname
, l_old
->hostname
))) {
1157 free(l_old
->hostname
);
1158 l_old
->hostname
= NULL
;
1160 if (l_new
->hostname
)
1161 l_old
->hostname
= strdup(l_new
->hostname
);
1166 if (l_old
->leasetime
!= l_new
->leasetime
) {
1167 l_old
->leasetime
= l_new
->leasetime
;
1171 if (l_old
->ipaddr
!= l_new
->ipaddr
) {
1172 l_old
->ipaddr
= l_new
->ipaddr
;
1173 lease_delete_assignments(l_old
, false);
1176 if (l_old
->hostid
!= l_new
->hostid
) {
1177 l_old
->hostid
= l_new
->hostid
;
1178 lease_delete_assignments(l_old
, true);
1182 lease_update_assignments(l_old
);
1187 static void lease_delete(struct lease
*l
)
1189 struct dhcp_assignment
*a
, *tmp
;
1191 list_for_each_entry_safe(a
, tmp
, &l
->assignments
, lease_list
)
1197 static void lease_update(_unused
struct vlist_tree
*tree
, struct vlist_node
*node_new
,
1198 struct vlist_node
*node_old
)
1200 struct lease
*lease_new
= container_of(node_new
, struct lease
, node
);
1201 struct lease
*lease_old
= container_of(node_old
, struct lease
, node
);
1203 if (node_old
&& node_new
)
1204 lease_change_config(lease_old
, lease_new
);
1206 lease_delete(lease_old
);
1209 struct lease
*config_find_lease_by_duid(const uint8_t *duid
, const uint16_t len
)
1213 vlist_for_each_element(&leases
, l
, node
) {
1214 if (l
->duid_len
== len
&& !memcmp(l
->duid
, duid
, len
))
1221 struct lease
*config_find_lease_by_mac(const uint8_t *mac
)
1225 vlist_for_each_element(&leases
, l
, node
) {
1226 if (!memcmp(l
->mac
.ether_addr_octet
, mac
,
1227 sizeof(l
->mac
.ether_addr_octet
)))
1234 struct lease
*config_find_lease_by_hostid(const uint64_t hostid
)
1238 vlist_for_each_element(&leases
, l
, node
) {
1239 if (l
->hostid
== hostid
)
1246 struct lease
*config_find_lease_by_ipaddr(const uint32_t ipaddr
)
1250 vlist_for_each_element(&leases
, l
, node
) {
1251 if (l
->ipaddr
== ipaddr
)
1258 void reload_services(struct interface
*iface
)
1260 if (iface
->ifflags
& IFF_RUNNING
) {
1261 syslog(LOG_DEBUG
, "Enabling services with %s running", iface
->ifname
);
1262 router_setup_interface(iface
, iface
->ra
!= MODE_DISABLED
);
1263 dhcpv6_setup_interface(iface
, iface
->dhcpv6
!= MODE_DISABLED
);
1264 ndp_setup_interface(iface
, iface
->ndp
!= MODE_DISABLED
);
1265 #ifdef DHCPV4_SUPPORT
1266 dhcpv4_setup_interface(iface
, iface
->dhcpv4
!= MODE_DISABLED
);
1269 syslog(LOG_DEBUG
, "Disabling services with %s not running", iface
->ifname
);
1270 router_setup_interface(iface
, false);
1271 dhcpv6_setup_interface(iface
, false);
1272 ndp_setup_interface(iface
, false);
1273 #ifdef DHCPV4_SUPPORT
1274 dhcpv4_setup_interface(iface
, false);
1279 void odhcpd_reload(void)
1281 struct uci_context
*uci
= uci_alloc_context();
1282 struct interface
*master
= NULL
, *i
, *tmp
;
1287 vlist_update(&leases
);
1288 avl_for_each_element(&interfaces
, i
, avl
)
1291 struct uci_package
*dhcp
= NULL
;
1292 if (!uci_load(uci
, "dhcp", &dhcp
)) {
1293 struct uci_element
*e
;
1295 /* 1. Global settings */
1296 uci_foreach_element(&dhcp
->sections
, e
) {
1297 struct uci_section
*s
= uci_to_section(e
);
1298 if (!strcmp(s
->type
, "odhcpd"))
1303 uci_foreach_element(&dhcp
->sections
, e
) {
1304 struct uci_section
*s
= uci_to_section(e
);
1305 if (!strcmp(s
->type
, "dhcp"))
1309 /* 3. Static leases */
1310 uci_foreach_element(&dhcp
->sections
, e
) {
1311 struct uci_section
* s
= uci_to_section(e
);
1312 if (!strcmp(s
->type
, "host"))
1313 set_lease_from_uci(s
);
1317 if (config
.dhcp_statefile
) {
1318 char *path
= strdup(config
.dhcp_statefile
);
1320 mkdir_p(dirname(path
), 0755);
1324 vlist_flush(&leases
);
1327 ubus_apply_network();
1330 bool any_dhcpv6_slave
= false, any_ra_slave
= false, any_ndp_slave
= false;
1333 avl_for_each_element(&interfaces
, i
, avl
) {
1337 if (i
->dhcpv6
== MODE_HYBRID
|| i
->dhcpv6
== MODE_RELAY
)
1338 any_dhcpv6_slave
= true;
1340 if (i
->ra
== MODE_HYBRID
|| i
->ra
== MODE_RELAY
)
1341 any_ra_slave
= true;
1343 if (i
->ndp
== MODE_HYBRID
|| i
->ndp
== MODE_RELAY
)
1344 any_ndp_slave
= true;
1347 /* Evaluate hybrid mode for master */
1348 avl_for_each_element(&interfaces
, i
, avl
) {
1352 enum odhcpd_mode hybrid_mode
= MODE_DISABLED
;
1354 if (!ubus_has_prefix(i
->name
, i
->ifname
))
1355 hybrid_mode
= MODE_RELAY
;
1358 if (i
->dhcpv6
== MODE_HYBRID
)
1359 i
->dhcpv6
= hybrid_mode
;
1361 if (i
->dhcpv6
== MODE_RELAY
&& !any_dhcpv6_slave
)
1362 i
->dhcpv6
= MODE_DISABLED
;
1364 if (i
->ra
== MODE_HYBRID
)
1365 i
->ra
= hybrid_mode
;
1367 if (i
->ra
== MODE_RELAY
&& !any_ra_slave
)
1368 i
->ra
= MODE_DISABLED
;
1370 if (i
->ndp
== MODE_HYBRID
)
1371 i
->ndp
= hybrid_mode
;
1373 if (i
->ndp
== MODE_RELAY
&& !any_ndp_slave
)
1374 i
->ndp
= MODE_DISABLED
;
1376 if (i
->dhcpv6
== MODE_RELAY
|| i
->ra
== MODE_RELAY
|| i
->ndp
== MODE_RELAY
)
1381 avl_for_each_element_safe(&interfaces
, i
, avl
, tmp
) {
1382 if (i
->inuse
&& i
->ifflags
& IFF_RUNNING
) {
1383 /* Resolve hybrid mode */
1384 if (i
->dhcpv6
== MODE_HYBRID
)
1385 i
->dhcpv6
= (master
&& master
->dhcpv6
== MODE_RELAY
) ?
1386 MODE_RELAY
: MODE_SERVER
;
1388 if (i
->ra
== MODE_HYBRID
)
1389 i
->ra
= (master
&& master
->ra
== MODE_RELAY
) ?
1390 MODE_RELAY
: MODE_SERVER
;
1392 if (i
->ndp
== MODE_HYBRID
)
1393 i
->ndp
= (master
&& master
->ndp
== MODE_RELAY
) ?
1394 MODE_RELAY
: MODE_DISABLED
;
1401 uci_unload(uci
, dhcp
);
1402 uci_free_context(uci
);
1405 static void handle_signal(int signal
)
1409 if (signal
== SIGHUP
) {
1410 if (write(reload_pipe
[1], b
, sizeof(b
)) < 0) {}
1415 static void reload_cb(struct uloop_fd
*u
, _unused
unsigned int events
)
1418 if (read(u
->fd
, b
, sizeof(b
)) < 0) {}
1423 static struct uloop_fd reload_fd
= { .fd
= -1, .cb
= reload_cb
};
1425 void odhcpd_run(void)
1427 if (pipe2(reload_pipe
, O_NONBLOCK
| O_CLOEXEC
) < 0) {}
1429 reload_fd
.fd
= reload_pipe
[0];
1430 uloop_fd_add(&reload_fd
, ULOOP_READ
);
1432 signal(SIGTERM
, handle_signal
);
1433 signal(SIGINT
, handle_signal
);
1434 signal(SIGHUP
, handle_signal
);