• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcp6c/src/ubus.c

  1 /**
  2  * SPDX-License-Identifier: BSD-2-Clause-Patent
  3  *
  4  * SPDX-FileCopyrightText: Copyright (c) 2024 SoftAtHome
  5  *
  6  * Redistribution and use in source and binary forms, with or
  7  * without modification, are permitted provided that the following
  8  * conditions are met:
  9  *
 10  * 1. Redistributions of source code must retain the above copyright
 11  * notice, this list of conditions and the following disclaimer.
 12  *
 13  * 2. Redistributions in binary form must reproduce the above
 14  * copyright notice, this list of conditions and the following
 15  * disclaimer in the documentation and/or other materials provided
 16  * with the distribution.
 17  *
 18  * Subject to the terms and conditions of this license, each
 19  * copyright holder and contributor hereby grants to those receiving
 20  * rights under this license a perpetual, worldwide, non-exclusive,
 21  * no-charge, royalty-free, irrevocable (except for failure to
 22  * satisfy the conditions of this license) patent license to make,
 23  * have made, use, offer to sell, sell, import, and otherwise
 24  * transfer this software, where such license applies only to those
 25  * patent claims, already acquired or hereafter acquired, licensable
 26  * by such copyright holder or contributor that are necessarily
 27  * infringed by:
 28  *
 29  * (a) their Contribution(s) (the licensed copyrights of copyright
 30  * holders and non-copyrightable additions of contributors, in
 31  * source or binary form) alone; or
 32  *
 33  * (b) combination of their Contribution(s) with the work of
 34  * authorship to which such Contribution(s) was added by such
 35  * copyright holder or contributor, if, at the time the Contribution
 36  * is added, such addition causes such combination to be necessarily
 37  * infringed. The patent license shall not apply to any other
 38  * combinations which include the Contribution.
 39  *
 40  * Except as expressly stated above, no rights or licenses from any
 41  * copyright holder or contributor is granted under this license,
 42  * whether expressly, by implication, estoppel or otherwise.
 43  *
 44  * DISCLAIMER
 45  *
 46  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 47  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 48  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 49  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 50  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 51  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 53  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 54  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 55  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 57  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 58  * POSSIBILITY OF SUCH DAMAGE.
 59  *
 60  */
 61 
 62 #include <arpa/inet.h>
 63 #include <inttypes.h>
 64 #include <libubox/blobmsg.h>
 65 #include <resolv.h>
 66 #include <stdio.h>
 67 #include <sys/types.h>
 68 
 69 #include "config.h"
 70 #include "odhcp6c.h"
 71 #include "ubus.h"
 72 
 73 #define CHECK(stmt) \
 74         do { \
 75                 int ret = (stmt); \
 76                 if (ret != UBUS_STATUS_OK) \
 77                 { \
 78                         error("%s failed: %s (%d)", #stmt, ubus_strerror(ret), ret); \
 79                         return ret; \
 80                 } \
 81         } while (0)
 82 
 83 #define CHECK_ALLOC(buf) \
 84         do { \
 85                 if (buf == NULL) \
 86                 { \
 87                         return UBUS_STATUS_NO_MEMORY; \
 88                 } \
 89         } while (0)
 90 
 91 enum entry_type {
 92         ENTRY_ADDRESS,
 93         ENTRY_HOST,
 94         ENTRY_ROUTE,
 95         ENTRY_PREFIX
 96 };
 97 
 98 enum {
 99         RECONFIGURE_DHCP_ATTR_DSCP,
100         RECONFIGURE_DHCP_ATTR_RELEASE,
101         RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT,
102         RECONFIGURE_DHCP_ATTR_SK_PRIORITY,
103         RECONFIGURE_DHCP_ATTR_OPT_REQUESTED,
104         RECONFIGURE_DHCP_ATTR_OPT_STRICT,
105         RECONFIGURE_DHCP_ATTR_OPT_RECONFIGURE,
106         RECONFIGURE_DHCP_ATTR_OPT_FQDN,
107         RECONFIGURE_DHCP_ATTR_OPT_UNICAST,
108         RECONFIGURE_DHCP_ATTR_OPT_SEND,
109         RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES,
110         RECONFIGURE_DHCP_ATTR_REQ_PREFIXES,
111         RECONFIGURE_DHCP_ATTR_STATEFUL,
112         RECONFIGURE_DHCP_ATTR_MSG_SOLICIT,
113         RECONFIGURE_DHCP_ATTR_MSG_REQUEST,
114         RECONFIGURE_DHCP_ATTR_MSG_RENEW,
115         RECONFIGURE_DHCP_ATTR_MSG_REBIND,
116         RECONFIGURE_DHCP_ATTR_MSG_RELEASE,
117         RECONFIGURE_DHCP_ATTR_MSG_DECLINE,
118         RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ,
119         RECONFIGURE_DHCP_ATTR_IRT_DEFAULT,
120         RECONFIGURE_DHCP_ATTR_IRT_MIN,
121         RECONFIGURE_DHCP_ATTR_RAND_FACTOR,
122         RECONFIGURE_DHCP_ATTR_AUTH_PROTO,
123         RECONFIGURE_DHCP_ATTR_AUTH_TOKEN,
124         RECONFIGURE_DHCP_ATTR_MAX,
125 };
126 
127 struct ubus_context *ubus = NULL;
128 static struct blob_buf b;
129 static char ubus_name[24];
130 
131 static int ubus_handle_get_state(struct ubus_context *ctx, struct ubus_object *obj,
132                 struct ubus_request_data *req, const char *method, struct blob_attr *msg);
133 static int ubus_handle_get_stats(struct ubus_context *ctx, struct ubus_object *obj,
134                 struct ubus_request_data *req, const char *method, struct blob_attr *msg);
135 static int ubus_handle_reset_stats(struct ubus_context *ctx, struct ubus_object *obj,
136                 struct ubus_request_data *req, const char *method, struct blob_attr *msg);
137 static int ubus_handle_reconfigure_dhcp(struct ubus_context *ctx, struct ubus_object *obj,
138                 struct ubus_request_data *req, const char *method, struct blob_attr *msg);
139 static int ubus_handle_renew(struct ubus_context *ctx, struct ubus_object *obj,
140                 struct ubus_request_data *req, const char *method, struct blob_attr *msg);
141 static int ubus_handle_release(struct ubus_context *ctx, struct ubus_object *obj,
142                 struct ubus_request_data *req, const char *method, struct blob_attr *msg);
143 
144 static const struct blobmsg_policy reconfigure_dhcp_policy[RECONFIGURE_DHCP_ATTR_MAX] = {
145         [RECONFIGURE_DHCP_ATTR_DSCP] = { .name = "dscp", .type = BLOBMSG_TYPE_INT32},
146         [RECONFIGURE_DHCP_ATTR_RELEASE] = { .name = "release", .type = BLOBMSG_TYPE_BOOL},
147         [RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT] = { .name = "sol_timeout", .type = BLOBMSG_TYPE_INT32},
148         [RECONFIGURE_DHCP_ATTR_SK_PRIORITY] = { .name = "sk_prio", .type = BLOBMSG_TYPE_INT32},
149         [RECONFIGURE_DHCP_ATTR_OPT_REQUESTED] = { .name = "opt_requested", .type = BLOBMSG_TYPE_ARRAY},
150         [RECONFIGURE_DHCP_ATTR_OPT_STRICT] = { .name = "opt_strict", .type = BLOBMSG_TYPE_BOOL},
151         [RECONFIGURE_DHCP_ATTR_OPT_RECONFIGURE] = { .name = "opt_reconfigure", .type = BLOBMSG_TYPE_BOOL},
152         [RECONFIGURE_DHCP_ATTR_OPT_FQDN] = { .name = "opt_fqdn", .type = BLOBMSG_TYPE_BOOL},
153         [RECONFIGURE_DHCP_ATTR_OPT_UNICAST] = { .name = "opt_unicast", .type = BLOBMSG_TYPE_BOOL},
154         [RECONFIGURE_DHCP_ATTR_OPT_SEND] = { .name = "opt_send", .type = BLOBMSG_TYPE_ARRAY},
155         [RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES] = { .name = "req_addresses", .type = BLOBMSG_TYPE_STRING},
156         [RECONFIGURE_DHCP_ATTR_REQ_PREFIXES] = { .name = "req_prefixes", .type = BLOBMSG_TYPE_INT32},
157         [RECONFIGURE_DHCP_ATTR_STATEFUL] = { .name = "stateful_only", .type = BLOBMSG_TYPE_BOOL},
158         [RECONFIGURE_DHCP_ATTR_MSG_SOLICIT] = { .name = "msg_solicit", .type = BLOBMSG_TYPE_TABLE},
159         [RECONFIGURE_DHCP_ATTR_MSG_REQUEST] = { .name = "msg_request", .type = BLOBMSG_TYPE_TABLE},
160         [RECONFIGURE_DHCP_ATTR_MSG_RENEW] = { .name = "msg_renew", .type = BLOBMSG_TYPE_TABLE},
161         [RECONFIGURE_DHCP_ATTR_MSG_REBIND] = { .name = "msg_rebind", .type = BLOBMSG_TYPE_TABLE},
162         [RECONFIGURE_DHCP_ATTR_MSG_RELEASE] = { .name = "msg_release", .type = BLOBMSG_TYPE_TABLE},
163         [RECONFIGURE_DHCP_ATTR_MSG_DECLINE] = { .name = "msg_decline", .type = BLOBMSG_TYPE_TABLE},
164         [RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ] = { .name = "msg_inforeq", .type = BLOBMSG_TYPE_TABLE},
165         [RECONFIGURE_DHCP_ATTR_IRT_DEFAULT] = { .name = "irt_default", .type = BLOBMSG_TYPE_INT32},
166         [RECONFIGURE_DHCP_ATTR_IRT_MIN] = { .name = "irt_min", .type = BLOBMSG_TYPE_INT32},
167         [RECONFIGURE_DHCP_ATTR_RAND_FACTOR] = { .name = "rand_factor", .type = BLOBMSG_TYPE_INT32},
168         [RECONFIGURE_DHCP_ATTR_AUTH_PROTO] = { .name = "auth_protocol", .type = BLOBMSG_TYPE_STRING},
169         [RECONFIGURE_DHCP_ATTR_AUTH_TOKEN] = { .name = "auth_token", .type = BLOBMSG_TYPE_STRING},
170 };
171 
172 static struct ubus_method odhcp6c_object_methods[] = {
173         UBUS_METHOD_NOARG("get_state", ubus_handle_get_state),
174         UBUS_METHOD_NOARG("get_statistics", ubus_handle_get_stats),
175         UBUS_METHOD_NOARG("reset_statistics", ubus_handle_reset_stats),
176         UBUS_METHOD("reconfigure_dhcp", ubus_handle_reconfigure_dhcp, reconfigure_dhcp_policy),
177         UBUS_METHOD_NOARG("renew", ubus_handle_renew),
178         UBUS_METHOD_NOARG("release", ubus_handle_release),
179 };
180 
181 static struct ubus_object_type odhcp6c_object_type =
182         UBUS_OBJECT_TYPE("odhcp6c", odhcp6c_object_methods);
183 
184 static struct ubus_object odhcp6c_object = {
185         .name = NULL,
186         .type = &odhcp6c_object_type,
187         .methods = odhcp6c_object_methods,
188         .n_methods = ARRAY_SIZE(odhcp6c_object_methods),
189 };
190 
191 static void ubus_disconnect_cb(struct ubus_context *ubus)
192 {
193         int ret;
194 
195         ret = ubus_reconnect(ubus, NULL);
196         if (ret) {
197                 error("Cannot reconnect to ubus: %s", ubus_strerror(ret));
198                 ubus_destroy(ubus);
199         }
200 }
201 
202 char *ubus_init(const char* interface)
203 {
204         int ret = 0;
205 
206         if (!(ubus = ubus_connect(NULL)))
207                 return NULL;
208 
209         snprintf(ubus_name, 24, "odhcp6c.%s", interface);
210         odhcp6c_object.name = ubus_name;
211 
212         ret = ubus_add_object(ubus, &odhcp6c_object);
213         if (ret) {
214                 ubus_destroy(ubus);
215                 return (char *)ubus_strerror(ret);
216         }
217 
218         ubus->connection_lost = ubus_disconnect_cb;
219         return NULL;
220 }
221 
222 struct ubus_context *ubus_get_ctx(void)
223 {
224         return ubus;
225 }
226 
227 void ubus_destroy(struct ubus_context *ubus)
228 {
229         notice("Disconnecting from ubus");
230 
231         if (ubus != NULL)
232                 ubus_free(ubus);
233         ubus = NULL;
234 
235         /* Forces re-initialization when we're reusing the same definitions later on. */
236         odhcp6c_object.id = 0;
237         odhcp6c_object.id = 0;
238 }
239 
240 static int ipv6_to_blob(const char *name,
241                 const struct in6_addr *addr, size_t cnt)
242 {
243         void *arr = blobmsg_open_array(&b, name);
244 
245         for (size_t i = 0; i < cnt; ++i) {
246                 char *buf = blobmsg_alloc_string_buffer(&b, NULL, INET6_ADDRSTRLEN);
247                 CHECK_ALLOC(buf);
248                 inet_ntop(AF_INET6, &addr[i], buf, INET6_ADDRSTRLEN);
249                 blobmsg_add_string_buffer(&b);
250         }
251 
252         blobmsg_close_array(&b, arr);
253         return UBUS_STATUS_OK;
254 }
255 
256 static int fqdn_to_blob(const char *name, const uint8_t *fqdn, size_t len)
257 {
258         size_t buf_size = len > 255 ? 256 : (len + 1);
259         const uint8_t *fqdn_end = fqdn + len;
260         char *buf = NULL;
261 
262         void *arr = blobmsg_open_array(&b, name);
263 
264         while (fqdn < fqdn_end) {
265                 buf = blobmsg_alloc_string_buffer(&b, name, buf_size);
266                 CHECK_ALLOC(buf);
267                 int l = dn_expand(fqdn, fqdn_end, fqdn, buf, buf_size);
268                 if (l < 1) {
269                         buf[0] = '\0';
270                         blobmsg_add_string_buffer(&b);
271                         break;
272                 }
273                 buf[l] = '\0';
274                 blobmsg_add_string_buffer(&b);
275                 fqdn += l;
276         }
277 
278         blobmsg_close_array(&b, arr);
279         return UBUS_STATUS_OK;
280 }
281 
282 static int bin_to_blob(uint8_t *opts, size_t len)
283 {
284         uint8_t *oend = opts + len, *odata;
285         uint16_t otype, olen;
286 
287         dhcpv6_for_each_option(opts, oend, otype, olen, odata) {
288                 char name[14];
289                 char *buf;
290 
291                 snprintf(name, 14, "OPTION_%hu", otype);
292                 buf = blobmsg_alloc_string_buffer(&b, name, olen * 2);
293                 CHECK_ALLOC(buf);
294                 script_hexlify(buf, odata, olen);
295                 blobmsg_add_string_buffer(&b);
296         }
297         return UBUS_STATUS_OK;
298 }
299 
300 static int entry_to_blob(const char *name, const void *data, size_t len, enum entry_type type)
301 {
302         const struct odhcp6c_entry *e = data;
303 
304         void *arr = blobmsg_open_array(&b, name);
305 
306         for (size_t i = 0; i < len / sizeof(*e); ++i) {
307                 void *entry = blobmsg_open_table(&b, name);
308 
309                 /*
310                  * The only invalid entries allowed to be passed to the script are prefix entries.
311                  * This will allow immediate removal of the old ipv6-prefix-assignment that might
312                  * otherwise be kept for up to 2 hours (see L-13 requirement of RFC 7084).
313                  */
314                 if (!e[i].valid && type != ENTRY_PREFIX)
315                         continue;
316 
317                 char *buf = blobmsg_alloc_string_buffer(&b, "target", INET6_ADDRSTRLEN);
318                 CHECK_ALLOC(buf);
319                 inet_ntop(AF_INET6, &e[i].target, buf, INET6_ADDRSTRLEN);
320                 blobmsg_add_string_buffer(&b);
321 
322                 if (type != ENTRY_HOST) {
323                         blobmsg_add_u32(&b, "length", e[i].length);
324                         if (type == ENTRY_ROUTE) {
325                                 if (!IN6_IS_ADDR_UNSPECIFIED(&e[i].router)) {
326                                         buf = blobmsg_alloc_string_buffer(&b, "router", INET6_ADDRSTRLEN);
327                                         CHECK_ALLOC(buf);
328                                         inet_ntop(AF_INET6, &e[i].router, buf, INET6_ADDRSTRLEN);
329                                         blobmsg_add_string_buffer(&b);
330                                 }
331 
332                                 blobmsg_add_u32(&b, "valid", e[i].valid);
333                                 blobmsg_add_u32(&b, "priority", e[i].priority);
334                         } else {
335                                 blobmsg_add_u32(&b, "valid", e[i].valid);
336                                 blobmsg_add_u32(&b, "preferred", e[i].preferred);
337                                 blobmsg_add_u32(&b, "t1", e[i].t1);
338                                 blobmsg_add_u32(&b, "t2", e[i].t2);
339                         }
340 
341                         if (type == ENTRY_PREFIX && ntohl(e[i].iaid) != 1) {
342                                 blobmsg_add_u32(&b, "iaid", ntohl(e[i].iaid));
343                         }
344 
345                         if (type == ENTRY_PREFIX && e[i].exclusion_length) {
346                                 buf = blobmsg_alloc_string_buffer(&b, "excluded", INET6_ADDRSTRLEN);
347                                 CHECK_ALLOC(buf);
348                                 // '.router' is dual-used: for prefixes it contains the prefix
349                                 inet_ntop(AF_INET6, &e[i].router, buf, INET6_ADDRSTRLEN);
350                                 blobmsg_add_string_buffer(&b);
351                                 blobmsg_add_u32(&b, "excluded_length", e[i].exclusion_length);
352                         }
353                 }
354 
355                 blobmsg_close_table(&b, entry);
356         }
357 
358         blobmsg_close_array(&b, arr);
359         return UBUS_STATUS_OK;
360 }
361 
362 static int search_to_blob(const char *name, const uint8_t *start, size_t len)
363 {
364         void *arr = blobmsg_open_array(&b, name);
365         char *buf = NULL;
366 
367         for (struct odhcp6c_entry *e = (struct odhcp6c_entry*)start;
368                                 (uint8_t*)e < &start[len] &&
369                                 (uint8_t*)odhcp6c_next_entry(e) <= &start[len];
370                                 e = odhcp6c_next_entry(e)) {
371                 if (!e->valid)
372                         continue;
373 
374                 buf = blobmsg_alloc_string_buffer(&b, NULL, e->auxlen+1);
375                 CHECK_ALLOC(buf);
376                 buf = mempcpy(buf, e->auxtarget, e->auxlen);
377                 *buf = '\0';
378                 blobmsg_add_string_buffer(&b);
379         }
380 
381         blobmsg_close_array(&b, arr);
382         return UBUS_STATUS_OK;
383 }
384 
385 static int s46_to_blob_portparams(const uint8_t *data, size_t len)
386 {
387         uint8_t *odata;
388         uint16_t otype, olen;
389 
390         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
391                 if (otype == DHCPV6_OPT_S46_PORTPARAMS &&
392                                 olen == sizeof(struct dhcpv6_s46_portparams)) {
393                         struct dhcpv6_s46_portparams *params = (void*)odata;
394                         blobmsg_add_u32(&b, "offset", params->offset);
395                         blobmsg_add_u32(&b, "psidlen", params->psid_len);
396                         blobmsg_add_u32(&b, "psid", ntohs(params->psid));
397                 }
398         }
399         return UBUS_STATUS_OK;
400 }
401 
402 static int s46_to_blob(enum odhcp6c_state state, const uint8_t *data, size_t len)
403 {
404         const char *name = (state == STATE_S46_MAPE) ? "MAPE" :
405                         (state == STATE_S46_MAPT) ? "MAPT" : "LW4O6";
406 
407         if (len == 0)
408                 return UBUS_STATUS_OK;
409 
410         char *buf = NULL;
411         void *arr = blobmsg_open_array(&b, name);
412 
413         const char *type = (state == STATE_S46_MAPE) ? "map-e" :
414                         (state == STATE_S46_MAPT) ? "map-t" : "lw4o6";
415 
416         uint8_t *odata;
417         uint16_t otype, olen;
418 
419         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
420                 struct dhcpv6_s46_rule *rule = (struct dhcpv6_s46_rule*)odata;
421                 struct dhcpv6_s46_v4v6bind *bind = (struct dhcpv6_s46_v4v6bind*)odata;
422 
423                 void *option = blobmsg_open_table(&b, NULL);
424 
425                 if (state != STATE_S46_LW && otype == DHCPV6_OPT_S46_RULE &&
426                                 olen >= sizeof(struct dhcpv6_s46_rule)) {
427                         struct in6_addr in6 = IN6ADDR_ANY_INIT;
428 
429                         size_t prefix6len = rule->prefix6_len;
430                         prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1;
431 
432                         if (prefix6len > sizeof(in6) ||
433                                 olen < sizeof(struct dhcpv6_s46_rule) + prefix6len)
434                                 continue;
435 
436                         memcpy(&in6, rule->ipv6_prefix, prefix6len);
437 
438                         buf = blobmsg_alloc_string_buffer(&b, "ipv4prefix", INET_ADDRSTRLEN);
439                         CHECK_ALLOC(buf);
440                         inet_ntop(AF_INET, &rule->ipv4_prefix, buf, INET_ADDRSTRLEN);
441                         blobmsg_add_string_buffer(&b);
442 
443                         buf = blobmsg_alloc_string_buffer(&b, "ipv6prefix", INET6_ADDRSTRLEN);
444                         CHECK_ALLOC(buf);
445                         inet_ntop(AF_INET6, &in6, buf, INET6_ADDRSTRLEN);
446                         blobmsg_add_string_buffer(&b);
447 
448                         blobmsg_add_u32(&b, "fmr", rule->flags);
449                         blobmsg_add_string(&b, "type", type);
450                         blobmsg_add_u32(&b, "ealen", rule->ea_len);
451                         blobmsg_add_u32(&b, "prefix4len", rule->prefix4_len);
452                         blobmsg_add_u32(&b, "prefix6len", rule->prefix6_len);
453 
454                         s46_to_blob_portparams(&rule->ipv6_prefix[prefix6len],
455                                         olen - sizeof(*rule) - prefix6len);
456 
457                         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
458                                 if (state != STATE_S46_MAPT && otype == DHCPV6_OPT_S46_BR &&
459                                                 olen == sizeof(struct in6_addr)) {
460                                         buf = blobmsg_alloc_string_buffer(&b, "br", INET6_ADDRSTRLEN);
461                                         CHECK_ALLOC(buf);
462                                         inet_ntop(AF_INET6, odata, buf, INET6_ADDRSTRLEN);
463                                         blobmsg_add_string_buffer(&b);
464                                 } else if (state == STATE_S46_MAPT && otype == DHCPV6_OPT_S46_DMR &&
465                                                 olen >= sizeof(struct dhcpv6_s46_dmr)) {
466                                         struct dhcpv6_s46_dmr *dmr = (struct dhcpv6_s46_dmr*)odata;
467                                         memset(&in6, 0, sizeof(in6));
468                                         size_t prefix6len = dmr->dmr_prefix6_len;
469                                         prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1;
470 
471                                         if (prefix6len > sizeof(in6) ||
472                                                 olen < sizeof(struct dhcpv6_s46_dmr) + prefix6len)
473                                                 continue;
474 
475                                         buf = blobmsg_alloc_string_buffer(&b, "dmr", INET6_ADDRSTRLEN);
476                                         CHECK_ALLOC(buf);
477                                         inet_ntop(AF_INET6, &in6, buf, INET6_ADDRSTRLEN);
478                                         blobmsg_add_string_buffer(&b);
479                                         blobmsg_add_u32(&b, "dmrprefix6len", dmr->dmr_prefix6_len);
480                                 }
481                         }
482                 } else if (state == STATE_S46_LW && otype == DHCPV6_OPT_S46_V4V6BIND &&
483                                 olen >= sizeof(struct dhcpv6_s46_v4v6bind)) {
484                         struct in6_addr in6 = IN6ADDR_ANY_INIT;
485 
486                         size_t prefix6len = bind->bindprefix6_len;
487                         prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1;
488 
489                         if (prefix6len > sizeof(in6) ||
490                                 olen < sizeof(struct dhcpv6_s46_v4v6bind) + prefix6len)
491                                 continue;
492 
493                         memcpy(&in6, bind->bind_ipv6_prefix, prefix6len);
494 
495                         buf = blobmsg_alloc_string_buffer(&b, "ipv4prefix", INET_ADDRSTRLEN);
496                         CHECK_ALLOC(buf);
497                         inet_ntop(AF_INET, &bind->ipv4_address, buf, INET_ADDRSTRLEN);
498                         blobmsg_add_string_buffer(&b);
499 
500                         buf = blobmsg_alloc_string_buffer(&b, "ipv6prefix", INET6_ADDRSTRLEN);
501                         CHECK_ALLOC(buf);
502                         inet_ntop(AF_INET6, &in6, buf, INET6_ADDRSTRLEN);
503                         blobmsg_add_string_buffer(&b);
504 
505                         blobmsg_add_string(&b, "type", type);
506                         blobmsg_add_u32(&b, "prefix4len", 32);
507                         blobmsg_add_u32(&b, "prefix6len", bind->bindprefix6_len);
508 
509                         s46_to_blob_portparams(&bind->bind_ipv6_prefix[prefix6len],
510                                         olen - sizeof(*bind) - prefix6len);
511 
512                         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
513                                 if (otype == DHCPV6_OPT_S46_BR && olen == sizeof(struct in6_addr)) {
514                                         buf = blobmsg_alloc_string_buffer(&b, "br", INET6_ADDRSTRLEN);
515                                         CHECK_ALLOC(buf);
516                                         inet_ntop(AF_INET6, odata, buf, INET6_ADDRSTRLEN);
517                                         blobmsg_add_string_buffer(&b);
518                                 }
519                         }
520                 }
521                 blobmsg_close_table(&b, option);
522         }
523 
524         blobmsg_close_array(&b, arr);
525         return UBUS_STATUS_OK;
526 }
527 
528 static int states_to_blob(void)
529 {
530         char *buf = NULL;
531         size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len;
532         size_t sip_ip_len, sip_fqdn_len, aftr_name_len, addr_len;
533         size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len;
534         size_t capt_port_ra_len, capt_port_dhcpv6_len;
535         struct in6_addr *addr = odhcp6c_get_state(STATE_SERVER_ADDR, &addr_len);
536         struct in6_addr *dns = odhcp6c_get_state(STATE_DNS, &dns_len);
537         uint8_t *search = odhcp6c_get_state(STATE_SEARCH, &search_len);
538         uint8_t *custom = odhcp6c_get_state(STATE_CUSTOM_OPTS, &custom_len);
539         struct in6_addr *sntp = odhcp6c_get_state(STATE_SNTP_IP, &sntp_ip_len);
540         struct in6_addr *ntp = odhcp6c_get_state(STATE_NTP_IP, &ntp_ip_len);
541         uint8_t *ntp_dns = odhcp6c_get_state(STATE_NTP_FQDN, &ntp_dns_len);
542         struct in6_addr *sip = odhcp6c_get_state(STATE_SIP_IP, &sip_ip_len);
543         uint8_t *sip_fqdn = odhcp6c_get_state(STATE_SIP_FQDN, &sip_fqdn_len);
544         uint8_t *aftr_name = odhcp6c_get_state(STATE_AFTR_NAME, &aftr_name_len);
545         uint8_t *s46_mapt = odhcp6c_get_state(STATE_S46_MAPT, &s46_mapt_len);
546         uint8_t *s46_mape = odhcp6c_get_state(STATE_S46_MAPE, &s46_mape_len);
547         uint8_t *s46_lw = odhcp6c_get_state(STATE_S46_LW, &s46_lw_len);
548         uint8_t *capt_port_ra = odhcp6c_get_state(STATE_CAPT_PORT_RA, &capt_port_ra_len);
549         uint8_t *capt_port_dhcpv6 = odhcp6c_get_state(STATE_CAPT_PORT_DHCPV6, &capt_port_dhcpv6_len);
550         uint8_t *passthru = odhcp6c_get_state(STATE_PASSTHRU, &passthru_len);
551 
552         size_t prefix_len, address_len, ra_pref_len,
553                 ra_route_len, ra_dns_len, ra_search_len;
554         uint8_t *prefix = odhcp6c_get_state(STATE_IA_PD, &prefix_len);
555         uint8_t *address = odhcp6c_get_state(STATE_IA_NA, &address_len);
556         uint8_t *ra_pref = odhcp6c_get_state(STATE_RA_PREFIX, &ra_pref_len);
557         uint8_t *ra_route = odhcp6c_get_state(STATE_RA_ROUTE, &ra_route_len);
558         uint8_t *ra_dns = odhcp6c_get_state(STATE_RA_DNS, &ra_dns_len);
559         uint8_t *ra_search = odhcp6c_get_state(STATE_RA_SEARCH, &ra_search_len);
560 
561         blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
562 
563         /* RFC8910 ยง3 */
564         if (capt_port_ra_len > 0 && capt_port_dhcpv6_len > 0) {
565                 if (capt_port_ra_len != capt_port_dhcpv6_len ||
566                         !memcmp(capt_port_dhcpv6, capt_port_ra, capt_port_dhcpv6_len))
567                         error(
568                                 "%s received via different vectors differ: preferring URI from DHCPv6",
569                                 CAPT_PORT_URI_STR);
570         }
571 
572         blobmsg_add_string(&b, "DHCPV6_STATE", dhcpv6_state_to_str(dhcpv6_get_state()));
573 
574         CHECK(ipv6_to_blob("SERVER", addr, addr_len / sizeof(*addr)));
575         CHECK(ipv6_to_blob("RDNSS", dns, dns_len / sizeof(*dns)));
576         CHECK(ipv6_to_blob("SNTP_IP", sntp, sntp_ip_len / sizeof(*sntp)));
577         CHECK(ipv6_to_blob("NTP_IP", ntp, ntp_ip_len / sizeof(*ntp)));
578         CHECK(fqdn_to_blob("NTP_FQDN", ntp_dns, ntp_dns_len));
579         CHECK(ipv6_to_blob("SIP_IP", sip, sip_ip_len / sizeof(*sip)));
580         CHECK(fqdn_to_blob("DOMAINS", search, search_len));
581         CHECK(fqdn_to_blob("SIP_DOMAIN", sip_fqdn, sip_fqdn_len));
582         CHECK(fqdn_to_blob("AFTR", aftr_name, aftr_name_len));
583         CHECK(s46_to_blob(STATE_S46_MAPE, s46_mape, s46_mape_len));
584         CHECK(s46_to_blob(STATE_S46_MAPT, s46_mapt, s46_mapt_len));
585         CHECK(s46_to_blob(STATE_S46_LW, s46_lw, s46_lw_len));
586         if (capt_port_dhcpv6_len > 0)
587                 blobmsg_add_string(&b, CAPT_PORT_URI_STR, (char *)capt_port_dhcpv6);
588         else if (capt_port_ra_len > 0)
589                 blobmsg_add_string(&b, CAPT_PORT_URI_STR, (char *)capt_port_ra);
590         CHECK(bin_to_blob(custom, custom_len));
591 
592         if (odhcp6c_is_bound()) {
593                 CHECK(entry_to_blob("PREFIXES", prefix, prefix_len, ENTRY_PREFIX));
594                 CHECK(entry_to_blob("ADDRESSES", address, address_len, ENTRY_ADDRESS));
595         }
596 
597         CHECK(entry_to_blob("RA_ADDRESSES", ra_pref, ra_pref_len, ENTRY_ADDRESS));
598         CHECK(entry_to_blob("RA_ROUTES", ra_route, ra_route_len, ENTRY_ROUTE));
599         CHECK(entry_to_blob("RA_DNS", ra_dns, ra_dns_len, ENTRY_HOST));
600         CHECK(search_to_blob("RA_DOMAINS", ra_search, ra_search_len));
601 
602         blobmsg_add_u32(&b, "RA_HOPLIMIT", ra_get_hoplimit());
603         blobmsg_add_u32(&b, "RA_MTU", ra_get_mtu());
604         blobmsg_add_u32(&b, "RA_REACHABLE", ra_get_reachable());
605         blobmsg_add_u32(&b, "RA_RETRANSMIT", ra_get_retransmit());
606 
607         buf = blobmsg_alloc_string_buffer(&b, "PASSTHRU", passthru_len * 2);
608         CHECK_ALLOC(buf);
609         script_hexlify(buf, passthru, passthru_len);
610         blobmsg_add_string_buffer(&b);
611 
612         return UBUS_STATUS_OK;
613 }
614 
615 static int ubus_handle_get_stats(struct ubus_context *ctx, _o_unused struct ubus_object *obj,
616                 struct ubus_request_data *req, _o_unused const char *method,
617                 _o_unused struct blob_attr *msg)
618 {
619         struct dhcpv6_stats stats = dhcpv6_get_stats();
620 
621         blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
622         blobmsg_add_u64(&b, "dhcp_solicit", stats.solicit);
623         blobmsg_add_u64(&b, "dhcp_advertise", stats.advertise);
624         blobmsg_add_u64(&b, "dhcp_request", stats.request);
625         blobmsg_add_u64(&b, "dhcp_confirm", stats.confirm);
626         blobmsg_add_u64(&b, "dhcp_renew", stats.renew);
627         blobmsg_add_u64(&b, "dhcp_rebind", stats.rebind);
628         blobmsg_add_u64(&b, "dhcp_reply", stats.reply);
629         blobmsg_add_u64(&b, "dhcp_release", stats.release);
630         blobmsg_add_u64(&b, "dhcp_decline", stats.decline);
631         blobmsg_add_u64(&b, "dhcp_reconfigure", stats.reconfigure);
632         blobmsg_add_u64(&b, "dhcp_information_request", stats.information_request);
633         blobmsg_add_u64(&b, "dhcp_discarded_packets", stats.discarded_packets);
634         blobmsg_add_u64(&b, "dhcp_transmit_failures", stats.transmit_failures);
635 
636         CHECK(ubus_send_reply(ctx, req, b.head));
637         blob_buf_free(&b);
638 
639         return UBUS_STATUS_OK;
640 }
641 
642 static int ubus_handle_reset_stats(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj,
643                 _o_unused struct ubus_request_data *req, _o_unused const char *method,
644                 _o_unused struct blob_attr *msg)
645 {
646         dhcpv6_reset_stats();
647 
648         return UBUS_STATUS_OK;
649 }
650 
651 static int ubus_handle_get_state(struct ubus_context *ctx, _o_unused struct ubus_object *obj,
652                 struct ubus_request_data *req, _o_unused const char *method,
653                 _o_unused struct blob_attr *msg)
654 {
655         CHECK(states_to_blob());
656         CHECK(ubus_send_reply(ctx, req, b.head));
657         blob_buf_free(&b);
658 
659         return UBUS_STATUS_OK;
660 }
661 
662 static int ubus_handle_reconfigure_dhcp_rtx(enum config_dhcp_msg msg, struct blob_attr* table)
663 {
664         struct blob_attr *cur = NULL;
665         uint32_t value = 0;
666         size_t rem = 0;
667 
668         if (msg >= CONFIG_DHCP_MAX || blobmsg_data_len(table) == 0)
669                 return UBUS_STATUS_INVALID_ARGUMENT;
670 
671         blobmsg_for_each_attr(cur, table, rem) {
672                 if (!blobmsg_check_attr(cur, true) || blobmsg_type(cur) != BLOBMSG_TYPE_INT32)
673                         return UBUS_STATUS_INVALID_ARGUMENT;
674 
675                 const char* name = blobmsg_name(cur);
676                 if (strcmp("delay_max", name) == 0) {
677                         value = blobmsg_get_u32(cur);
678                         if (!config_set_rtx_delay_max(msg, value))
679                                 return UBUS_STATUS_INVALID_ARGUMENT;
680                 } else if (strcmp("timeout_init", name) == 0 ) {
681                         value = blobmsg_get_u32(cur);
682                         if (!config_set_rtx_timeout_init(msg, value))
683                                 return UBUS_STATUS_INVALID_ARGUMENT;
684                 } else if (strcmp("timeout_max", name) == 0 ) {
685                         value = blobmsg_get_u32(cur);
686                         if (!config_set_rtx_timeout_max(msg, value))
687                                 return UBUS_STATUS_INVALID_ARGUMENT;
688                 } else if (strcmp("rc_max", name) == 0) {
689                         value = blobmsg_get_u32(cur);
690                         if (!config_set_rtx_rc_max(msg, value))
691                                 return UBUS_STATUS_INVALID_ARGUMENT;
692                 } else {
693                         return UBUS_STATUS_INVALID_ARGUMENT;
694                 }
695     }
696 
697         return UBUS_STATUS_OK;
698 }
699 
700 static int ubus_handle_reconfigure_dhcp(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj,
701                 _o_unused struct ubus_request_data *req, _o_unused const char *method,
702                 struct blob_attr *msg)
703 {
704         const struct blobmsg_policy *policy = reconfigure_dhcp_policy;
705         struct blob_attr *tb[RECONFIGURE_DHCP_ATTR_MAX];
706         struct blob_attr *cur = NULL;
707         struct blob_attr *elem = NULL;
708         char *string = NULL;
709         uint32_t value = 0;
710         uint32_t index = 0;
711         bool enabled = false;
712         bool valid_args = false;
713         bool need_reinit = false;
714 
715         if (blobmsg_parse(policy, RECONFIGURE_DHCP_ATTR_MAX, tb, blob_data(msg), blob_len(msg)))
716                 return UBUS_STATUS_INVALID_ARGUMENT;
717 
718         if ((cur = tb[RECONFIGURE_DHCP_ATTR_DSCP])) {
719                 value = blobmsg_get_u32(cur);
720                 if (!config_set_dscp(value))
721                         return UBUS_STATUS_INVALID_ARGUMENT;
722                 need_reinit = true;
723                 valid_args = true;
724         }
725 
726         if ((cur = tb[RECONFIGURE_DHCP_ATTR_RELEASE])) {
727                 enabled = blobmsg_get_bool(cur);
728                 config_set_release(enabled);
729                 valid_args = true;
730         }
731 
732         if ((cur = tb[RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT])) {
733                 value = blobmsg_get_u32(cur);
734                 if (!config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, value))
735                         return UBUS_STATUS_INVALID_ARGUMENT;
736                 need_reinit = true;
737                 valid_args = true;
738         }
739 
740         if ((cur = tb[RECONFIGURE_DHCP_ATTR_SK_PRIORITY])) {
741                 value = blobmsg_get_u32(cur);
742                 if (!config_set_sk_priority(value))
743                         return UBUS_STATUS_INVALID_ARGUMENT;
744                 need_reinit = true;
745                 valid_args = true;
746         }
747 
748         if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_REQUESTED])) {
749                 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, false))
750                         return UBUS_STATUS_INVALID_ARGUMENT;
751 
752                 config_clear_requested_options();
753 
754                 blobmsg_for_each_attr(elem, cur, index) {
755                         if (blobmsg_type(elem) != BLOBMSG_TYPE_INT32)
756                                 return UBUS_STATUS_INVALID_ARGUMENT;
757 
758                         value = blobmsg_get_u32(elem);
759                         if (!config_add_requested_options(value))
760                                 return UBUS_STATUS_INVALID_ARGUMENT;
761                 }
762 
763                 need_reinit = true;
764                 valid_args = true;
765         }
766 
767         if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_STRICT])) {
768                 enabled = blobmsg_get_bool(cur);
769                 config_set_client_options(DHCPV6_STRICT_OPTIONS, enabled);
770                 need_reinit = true;
771                 valid_args = true;
772         }
773 
774         if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_RECONFIGURE])) {
775                 enabled = blobmsg_get_bool(cur);
776                 config_set_client_options(DHCPV6_ACCEPT_RECONFIGURE, enabled);
777                 need_reinit = true;
778                 valid_args = true;
779         }
780 
781         if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_FQDN])) {
782                 enabled = blobmsg_get_bool(cur);
783                 config_set_client_options(DHCPV6_CLIENT_FQDN, enabled);
784                 need_reinit = true;
785                 valid_args = true;
786         }
787 
788         if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_UNICAST])) {
789                 enabled = blobmsg_get_bool(cur);
790                 config_set_client_options(DHCPV6_IGNORE_OPT_UNICAST, enabled);
791                 need_reinit = true;
792                 valid_args = true;
793         }
794 
795         if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_SEND])) {
796                 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, false))
797                         return UBUS_STATUS_INVALID_ARGUMENT;
798 
799                 config_clear_send_options();
800 
801                 blobmsg_for_each_attr(elem, cur, index) {
802                         string = blobmsg_get_string(elem);
803                         if (string == NULL || !config_add_send_options(string))
804                                 return UBUS_STATUS_INVALID_ARGUMENT;
805                 }
806 
807                 need_reinit = true;
808                 valid_args = true;
809         }
810 
811         if ((cur = tb[RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES])) {
812                 string = blobmsg_get_string(cur);
813                 if (string == NULL || !config_set_request_addresses(string))
814                         return UBUS_STATUS_INVALID_ARGUMENT;
815 
816                 need_reinit = true;
817                 valid_args = true;
818         }
819 
820         if ((cur = tb[RECONFIGURE_DHCP_ATTR_REQ_PREFIXES])) {
821                 value = blobmsg_get_u32(cur);
822 
823                 if (!config_set_request_prefix(value, 1))
824                         return UBUS_STATUS_INVALID_ARGUMENT;
825 
826                 need_reinit = true;
827                 valid_args = true;
828         }
829 
830         if ((cur = tb[RECONFIGURE_DHCP_ATTR_STATEFUL])) {
831                 enabled = blobmsg_get_bool(cur);
832                 config_set_stateful_only(enabled);
833                 need_reinit = true;
834                 valid_args = true;
835         }
836 
837         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_SOLICIT])) {
838                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_SOLICIT, cur))
839                         return UBUS_STATUS_INVALID_ARGUMENT;
840 
841                 need_reinit = true;
842                 valid_args = true;
843         }
844 
845         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REQUEST])) {
846                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REQUEST, cur))
847                         return UBUS_STATUS_INVALID_ARGUMENT;
848 
849                 need_reinit = true;
850                 valid_args = true;
851         }
852 
853         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RENEW])) {
854                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RENEW, cur))
855                         return UBUS_STATUS_INVALID_ARGUMENT;
856 
857                 need_reinit = true;
858                 valid_args = true;
859         }
860 
861         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REBIND])) {
862                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REBIND, cur))
863                         return UBUS_STATUS_INVALID_ARGUMENT;
864 
865                 need_reinit = true;
866                 valid_args = true;
867         }
868 
869         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RELEASE])) {
870                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RELEASE, cur))
871                         return UBUS_STATUS_INVALID_ARGUMENT;
872 
873                 need_reinit = true;
874                 valid_args = true;
875         }
876 
877         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_DECLINE])) {
878                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_DECLINE, cur))
879                         return UBUS_STATUS_INVALID_ARGUMENT;
880 
881                 need_reinit = true;
882                 valid_args = true;
883         }
884 
885         if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ])) {
886                 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_INFO_REQ, cur))
887                         return UBUS_STATUS_INVALID_ARGUMENT;
888 
889                 need_reinit = true;
890                 valid_args = true;
891         }
892 
893         if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_MIN])) {
894                 value = blobmsg_get_u32(cur);
895 
896                 if (!config_set_irt_min(value))
897                         return UBUS_STATUS_INVALID_ARGUMENT;
898 
899                 need_reinit = true;
900                 valid_args = true;
901         }
902 
903         if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_DEFAULT])) {
904                 value = blobmsg_get_u32(cur);
905 
906                 if (!config_set_irt_default(value))
907                         return UBUS_STATUS_INVALID_ARGUMENT;
908 
909                 need_reinit = true;
910                 valid_args = true;
911         }
912 
913         if ((cur = tb[RECONFIGURE_DHCP_ATTR_RAND_FACTOR])) {
914                 value = blobmsg_get_u32(cur);
915 
916                 if (!config_set_rand_factor(value))
917                         return UBUS_STATUS_INVALID_ARGUMENT;
918 
919                 need_reinit = true;
920                 valid_args = true;
921         }
922 
923         if ((cur = tb[RECONFIGURE_DHCP_ATTR_AUTH_PROTO])) {
924                 string = blobmsg_get_string(cur);
925 
926                 if (string == NULL || !config_set_auth_protocol(string))
927                         return UBUS_STATUS_INVALID_ARGUMENT;
928 
929                 need_reinit = true;
930                 valid_args = true;
931         }
932 
933         if ((cur = tb[RECONFIGURE_DHCP_ATTR_AUTH_TOKEN])) {
934                 string = blobmsg_get_string(cur);
935 
936                 if (string == NULL || !config_set_auth_token(string))
937                         return UBUS_STATUS_INVALID_ARGUMENT;
938 
939                 need_reinit = true;
940                 valid_args = true;
941         }
942 
943         if (need_reinit)
944                 raise(SIGUSR2);
945 
946         return valid_args ? UBUS_STATUS_OK : UBUS_STATUS_INVALID_ARGUMENT;
947 }
948 
949 static int ubus_handle_renew(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj,
950                 _o_unused struct ubus_request_data *req, _o_unused const char *method,
951                 _o_unused struct blob_attr *msg)
952 {
953         raise(SIGUSR1);
954         return UBUS_STATUS_OK;
955 }
956 
957 static int ubus_handle_release(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj,
958                 _o_unused struct ubus_request_data *req, _o_unused const char *method,
959                 _o_unused struct blob_attr *msg)
960 {
961         raise(SIGUSR2);
962         return UBUS_STATUS_OK;
963 }
964 
965 int ubus_dhcp_event(const char *status)
966 {
967         if (!ubus || !odhcp6c_object.has_subscribers)
968                 return UBUS_STATUS_UNKNOWN_ERROR;
969 
970         CHECK(states_to_blob());
971         CHECK(ubus_notify(ubus, &odhcp6c_object, status, b.head, -1));
972         blob_buf_free(&b);
973 
974         return UBUS_STATUS_OK;
975 }
976 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt