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

Sources/ucode/lib/ubus.c

  1 /*
  2  * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 #include <unistd.h>
 18 #include <limits.h>
 19 #include <fnmatch.h>
 20 #include <libubus.h>
 21 #include <libubox/blobmsg.h>
 22 
 23 #include "ucode/module.h"
 24 
 25 #define ok_return(expr) do { set_error(0, NULL); return (expr); } while(0)
 26 #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0)
 27 #define errval_return(err, ...) do { set_error(err, __VA_ARGS__); return err; } while(0)
 28 
 29 #define REQUIRED        0
 30 #define OPTIONAL        1
 31 #define NAMED           2
 32 
 33 static struct {
 34         enum ubus_msg_status code;
 35         char *msg;
 36 } last_error;
 37 
 38 __attribute__((format(printf, 2, 3))) static void
 39 set_error(int errcode, const char *fmt, ...)
 40 {
 41         va_list ap;
 42 
 43         free(last_error.msg);
 44 
 45         last_error.code = errcode;
 46         last_error.msg = NULL;
 47 
 48         if (fmt) {
 49                 va_start(ap, fmt);
 50                 xvasprintf(&last_error.msg, fmt, ap);
 51                 va_end(ap);
 52         }
 53 }
 54 
 55 static char *
 56 _arg_type(uc_type_t type)
 57 {
 58         switch (type) {
 59         case UC_INTEGER:   return "an integer value";
 60         case UC_BOOLEAN:   return "a boolean value";
 61         case UC_STRING:    return "a string value";
 62         case UC_DOUBLE:    return "a double value";
 63         case UC_ARRAY:     return "an array";
 64         case UC_OBJECT:    return "an object";
 65         case UC_REGEXP:    return "a regular expression";
 66         case UC_CLOSURE:   return "a function";
 67         default:           return "the expected type";
 68         }
 69 }
 70 
 71 static bool
 72 _args_get(uc_vm_t *vm, bool named, size_t nargs, ...)
 73 {
 74         uc_value_t **ptr, *arg, *obj = NULL;
 75         uc_type_t type, t;
 76         const char *name;
 77         size_t index = 0;
 78         va_list ap;
 79         int opt;
 80 
 81         if (named) {
 82                 obj = uc_fn_arg(0);
 83 
 84                 if (nargs != 1 || ucv_type(obj) != UC_OBJECT)
 85                         named = false;
 86         }
 87 
 88         va_start(ap, nargs);
 89 
 90         while (true) {
 91                 name = va_arg(ap, const char *);
 92 
 93                 if (!name)
 94                         break;
 95 
 96                 type = va_arg(ap, uc_type_t);
 97                 opt = va_arg(ap, int);
 98                 ptr = va_arg(ap, uc_value_t **);
 99 
100                 if (named)
101                         arg = ucv_object_get(obj, name, NULL);
102                 else if (opt != NAMED)
103                         arg = uc_fn_arg(index++);
104                 else
105                         arg = NULL;
106 
107                 if (opt == REQUIRED && !arg)
108                         err_return(UBUS_STATUS_INVALID_ARGUMENT, "Argument %s is required", name);
109 
110                 t = ucv_type(arg);
111 
112                 if (t == UC_CFUNCTION)
113                         t = UC_CLOSURE;
114 
115                 if (arg && type && t != type)
116                         err_return(UBUS_STATUS_INVALID_ARGUMENT, "Argument %s is not %s", name, _arg_type(type));
117 
118                 *ptr = arg;
119         }
120 
121         va_end(ap);
122 
123         ok_return(true);
124 }
125 
126 #define args_get_named(vm, nargs, ...) do { if (!_args_get(vm, true, nargs, __VA_ARGS__, NULL)) return NULL; } while(0)
127 #define args_get(vm, nargs, ...) do { if (!_args_get(vm, false, nargs, __VA_ARGS__, NULL)) return NULL; } while(0)
128 
129 static struct blob_buf buf;
130 
131 typedef struct {
132         struct ubus_context ctx;
133         struct blob_buf buf;
134         int timeout;
135 
136         uc_vm_t *vm;
137         uc_value_t *res;
138 } uc_ubus_connection_t;
139 
140 typedef struct {
141         struct ubus_request request;
142         struct uloop_timeout timeout;
143         struct ubus_context *ctx;
144         bool complete;
145         uc_vm_t *vm;
146         uc_value_t *res;
147         uc_value_t *fd_callback;
148         uc_value_t *response;
149 } uc_ubus_deferred_t;
150 
151 typedef struct {
152         struct ubus_object obj;
153         struct ubus_object_type type;
154         struct ubus_context *ctx;
155         uc_vm_t *vm;
156         uc_value_t *res;
157         struct ubus_method methods[];
158 } uc_ubus_object_t;
159 
160 typedef struct {
161         struct ubus_request_data req;
162         struct uloop_timeout timeout;
163         struct ubus_context *ctx;
164         uc_value_t *res;
165         uc_vm_t *vm;
166         bool deferred;
167         bool replied;
168 } uc_ubus_request_t;
169 
170 typedef struct {
171         struct ubus_notify_request req;
172         struct ubus_context *ctx;
173         uc_vm_t *vm;
174         uc_value_t *res;
175         bool complete;
176 } uc_ubus_notify_t;
177 
178 typedef struct {
179         struct ubus_event_handler ev;
180         struct ubus_context *ctx;
181         uc_vm_t *vm;
182         uc_value_t *res;
183 } uc_ubus_listener_t;
184 
185 typedef struct {
186         struct ubus_subscriber sub;
187         struct ubus_context *ctx;
188         uc_vm_t *vm;
189         uc_value_t *res;
190 } uc_ubus_subscriber_t;
191 
192 typedef struct {
193         bool mret;
194         uc_value_t *res;
195 } uc_ubus_call_res_t;
196 
197 static uc_value_t *
198 uc_ubus_error(uc_vm_t *vm, size_t nargs)
199 {
200         uc_value_t *numeric = uc_fn_arg(0), *rv;
201         uc_stringbuf_t *buf;
202         const char *s;
203 
204         if (last_error.code == 0)
205                 return NULL;
206 
207         if (ucv_is_truish(numeric)) {
208                 rv = ucv_int64_new(last_error.code);
209         }
210         else {
211                 buf = ucv_stringbuf_new();
212 
213                 if (last_error.code == UBUS_STATUS_UNKNOWN_ERROR && last_error.msg) {
214                         ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg));
215                 }
216                 else {
217                         s = ubus_strerror(last_error.code);
218 
219                         ucv_stringbuf_addstr(buf, s, strlen(s));
220 
221                         if (last_error.msg)
222                                 ucv_stringbuf_printf(buf, ": %s", last_error.msg);
223                 }
224 
225                 rv = ucv_stringbuf_finish(buf);
226         }
227 
228         set_error(0, NULL);
229 
230         return rv;
231 }
232 
233 static void
234 uc_ubus_put_res(uc_value_t **rp)
235 {
236         uc_value_t *res = *rp;
237 
238         *rp = NULL;
239         ucv_resource_persistent_set(res, false);
240         ucv_put(res);
241 }
242 
243 enum {
244         CONN_RES_FD,
245         CONN_RES_CB,
246         CONN_RES_DISCONNECT_CB,
247         __CONN_RES_MAX
248 };
249 
250 enum {
251         DEFER_RES_CONN,
252         DEFER_RES_CB,
253         DEFER_RES_DATA_CB,
254         DEFER_RES_FD_CB,
255         DEFER_RES_FD,
256         DEFER_RES_RESPONSE,
257         __DEFER_RES_MAX
258 };
259 
260 enum {
261         OBJ_RES_CONN,
262         OBJ_RES_METHODS,
263         OBJ_RES_SUB_CB,
264         __OBJ_RES_MAX
265 };
266 
267 enum {
268         NOTIFY_RES_CONN,
269         NOTIFY_RES_CB,
270         NOTIFY_RES_DATA_CB,
271         NOTIFY_RES_STATUS_CB,
272         __NOTIFY_RES_MAX,
273 };
274 
275 enum {
276         SUB_RES_NOTIFY_CB,
277         SUB_RES_REMOVE_CB,
278         SUB_RES_PATTERNS,
279         __SUB_RES_MAX,
280 };
281 
282 static uc_value_t *
283 blob_to_ucv(uc_vm_t *vm, struct blob_attr *attr, bool table, const char **name);
284 
285 static uc_value_t *
286 blob_array_to_ucv(uc_vm_t *vm, struct blob_attr *attr, size_t len, bool table)
287 {
288         uc_value_t *o = table ? ucv_object_new(vm) : ucv_array_new(vm);
289         uc_value_t *v;
290         struct blob_attr *pos;
291         size_t rem = len;
292         const char *name;
293 
294         if (!o)
295                 return NULL;
296 
297         __blob_for_each_attr(pos, attr, rem) {
298                 name = NULL;
299                 v = blob_to_ucv(vm, pos, table, &name);
300 
301                 if (table && name)
302                         ucv_object_add(o, name, v);
303                 else if (!table)
304                         ucv_array_push(o, v);
305                 else
306                         ucv_put(v);
307         }
308 
309         return o;
310 }
311 
312 static uc_value_t *
313 blob_to_ucv(uc_vm_t *vm, struct blob_attr *attr, bool table, const char **name)
314 {
315         void *data;
316         int len;
317 
318         if (!blobmsg_check_attr(attr, false))
319                 return NULL;
320 
321         if (table && blobmsg_name(attr)[0])
322                 *name = blobmsg_name(attr);
323 
324         data = blobmsg_data(attr);
325         len = blobmsg_data_len(attr);
326 
327         switch (blob_id(attr)) {
328         case BLOBMSG_TYPE_BOOL:
329                 return ucv_boolean_new(*(uint8_t *)data);
330 
331         case BLOBMSG_TYPE_INT16:
332                 return ucv_int64_new((int16_t)be16_to_cpu(*(uint16_t *)data));
333 
334         case BLOBMSG_TYPE_INT32:
335                 return ucv_int64_new((int32_t)be32_to_cpu(*(uint32_t *)data));
336 
337         case BLOBMSG_TYPE_INT64:
338                 return ucv_int64_new((int64_t)be64_to_cpu(*(uint64_t *)data));
339 
340         case BLOBMSG_TYPE_DOUBLE:
341                 ;
342                 union {
343                         double d;
344                         uint64_t u64;
345                 } v;
346 
347                 v.u64 = be64_to_cpu(*(uint64_t *)data);
348 
349                 return ucv_double_new(v.d);
350 
351         case BLOBMSG_TYPE_STRING:
352                 return ucv_string_new_length(data, len - 1);
353 
354         case BLOBMSG_TYPE_ARRAY:
355                 return blob_array_to_ucv(vm, data, len, false);
356 
357         case BLOBMSG_TYPE_TABLE:
358                 return blob_array_to_ucv(vm, data, len, true);
359 
360         default:
361                 return NULL;
362         }
363 }
364 
365 static void
366 ucv_array_to_blob(uc_value_t *val, struct blob_buf *blob);
367 
368 static void
369 ucv_object_to_blob(uc_value_t *val, struct blob_buf *blob);
370 
371 static void
372 ucv_to_blob(const char *name, uc_value_t *val, struct blob_buf *blob)
373 {
374         int64_t n;
375         void *c;
376 
377         switch (ucv_type(val)) {
378         case UC_NULL:
379                 blobmsg_add_field(blob, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
380                 break;
381 
382         case UC_BOOLEAN:
383                 blobmsg_add_u8(blob, name, ucv_boolean_get(val));
384                 break;
385 
386         case UC_INTEGER:
387                 n = ucv_int64_get(val);
388 
389                 if (errno == ERANGE)
390                         blobmsg_add_u64(blob, name, ucv_uint64_get(val));
391                 else if (n >= INT32_MIN && n <= INT32_MAX)
392                         blobmsg_add_u32(blob, name, n);
393                 else
394                         blobmsg_add_u64(blob, name, n);
395 
396                 break;
397 
398         case UC_DOUBLE:
399                 blobmsg_add_double(blob, name, ucv_double_get(val));
400                 break;
401 
402         case UC_STRING:
403                 blobmsg_add_field(blob, BLOBMSG_TYPE_STRING, name,
404                                   ucv_string_get(val), ucv_string_length(val) + 1);
405                 break;
406 
407         case UC_ARRAY:
408                 c = blobmsg_open_array(blob, name);
409                 ucv_array_to_blob(val, blob);
410                 blobmsg_close_array(blob, c);
411                 break;
412 
413         case UC_OBJECT:
414                 c = blobmsg_open_table(blob, name);
415                 ucv_object_to_blob(val, blob);
416                 blobmsg_close_table(blob, c);
417                 break;
418 
419         default:
420                 break;
421         }
422 }
423 
424 static void
425 ucv_array_to_blob(uc_value_t *val, struct blob_buf *blob)
426 {
427         size_t i;
428 
429         for (i = 0; i < ucv_array_length(val); i++)
430                 ucv_to_blob(NULL, ucv_array_get(val, i), blob);
431 }
432 
433 static void
434 ucv_object_to_blob(uc_value_t *val, struct blob_buf *blob)
435 {
436         ucv_object_foreach(val, k, v)
437                 ucv_to_blob(k, v, blob);
438 }
439 
440 
441 static uc_ubus_connection_t *
442 uc_ubus_conn_alloc(uc_vm_t *vm, uc_value_t *timeout, const char *type)
443 {
444         uc_ubus_connection_t *c = NULL;
445         uc_value_t *res;
446 
447         res = ucv_resource_create_ex(vm, type, (void **)&c, __CONN_RES_MAX, sizeof(*c));
448         if (!c)
449                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory");
450 
451         c->vm = vm;
452         c->res = res;
453         c->timeout = timeout ? ucv_int64_get(timeout) : 30;
454         if (c->timeout < 0)
455                 c->timeout = 30;
456 
457         return c;
458 }
459 
460 static uc_value_t *
461 uc_ubus_connect(uc_vm_t *vm, size_t nargs)
462 {
463         uc_value_t *socket, *timeout;
464         uc_ubus_connection_t *c;
465 
466         args_get(vm, nargs,
467                  "socket", UC_STRING, true, &socket,
468                  "timeout", UC_INTEGER, true, &timeout);
469 
470         c = uc_ubus_conn_alloc(vm, timeout, "ubus.connection");
471 
472         if (!c)
473                 return NULL;
474 
475         if (ubus_connect_ctx(&c->ctx, socket ? ucv_string_get(socket) : NULL)) {
476                 ucv_put(c->res);
477                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to connect to ubus socket");
478         }
479 
480         if (c->timeout < 0)
481                 c->timeout = 30;
482 
483         ubus_add_uloop(&c->ctx);
484 
485         ok_return(ucv_get(c->res));
486 }
487 
488 static void
489 uc_ubus_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
490 {
491         uc_value_t *arr = p;
492         uc_value_t *sig;
493 
494         if (!o->signature)
495                 return;
496 
497         sig = blob_array_to_ucv(NULL, blob_data(o->signature), blob_len(o->signature), true);
498 
499         if (sig)
500                 ucv_array_push(arr, sig);
501 }
502 
503 static void
504 uc_ubus_objects_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
505 {
506         uc_value_t *arr = p;
507 
508         ucv_array_push(arr, ucv_string_new(o->path));
509 }
510 
511 static bool
512 _conn_get(uc_vm_t *vm, uc_ubus_connection_t **conn)
513 {
514         uc_ubus_connection_t *c = uc_fn_thisval("ubus.connection");
515 
516         if (!c)
517                 c = uc_fn_thisval("ubus.channel");
518         if (!c)
519                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid connection context");
520 
521         if (c->ctx.sock.fd < 0)
522                 err_return(UBUS_STATUS_CONNECTION_FAILED, "Connection is closed");
523 
524         *conn = c;
525 
526         ok_return(true);
527 }
528 
529 #define conn_get(vm, ptr) do { if (!_conn_get(vm, ptr)) return NULL; } while(0)
530 
531 static uc_value_t *
532 uc_ubus_list(uc_vm_t *vm, size_t nargs)
533 {
534         uc_ubus_connection_t *c;
535         uc_value_t *objname, *res = NULL;
536         enum ubus_msg_status rv;
537 
538         conn_get(vm, &c);
539 
540         args_get(vm, nargs,
541                  "object name", UC_STRING, true, &objname);
542 
543         res = ucv_array_new(vm);
544 
545         rv = ubus_lookup(&c->ctx,
546                          objname ? ucv_string_get(objname) : NULL,
547                          objname ? uc_ubus_signatures_cb : uc_ubus_objects_cb,
548                          res);
549 
550         if (rv != UBUS_STATUS_OK) {
551                 ucv_put(res);
552                 err_return(rv, NULL);
553         }
554 
555         ok_return(res);
556 }
557 
558 static void
559 uc_ubus_call_cb(struct ubus_request *req, int type, struct blob_attr *msg)
560 {
561         uc_ubus_call_res_t *res = req->priv;
562         uc_value_t *val;
563 
564         val = msg ? blob_array_to_ucv(NULL, blob_data(msg), blob_len(msg), true) : NULL;
565 
566         if (res->mret) {
567                 if (!res->res)
568                         res->res = ucv_array_new(NULL);
569 
570                 ucv_array_push(res->res, val);
571         }
572         else if (!res->res) {
573                 res->res = val;
574         }
575 }
576 
577 static void
578 uc_ubus_call_user_cb(uc_ubus_deferred_t *defer, int ret, uc_value_t *reply)
579 {
580         uc_value_t *this = ucv_get(defer->res);
581         uc_vm_t *vm = defer->vm;
582         uc_value_t *func;
583 
584         func = ucv_resource_value_get(this, DEFER_RES_CB);
585 
586         if (ucv_is_callable(func)) {
587                 uc_vm_stack_push(vm, ucv_get(this));
588                 uc_vm_stack_push(vm, ucv_get(func));
589                 uc_vm_stack_push(vm, ucv_int64_new(ret));
590                 uc_vm_stack_push(vm, ucv_get(reply));
591 
592                 if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE)
593                         ucv_put(uc_vm_stack_pop(vm));
594         }
595 
596         uc_ubus_put_res(&defer->res);
597         ucv_put(this);
598 }
599 
600 static void
601 uc_ubus_call_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
602 {
603         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
604 
605         if (defer->response != NULL)
606                 return;
607 
608         defer->response = blob_array_to_ucv(defer->vm, blob_data(msg), blob_len(msg), true);
609         ucv_resource_value_set(defer->res, DEFER_RES_RESPONSE, defer->response);
610 }
611 
612 static void
613 uc_ubus_call_data_user_cb(struct ubus_request *req, int type, struct blob_attr *msg)
614 {
615         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
616         uc_vm_t *vm = defer->vm;
617         uc_value_t *func, *reply;
618 
619         func = ucv_resource_value_get(defer->res, DEFER_RES_DATA_CB);
620 
621         if (ucv_is_callable(func)) {
622                 reply = blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true);
623 
624                 uc_vm_stack_push(vm, ucv_get(defer->res));
625                 uc_vm_stack_push(vm, ucv_get(func));
626                 uc_vm_stack_push(vm, ucv_get(reply));
627 
628                 if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE)
629                         ucv_put(uc_vm_stack_pop(vm));
630                 else
631                         uloop_end();
632         }
633 }
634 
635 static void
636 uc_ubus_call_fd_cb(struct ubus_request *req, int fd)
637 {
638         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
639         uc_value_t *func = defer->fd_callback;
640         uc_vm_t *vm = defer->vm;
641 
642         if (defer->complete)
643                 return;
644 
645         if (ucv_is_callable(func)) {
646                 uc_vm_stack_push(vm, ucv_get(defer->res));
647                 uc_vm_stack_push(vm, ucv_get(func));
648                 uc_vm_stack_push(vm, ucv_int64_new(fd));
649 
650                 if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE)
651                         ucv_put(uc_vm_stack_pop(vm));
652                 else
653                         uloop_end();
654         }
655 }
656 
657 static void
658 uc_ubus_call_done_cb(struct ubus_request *req, int ret)
659 {
660         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
661 
662         if (defer->complete)
663                 return;
664 
665         defer->complete = true;
666         uloop_timeout_cancel(&defer->timeout);
667 
668         uc_ubus_call_user_cb(defer, ret, defer->response);
669 }
670 
671 static void
672 uc_ubus_call_timeout_cb(struct uloop_timeout *timeout)
673 {
674         uc_ubus_deferred_t *defer = container_of(timeout, uc_ubus_deferred_t, timeout);
675 
676         if (defer->complete)
677                 return;
678 
679         defer->complete = true;
680         ubus_abort_request(defer->ctx, &defer->request);
681 
682         uc_ubus_call_user_cb(defer, UBUS_STATUS_TIMEOUT, NULL);
683 }
684 
685 static int
686 get_fd(uc_vm_t *vm, uc_value_t *val)
687 {
688         uc_value_t *fn;
689         int64_t n;
690 
691         fn = ucv_property_get(val, "fileno");
692 
693         if (ucv_is_callable(fn)) {
694                 uc_vm_stack_push(vm, ucv_get(val));
695                 uc_vm_stack_push(vm, ucv_get(fn));
696 
697                 if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE)
698                         return -1;
699 
700                 val = uc_vm_stack_pop(vm);
701                 n = ucv_int64_get(val);
702                 ucv_put(val);
703         }
704         else {
705                 n = ucv_int64_get(val);
706         }
707 
708         if (errno || n < 0 || n > (int64_t)INT_MAX)
709                 return -1;
710 
711         return (int)n;
712 }
713 
714 static int
715 uc_ubus_call_common(uc_vm_t *vm, uc_ubus_connection_t *c, uc_ubus_call_res_t *res,
716                     uint32_t id, uc_value_t *funname, uc_value_t *funargs,
717                     uc_value_t *fd, uc_value_t *fdcb, uc_value_t *mret)
718 {
719         uc_ubus_deferred_t defer = {};
720         enum ubus_msg_status rv;
721         int fd_val = -1;
722 
723         enum {
724                 RET_MODE_SINGLE,
725                 RET_MODE_MULTIPLE,
726                 RET_MODE_IGNORE,
727         } ret_mode = RET_MODE_SINGLE;
728 
729         const char * const ret_modes[] = {
730                 [RET_MODE_SINGLE] = "single",
731                 [RET_MODE_MULTIPLE] = "multiple",
732                 [RET_MODE_IGNORE] = "ignore",
733         };
734 
735         if (ucv_type(mret) == UC_STRING) {
736                 const char *str = ucv_string_get(mret);
737                 size_t i;
738 
739                 for (i = 0; i < ARRAY_SIZE(ret_modes); i++)
740                         if (!strcmp(str, ret_modes[i]))
741                                 break;
742 
743                 if (i == ARRAY_SIZE(ret_modes))
744                         errval_return(UBUS_STATUS_INVALID_ARGUMENT,
745                                       "Invalid return mode argument");
746 
747                 ret_mode = i;
748         }
749         else if (ucv_type(mret) == UC_BOOLEAN) {
750                 ret_mode = ucv_boolean_get(mret);
751         }
752         else if (ret_mode) {
753                 errval_return(UBUS_STATUS_INVALID_ARGUMENT,
754                               "Invalid return mode argument");
755         }
756 
757         blob_buf_init(&c->buf, 0);
758 
759         if (funargs)
760                 ucv_object_to_blob(funargs, &c->buf);
761 
762         if (fd) {
763                 fd_val = get_fd(vm, fd);
764 
765                 if (fd_val < 0)
766                         errval_return(UBUS_STATUS_INVALID_ARGUMENT,
767                                       "Invalid file descriptor argument");
768         }
769 
770         res->mret = (ret_mode == RET_MODE_MULTIPLE);
771 
772         rv = ubus_invoke_async_fd(&c->ctx, id, ucv_string_get(funname),
773                                   c->buf.head, &defer.request, fd_val);
774 
775         defer.vm = vm;
776         defer.ctx = &c->ctx;
777         defer.request.data_cb = uc_ubus_call_cb;
778         defer.request.priv = res;
779 
780         if (ucv_is_callable(fdcb)) {
781                 defer.request.fd_cb = uc_ubus_call_fd_cb;
782                 defer.fd_callback = fdcb;
783         }
784 
785         if (rv == UBUS_STATUS_OK) {
786                 if (ret_mode == RET_MODE_IGNORE)
787                         ubus_abort_request(&c->ctx, &defer.request);
788                 else
789                         rv = ubus_complete_request(&c->ctx, &defer.request, c->timeout * 1000);
790         }
791 
792         return rv;
793 }
794 
795 static uc_value_t *
796 uc_ubus_call(uc_vm_t *vm, size_t nargs)
797 {
798         uc_value_t *obj, *funname, *funargs, *fd, *fdcb, *mret = NULL;
799         uc_ubus_call_res_t res = { 0 };
800         uc_ubus_connection_t *c;
801         enum ubus_msg_status rv;
802         uint32_t id;
803 
804         args_get_named(vm, nargs,
805                        "object", 0, REQUIRED, &obj,
806                        "method", UC_STRING, REQUIRED, &funname,
807                        "data", UC_OBJECT, OPTIONAL, &funargs,
808                        "return", 0, OPTIONAL, &mret,
809                        "fd", 0, NAMED, &fd,
810                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
811 
812         conn_get(vm, &c);
813 
814         if (ucv_type(obj) == UC_INTEGER) {
815                 id = ucv_int64_get(obj);
816         }
817         else if (ucv_type(obj) == UC_STRING) {
818                 rv = ubus_lookup_id(&c->ctx, ucv_string_get(obj), &id);
819 
820                 if (rv != UBUS_STATUS_OK)
821                         err_return(rv, "Failed to resolve object name '%s'",
822                                    ucv_string_get(obj));
823         }
824         else {
825                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
826                            "Argument object is not string or integer");
827         }
828 
829         rv = uc_ubus_call_common(vm, c, &res, id, funname, funargs, fd, fdcb, mret);
830 
831         if (rv != UBUS_STATUS_OK) {
832                 if (ucv_type(obj) == UC_STRING)
833                         err_return(rv, "Failed to invoke function '%s' on object '%s'",
834                                    ucv_string_get(funname), ucv_string_get(obj));
835                 else
836                         err_return(rv, "Failed to invoke function '%s' on system object %d",
837                                    ucv_string_get(funname), (int)ucv_int64_get(obj));
838         }
839 
840         ok_return(res.res);
841 }
842 
843 static uc_value_t *
844 uc_ubus_chan_request(uc_vm_t *vm, size_t nargs)
845 {
846         uc_value_t *funname, *funargs, *fd, *fdcb, *mret = NULL;
847         uc_ubus_call_res_t res = { 0 };
848         uc_ubus_connection_t *c;
849         enum ubus_msg_status rv;
850 
851         args_get_named(vm, nargs,
852                        "method", UC_STRING, REQUIRED, &funname,
853                        "data", UC_OBJECT, OPTIONAL, &funargs,
854                        "return", 0, OPTIONAL, &mret,
855                        "fd", 0, NAMED, &fd,
856                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
857 
858         conn_get(vm, &c);
859 
860         rv = uc_ubus_call_common(vm, c, &res, 0, funname, funargs, fd, fdcb, mret);
861 
862         if (rv != UBUS_STATUS_OK)
863                 err_return(rv, "Failed to send request '%s' on channel",
864                            ucv_string_get(funname));
865 
866         ok_return(res.res);
867 }
868 
869 static int
870 uc_ubus_defer_common(uc_vm_t *vm, uc_ubus_connection_t *c, uc_ubus_call_res_t *res,
871                      uint32_t id, uc_value_t *funname, uc_value_t *funargs,
872                      uc_value_t *fd, uc_value_t *fdcb, uc_value_t *replycb,
873                      uc_value_t *datacb)
874 {
875         uc_ubus_deferred_t *defer = NULL;
876         enum ubus_msg_status rv;
877         int fd_val = -1;
878 
879         blob_buf_init(&c->buf, 0);
880 
881         if (funargs)
882                 ucv_object_to_blob(funargs, &c->buf);
883 
884         if (fd) {
885                 fd_val = get_fd(vm, fd);
886 
887                 if (fd_val < 0)
888                         errval_return(UBUS_STATUS_INVALID_ARGUMENT,
889                                       "Invalid file descriptor argument");
890         }
891 
892         res->res = ucv_resource_create_ex(vm, "ubus.deferred", (void **)&defer, __DEFER_RES_MAX, sizeof(*defer));
893 
894         if (!defer)
895                 errval_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory");
896 
897         rv = ubus_invoke_async_fd(&c->ctx, id, ucv_string_get(funname),
898                                   c->buf.head, &defer->request, fd_val);
899 
900         if (rv == UBUS_STATUS_OK) {
901                 defer->vm = vm;
902                 defer->ctx = &c->ctx;
903                 defer->res = ucv_get(res->res);
904                 ucv_resource_persistent_set(defer->res, true);
905                 ucv_resource_value_set(defer->res, DEFER_RES_CONN, ucv_get(c->res));
906                 ucv_resource_value_set(defer->res, DEFER_RES_CB, ucv_get(replycb));
907                 ucv_resource_value_set(defer->res, DEFER_RES_FD, ucv_get(fd));
908                 ucv_resource_value_set(defer->res, DEFER_RES_DATA_CB, ucv_get(datacb));
909 
910                 if (ucv_is_callable(datacb))
911                         defer->request.data_cb = uc_ubus_call_data_user_cb;
912                 else
913                         defer->request.data_cb = uc_ubus_call_data_cb;
914 
915                 if (ucv_is_callable(fdcb)) {
916                         defer->request.fd_cb = uc_ubus_call_fd_cb;
917                         defer->fd_callback = fdcb;
918                         ucv_resource_value_set(defer->res, DEFER_RES_FD_CB, ucv_get(fdcb));
919                 }
920 
921                 defer->request.complete_cb = uc_ubus_call_done_cb;
922 
923                 ubus_complete_request_async(&c->ctx, &defer->request);
924 
925                 defer->timeout.cb = uc_ubus_call_timeout_cb;
926                 uloop_timeout_set(&defer->timeout, c->timeout * 1000);
927         }
928         else {
929                 uc_vm_stack_push(vm, ucv_get(replycb));
930                 uc_vm_stack_push(vm, ucv_int64_new(rv));
931 
932                 if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE)
933                         ucv_put(uc_vm_stack_pop(vm));
934                 else
935                         uloop_end();
936 
937                 ucv_put(res->res);
938         }
939 
940         return rv;
941 }
942 
943 static uc_value_t *
944 uc_ubus_defer(uc_vm_t *vm, size_t nargs)
945 {
946         uc_value_t *objname, *funname, *funargs, *replycb, *datacb, *fd, *fdcb = NULL;
947         uc_ubus_call_res_t res = { 0 };
948         uc_ubus_connection_t *c;
949         uint32_t id;
950         int rv;
951 
952         conn_get(vm, &c);
953 
954         args_get_named(vm, nargs,
955                        "object", UC_STRING, REQUIRED, &objname,
956                        "method", UC_STRING, REQUIRED, &funname,
957                        "data", UC_OBJECT, OPTIONAL, &funargs,
958                        "cb", UC_CLOSURE, OPTIONAL, &replycb,
959                        "data_cb", UC_CLOSURE, OPTIONAL, &datacb,
960                        "fd", 0, NAMED, &fd,
961                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
962 
963         rv = ubus_lookup_id(&c->ctx, ucv_string_get(objname), &id);
964 
965         if (rv != UBUS_STATUS_OK)
966                 err_return(rv, "Failed to resolve object name '%s'",
967                            ucv_string_get(objname));
968 
969         rv = uc_ubus_defer_common(vm, c, &res, id, funname, funargs, fd, fdcb, replycb, datacb);
970 
971         if (rv != UBUS_STATUS_OK)
972                 err_return(rv, "Failed to invoke function '%s' on object '%s'",
973                            ucv_string_get(funname), ucv_string_get(objname));
974 
975         ok_return(res.res);
976 }
977 
978 static uc_value_t *
979 uc_ubus_chan_defer(uc_vm_t *vm, size_t nargs)
980 {
981         uc_value_t *funname, *funargs, *replycb, *datacb, *fd, *fdcb = NULL;
982         uc_ubus_call_res_t res = { 0 };
983         uc_ubus_connection_t *c;
984         int rv;
985 
986         conn_get(vm, &c);
987 
988         args_get_named(vm, nargs,
989                        "method", UC_STRING, REQUIRED, &funname,
990                        "data", UC_OBJECT, OPTIONAL, &funargs,
991                        "cb", UC_CLOSURE, OPTIONAL, &replycb,
992                        "data_cb", UC_CLOSURE, OPTIONAL, &datacb,
993                        "fd", 0, NAMED, &fd,
994                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
995 
996         rv = uc_ubus_defer_common(vm, c, &res, 0, funname, funargs, fd, fdcb, replycb, datacb);
997 
998         if (rv != UBUS_STATUS_OK)
999                 err_return(rv, "Failed to invoke function '%s' on channel",
1000                            ucv_string_get(funname));
1001 
1002         ok_return(res.res);
1003 }
1004 
1005 
1006 /*
1007  * ubus object request context functions
1008  * --------------------------------------------------------------------------
1009  */
1010 
1011 static void
1012 uc_ubus_request_finish_common(uc_ubus_request_t *callctx, int code)
1013 {
1014         int fd;
1015 
1016         fd = ubus_request_get_caller_fd(&callctx->req);
1017 
1018         if (fd >= 0)
1019                 close(fd);
1020 
1021         callctx->replied = true;
1022         uloop_timeout_cancel(&callctx->timeout);
1023         ubus_complete_deferred_request(callctx->ctx, &callctx->req, code);
1024 }
1025 
1026 static void
1027 uc_ubus_request_send_reply(uc_ubus_request_t *callctx, uc_value_t *reply)
1028 {
1029         if (!reply)
1030                 return;
1031 
1032         blob_buf_init(&buf, 0);
1033         ucv_object_to_blob(reply, &buf);
1034         ubus_send_reply(callctx->ctx, &callctx->req, buf.head);
1035 }
1036 
1037 static void
1038 uc_ubus_request_finish(uc_ubus_request_t *callctx, int code)
1039 {
1040         if (callctx->replied)
1041                 return;
1042 
1043         uc_ubus_request_finish_common(callctx, code);
1044         uc_ubus_put_res(&callctx->res);
1045 }
1046 
1047 static void
1048 uc_ubus_request_timeout(struct uloop_timeout *timeout)
1049 {
1050         uc_ubus_request_t *callctx = container_of(timeout, uc_ubus_request_t, timeout);
1051 
1052         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT);
1053 }
1054 
1055 static uc_value_t *
1056 uc_ubus_request_reply(uc_vm_t *vm, size_t nargs)
1057 {
1058         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1059         int64_t code = UBUS_STATUS_OK;
1060         uc_value_t *reply, *rcode;
1061         bool more = false;
1062 
1063         if (!callctx)
1064                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
1065 
1066         args_get(vm, nargs,
1067                  "reply", UC_OBJECT, true, &reply,
1068                  "rcode", UC_INTEGER, true, &rcode);
1069 
1070         if (callctx->replied)
1071                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
1072 
1073         if (rcode) {
1074                 code = ucv_int64_get(rcode);
1075 
1076                 if (errno == ERANGE || code < -1 || code > __UBUS_STATUS_LAST)
1077                         code = UBUS_STATUS_UNKNOWN_ERROR;
1078 
1079                 if (code < 0)
1080                         more = true;
1081         }
1082 
1083         uc_ubus_request_send_reply(callctx, reply);
1084 
1085         if (!more)
1086                 uc_ubus_request_finish(callctx, code);
1087 
1088         ok_return(ucv_boolean_new(true));
1089 }
1090 
1091 static uc_value_t *
1092 uc_ubus_request_defer(uc_vm_t *vm, size_t nargs)
1093 {
1094         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1095 
1096         if (!callctx)
1097                 return NULL;
1098 
1099         callctx->deferred = true;
1100         return ucv_boolean_new(true);
1101 }
1102 
1103 static uc_value_t *
1104 uc_ubus_request_get_fd(uc_vm_t *vm, size_t nargs)
1105 {
1106         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1107 
1108         if (!callctx)
1109                 return NULL;
1110 
1111         return ucv_int64_new(ubus_request_get_caller_fd(&callctx->req));
1112 }
1113 
1114 static uc_value_t *
1115 uc_ubus_request_set_fd(uc_vm_t *vm, size_t nargs)
1116 {
1117         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1118         int fd;
1119 
1120         if (!callctx)
1121                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
1122 
1123         fd = get_fd(vm, uc_fn_arg(0));
1124 
1125         if (fd < 0)
1126                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor");
1127 
1128         ubus_request_set_fd(callctx->ctx, &callctx->req, fd);
1129 
1130         return ucv_boolean_new(true);
1131 }
1132 
1133 static uc_value_t *
1134 uc_ubus_request_error(uc_vm_t *vm, size_t nargs)
1135 {
1136         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1137         uc_value_t *rcode = uc_fn_arg(0);
1138         int64_t code;
1139 
1140         if (!callctx)
1141                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
1142 
1143         args_get(vm, nargs,
1144                  "rcode", UC_INTEGER, false, &rcode);
1145 
1146         if (callctx->replied)
1147                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
1148 
1149         code = ucv_int64_get(rcode);
1150 
1151         if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST)
1152                 code = UBUS_STATUS_UNKNOWN_ERROR;
1153 
1154         uc_ubus_request_finish(callctx, code);
1155 
1156         ok_return(ucv_boolean_new(true));
1157 }
1158 
1159 
1160 /*
1161  * ubus object notify
1162  * --------------------------------------------------------------------------
1163  */
1164 
1165 static uc_value_t *
1166 uc_ubus_notify_completed(uc_vm_t *vm, size_t nargs)
1167 {
1168         uc_ubus_notify_t *notifyctx = uc_fn_thisval("ubus.notify");
1169 
1170         ok_return(ucv_boolean_new(notifyctx->complete));
1171 }
1172 
1173 static uc_value_t *
1174 uc_ubus_notify_abort(uc_vm_t *vm, size_t nargs)
1175 {
1176         uc_ubus_notify_t *notifyctx = uc_fn_thisval("ubus.notify");
1177 
1178         if (notifyctx->complete)
1179                 ok_return(ucv_boolean_new(false));
1180 
1181         ubus_abort_request(notifyctx->ctx, &notifyctx->req.req);
1182         notifyctx->complete = true;
1183         uc_ubus_put_res(&notifyctx->res);
1184 
1185         ok_return(ucv_boolean_new(true));
1186 }
1187 
1188 static void
1189 uc_ubus_object_notify_data_cb(struct ubus_notify_request *req, int type, struct blob_attr *msg)
1190 {
1191         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
1192         uc_vm_t *vm = notifyctx->vm;
1193         uc_value_t *this, *func;
1194 
1195         this = notifyctx->res;
1196         func = ucv_resource_value_get(this, NOTIFY_RES_DATA_CB);
1197 
1198         if (ucv_is_callable(func)) {
1199                 uc_vm_stack_push(vm, ucv_get(this));
1200                 uc_vm_stack_push(vm, ucv_get(func));
1201                 uc_vm_stack_push(vm, ucv_int64_new(type));
1202                 uc_vm_stack_push(vm, blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true));
1203 
1204                 if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE)
1205                         ucv_put(uc_vm_stack_pop(vm));
1206                 else
1207                         uloop_end();
1208         }
1209 }
1210 
1211 static void
1212 uc_ubus_object_notify_status_cb(struct ubus_notify_request *req, int idx, int ret)
1213 {
1214         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
1215         uc_vm_t *vm = notifyctx->vm;
1216         uc_value_t *this, *func;
1217 
1218         this = notifyctx->res;
1219         func = ucv_resource_value_get(this, NOTIFY_RES_STATUS_CB);
1220 
1221         if (ucv_is_callable(func)) {
1222                 uc_vm_stack_push(vm, ucv_get(this));
1223                 uc_vm_stack_push(vm, ucv_get(func));
1224                 uc_vm_stack_push(vm, ucv_int64_new(idx));
1225                 uc_vm_stack_push(vm, ucv_int64_new(ret));
1226 
1227                 if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE)
1228                         ucv_put(uc_vm_stack_pop(vm));
1229                 else
1230                         uloop_end();
1231         }
1232 }
1233 
1234 static void
1235 uc_ubus_object_notify_complete_cb(struct ubus_notify_request *req, int idx, int ret)
1236 {
1237         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
1238         uc_vm_t *vm = notifyctx->vm;
1239         uc_value_t *this, *func;
1240 
1241         this = ucv_get(notifyctx->res);
1242         func = ucv_resource_value_get(this, NOTIFY_RES_CB);
1243 
1244         if (ucv_is_callable(func)) {
1245                 uc_vm_stack_push(vm, ucv_get(this));
1246                 uc_vm_stack_push(vm, ucv_get(func));
1247                 uc_vm_stack_push(vm, ucv_int64_new(idx));
1248                 uc_vm_stack_push(vm, ucv_int64_new(ret));
1249 
1250                 if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE)
1251                         ucv_put(uc_vm_stack_pop(vm));
1252                 else
1253                         uloop_end();
1254         }
1255 
1256         notifyctx->complete = true;
1257         uc_ubus_put_res(&notifyctx->res);
1258         ucv_put(this);
1259 }
1260 
1261 static uc_value_t *
1262 uc_ubus_object_notify(uc_vm_t *vm, size_t nargs)
1263 {
1264         uc_value_t *typename, *message, *data_cb, *status_cb, *complete_cb, *timeout;
1265         uc_ubus_object_t *uuobj = uc_fn_thisval("ubus.object");
1266         uc_ubus_notify_t *notifyctx = NULL;
1267         uc_value_t *res;
1268         int64_t t;
1269         int rv = UBUS_STATUS_UNKNOWN_ERROR;
1270 
1271         if (!uuobj)
1272                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1273 
1274         args_get_named(vm, nargs,
1275                       "type", UC_STRING, REQUIRED, &typename,
1276                       "data", UC_OBJECT, OPTIONAL, &message,
1277                       "data_cb", UC_CLOSURE, OPTIONAL, &data_cb,
1278                       "status_cb", UC_CLOSURE, OPTIONAL, &status_cb,
1279                       "cb", UC_CLOSURE, OPTIONAL, &complete_cb,
1280                       "timeout", UC_INTEGER, OPTIONAL, &timeout);
1281 
1282         t = timeout ? ucv_int64_get(timeout) : -1;
1283 
1284         if (errno)
1285                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1286                            "Invalid timeout value: %s", strerror(errno));
1287 
1288         res = ucv_resource_create_ex(vm, "ubus.notify", (void **)&notifyctx, __NOTIFY_RES_MAX, sizeof(*notifyctx));
1289 
1290         if (!notifyctx)
1291                 err_return(rv, "Out of memory");
1292 
1293         notifyctx->vm = vm;
1294         notifyctx->ctx = uuobj->ctx;
1295 
1296         blob_buf_init(&buf, 0);
1297 
1298         if (message)
1299                 ucv_object_to_blob(message, &buf);
1300 
1301         rv = ubus_notify_async(uuobj->ctx, &uuobj->obj,
1302                                ucv_string_get(typename), buf.head,
1303                                &notifyctx->req);
1304 
1305         if (rv != UBUS_STATUS_OK) {
1306                 ucv_put(res);
1307                 err_return(rv, "Failed to send notification");
1308         }
1309 
1310         notifyctx->res = ucv_get(res);
1311         notifyctx->req.data_cb = uc_ubus_object_notify_data_cb;
1312         notifyctx->req.status_cb = uc_ubus_object_notify_status_cb;
1313         notifyctx->req.complete_cb = uc_ubus_object_notify_complete_cb;
1314 
1315         ucv_resource_value_set(res, NOTIFY_RES_CONN, ucv_get(uuobj->res));
1316         ucv_resource_value_set(res, NOTIFY_RES_CB, ucv_get(complete_cb));
1317         ucv_resource_value_set(res, NOTIFY_RES_DATA_CB, ucv_get(data_cb));
1318         ucv_resource_value_set(res, NOTIFY_RES_STATUS_CB, ucv_get(status_cb));
1319 
1320         if (t >= 0) {
1321                 rv = ubus_complete_request(uuobj->ctx, &notifyctx->req.req, t);
1322 
1323                 ucv_put(res);
1324 
1325                 ok_return(ucv_int64_new(rv));
1326         }
1327 
1328         ucv_resource_persistent_set(res, true);
1329         ubus_complete_request_async(uuobj->ctx, &notifyctx->req.req);
1330 
1331         ok_return(res);
1332 }
1333 
1334 
1335 /*
1336  * ubus object remove
1337  * --------------------------------------------------------------------------
1338  */
1339 
1340 static int
1341 uc_ubus_object_remove_common(uc_ubus_object_t *uuobj)
1342 {
1343         int rv = ubus_remove_object(uuobj->ctx, &uuobj->obj);
1344 
1345         if (rv != UBUS_STATUS_OK)
1346                 return rv;
1347 
1348         uc_ubus_put_res(&uuobj->res);
1349 
1350         return rv;
1351 }
1352 
1353 static uc_value_t *
1354 uc_ubus_object_remove(uc_vm_t *vm, size_t nargs)
1355 {
1356         uc_ubus_object_t *uuobj = uc_fn_thisval("ubus.object");
1357         int rv;
1358 
1359         if (!uuobj)
1360                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1361 
1362         rv = uc_ubus_object_remove_common(uuobj);
1363 
1364         if (rv != UBUS_STATUS_OK)
1365                 err_return(rv, "Failed to remove object");
1366 
1367         ok_return(ucv_boolean_new(true));
1368 }
1369 
1370 
1371 /*
1372  * ubus object subscription status
1373  */
1374 
1375 static uc_value_t *
1376 uc_ubus_object_subscribed(uc_vm_t *vm, size_t nargs)
1377 {
1378         uc_ubus_object_t *uuobj = uc_fn_thisval("ubus.object");
1379 
1380         if (!uuobj)
1381                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1382 
1383         ok_return(ucv_boolean_new(uuobj->obj.has_subscribers));
1384 }
1385 
1386 
1387 /*
1388  * ubus object method call handling
1389  * --------------------------------------------------------------------------
1390  */
1391 
1392 static int
1393 uc_ubus_object_call_args(struct ubus_object *obj, const char *ubus_method_name,
1394                          struct blob_attr *msg, uc_value_t **res)
1395 {
1396         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1397         const struct ubus_method *method = NULL;
1398         const struct blobmsg_hdr *hdr;
1399         struct blob_attr *attr;
1400         size_t len;
1401         bool found;
1402         int i;
1403 
1404         for (i = 0; i < obj->n_methods; i++) {
1405                 if (!strcmp(obj->methods[i].name, ubus_method_name)) {
1406                         method = &obj->methods[i];
1407                         break;
1408                 }
1409         }
1410 
1411         if (!method)
1412                 return UBUS_STATUS_METHOD_NOT_FOUND;
1413 
1414         len = blob_len(msg);
1415 
1416         __blob_for_each_attr(attr, blob_data(msg), len) {
1417                 if (!blobmsg_check_attr_len(attr, false, len))
1418                         return UBUS_STATUS_INVALID_ARGUMENT;
1419 
1420                 if (!blob_is_extended(attr))
1421                         return UBUS_STATUS_INVALID_ARGUMENT;
1422 
1423                 hdr = blob_data(attr);
1424                 found = false;
1425 
1426                 for (i = 0; i < method->n_policy; i++) {
1427                         if (blobmsg_namelen(hdr) != strlen(method->policy[i].name))
1428                                 continue;
1429 
1430                         if (strcmp(method->policy[i].name, (char *)hdr->name))
1431                                 continue;
1432 
1433                         /* named argument found but wrong type */
1434                         if (blob_id(attr) != method->policy[i].type)
1435                                 goto inval;
1436 
1437                         found = true;
1438                         break;
1439                 }
1440 
1441                 /* named argument not found in policy */
1442                 if (!found)
1443                         goto inval;
1444         }
1445 
1446         *res = blob_array_to_ucv(uuobj->vm, blob_data(msg), blob_len(msg), true);
1447 
1448         return UBUS_STATUS_OK;
1449 
1450 inval:
1451         *res = NULL;
1452 
1453         return UBUS_STATUS_INVALID_ARGUMENT;
1454 }
1455 
1456 static uc_value_t *
1457 uc_ubus_object_call_info(uc_vm_t *vm,
1458                          struct ubus_context *ctx, struct ubus_request_data *req,
1459                          struct ubus_object *obj, const char *ubus_method_name)
1460 {
1461         uc_value_t *info, *o;
1462 
1463         info = ucv_object_new(vm);
1464 
1465         o = ucv_object_new(vm);
1466 
1467         ucv_object_add(o, "user", ucv_string_new(req->acl.user));
1468         ucv_object_add(o, "group", ucv_string_new(req->acl.group));
1469 
1470         if (req->acl.object)
1471                 ucv_object_add(o, "object", ucv_string_new(req->acl.object));
1472 
1473         ucv_object_add(info, "acl", o);
1474 
1475         o = ucv_object_new(vm);
1476 
1477         ucv_object_add(o, "id", ucv_int64_new(obj->id));
1478 
1479         if (obj->name)
1480                 ucv_object_add(o, "name", ucv_string_new(obj->name));
1481 
1482         if (obj->path)
1483                 ucv_object_add(o, "path", ucv_string_new(obj->path));
1484 
1485         ucv_object_add(info, "object", o);
1486 
1487         if (ubus_method_name)
1488                 ucv_object_add(info, "method", ucv_string_new(ubus_method_name));
1489 
1490         return info;
1491 }
1492 
1493 static int
1494 uc_ubus_handle_reply_common(struct ubus_context *ctx,
1495                               struct ubus_request_data *req,
1496                               uc_vm_t *vm, uc_value_t *this, uc_value_t *func,
1497                               uc_value_t *reqproto)
1498 {
1499         uc_ubus_connection_t *conn = container_of(ctx, uc_ubus_connection_t, ctx);
1500         uc_ubus_request_t *callctx = NULL;
1501         uc_value_t *reqobj, *res;
1502         int rv;
1503 
1504         /* allocate deferred method call context */
1505         reqobj = ucv_resource_create_ex(vm, "ubus.request", (void **)&callctx, 1, sizeof(*callctx));
1506 
1507         if (!callctx)
1508                 return UBUS_STATUS_UNKNOWN_ERROR;
1509 
1510         callctx->ctx = ctx;
1511         callctx->vm = vm;
1512         ucv_resource_value_set(reqobj, 0, ucv_get(conn->res));
1513 
1514         ubus_defer_request(ctx, req, &callctx->req);
1515 
1516         /* fd is copied to deferred request. ensure it does not get closed early */
1517         ubus_request_get_caller_fd(req);
1518 
1519         if (reqproto)
1520                 ucv_prototype_set(ucv_prototype_get(reqobj), reqproto);
1521 
1522         /* push object context, handler and request object onto stack */
1523         uc_vm_stack_push(vm, ucv_get(this));
1524         uc_vm_stack_push(vm, ucv_get(func));
1525         uc_vm_stack_push(vm, ucv_get(reqobj));
1526 
1527         /* execute request handler function */
1528         switch (uc_vm_call(vm, true, 1)) {
1529         case EXCEPTION_NONE:
1530                 res = uc_vm_stack_pop(vm);
1531 
1532                 /* The handler function invoked a nested aync ubus request and returned it */
1533                 if (ucv_resource_data(res, "ubus.deferred")) {
1534                         /* Install guard timer in case the reply callback is never called */
1535                         callctx->timeout.cb = uc_ubus_request_timeout;
1536                         uloop_timeout_set(&callctx->timeout, 10000 /* FIXME */);
1537                         callctx->res = ucv_get(reqobj);
1538                         ucv_resource_persistent_set(callctx->res, true);
1539                 }
1540 
1541                 /* Otherwise, when the function returned an object, treat it as
1542                 * reply data and conclude deferred request immediately */
1543                 else if (ucv_type(res) == UC_OBJECT) {
1544                         blob_buf_init(&buf, 0);
1545                         ucv_object_to_blob(res, &buf);
1546                         ubus_send_reply(ctx, &callctx->req, buf.head);
1547 
1548                         uc_ubus_request_finish_common(callctx, UBUS_STATUS_OK);
1549                 }
1550 
1551                 /* If neither a deferred ubus request, nor a plain object were
1552                  * returned and if reqobj.reply() hasn't been called, immediately
1553                  * finish deferred request with UBUS_STATUS_NO_DATA. */
1554                 else if (!callctx->replied && !callctx->deferred) {
1555                         rv = UBUS_STATUS_NO_DATA;
1556 
1557                         if (ucv_type(res) == UC_INTEGER) {
1558                                 rv = (int)ucv_int64_get(res);
1559 
1560                                 if (rv < 0 || rv > __UBUS_STATUS_LAST)
1561                                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1562                         }
1563 
1564                         uc_ubus_request_finish_common(callctx, rv);
1565                 }
1566 
1567                 ucv_put(res);
1568                 break;
1569 
1570         /* if the handler function invoked exit(), forward exit status as ubus
1571          * return code, map out of range values to UBUS_STATUS_UNKNOWN_ERROR. */
1572         case EXCEPTION_EXIT:
1573                 rv = vm->arg.s32;
1574 
1575                 if (rv < UBUS_STATUS_OK || rv >= __UBUS_STATUS_LAST)
1576                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1577 
1578                 uc_ubus_request_finish_common(callctx, rv);
1579                 break;
1580 
1581         /* treat other exceptions as fatal and halt uloop */
1582         default:
1583                 uc_ubus_request_finish_common(callctx, UBUS_STATUS_UNKNOWN_ERROR);
1584                 uloop_end();
1585                 break;
1586         }
1587 
1588         /* release request object */
1589         ucv_put(reqobj);
1590 
1591         /* garbage collect */
1592         ucv_gc(vm);
1593 
1594         return UBUS_STATUS_OK;
1595 }
1596 
1597 static int
1598 uc_ubus_object_call_cb(struct ubus_context *ctx, struct ubus_object *obj,
1599                        struct ubus_request_data *req, const char *ubus_method_name,
1600                        struct blob_attr *msg)
1601 {
1602         uc_value_t *func, *args = NULL, *reqproto, *methods;
1603         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1604         int rv;
1605 
1606         methods = ucv_resource_value_get(uuobj->res, OBJ_RES_METHODS);
1607         func = ucv_object_get(ucv_object_get(methods, ubus_method_name, NULL), "call", NULL);
1608 
1609         if (!ucv_is_callable(func))
1610                 return UBUS_STATUS_METHOD_NOT_FOUND;
1611 
1612         rv = uc_ubus_object_call_args(obj, ubus_method_name, msg, &args);
1613 
1614         if (rv != UBUS_STATUS_OK)
1615                 return rv;
1616 
1617         reqproto = ucv_object_new(uuobj->vm);
1618 
1619         ucv_object_add(reqproto, "args", args);
1620         ucv_object_add(reqproto, "info",
1621                 uc_ubus_object_call_info(uuobj->vm, ctx, req, obj, ubus_method_name));
1622 
1623         return uc_ubus_handle_reply_common(ctx, req, uuobj->vm, uuobj->res, func, reqproto);
1624 }
1625 
1626 
1627 /*
1628  * ubus object registration
1629  * --------------------------------------------------------------------------
1630  */
1631 
1632 static void
1633 uc_ubus_object_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
1634 {
1635         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1636         uc_value_t *func;
1637 
1638         func = ucv_resource_value_get(uuobj->res, OBJ_RES_SUB_CB);
1639 
1640         uc_vm_stack_push(uuobj->vm, ucv_get(uuobj->res));
1641         uc_vm_stack_push(uuobj->vm, ucv_get(func));
1642 
1643         if (uc_vm_call(uuobj->vm, true, 0) == EXCEPTION_NONE)
1644                 ucv_put(uc_vm_stack_pop(uuobj->vm));
1645         else
1646                 uloop_end();
1647 }
1648 
1649 static bool
1650 uc_ubus_object_methods_validate(uc_value_t *methods)
1651 {
1652         uc_value_t *func, *args;
1653 
1654         ucv_object_foreach(methods, ubus_method_name, ubus_method_definition) {
1655                 (void)ubus_method_name;
1656 
1657                 func = ucv_object_get(ubus_method_definition, "call", NULL);
1658                 args = ucv_object_get(ubus_method_definition, "args", NULL);
1659 
1660                 if (!ucv_is_callable(func))
1661                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1662                                    "Method '%s' field 'call' is not a function value",
1663                                    ubus_method_name);
1664 
1665                 if (args) {
1666                         if (ucv_type(args) != UC_OBJECT)
1667                                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1668                                            "Method '%s' field 'args' is not an object value",
1669                                            ubus_method_name);
1670 
1671                         ucv_object_foreach(args, ubus_argument_name, ubus_argument_typehint) {
1672                                 (void)ubus_argument_name;
1673 
1674                                 switch (ucv_type(ubus_argument_typehint)) {
1675                                 case UC_BOOLEAN:
1676                                 case UC_INTEGER:
1677                                 case UC_DOUBLE:
1678                                 case UC_STRING:
1679                                 case UC_ARRAY:
1680                                 case UC_OBJECT:
1681                                         continue;
1682 
1683                                 default:
1684                                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1685                                                    "Method '%s' field 'args' argument '%s' hint has unsupported type %s",
1686                                                    ubus_method_name, ubus_argument_name,
1687                                                    ucv_typename(ubus_argument_typehint));
1688                                 }
1689                         }
1690                 }
1691         }
1692 
1693         ok_return(true);
1694 }
1695 
1696 static bool
1697 uc_ubus_object_method_register(struct ubus_method *method, const char *ubus_method_name,
1698                                uc_value_t *ubus_method_arguments)
1699 {
1700         struct blobmsg_policy *policy;
1701         enum blobmsg_type type;
1702 
1703         method->name = strdup(ubus_method_name);
1704         method->policy = calloc(ucv_object_length(ubus_method_arguments), sizeof(*method->policy));
1705         method->handler = uc_ubus_object_call_cb;
1706 
1707         if (!method->name || !method->policy)
1708                 return false;
1709 
1710         ucv_object_foreach(ubus_method_arguments, ubus_argument_name, ubus_argument_typehint) {
1711                 switch (ucv_type(ubus_argument_typehint)) {
1712                 case UC_BOOLEAN:
1713                         type = BLOBMSG_TYPE_INT8;
1714                         break;
1715 
1716                 case UC_INTEGER:
1717                         switch (ucv_int64_get(ubus_argument_typehint)) {
1718                         case 8:
1719                                 type = BLOBMSG_TYPE_INT8;
1720                                 break;
1721 
1722                         case 16:
1723                                 type = BLOBMSG_TYPE_INT16;
1724                                 break;
1725 
1726                         case 64:
1727                                 type = BLOBMSG_TYPE_INT64;
1728                                 break;
1729 
1730                         default:
1731                                 type = BLOBMSG_TYPE_INT32;
1732                                 break;
1733                         }
1734 
1735                         break;
1736 
1737                 case UC_DOUBLE:
1738                         type = BLOBMSG_TYPE_DOUBLE;
1739                         break;
1740 
1741                 case UC_ARRAY:
1742                         type = BLOBMSG_TYPE_ARRAY;
1743                         break;
1744 
1745                 case UC_OBJECT:
1746                         type = BLOBMSG_TYPE_TABLE;
1747                         break;
1748 
1749                 default:
1750                         type = BLOBMSG_TYPE_STRING;
1751                         break;
1752                 }
1753 
1754                 policy = (struct blobmsg_policy *)&method->policy[method->n_policy++];
1755                 policy->type = type;
1756                 policy->name = strdup(ubus_argument_name);
1757 
1758                 if (!policy->name)
1759                         return false;
1760         }
1761 
1762         return true;
1763 }
1764 
1765 static uc_ubus_object_t *
1766 uc_ubus_object_register(uc_vm_t *vm, uc_ubus_connection_t *c, const char *ubus_object_name,
1767                         uc_value_t *ubus_object_methods)
1768 {
1769         struct ubus_context *ctx = &c->ctx;
1770         const struct blobmsg_policy *policy;
1771         uc_ubus_object_t *uuobj = NULL;
1772         int rv = UBUS_STATUS_UNKNOWN_ERROR;
1773         char *tnptr, *onptr;
1774         struct ubus_method *method;
1775         struct ubus_object *obj;
1776         size_t len, typelen, namelen, methodlen;
1777         uc_value_t *args, *res;
1778 
1779         namelen = strlen(ubus_object_name);
1780         typelen = strlen("ucode-ubus-") + namelen;
1781         methodlen = ucv_object_length(ubus_object_methods) * sizeof(struct ubus_method);
1782         len = sizeof(*uuobj) + methodlen + namelen + 1 + typelen + 1;
1783 
1784         res = ucv_resource_create_ex(vm, "ubus.object", (void **)&uuobj, __OBJ_RES_MAX, len);
1785 
1786         if (!uuobj)
1787                 err_return(rv, "Out of memory");
1788 
1789         method = uuobj->methods;
1790 
1791         obj = &uuobj->obj;
1792         obj->methods = method;
1793 
1794         if (ubus_object_methods) {
1795                 ucv_object_foreach(ubus_object_methods, ubus_method_name, ubus_method_definition) {
1796                         args = ucv_object_get(ubus_method_definition, "args", NULL);
1797 
1798                         if (!uc_ubus_object_method_register(&method[obj->n_methods++], ubus_method_name, args))
1799                                 goto out;
1800                 }
1801         }
1802 
1803         onptr = (char *)&uuobj->methods[obj->n_methods];
1804         tnptr = onptr + namelen + 1;
1805 
1806         snprintf(tnptr, typelen, "ucode-ubus-%s", ubus_object_name);
1807         obj->name = memcpy(onptr, ubus_object_name, namelen);
1808 
1809         obj->type = (struct ubus_object_type *)&uuobj->type;
1810         obj->type->name = tnptr;
1811         obj->type->methods = obj->methods;
1812         obj->type->n_methods = obj->n_methods;
1813 
1814         rv = ubus_add_object(ctx, obj);
1815 
1816         if (rv != UBUS_STATUS_OK)
1817                 goto out;
1818 
1819         uuobj->vm = vm;
1820         uuobj->ctx = ctx;
1821         uuobj->res = ucv_get(res);
1822         ucv_resource_persistent_set(res, true);
1823         ucv_resource_value_set(res, OBJ_RES_CONN, ucv_get(c->res));
1824         ucv_resource_value_set(res, OBJ_RES_METHODS, ucv_get(ubus_object_methods));
1825 
1826         return uuobj;
1827 
1828 out:
1829         for (; obj->n_methods > 0; method++, obj->n_methods--) {
1830                 for (policy = method->policy; method->n_policy > 0; policy++, method->n_policy--)
1831                         free((char *)policy->name);
1832 
1833                 free((char *)method->name);
1834                 free((char *)method->policy);
1835         }
1836 
1837         ucv_put(res);
1838 
1839         err_return(rv, "Unable to add ubus object");
1840 }
1841 
1842 static uc_value_t *
1843 uc_ubus_publish(uc_vm_t *vm, size_t nargs)
1844 {
1845         uc_value_t *objname, *methods, *subscribecb;
1846         uc_ubus_connection_t *c;
1847         uc_ubus_object_t *uuobj;
1848 
1849         conn_get(vm, &c);
1850 
1851         args_get(vm, nargs,
1852                  "object name", UC_STRING, false, &objname,
1853                  "object methods", UC_OBJECT, true, &methods,
1854                  "subscribe callback", UC_CLOSURE, true, &subscribecb);
1855 
1856         if (!methods && !subscribecb)
1857                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either methods or subscribe callback required");
1858 
1859         if (methods && !uc_ubus_object_methods_validate(methods))
1860                 return NULL;
1861 
1862         uuobj = uc_ubus_object_register(vm, c, ucv_string_get(objname), methods);
1863 
1864         if (!uuobj)
1865                 return NULL;
1866 
1867         if (subscribecb) {
1868                 uuobj->obj.subscribe_cb = uc_ubus_object_subscribe_cb;
1869                 ucv_resource_value_set(uuobj->res, OBJ_RES_SUB_CB, ucv_get(subscribecb));
1870         }
1871 
1872         ok_return(uuobj->res);
1873 }
1874 
1875 
1876 /*
1877  * ubus events
1878  * --------------------------------------------------------------------------
1879  */
1880 
1881 static int
1882 uc_ubus_listener_remove_common(uc_ubus_listener_t *uul)
1883 {
1884         int rv = ubus_unregister_event_handler(uul->ctx, &uul->ev);
1885 
1886         if (rv == UBUS_STATUS_OK)
1887                 uc_ubus_put_res(&uul->res);
1888 
1889         return rv;
1890 }
1891 
1892 static uc_value_t *
1893 uc_ubus_listener_remove(uc_vm_t *vm, size_t nargs)
1894 {
1895         uc_ubus_listener_t *uul = uc_fn_thisval("ubus.listener");
1896         int rv;
1897 
1898         rv = uc_ubus_listener_remove_common(uul);
1899 
1900         if (rv != UBUS_STATUS_OK)
1901                 err_return(rv, "Failed to remove listener object");
1902 
1903         ok_return(ucv_boolean_new(true));
1904 }
1905 
1906 static void
1907 uc_ubus_listener_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
1908                     const char *type, struct blob_attr *msg)
1909 {
1910         uc_ubus_listener_t *uul = (uc_ubus_listener_t *)ev;
1911         uc_value_t *this, *func;
1912         uc_vm_t *vm = uul->vm;
1913 
1914         this = uul->res;
1915         func = ucv_resource_value_get(this, 0);
1916 
1917         uc_vm_stack_push(vm, ucv_get(this));
1918         uc_vm_stack_push(vm, ucv_get(func));
1919         uc_vm_stack_push(vm, ucv_string_new(type));
1920         uc_vm_stack_push(vm, blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true));
1921 
1922         if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE)
1923                 ucv_put(uc_vm_stack_pop(vm));
1924         else
1925                 uloop_end();
1926 }
1927 
1928 static uc_value_t *
1929 uc_ubus_listener(uc_vm_t *vm, size_t nargs)
1930 {
1931         uc_value_t *cb, *pattern;
1932         uc_ubus_connection_t *c;
1933         uc_ubus_listener_t *uul = NULL;
1934         uc_value_t *res;
1935         int rv;
1936 
1937         conn_get(vm, &c);
1938 
1939         args_get(vm, nargs,
1940                  "event type pattern", UC_STRING, false, &pattern,
1941                  "event callback", UC_CLOSURE, false, &cb);
1942 
1943         res = ucv_resource_create_ex(vm, "ubus.listener", (void **)&uul, 1, sizeof(*uul));
1944 
1945         if (!uul)
1946                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory");
1947 
1948         uul->vm = vm;
1949         uul->ctx = &c->ctx;
1950         uul->res = res;
1951         uul->ev.cb = uc_ubus_listener_cb;
1952 
1953         rv = ubus_register_event_handler(&c->ctx, &uul->ev,
1954                                          ucv_string_get(pattern));
1955 
1956         if (rv != UBUS_STATUS_OK) {
1957                 ucv_put(res);
1958                 err_return(rv, "Failed to register listener object");
1959         }
1960 
1961         ucv_resource_persistent_set(res, true);
1962         ucv_resource_value_set(res, 0, ucv_get(cb));
1963 
1964         ok_return(ucv_get(res));
1965 }
1966 
1967 static uc_value_t *
1968 uc_ubus_event(uc_vm_t *vm, size_t nargs)
1969 {
1970         uc_value_t *eventtype, *eventdata;
1971         uc_ubus_connection_t *c;
1972         int rv;
1973 
1974         conn_get(vm, &c);
1975 
1976         args_get(vm, nargs,
1977                  "event id", UC_STRING, false, &eventtype,
1978                  "event data", UC_OBJECT, true, &eventdata);
1979 
1980         blob_buf_init(&buf, 0);
1981 
1982         if (eventdata)
1983                 ucv_object_to_blob(eventdata, &buf);
1984 
1985         rv = ubus_send_event(&c->ctx, ucv_string_get(eventtype), buf.head);
1986 
1987         if (rv != UBUS_STATUS_OK)
1988                 err_return(rv, "Unable to send event");
1989 
1990         ok_return(ucv_boolean_new(true));
1991 }
1992 
1993 
1994 /*
1995  * ubus subscriptions
1996  * --------------------------------------------------------------------------
1997  */
1998 
1999 static int
2000 uc_ubus_subscriber_notify_cb(struct ubus_context *ctx, struct ubus_object *obj,
2001                                  struct ubus_request_data *req, const char *method,
2002                                  struct blob_attr *msg)
2003 {
2004         struct ubus_subscriber *sub = container_of(obj, struct ubus_subscriber, obj);
2005         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
2006         uc_value_t *this, *func, *reqproto;
2007 
2008         this = uusub->res;
2009         func = ucv_resource_value_get(this, SUB_RES_NOTIFY_CB);
2010 
2011         if (!ucv_is_callable(func))
2012                 return UBUS_STATUS_METHOD_NOT_FOUND;
2013 
2014         reqproto = ucv_object_new(uusub->vm);
2015 
2016         ucv_object_add(reqproto, "type", ucv_string_new(method));
2017 
2018         ucv_object_add(reqproto, "data",
2019                 blob_array_to_ucv(uusub->vm, blob_data(msg), blob_len(msg), true));
2020 
2021         ucv_object_add(reqproto, "info",
2022                 uc_ubus_object_call_info(uusub->vm, ctx, req, obj, NULL));
2023 
2024         return uc_ubus_handle_reply_common(ctx, req, uusub->vm, this, func, reqproto);
2025 }
2026 
2027 static void
2028 uc_ubus_subscriber_remove_cb(struct ubus_context *ctx,
2029                              struct ubus_subscriber *sub, uint32_t id)
2030 {
2031         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
2032         uc_value_t *this, *func;
2033         uc_vm_t *vm = uusub->vm;
2034 
2035         this = uusub->res;
2036         func = ucv_resource_value_get(this, SUB_RES_REMOVE_CB);
2037 
2038         if (!ucv_is_callable(func))
2039                 return;
2040 
2041         uc_vm_stack_push(vm, ucv_get(this));
2042         uc_vm_stack_push(vm, ucv_get(func));
2043         uc_vm_stack_push(vm, ucv_uint64_new(id));
2044 
2045         if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE)
2046                 ucv_put(uc_vm_stack_pop(vm));
2047         else
2048                 uloop_end();
2049 }
2050 
2051 static uc_value_t *
2052 uc_ubus_subscriber_subunsub_common(uc_vm_t *vm, size_t nargs, bool subscribe)
2053 {
2054         uc_ubus_subscriber_t *uusub = uc_fn_thisval("ubus.subscriber");
2055         uc_value_t *objname;
2056         uint32_t id;
2057         int rv;
2058 
2059         if (!uusub)
2060                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
2061 
2062         args_get(vm, nargs,
2063                  "object name", UC_STRING, false, &objname);
2064 
2065         rv = ubus_lookup_id(uusub->ctx, ucv_string_get(objname), &id);
2066 
2067         if (rv != UBUS_STATUS_OK)
2068                 err_return(rv, "Failed to resolve object name '%s'",
2069                            ucv_string_get(objname));
2070 
2071         if (subscribe)
2072                 rv = ubus_subscribe(uusub->ctx, &uusub->sub, id);
2073         else
2074                 rv = ubus_unsubscribe(uusub->ctx, &uusub->sub, id);
2075 
2076         if (rv != UBUS_STATUS_OK)
2077                 err_return(rv, "Failed to %s object '%s'",
2078                            subscribe ? "subscribe" : "unsubscribe",
2079                            ucv_string_get(objname));
2080 
2081         ok_return(ucv_boolean_new(true));
2082 }
2083 
2084 static uc_value_t *
2085 uc_ubus_subscriber_subscribe(uc_vm_t *vm, size_t nargs)
2086 {
2087         return uc_ubus_subscriber_subunsub_common(vm, nargs, true);
2088 }
2089 
2090 static uc_value_t *
2091 uc_ubus_subscriber_unsubscribe(uc_vm_t *vm, size_t nargs)
2092 {
2093         return uc_ubus_subscriber_subunsub_common(vm, nargs, false);
2094 }
2095 
2096 static int
2097 uc_ubus_subscriber_remove_common(uc_ubus_subscriber_t *uusub)
2098 {
2099         int rv = ubus_unregister_subscriber(uusub->ctx, &uusub->sub);
2100 
2101         if (rv == UBUS_STATUS_OK)
2102                 uc_ubus_put_res(&uusub->res);
2103 
2104         return rv;
2105 }
2106 
2107 #ifdef HAVE_UBUS_NEW_OBJ_CB
2108 static bool
2109 uc_ubus_subscriber_new_object_cb(struct ubus_context *ctx, struct ubus_subscriber *sub, const char *path)
2110 {
2111         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
2112         uc_value_t *patterns = ucv_resource_value_get(uusub->res, SUB_RES_PATTERNS);
2113         size_t len = ucv_array_length(patterns);
2114 
2115         for (size_t i = 0; i < len; i++) {
2116                 uc_value_t *val = ucv_array_get(patterns, i);
2117                 const char *pattern;
2118 
2119                 if (ucv_type(val) != UC_STRING)
2120                         continue;
2121 
2122                 pattern = ucv_string_get(val);
2123 
2124                 if (fnmatch(pattern, path, 0) == 0)
2125                         return true;
2126         }
2127 
2128         return false;
2129 }
2130 #endif
2131 
2132 static uc_value_t *
2133 uc_ubus_subscriber_remove(uc_vm_t *vm, size_t nargs)
2134 {
2135         uc_ubus_subscriber_t *uusub = uc_fn_thisval("ubus.subscriber");
2136         int rv;
2137 
2138         if (!uusub)
2139                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
2140 
2141         rv = uc_ubus_subscriber_remove_common(uusub);
2142 
2143         if (rv != UBUS_STATUS_OK)
2144                 err_return(rv, "Failed to remove subscriber object");
2145 
2146         ok_return(ucv_boolean_new(true));
2147 }
2148 
2149 static uc_value_t *
2150 uc_ubus_subscriber(uc_vm_t *vm, size_t nargs)
2151 {
2152         uc_value_t *notify_cb, *remove_cb, *subscriptions;
2153         uc_ubus_subscriber_t *uusub = NULL;
2154         uc_ubus_connection_t *c;
2155         uc_value_t *res;
2156         int rv;
2157 
2158         conn_get(vm, &c);
2159 
2160         args_get(vm, nargs,
2161                  "notify callback", UC_CLOSURE, true, &notify_cb,
2162                  "remove callback", UC_CLOSURE, true, &remove_cb,
2163                  "subscription patterns", UC_ARRAY, true, &subscriptions);
2164 
2165         if (!notify_cb && !remove_cb)
2166                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either notify or remove callback required");
2167 
2168         res = ucv_resource_create_ex(vm, "ubus.subscriber", (void **)&uusub, __SUB_RES_MAX, sizeof(*uusub));
2169 
2170         if (!uusub)
2171                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory");
2172 
2173         uusub->vm = vm;
2174         uusub->ctx = &c->ctx;
2175         uusub->res = ucv_get(res);
2176 
2177         ucv_resource_value_set(res, SUB_RES_NOTIFY_CB, ucv_get(notify_cb));
2178         ucv_resource_value_set(res, SUB_RES_REMOVE_CB, ucv_get(remove_cb));
2179         ucv_resource_value_set(res, SUB_RES_PATTERNS, ucv_get(subscriptions));
2180 
2181 #ifdef HAVE_UBUS_NEW_OBJ_CB
2182         if (subscriptions)
2183                 uusub->sub.new_obj_cb = uc_ubus_subscriber_new_object_cb;
2184 #endif
2185 
2186         rv = ubus_register_subscriber(&c->ctx, &uusub->sub);
2187 
2188         if (rv != UBUS_STATUS_OK) {
2189                 ucv_put(uusub->res);
2190                 ucv_put(res);
2191                 err_return(rv, "Failed to register subscriber object");
2192         }
2193 
2194         if (notify_cb)
2195                 uusub->sub.cb = uc_ubus_subscriber_notify_cb;
2196 
2197         if (remove_cb)
2198                 uusub->sub.remove_cb = uc_ubus_subscriber_remove_cb;
2199 
2200         ucv_resource_persistent_set(res, true);
2201 
2202         ok_return(res);
2203 }
2204 
2205 
2206 /*
2207  * connection methods
2208  * --------------------------------------------------------------------------
2209  */
2210 
2211 static uc_value_t *
2212 uc_ubus_remove(uc_vm_t *vm, size_t nargs)
2213 {
2214         uc_ubus_subscriber_t **uusub;
2215         uc_ubus_connection_t *c;
2216         uc_ubus_object_t *uuobj;
2217         uc_ubus_listener_t **uul;
2218         int rv;
2219 
2220         conn_get(vm, &c);
2221 
2222         uusub = (uc_ubus_subscriber_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.subscriber");
2223         uuobj = (uc_ubus_object_t *)ucv_resource_data(uc_fn_arg(0), "ubus.object");
2224         uul = (uc_ubus_listener_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.listener");
2225 
2226         if (uusub && *uusub) {
2227                 if ((*uusub)->ctx != &c->ctx)
2228                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
2229                                    "Subscriber belongs to different connection");
2230 
2231                 rv = uc_ubus_subscriber_remove_common(*uusub);
2232 
2233                 if (rv != UBUS_STATUS_OK)
2234                         err_return(rv, "Unable to remove subscriber");
2235         }
2236         else if (uuobj) {
2237                 if (uuobj->ctx != &c->ctx)
2238                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
2239                                    "Object belongs to different connection");
2240 
2241                 rv = uc_ubus_object_remove_common(uuobj);
2242 
2243                 if (rv != UBUS_STATUS_OK)
2244                         err_return(rv, "Unable to remove object");
2245         }
2246         else if (uul && *uul) {
2247                 if ((*uul)->ctx != &c->ctx)
2248                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
2249                                    "Listener belongs to different connection");
2250 
2251                 rv = uc_ubus_listener_remove_common(*uul);
2252 
2253                 if (rv != UBUS_STATUS_OK)
2254                         err_return(rv, "Unable to remove listener");
2255         }
2256         else {
2257                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Unhandled resource type");
2258         }
2259 
2260         ok_return(ucv_boolean_new(true));
2261 }
2262 
2263 
2264 static uc_value_t *
2265 uc_ubus_disconnect(uc_vm_t *vm, size_t nargs)
2266 {
2267         uc_ubus_connection_t *c;
2268 
2269         conn_get(vm, &c);
2270 
2271         ubus_shutdown(&c->ctx);
2272         c->ctx.sock.fd = -1;
2273         uc_ubus_put_res(&c->res);
2274 
2275         ok_return(ucv_boolean_new(true));
2276 }
2277 
2278 static uc_value_t *
2279 uc_ubus_defer_completed(uc_vm_t *vm, size_t nargs)
2280 {
2281         uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred");
2282 
2283         if (!d)
2284                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
2285 
2286         ok_return(ucv_boolean_new(d->complete));
2287 }
2288 
2289 static uc_value_t *
2290 uc_ubus_defer_await(uc_vm_t *vm, size_t nargs)
2291 {
2292         uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred");
2293         int64_t remaining;
2294 
2295         if (!d)
2296                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
2297 
2298         if (d->complete)
2299                 ok_return(ucv_boolean_new(false));
2300 
2301 #ifdef HAVE_ULOOP_TIMEOUT_REMAINING64
2302         remaining = uloop_timeout_remaining64(&d->timeout);
2303 #else
2304         remaining = uloop_timeout_remaining(&d->timeout);
2305 #endif
2306 
2307         ubus_complete_request(d->ctx, &d->request, remaining);
2308 
2309         ok_return(ucv_boolean_new(true));
2310 }
2311 
2312 static uc_value_t *
2313 uc_ubus_defer_abort(uc_vm_t *vm, size_t nargs)
2314 {
2315         uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred");
2316 
2317         if (!d)
2318                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
2319 
2320         if (d->complete)
2321                 ok_return(ucv_boolean_new(false));
2322 
2323         ubus_abort_request(d->ctx, &d->request);
2324         uloop_timeout_cancel(&d->timeout);
2325 
2326         uc_ubus_put_res(&d->res);
2327         d->complete = true;
2328 
2329         ok_return(ucv_boolean_new(true));
2330 }
2331 
2332 /*
2333  * channel related methods
2334  * --------------------------------------------------------------------------
2335  */
2336 
2337 #ifdef HAVE_UBUS_CHANNEL_SUPPORT
2338 static int
2339 uc_ubus_channel_req_cb(struct ubus_context *ctx, struct ubus_object *obj,
2340                        struct ubus_request_data *req, const char *method,
2341                        struct blob_attr *msg)
2342 {
2343         uc_ubus_connection_t *c = container_of(ctx, uc_ubus_connection_t, ctx);
2344         uc_value_t *func, *args, *reqproto;
2345 
2346         func = ucv_resource_value_get(c->res, CONN_RES_CB);
2347 
2348         if (!ucv_is_callable(func))
2349                 return UBUS_STATUS_METHOD_NOT_FOUND;
2350 
2351         args = blob_array_to_ucv(c->vm, blob_data(msg), blob_len(msg), true);
2352         reqproto = ucv_object_new(c->vm);
2353         ucv_object_add(reqproto, "args", ucv_get(args));
2354 
2355         if (method)
2356                 ucv_object_add(reqproto, "type", ucv_get(ucv_string_new(method)));
2357 
2358         return uc_ubus_handle_reply_common(ctx, req, c->vm, c->res, func, reqproto);
2359 }
2360 
2361 static void
2362 uc_ubus_channel_disconnect_cb(struct ubus_context *ctx)
2363 {
2364         uc_ubus_connection_t *c = container_of(ctx, uc_ubus_connection_t, ctx);
2365         uc_value_t *func;
2366 
2367         func = ucv_resource_value_get(c->res, CONN_RES_DISCONNECT_CB);
2368 
2369         if (ucv_is_callable(func)) {
2370                 uc_vm_stack_push(c->vm, ucv_get(c->res));
2371                 uc_vm_stack_push(c->vm, ucv_get(func));
2372 
2373                 if (uc_vm_call(c->vm, true, 0) == EXCEPTION_NONE)
2374                         ucv_put(uc_vm_stack_pop(c->vm));
2375                 else
2376                         uloop_end();
2377         }
2378 
2379         blob_buf_free(&c->buf);
2380 
2381         if (c->ctx.sock.fd >= 0) {
2382                 ubus_shutdown(&c->ctx);
2383                 c->ctx.sock.fd = -1;
2384         }
2385 
2386         uc_ubus_put_res(&c->res);
2387 }
2388 
2389 static uc_value_t *
2390 uc_ubus_channel_add(uc_ubus_connection_t *c, uc_value_t *cb,
2391                     uc_value_t *disconnect_cb, uc_value_t *fd)
2392 {
2393         ucv_resource_persistent_set(c->res, true);
2394         ucv_resource_value_set(c->res, CONN_RES_FD, ucv_get(fd));
2395         ucv_resource_value_set(c->res, CONN_RES_CB, ucv_get(cb));
2396         ucv_resource_value_set(c->res, CONN_RES_DISCONNECT_CB, ucv_get(disconnect_cb));
2397         c->ctx.connection_lost = uc_ubus_channel_disconnect_cb;
2398         ubus_add_uloop(&c->ctx);
2399 
2400         ok_return(ucv_get(c->res));
2401 }
2402 
2403 #endif
2404 
2405 static uc_value_t *
2406 uc_ubus_request_new_channel(uc_vm_t *vm, size_t nargs)
2407 {
2408 #ifdef HAVE_UBUS_CHANNEL_SUPPORT
2409         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
2410         uc_value_t *cb, *disconnect_cb, *timeout;
2411         uc_ubus_connection_t *c;
2412         int fd;
2413 
2414         if (!callctx)
2415                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
2416 
2417         args_get(vm, nargs,
2418                  "cb", UC_CLOSURE, true, &cb,
2419                  "disconnect_cb", UC_CLOSURE, true, &disconnect_cb,
2420                  "timeout", UC_INTEGER, true, &timeout);
2421 
2422         c = uc_ubus_conn_alloc(vm, timeout, "ubus.channel");
2423 
2424         if (!c)
2425                 return NULL;
2426 
2427         if (ubus_channel_create(&c->ctx, &fd, cb ? uc_ubus_channel_req_cb : NULL)) {
2428                 ucv_put(c->res);
2429                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel");
2430         }
2431 
2432         ubus_request_set_fd(callctx->ctx, &callctx->req, fd);
2433 
2434         return uc_ubus_channel_add(c, cb, disconnect_cb, NULL);
2435 #else
2436         err_return(UBUS_STATUS_NOT_SUPPORTED, "No ubus channel support");
2437 #endif
2438 }
2439 
2440 
2441 static uc_value_t *
2442 uc_ubus_channel_connect(uc_vm_t *vm, size_t nargs)
2443 {
2444 #ifdef HAVE_UBUS_CHANNEL_SUPPORT
2445         uc_value_t *fd, *cb, *disconnect_cb, *timeout;
2446         uc_ubus_connection_t *c;
2447         int fd_val;
2448 
2449         args_get(vm, nargs,
2450                  "fd", UC_NULL, false, &fd,
2451                  "cb", UC_CLOSURE, true, &cb,
2452                  "disconnect_cb", UC_CLOSURE, true, &disconnect_cb,
2453                  "timeout", UC_INTEGER, true, &timeout);
2454 
2455         fd_val = get_fd(vm, fd);
2456 
2457         if (fd_val < 0)
2458                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor argument");
2459 
2460         c = uc_ubus_conn_alloc(vm, timeout, "ubus.channel");
2461 
2462         if (!c)
2463                 return NULL;
2464 
2465         if (ubus_channel_connect(&c->ctx, fd_val, cb ? uc_ubus_channel_req_cb : NULL)) {
2466                 ucv_put(c->res);
2467                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel");
2468         }
2469 
2470         return uc_ubus_channel_add(c, cb, disconnect_cb, fd);
2471 #else
2472         err_return(UBUS_STATUS_NOT_SUPPORTED, "No ubus channel support");
2473 #endif
2474 }
2475 
2476 
2477 static const uc_function_list_t global_fns[] = {
2478         { "error",                      uc_ubus_error },
2479         { "connect",            uc_ubus_connect },
2480         { "open_channel",       uc_ubus_channel_connect },
2481 };
2482 
2483 static const uc_function_list_t conn_fns[] = {
2484         { "list",                       uc_ubus_list },
2485         { "call",                       uc_ubus_call },
2486         { "defer",                      uc_ubus_defer },
2487         { "publish",            uc_ubus_publish },
2488         { "remove",                     uc_ubus_remove },
2489         { "listener",           uc_ubus_listener },
2490         { "subscriber",         uc_ubus_subscriber },
2491         { "event",                      uc_ubus_event },
2492         { "error",                      uc_ubus_error },
2493         { "disconnect",         uc_ubus_disconnect },
2494 };
2495 
2496 static const uc_function_list_t chan_fns[] = {
2497         { "request",            uc_ubus_chan_request },
2498         { "defer",                      uc_ubus_chan_defer },
2499         { "error",                      uc_ubus_error },
2500         { "disconnect",         uc_ubus_disconnect },
2501 };
2502 
2503 static const uc_function_list_t defer_fns[] = {
2504         { "await",                      uc_ubus_defer_await },
2505         { "completed",          uc_ubus_defer_completed },
2506         { "abort",                      uc_ubus_defer_abort },
2507 };
2508 
2509 static const uc_function_list_t object_fns[] = {
2510         { "subscribed",         uc_ubus_object_subscribed },
2511         { "notify",                     uc_ubus_object_notify },
2512         { "remove",                     uc_ubus_object_remove },
2513 };
2514 
2515 static const uc_function_list_t request_fns[] = {
2516         { "reply",                      uc_ubus_request_reply },
2517         { "error",                      uc_ubus_request_error },
2518         { "defer",                      uc_ubus_request_defer },
2519         { "get_fd",                     uc_ubus_request_get_fd },
2520         { "set_fd",                     uc_ubus_request_set_fd },
2521         { "new_channel",        uc_ubus_request_new_channel },
2522 };
2523 
2524 static const uc_function_list_t notify_fns[] = {
2525         { "completed",          uc_ubus_notify_completed },
2526         { "abort",                      uc_ubus_notify_abort },
2527 };
2528 
2529 static const uc_function_list_t listener_fns[] = {
2530         { "remove",                     uc_ubus_listener_remove },
2531 };
2532 
2533 static const uc_function_list_t subscriber_fns[] = {
2534         { "subscribe",          uc_ubus_subscriber_subscribe },
2535         { "unsubscribe",        uc_ubus_subscriber_unsubscribe },
2536         { "remove",                     uc_ubus_subscriber_remove },
2537 };
2538 
2539 static void free_connection(void *ud) {
2540         uc_ubus_connection_t *conn = ud;
2541 
2542         blob_buf_free(&conn->buf);
2543 
2544         if (conn->ctx.sock.fd >= 0)
2545                 ubus_shutdown(&conn->ctx);
2546 }
2547 
2548 static void free_deferred(void *ud) {
2549         uc_ubus_deferred_t *defer = ud;
2550 
2551         uloop_timeout_cancel(&defer->timeout);
2552 }
2553 
2554 static void free_object(void *ud) {
2555         uc_ubus_object_t *uuobj = ud;
2556         struct ubus_object *obj = &uuobj->obj;
2557         int i, j;
2558 
2559         for (i = 0; i < obj->n_methods; i++) {
2560                 for (j = 0; j < obj->methods[i].n_policy; j++)
2561                         free((char *)obj->methods[i].policy[j].name);
2562 
2563                 free((char *)obj->methods[i].name);
2564                 free((char *)obj->methods[i].policy);
2565         }
2566 }
2567 
2568 static void free_request(void *ud) {
2569         uc_ubus_request_t *callctx = ud;
2570 
2571         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT);
2572 }
2573 
2574 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
2575 {
2576         uc_function_list_register(scope, global_fns);
2577 
2578 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(UBUS_##x))
2579         ADD_CONST(STATUS_OK);
2580         ADD_CONST(STATUS_INVALID_COMMAND);
2581         ADD_CONST(STATUS_INVALID_ARGUMENT);
2582         ADD_CONST(STATUS_METHOD_NOT_FOUND);
2583         ADD_CONST(STATUS_NOT_FOUND);
2584         ADD_CONST(STATUS_NO_DATA);
2585         ADD_CONST(STATUS_PERMISSION_DENIED);
2586         ADD_CONST(STATUS_TIMEOUT);
2587         ADD_CONST(STATUS_NOT_SUPPORTED);
2588         ADD_CONST(STATUS_UNKNOWN_ERROR);
2589         ADD_CONST(STATUS_CONNECTION_FAILED);
2590 
2591 #ifdef HAVE_NEW_UBUS_STATUS_CODES
2592         ADD_CONST(STATUS_NO_MEMORY);
2593         ADD_CONST(STATUS_PARSE_ERROR);
2594         ADD_CONST(STATUS_SYSTEM_ERROR);
2595 #endif
2596 
2597         /* virtual status code for reply */
2598 #define UBUS_STATUS_CONTINUE -1
2599         ADD_CONST(STATUS_CONTINUE);
2600 
2601         ADD_CONST(SYSTEM_OBJECT_ACL);
2602 
2603         uc_type_declare(vm, "ubus.connection", conn_fns, free_connection);
2604         uc_type_declare(vm, "ubus.channel", chan_fns, free_connection);
2605         uc_type_declare(vm, "ubus.deferred", defer_fns, free_deferred);
2606         uc_type_declare(vm, "ubus.object", object_fns, free_object);
2607         uc_type_declare(vm, "ubus.notify", notify_fns, NULL);
2608         uc_type_declare(vm, "ubus.request", request_fns, free_request);
2609         uc_type_declare(vm, "ubus.listener", listener_fns, NULL);
2610         uc_type_declare(vm, "ubus.subscriber", subscriber_fns, NULL);
2611 }
2612 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt