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; 515 uc_value_t *res; 516 517 if (ucv_type(_uc_fn_this_res(vm)) == UC_OBJECT) { 518 res = uc_vm_registry_get(vm, "ubus.connection"); 519 c = ucv_resource_data(res, "ubus.connection"); 520 521 if (c && c->ctx.sock.fd >= 0) 522 goto out; 523 524 c = uc_ubus_conn_alloc(vm, NULL, "ubus.connection"); 525 if (!c) 526 return NULL; 527 528 if (ubus_connect_ctx(&c->ctx, NULL)) { 529 ucv_put(c->res); 530 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to connect to ubus socket"); 531 } 532 533 ubus_add_uloop(&c->ctx); 534 535 uc_vm_registry_set(vm, "ubus.connection", ucv_get(c->res)); 536 } 537 else { 538 c = uc_fn_thisval("ubus.connection"); 539 if (!c) 540 c = uc_fn_thisval("ubus.channel"); 541 542 if (!c) 543 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid connection context"); 544 545 if (c->ctx.sock.fd < 0) 546 err_return(UBUS_STATUS_CONNECTION_FAILED, "Connection is closed"); 547 } 548 549 out: 550 *conn = c; 551 552 ok_return(true); 553 } 554 555 #define conn_get(vm, ptr) do { if (!_conn_get(vm, ptr)) return NULL; } while(0) 556 557 static uc_value_t * 558 uc_ubus_list(uc_vm_t *vm, size_t nargs) 559 { 560 uc_ubus_connection_t *c; 561 uc_value_t *objname, *res = NULL; 562 enum ubus_msg_status rv; 563 564 conn_get(vm, &c); 565 566 args_get(vm, nargs, 567 "object name", UC_STRING, true, &objname); 568 569 res = ucv_array_new(vm); 570 571 rv = ubus_lookup(&c->ctx, 572 objname ? ucv_string_get(objname) : NULL, 573 objname ? uc_ubus_signatures_cb : uc_ubus_objects_cb, 574 res); 575 576 if (rv != UBUS_STATUS_OK) { 577 ucv_put(res); 578 err_return(rv, NULL); 579 } 580 581 ok_return(res); 582 } 583 584 static void 585 uc_ubus_call_cb(struct ubus_request *req, int type, struct blob_attr *msg) 586 { 587 uc_ubus_call_res_t *res = req->priv; 588 uc_value_t *val; 589 590 val = msg ? blob_array_to_ucv(NULL, blob_data(msg), blob_len(msg), true) : NULL; 591 592 if (res->mret) { 593 if (!res->res) 594 res->res = ucv_array_new(NULL); 595 596 ucv_array_push(res->res, val); 597 } 598 else if (!res->res) { 599 res->res = val; 600 } 601 } 602 603 static void 604 uc_ubus_vm_handle_exception(uc_vm_t *vm) 605 { 606 uc_value_t *exh, *val; 607 608 exh = uc_vm_registry_get(vm, "ubus.ex_handler"); 609 if (!ucv_is_callable(exh)) 610 goto error; 611 612 val = uc_vm_exception_object(vm); 613 uc_vm_stack_push(vm, ucv_get(exh)); 614 uc_vm_stack_push(vm, val); 615 616 if (uc_vm_call(vm, false, 1) != EXCEPTION_NONE) 617 goto error; 618 619 ucv_put(uc_vm_stack_pop(vm)); 620 return; 621 622 error: 623 uloop_end(); 624 } 625 626 static bool 627 uc_ubus_vm_call(uc_vm_t *vm, bool mcall, size_t nargs) 628 { 629 if (uc_vm_call(vm, mcall, nargs) == EXCEPTION_NONE) 630 return true; 631 632 uc_ubus_vm_handle_exception(vm); 633 634 return false; 635 } 636 637 static void 638 uc_ubus_call_user_cb(uc_ubus_deferred_t *defer, int ret, uc_value_t *reply) 639 { 640 uc_value_t *this = ucv_get(defer->res); 641 uc_vm_t *vm = defer->vm; 642 uc_value_t *func; 643 644 func = ucv_resource_value_get(this, DEFER_RES_CB); 645 646 if (ucv_is_callable(func)) { 647 uc_vm_stack_push(vm, ucv_get(this)); 648 uc_vm_stack_push(vm, ucv_get(func)); 649 uc_vm_stack_push(vm, ucv_int64_new(ret)); 650 uc_vm_stack_push(vm, ucv_get(reply)); 651 652 if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE) 653 ucv_put(uc_vm_stack_pop(vm)); 654 } 655 656 uc_ubus_put_res(&defer->res); 657 ucv_put(this); 658 } 659 660 static void 661 uc_ubus_call_data_cb(struct ubus_request *req, int type, struct blob_attr *msg) 662 { 663 uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request); 664 665 if (defer->response != NULL) 666 return; 667 668 defer->response = blob_array_to_ucv(defer->vm, blob_data(msg), blob_len(msg), true); 669 ucv_resource_value_set(defer->res, DEFER_RES_RESPONSE, defer->response); 670 } 671 672 static void 673 uc_ubus_call_data_user_cb(struct ubus_request *req, int type, struct blob_attr *msg) 674 { 675 uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request); 676 uc_vm_t *vm = defer->vm; 677 uc_value_t *func, *reply; 678 679 func = ucv_resource_value_get(defer->res, DEFER_RES_DATA_CB); 680 681 if (ucv_is_callable(func)) { 682 reply = blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true); 683 684 uc_vm_stack_push(vm, ucv_get(defer->res)); 685 uc_vm_stack_push(vm, ucv_get(func)); 686 uc_vm_stack_push(vm, ucv_get(reply)); 687 688 if (uc_ubus_vm_call(vm, true, 1)) 689 ucv_put(uc_vm_stack_pop(vm)); 690 } 691 } 692 693 static void 694 uc_ubus_call_fd_cb(struct ubus_request *req, int fd) 695 { 696 uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request); 697 uc_value_t *func = defer->fd_callback; 698 uc_vm_t *vm = defer->vm; 699 700 if (defer->complete) 701 return; 702 703 if (ucv_is_callable(func)) { 704 uc_vm_stack_push(vm, ucv_get(defer->res)); 705 uc_vm_stack_push(vm, ucv_get(func)); 706 uc_vm_stack_push(vm, ucv_int64_new(fd)); 707 708 if (uc_ubus_vm_call(vm, true, 1)) 709 ucv_put(uc_vm_stack_pop(vm)); 710 } 711 } 712 713 static void 714 uc_ubus_call_done_cb(struct ubus_request *req, int ret) 715 { 716 uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request); 717 718 if (defer->complete) 719 return; 720 721 defer->complete = true; 722 uloop_timeout_cancel(&defer->timeout); 723 724 uc_ubus_call_user_cb(defer, ret, defer->response); 725 } 726 727 static void 728 uc_ubus_call_timeout_cb(struct uloop_timeout *timeout) 729 { 730 uc_ubus_deferred_t *defer = container_of(timeout, uc_ubus_deferred_t, timeout); 731 732 if (defer->complete) 733 return; 734 735 defer->complete = true; 736 ubus_abort_request(defer->ctx, &defer->request); 737 738 uc_ubus_call_user_cb(defer, UBUS_STATUS_TIMEOUT, NULL); 739 } 740 741 static int 742 get_fd(uc_vm_t *vm, uc_value_t *val) 743 { 744 uc_value_t *fn; 745 int64_t n; 746 747 fn = ucv_property_get(val, "fileno"); 748 749 if (ucv_is_callable(fn)) { 750 uc_vm_stack_push(vm, ucv_get(val)); 751 uc_vm_stack_push(vm, ucv_get(fn)); 752 753 if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE) 754 return -1; 755 756 val = uc_vm_stack_pop(vm); 757 n = ucv_int64_get(val); 758 ucv_put(val); 759 } 760 else { 761 n = ucv_int64_get(val); 762 } 763 764 if (errno || n < 0 || n > (int64_t)INT_MAX) 765 return -1; 766 767 return (int)n; 768 } 769 770 static int 771 uc_ubus_call_common(uc_vm_t *vm, uc_ubus_connection_t *c, uc_ubus_call_res_t *res, 772 uint32_t id, uc_value_t *funname, uc_value_t *funargs, 773 uc_value_t *fd, uc_value_t *fdcb, uc_value_t *mret) 774 { 775 uc_ubus_deferred_t defer = {}; 776 enum ubus_msg_status rv; 777 int fd_val = -1; 778 779 enum { 780 RET_MODE_SINGLE, 781 RET_MODE_MULTIPLE, 782 RET_MODE_IGNORE, 783 } ret_mode = RET_MODE_SINGLE; 784 785 const char * const ret_modes[] = { 786 [RET_MODE_SINGLE] = "single", 787 [RET_MODE_MULTIPLE] = "multiple", 788 [RET_MODE_IGNORE] = "ignore", 789 }; 790 791 if (ucv_type(mret) == UC_STRING) { 792 const char *str = ucv_string_get(mret); 793 size_t i; 794 795 for (i = 0; i < ARRAY_SIZE(ret_modes); i++) 796 if (!strcmp(str, ret_modes[i])) 797 break; 798 799 if (i == ARRAY_SIZE(ret_modes)) 800 errval_return(UBUS_STATUS_INVALID_ARGUMENT, 801 "Invalid return mode argument"); 802 803 ret_mode = i; 804 } 805 else if (ucv_type(mret) == UC_BOOLEAN) { 806 ret_mode = ucv_boolean_get(mret); 807 } 808 else if (ret_mode) { 809 errval_return(UBUS_STATUS_INVALID_ARGUMENT, 810 "Invalid return mode argument"); 811 } 812 813 blob_buf_init(&c->buf, 0); 814 815 if (funargs) 816 ucv_object_to_blob(funargs, &c->buf); 817 818 if (fd) { 819 fd_val = get_fd(vm, fd); 820 821 if (fd_val < 0) 822 errval_return(UBUS_STATUS_INVALID_ARGUMENT, 823 "Invalid file descriptor argument"); 824 } 825 826 res->mret = (ret_mode == RET_MODE_MULTIPLE); 827 828 rv = ubus_invoke_async_fd(&c->ctx, id, ucv_string_get(funname), 829 c->buf.head, &defer.request, fd_val); 830 831 defer.vm = vm; 832 defer.ctx = &c->ctx; 833 defer.request.data_cb = uc_ubus_call_cb; 834 defer.request.priv = res; 835 836 if (ucv_is_callable(fdcb)) { 837 defer.request.fd_cb = uc_ubus_call_fd_cb; 838 defer.fd_callback = fdcb; 839 } 840 841 if (rv == UBUS_STATUS_OK) { 842 if (ret_mode == RET_MODE_IGNORE) 843 ubus_abort_request(&c->ctx, &defer.request); 844 else 845 rv = ubus_complete_request(&c->ctx, &defer.request, c->timeout * 1000); 846 } 847 848 return rv; 849 } 850 851 static uc_value_t * 852 uc_ubus_call(uc_vm_t *vm, size_t nargs) 853 { 854 uc_value_t *obj, *funname, *funargs, *fd, *fdcb, *mret = NULL; 855 uc_ubus_call_res_t res = { 0 }; 856 uc_ubus_connection_t *c; 857 enum ubus_msg_status rv; 858 uint32_t id; 859 860 args_get_named(vm, nargs, 861 "object", 0, REQUIRED, &obj, 862 "method", UC_STRING, REQUIRED, &funname, 863 "data", UC_OBJECT, OPTIONAL, &funargs, 864 "return", 0, OPTIONAL, &mret, 865 "fd", 0, NAMED, &fd, 866 "fd_cb", UC_CLOSURE, NAMED, &fdcb); 867 868 conn_get(vm, &c); 869 870 if (ucv_type(obj) == UC_INTEGER) { 871 id = ucv_int64_get(obj); 872 } 873 else if (ucv_type(obj) == UC_STRING) { 874 rv = ubus_lookup_id(&c->ctx, ucv_string_get(obj), &id); 875 876 if (rv != UBUS_STATUS_OK) 877 err_return(rv, "Failed to resolve object name '%s'", 878 ucv_string_get(obj)); 879 } 880 else { 881 err_return(UBUS_STATUS_INVALID_ARGUMENT, 882 "Argument object is not string or integer"); 883 } 884 885 rv = uc_ubus_call_common(vm, c, &res, id, funname, funargs, fd, fdcb, mret); 886 887 if (rv != UBUS_STATUS_OK) { 888 if (ucv_type(obj) == UC_STRING) 889 err_return(rv, "Failed to invoke function '%s' on object '%s'", 890 ucv_string_get(funname), ucv_string_get(obj)); 891 else 892 err_return(rv, "Failed to invoke function '%s' on system object %d", 893 ucv_string_get(funname), (int)ucv_int64_get(obj)); 894 } 895 896 ok_return(res.res); 897 } 898 899 static uc_value_t * 900 uc_ubus_chan_request(uc_vm_t *vm, size_t nargs) 901 { 902 uc_value_t *funname, *funargs, *fd, *fdcb, *mret = NULL; 903 uc_ubus_call_res_t res = { 0 }; 904 uc_ubus_connection_t *c; 905 enum ubus_msg_status rv; 906 907 args_get_named(vm, nargs, 908 "method", UC_STRING, REQUIRED, &funname, 909 "data", UC_OBJECT, OPTIONAL, &funargs, 910 "return", 0, OPTIONAL, &mret, 911 "fd", 0, NAMED, &fd, 912 "fd_cb", UC_CLOSURE, NAMED, &fdcb); 913 914 conn_get(vm, &c); 915 916 rv = uc_ubus_call_common(vm, c, &res, 0, funname, funargs, fd, fdcb, mret); 917 918 if (rv != UBUS_STATUS_OK) 919 err_return(rv, "Failed to send request '%s' on channel", 920 ucv_string_get(funname)); 921 922 ok_return(res.res); 923 } 924 925 static int 926 uc_ubus_defer_common(uc_vm_t *vm, uc_ubus_connection_t *c, uc_ubus_call_res_t *res, 927 uint32_t id, uc_value_t *funname, uc_value_t *funargs, 928 uc_value_t *fd, uc_value_t *fdcb, uc_value_t *replycb, 929 uc_value_t *datacb) 930 { 931 uc_ubus_deferred_t *defer = NULL; 932 enum ubus_msg_status rv; 933 int fd_val = -1; 934 935 blob_buf_init(&c->buf, 0); 936 937 if (funargs) 938 ucv_object_to_blob(funargs, &c->buf); 939 940 if (fd) { 941 fd_val = get_fd(vm, fd); 942 943 if (fd_val < 0) 944 errval_return(UBUS_STATUS_INVALID_ARGUMENT, 945 "Invalid file descriptor argument"); 946 } 947 948 res->res = ucv_resource_create_ex(vm, "ubus.deferred", (void **)&defer, __DEFER_RES_MAX, sizeof(*defer)); 949 950 if (!defer) 951 errval_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory"); 952 953 rv = ubus_invoke_async_fd(&c->ctx, id, ucv_string_get(funname), 954 c->buf.head, &defer->request, fd_val); 955 956 if (rv == UBUS_STATUS_OK) { 957 defer->vm = vm; 958 defer->ctx = &c->ctx; 959 defer->res = ucv_get(res->res); 960 ucv_resource_persistent_set(defer->res, true); 961 ucv_resource_value_set(defer->res, DEFER_RES_CONN, ucv_get(c->res)); 962 ucv_resource_value_set(defer->res, DEFER_RES_CB, ucv_get(replycb)); 963 ucv_resource_value_set(defer->res, DEFER_RES_FD, ucv_get(fd)); 964 ucv_resource_value_set(defer->res, DEFER_RES_DATA_CB, ucv_get(datacb)); 965 966 if (ucv_is_callable(datacb)) 967 defer->request.data_cb = uc_ubus_call_data_user_cb; 968 else 969 defer->request.data_cb = uc_ubus_call_data_cb; 970 971 if (ucv_is_callable(fdcb)) { 972 defer->request.fd_cb = uc_ubus_call_fd_cb; 973 defer->fd_callback = fdcb; 974 ucv_resource_value_set(defer->res, DEFER_RES_FD_CB, ucv_get(fdcb)); 975 } 976 977 defer->request.complete_cb = uc_ubus_call_done_cb; 978 979 ubus_complete_request_async(&c->ctx, &defer->request); 980 981 defer->timeout.cb = uc_ubus_call_timeout_cb; 982 uloop_timeout_set(&defer->timeout, c->timeout * 1000); 983 } 984 else { 985 uc_vm_stack_push(vm, ucv_get(replycb)); 986 uc_vm_stack_push(vm, ucv_int64_new(rv)); 987 988 if (uc_ubus_vm_call(vm, false, 1)) 989 ucv_put(uc_vm_stack_pop(vm)); 990 991 ucv_put(res->res); 992 } 993 994 return rv; 995 } 996 997 static uc_value_t * 998 uc_ubus_defer(uc_vm_t *vm, size_t nargs) 999 { 1000 uc_value_t *objname, *funname, *funargs, *replycb, *datacb, *fd, *fdcb = NULL; 1001 uc_ubus_call_res_t res = { 0 }; 1002 uc_ubus_connection_t *c; 1003 uint32_t id; 1004 int rv; 1005 1006 conn_get(vm, &c); 1007 1008 args_get_named(vm, nargs, 1009 "object", UC_STRING, REQUIRED, &objname, 1010 "method", UC_STRING, REQUIRED, &funname, 1011 "data", UC_OBJECT, OPTIONAL, &funargs, 1012 "cb", UC_CLOSURE, OPTIONAL, &replycb, 1013 "data_cb", UC_CLOSURE, OPTIONAL, &datacb, 1014 "fd", 0, NAMED, &fd, 1015 "fd_cb", UC_CLOSURE, NAMED, &fdcb); 1016 1017 rv = ubus_lookup_id(&c->ctx, ucv_string_get(objname), &id); 1018 1019 if (rv != UBUS_STATUS_OK) 1020 err_return(rv, "Failed to resolve object name '%s'", 1021 ucv_string_get(objname)); 1022 1023 rv = uc_ubus_defer_common(vm, c, &res, id, funname, funargs, fd, fdcb, replycb, datacb); 1024 1025 if (rv != UBUS_STATUS_OK) 1026 err_return(rv, "Failed to invoke function '%s' on object '%s'", 1027 ucv_string_get(funname), ucv_string_get(objname)); 1028 1029 ok_return(res.res); 1030 } 1031 1032 static uc_value_t * 1033 uc_ubus_chan_defer(uc_vm_t *vm, size_t nargs) 1034 { 1035 uc_value_t *funname, *funargs, *replycb, *datacb, *fd, *fdcb = NULL; 1036 uc_ubus_call_res_t res = { 0 }; 1037 uc_ubus_connection_t *c; 1038 int rv; 1039 1040 conn_get(vm, &c); 1041 1042 args_get_named(vm, nargs, 1043 "method", UC_STRING, REQUIRED, &funname, 1044 "data", UC_OBJECT, OPTIONAL, &funargs, 1045 "cb", UC_CLOSURE, OPTIONAL, &replycb, 1046 "data_cb", UC_CLOSURE, OPTIONAL, &datacb, 1047 "fd", 0, NAMED, &fd, 1048 "fd_cb", UC_CLOSURE, NAMED, &fdcb); 1049 1050 rv = uc_ubus_defer_common(vm, c, &res, 0, funname, funargs, fd, fdcb, replycb, datacb); 1051 1052 if (rv != UBUS_STATUS_OK) 1053 err_return(rv, "Failed to invoke function '%s' on channel", 1054 ucv_string_get(funname)); 1055 1056 ok_return(res.res); 1057 } 1058 1059 1060 /* 1061 * ubus object request context functions 1062 * -------------------------------------------------------------------------- 1063 */ 1064 1065 static void 1066 uc_ubus_request_finish_common(uc_ubus_request_t *callctx, int code) 1067 { 1068 int fd; 1069 1070 fd = ubus_request_get_caller_fd(&callctx->req); 1071 1072 if (fd >= 0) 1073 close(fd); 1074 1075 callctx->replied = true; 1076 uloop_timeout_cancel(&callctx->timeout); 1077 ubus_complete_deferred_request(callctx->ctx, &callctx->req, code); 1078 } 1079 1080 static void 1081 uc_ubus_request_send_reply(uc_ubus_request_t *callctx, uc_value_t *reply) 1082 { 1083 if (!reply) 1084 return; 1085 1086 blob_buf_init(&buf, 0); 1087 ucv_object_to_blob(reply, &buf); 1088 ubus_send_reply(callctx->ctx, &callctx->req, buf.head); 1089 } 1090 1091 static void 1092 uc_ubus_request_finish(uc_ubus_request_t *callctx, int code) 1093 { 1094 if (callctx->replied) 1095 return; 1096 1097 uc_ubus_request_finish_common(callctx, code); 1098 uc_ubus_put_res(&callctx->res); 1099 } 1100 1101 static void 1102 uc_ubus_request_timeout(struct uloop_timeout *timeout) 1103 { 1104 uc_ubus_request_t *callctx = container_of(timeout, uc_ubus_request_t, timeout); 1105 1106 uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT); 1107 } 1108 1109 static uc_value_t * 1110 uc_ubus_request_reply(uc_vm_t *vm, size_t nargs) 1111 { 1112 uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request"); 1113 int64_t code = UBUS_STATUS_OK; 1114 uc_value_t *reply, *rcode; 1115 bool more = false; 1116 1117 if (!callctx) 1118 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context"); 1119 1120 args_get(vm, nargs, 1121 "reply", UC_OBJECT, true, &reply, 1122 "rcode", UC_INTEGER, true, &rcode); 1123 1124 if (callctx->replied) 1125 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent"); 1126 1127 if (rcode) { 1128 code = ucv_int64_get(rcode); 1129 1130 if (errno == ERANGE || code < -1 || code > __UBUS_STATUS_LAST) 1131 code = UBUS_STATUS_UNKNOWN_ERROR; 1132 1133 if (code < 0) 1134 more = true; 1135 } 1136 1137 uc_ubus_request_send_reply(callctx, reply); 1138 1139 if (!more) 1140 uc_ubus_request_finish(callctx, code); 1141 1142 ok_return(ucv_boolean_new(true)); 1143 } 1144 1145 static uc_value_t * 1146 uc_ubus_request_defer(uc_vm_t *vm, size_t nargs) 1147 { 1148 uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request"); 1149 1150 if (!callctx) 1151 return NULL; 1152 1153 callctx->deferred = true; 1154 return ucv_boolean_new(true); 1155 } 1156 1157 static uc_value_t * 1158 uc_ubus_request_get_fd(uc_vm_t *vm, size_t nargs) 1159 { 1160 uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request"); 1161 1162 if (!callctx) 1163 return NULL; 1164 1165 return ucv_int64_new(ubus_request_get_caller_fd(&callctx->req)); 1166 } 1167 1168 static uc_value_t * 1169 uc_ubus_request_set_fd(uc_vm_t *vm, size_t nargs) 1170 { 1171 uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request"); 1172 int fd; 1173 1174 if (!callctx) 1175 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context"); 1176 1177 fd = get_fd(vm, uc_fn_arg(0)); 1178 1179 if (fd < 0) 1180 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor"); 1181 1182 ubus_request_set_fd(callctx->ctx, &callctx->req, fd); 1183 1184 return ucv_boolean_new(true); 1185 } 1186 1187 static uc_value_t * 1188 uc_ubus_request_error(uc_vm_t *vm, size_t nargs) 1189 { 1190 uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request"); 1191 uc_value_t *rcode = uc_fn_arg(0); 1192 int64_t code; 1193 1194 if (!callctx) 1195 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context"); 1196 1197 args_get(vm, nargs, 1198 "rcode", UC_INTEGER, false, &rcode); 1199 1200 if (callctx->replied) 1201 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent"); 1202 1203 code = ucv_int64_get(rcode); 1204 1205 if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST) 1206 code = UBUS_STATUS_UNKNOWN_ERROR; 1207 1208 uc_ubus_request_finish(callctx, code); 1209 1210 ok_return(ucv_boolean_new(true)); 1211 } 1212 1213 1214 /* 1215 * ubus object notify 1216 * -------------------------------------------------------------------------- 1217 */ 1218 1219 static uc_value_t * 1220 uc_ubus_notify_completed(uc_vm_t *vm, size_t nargs) 1221 { 1222 uc_ubus_notify_t *notifyctx = uc_fn_thisval("ubus.notify"); 1223 1224 ok_return(ucv_boolean_new(notifyctx->complete)); 1225 } 1226 1227 static uc_value_t * 1228 uc_ubus_notify_abort(uc_vm_t *vm, size_t nargs) 1229 { 1230 uc_ubus_notify_t *notifyctx = uc_fn_thisval("ubus.notify"); 1231 1232 if (notifyctx->complete) 1233 ok_return(ucv_boolean_new(false)); 1234 1235 ubus_abort_request(notifyctx->ctx, ¬ifyctx->req.req); 1236 notifyctx->complete = true; 1237 uc_ubus_put_res(¬ifyctx->res); 1238 1239 ok_return(ucv_boolean_new(true)); 1240 } 1241 1242 static void 1243 uc_ubus_object_notify_data_cb(struct ubus_notify_request *req, int type, struct blob_attr *msg) 1244 { 1245 uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req; 1246 uc_vm_t *vm = notifyctx->vm; 1247 uc_value_t *this, *func; 1248 1249 this = notifyctx->res; 1250 func = ucv_resource_value_get(this, NOTIFY_RES_DATA_CB); 1251 1252 if (ucv_is_callable(func)) { 1253 uc_vm_stack_push(vm, ucv_get(this)); 1254 uc_vm_stack_push(vm, ucv_get(func)); 1255 uc_vm_stack_push(vm, ucv_int64_new(type)); 1256 uc_vm_stack_push(vm, blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true)); 1257 1258 if (uc_ubus_vm_call(vm, true, 2)) 1259 ucv_put(uc_vm_stack_pop(vm)); 1260 } 1261 } 1262 1263 static void 1264 uc_ubus_object_notify_status_cb(struct ubus_notify_request *req, int idx, int ret) 1265 { 1266 uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req; 1267 uc_vm_t *vm = notifyctx->vm; 1268 uc_value_t *this, *func; 1269 1270 this = notifyctx->res; 1271 func = ucv_resource_value_get(this, NOTIFY_RES_STATUS_CB); 1272 1273 if (ucv_is_callable(func)) { 1274 uc_vm_stack_push(vm, ucv_get(this)); 1275 uc_vm_stack_push(vm, ucv_get(func)); 1276 uc_vm_stack_push(vm, ucv_int64_new(idx)); 1277 uc_vm_stack_push(vm, ucv_int64_new(ret)); 1278 1279 if (uc_ubus_vm_call(vm, true, 2)) 1280 ucv_put(uc_vm_stack_pop(vm)); 1281 } 1282 } 1283 1284 static void 1285 uc_ubus_object_notify_complete_cb(struct ubus_notify_request *req, int idx, int ret) 1286 { 1287 uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req; 1288 uc_vm_t *vm = notifyctx->vm; 1289 uc_value_t *this, *func; 1290 1291 this = ucv_get(notifyctx->res); 1292 func = ucv_resource_value_get(this, NOTIFY_RES_CB); 1293 1294 if (ucv_is_callable(func)) { 1295 uc_vm_stack_push(vm, ucv_get(this)); 1296 uc_vm_stack_push(vm, ucv_get(func)); 1297 uc_vm_stack_push(vm, ucv_int64_new(idx)); 1298 uc_vm_stack_push(vm, ucv_int64_new(ret)); 1299 1300 if (uc_ubus_vm_call(vm, true, 2)) 1301 ucv_put(uc_vm_stack_pop(vm)); 1302 } 1303 1304 notifyctx->complete = true; 1305 uc_ubus_put_res(¬ifyctx->res); 1306 ucv_put(this); 1307 } 1308 1309 static uc_value_t * 1310 uc_ubus_object_notify(uc_vm_t *vm, size_t nargs) 1311 { 1312 uc_value_t *typename, *message, *data_cb, *status_cb, *complete_cb, *timeout; 1313 uc_ubus_object_t *uuobj = uc_fn_thisval("ubus.object"); 1314 uc_ubus_notify_t *notifyctx = NULL; 1315 uc_value_t *res; 1316 int64_t t; 1317 int rv = UBUS_STATUS_UNKNOWN_ERROR; 1318 1319 if (!uuobj) 1320 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context"); 1321 1322 args_get_named(vm, nargs, 1323 "type", UC_STRING, REQUIRED, &typename, 1324 "data", UC_OBJECT, OPTIONAL, &message, 1325 "data_cb", UC_CLOSURE, OPTIONAL, &data_cb, 1326 "status_cb", UC_CLOSURE, OPTIONAL, &status_cb, 1327 "cb", UC_CLOSURE, OPTIONAL, &complete_cb, 1328 "timeout", UC_INTEGER, OPTIONAL, &timeout); 1329 1330 t = timeout ? ucv_int64_get(timeout) : -1; 1331 1332 if (errno) 1333 err_return(UBUS_STATUS_INVALID_ARGUMENT, 1334 "Invalid timeout value: %s", strerror(errno)); 1335 1336 res = ucv_resource_create_ex(vm, "ubus.notify", (void **)¬ifyctx, __NOTIFY_RES_MAX, sizeof(*notifyctx)); 1337 1338 if (!notifyctx) 1339 err_return(rv, "Out of memory"); 1340 1341 notifyctx->vm = vm; 1342 notifyctx->ctx = uuobj->ctx; 1343 1344 blob_buf_init(&buf, 0); 1345 1346 if (message) 1347 ucv_object_to_blob(message, &buf); 1348 1349 rv = ubus_notify_async(uuobj->ctx, &uuobj->obj, 1350 ucv_string_get(typename), buf.head, 1351 ¬ifyctx->req); 1352 1353 if (rv != UBUS_STATUS_OK) { 1354 ucv_put(res); 1355 err_return(rv, "Failed to send notification"); 1356 } 1357 1358 notifyctx->res = ucv_get(res); 1359 notifyctx->req.data_cb = uc_ubus_object_notify_data_cb; 1360 notifyctx->req.status_cb = uc_ubus_object_notify_status_cb; 1361 notifyctx->req.complete_cb = uc_ubus_object_notify_complete_cb; 1362 1363 ucv_resource_value_set(res, NOTIFY_RES_CONN, ucv_get(uuobj->res)); 1364 ucv_resource_value_set(res, NOTIFY_RES_CB, ucv_get(complete_cb)); 1365 ucv_resource_value_set(res, NOTIFY_RES_DATA_CB, ucv_get(data_cb)); 1366 ucv_resource_value_set(res, NOTIFY_RES_STATUS_CB, ucv_get(status_cb)); 1367 1368 if (t >= 0) { 1369 rv = ubus_complete_request(uuobj->ctx, ¬ifyctx->req.req, t); 1370 1371 ucv_put(res); 1372 1373 ok_return(ucv_int64_new(rv)); 1374 } 1375 1376 ucv_resource_persistent_set(res, true); 1377 ubus_complete_request_async(uuobj->ctx, ¬ifyctx->req.req); 1378 1379 ok_return(res); 1380 } 1381 1382 1383 /* 1384 * ubus object remove 1385 * -------------------------------------------------------------------------- 1386 */ 1387 1388 static int 1389 uc_ubus_object_remove_common(uc_ubus_object_t *uuobj) 1390 { 1391 int rv = ubus_remove_object(uuobj->ctx, &uuobj->obj); 1392 1393 if (rv != UBUS_STATUS_OK) 1394 return rv; 1395 1396 uc_ubus_put_res(&uuobj->res); 1397 1398 return rv; 1399 } 1400 1401 static uc_value_t * 1402 uc_ubus_object_remove(uc_vm_t *vm, size_t nargs) 1403 { 1404 uc_ubus_object_t *uuobj = uc_fn_thisval("ubus.object"); 1405 int rv; 1406 1407 if (!uuobj) 1408 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context"); 1409 1410 rv = uc_ubus_object_remove_common(uuobj); 1411 1412 if (rv != UBUS_STATUS_OK) 1413 err_return(rv, "Failed to remove object"); 1414 1415 ok_return(ucv_boolean_new(true)); 1416 } 1417 1418 1419 /* 1420 * ubus object subscription status 1421 */ 1422 1423 static uc_value_t * 1424 uc_ubus_object_subscribed(uc_vm_t *vm, size_t nargs) 1425 { 1426 uc_ubus_object_t *uuobj = uc_fn_thisval("ubus.object"); 1427 1428 if (!uuobj) 1429 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context"); 1430 1431 ok_return(ucv_boolean_new(uuobj->obj.has_subscribers)); 1432 } 1433 1434 1435 /* 1436 * ubus object method call handling 1437 * -------------------------------------------------------------------------- 1438 */ 1439 1440 static int 1441 uc_ubus_object_call_args(struct ubus_object *obj, const char *ubus_method_name, 1442 struct blob_attr *msg, uc_value_t **res) 1443 { 1444 uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj; 1445 const struct ubus_method *method = NULL; 1446 const struct blobmsg_hdr *hdr; 1447 struct blob_attr *attr; 1448 size_t len; 1449 bool found; 1450 int i; 1451 1452 for (i = 0; i < obj->n_methods; i++) { 1453 if (!strcmp(obj->methods[i].name, ubus_method_name)) { 1454 method = &obj->methods[i]; 1455 break; 1456 } 1457 } 1458 1459 if (!method) 1460 return UBUS_STATUS_METHOD_NOT_FOUND; 1461 1462 len = blob_len(msg); 1463 1464 __blob_for_each_attr(attr, blob_data(msg), len) { 1465 if (!blobmsg_check_attr_len(attr, false, len)) 1466 return UBUS_STATUS_INVALID_ARGUMENT; 1467 1468 if (!blob_is_extended(attr)) 1469 return UBUS_STATUS_INVALID_ARGUMENT; 1470 1471 hdr = blob_data(attr); 1472 found = false; 1473 1474 for (i = 0; i < method->n_policy; i++) { 1475 if (blobmsg_namelen(hdr) != strlen(method->policy[i].name)) 1476 continue; 1477 1478 if (strcmp(method->policy[i].name, (char *)hdr->name)) 1479 continue; 1480 1481 /* named argument found but wrong type */ 1482 if (blob_id(attr) != method->policy[i].type) 1483 goto inval; 1484 1485 found = true; 1486 break; 1487 } 1488 1489 /* named argument not found in policy */ 1490 if (!found) 1491 goto inval; 1492 } 1493 1494 *res = blob_array_to_ucv(uuobj->vm, blob_data(msg), blob_len(msg), true); 1495 1496 return UBUS_STATUS_OK; 1497 1498 inval: 1499 *res = NULL; 1500 1501 return UBUS_STATUS_INVALID_ARGUMENT; 1502 } 1503 1504 static uc_value_t * 1505 uc_ubus_object_call_info(uc_vm_t *vm, 1506 struct ubus_context *ctx, struct ubus_request_data *req, 1507 struct ubus_object *obj, const char *ubus_method_name) 1508 { 1509 uc_value_t *info, *o; 1510 1511 info = ucv_object_new(vm); 1512 1513 o = ucv_object_new(vm); 1514 1515 ucv_object_add(o, "user", ucv_string_new(req->acl.user)); 1516 ucv_object_add(o, "group", ucv_string_new(req->acl.group)); 1517 1518 if (req->acl.object) 1519 ucv_object_add(o, "object", ucv_string_new(req->acl.object)); 1520 1521 ucv_object_add(info, "acl", o); 1522 1523 o = ucv_object_new(vm); 1524 1525 ucv_object_add(o, "id", ucv_int64_new(obj->id)); 1526 1527 if (obj->name) 1528 ucv_object_add(o, "name", ucv_string_new(obj->name)); 1529 1530 if (obj->path) 1531 ucv_object_add(o, "path", ucv_string_new(obj->path)); 1532 1533 ucv_object_add(info, "object", o); 1534 1535 if (ubus_method_name) 1536 ucv_object_add(info, "method", ucv_string_new(ubus_method_name)); 1537 1538 return info; 1539 } 1540 1541 static int 1542 uc_ubus_handle_reply_common(struct ubus_context *ctx, 1543 struct ubus_request_data *req, 1544 uc_vm_t *vm, uc_value_t *this, uc_value_t *func, 1545 uc_value_t *reqproto) 1546 { 1547 uc_ubus_connection_t *conn = container_of(ctx, uc_ubus_connection_t, ctx); 1548 uc_ubus_request_t *callctx = NULL; 1549 uc_value_t *reqobj, *res; 1550 int rv; 1551 1552 /* allocate deferred method call context */ 1553 reqobj = ucv_resource_create_ex(vm, "ubus.request", (void **)&callctx, 1, sizeof(*callctx)); 1554 1555 if (!callctx) 1556 return UBUS_STATUS_UNKNOWN_ERROR; 1557 1558 callctx->ctx = ctx; 1559 callctx->vm = vm; 1560 ucv_resource_value_set(reqobj, 0, ucv_get(conn->res)); 1561 1562 ubus_defer_request(ctx, req, &callctx->req); 1563 1564 /* fd is copied to deferred request. ensure it does not get closed early */ 1565 ubus_request_get_caller_fd(req); 1566 1567 if (reqproto) 1568 ucv_prototype_set(ucv_prototype_get(reqobj), reqproto); 1569 1570 /* push object context, handler and request object onto stack */ 1571 uc_vm_stack_push(vm, ucv_get(this)); 1572 uc_vm_stack_push(vm, ucv_get(func)); 1573 uc_vm_stack_push(vm, ucv_get(reqobj)); 1574 1575 /* execute request handler function */ 1576 switch (uc_vm_call(vm, true, 1)) { 1577 case EXCEPTION_NONE: 1578 res = uc_vm_stack_pop(vm); 1579 1580 /* The handler function invoked a nested aync ubus request and returned it */ 1581 if (ucv_resource_data(res, "ubus.deferred")) { 1582 /* Install guard timer in case the reply callback is never called */ 1583 callctx->timeout.cb = uc_ubus_request_timeout; 1584 uloop_timeout_set(&callctx->timeout, 10000 /* FIXME */); 1585 callctx->res = ucv_get(reqobj); 1586 ucv_resource_persistent_set(callctx->res, true); 1587 } 1588 1589 /* Otherwise, when the function returned an object, treat it as 1590 * reply data and conclude deferred request immediately */ 1591 else if (ucv_type(res) == UC_OBJECT) { 1592 blob_buf_init(&buf, 0); 1593 ucv_object_to_blob(res, &buf); 1594 ubus_send_reply(ctx, &callctx->req, buf.head); 1595 1596 uc_ubus_request_finish_common(callctx, UBUS_STATUS_OK); 1597 } 1598 1599 /* If neither a deferred ubus request, nor a plain object were 1600 * returned and if reqobj.reply() hasn't been called, immediately 1601 * finish deferred request with UBUS_STATUS_NO_DATA. */ 1602 else if (!callctx->replied && !callctx->deferred) { 1603 rv = UBUS_STATUS_NO_DATA; 1604 1605 if (ucv_type(res) == UC_INTEGER) { 1606 rv = (int)ucv_int64_get(res); 1607 1608 if (rv < 0 || rv > __UBUS_STATUS_LAST) 1609 rv = UBUS_STATUS_UNKNOWN_ERROR; 1610 } 1611 1612 uc_ubus_request_finish_common(callctx, rv); 1613 } 1614 1615 ucv_put(res); 1616 break; 1617 1618 /* if the handler function invoked exit(), forward exit status as ubus 1619 * return code, map out of range values to UBUS_STATUS_UNKNOWN_ERROR. */ 1620 case EXCEPTION_EXIT: 1621 rv = vm->arg.s32; 1622 1623 if (rv < UBUS_STATUS_OK || rv >= __UBUS_STATUS_LAST) 1624 rv = UBUS_STATUS_UNKNOWN_ERROR; 1625 1626 uc_ubus_request_finish_common(callctx, rv); 1627 break; 1628 1629 /* treat other exceptions as fatal and halt uloop */ 1630 default: 1631 uc_ubus_request_finish_common(callctx, UBUS_STATUS_UNKNOWN_ERROR); 1632 uc_ubus_vm_handle_exception(vm); 1633 break; 1634 } 1635 1636 /* release request object */ 1637 ucv_put(reqobj); 1638 1639 /* garbage collect */ 1640 ucv_gc(vm); 1641 1642 return UBUS_STATUS_OK; 1643 } 1644 1645 static int 1646 uc_ubus_object_call_cb(struct ubus_context *ctx, struct ubus_object *obj, 1647 struct ubus_request_data *req, const char *ubus_method_name, 1648 struct blob_attr *msg) 1649 { 1650 uc_value_t *func, *args = NULL, *reqproto, *methods; 1651 uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj; 1652 int rv; 1653 1654 methods = ucv_resource_value_get(uuobj->res, OBJ_RES_METHODS); 1655 func = ucv_object_get(ucv_object_get(methods, ubus_method_name, NULL), "call", NULL); 1656 1657 if (!ucv_is_callable(func)) 1658 return UBUS_STATUS_METHOD_NOT_FOUND; 1659 1660 rv = uc_ubus_object_call_args(obj, ubus_method_name, msg, &args); 1661 1662 if (rv != UBUS_STATUS_OK) 1663 return rv; 1664 1665 reqproto = ucv_object_new(uuobj->vm); 1666 1667 ucv_object_add(reqproto, "args", args); 1668 ucv_object_add(reqproto, "info", 1669 uc_ubus_object_call_info(uuobj->vm, ctx, req, obj, ubus_method_name)); 1670 1671 return uc_ubus_handle_reply_common(ctx, req, uuobj->vm, uuobj->res, func, reqproto); 1672 } 1673 1674 1675 /* 1676 * ubus object registration 1677 * -------------------------------------------------------------------------- 1678 */ 1679 1680 static void 1681 uc_ubus_object_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) 1682 { 1683 uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj; 1684 uc_value_t *func; 1685 1686 func = ucv_resource_value_get(uuobj->res, OBJ_RES_SUB_CB); 1687 1688 uc_vm_stack_push(uuobj->vm, ucv_get(uuobj->res)); 1689 uc_vm_stack_push(uuobj->vm, ucv_get(func)); 1690 1691 if (uc_ubus_vm_call(uuobj->vm, true, 0)) 1692 ucv_put(uc_vm_stack_pop(uuobj->vm)); 1693 } 1694 1695 static bool 1696 uc_ubus_object_methods_validate(uc_value_t *methods) 1697 { 1698 uc_value_t *func, *args; 1699 1700 ucv_object_foreach(methods, ubus_method_name, ubus_method_definition) { 1701 (void)ubus_method_name; 1702 1703 func = ucv_object_get(ubus_method_definition, "call", NULL); 1704 args = ucv_object_get(ubus_method_definition, "args", NULL); 1705 1706 if (!ucv_is_callable(func)) 1707 err_return(UBUS_STATUS_INVALID_ARGUMENT, 1708 "Method '%s' field 'call' is not a function value", 1709 ubus_method_name); 1710 1711 if (args) { 1712 if (ucv_type(args) != UC_OBJECT) 1713 err_return(UBUS_STATUS_INVALID_ARGUMENT, 1714 "Method '%s' field 'args' is not an object value", 1715 ubus_method_name); 1716 1717 ucv_object_foreach(args, ubus_argument_name, ubus_argument_typehint) { 1718 (void)ubus_argument_name; 1719 1720 switch (ucv_type(ubus_argument_typehint)) { 1721 case UC_BOOLEAN: 1722 case UC_INTEGER: 1723 case UC_DOUBLE: 1724 case UC_STRING: 1725 case UC_ARRAY: 1726 case UC_OBJECT: 1727 continue; 1728 1729 default: 1730 err_return(UBUS_STATUS_INVALID_ARGUMENT, 1731 "Method '%s' field 'args' argument '%s' hint has unsupported type %s", 1732 ubus_method_name, ubus_argument_name, 1733 ucv_typename(ubus_argument_typehint)); 1734 } 1735 } 1736 } 1737 } 1738 1739 ok_return(true); 1740 } 1741 1742 static bool 1743 uc_ubus_object_method_register(struct ubus_method *method, const char *ubus_method_name, 1744 uc_value_t *ubus_method_arguments) 1745 { 1746 struct blobmsg_policy *policy; 1747 enum blobmsg_type type; 1748 1749 method->name = strdup(ubus_method_name); 1750 method->policy = calloc(ucv_object_length(ubus_method_arguments), sizeof(*method->policy)); 1751 method->handler = uc_ubus_object_call_cb; 1752 1753 if (!method->name || !method->policy) 1754 return false; 1755 1756 ucv_object_foreach(ubus_method_arguments, ubus_argument_name, ubus_argument_typehint) { 1757 switch (ucv_type(ubus_argument_typehint)) { 1758 case UC_BOOLEAN: 1759 type = BLOBMSG_TYPE_INT8; 1760 break; 1761 1762 case UC_INTEGER: 1763 switch (ucv_int64_get(ubus_argument_typehint)) { 1764 case 8: 1765 type = BLOBMSG_TYPE_INT8; 1766 break; 1767 1768 case 16: 1769 type = BLOBMSG_TYPE_INT16; 1770 break; 1771 1772 case 64: 1773 type = BLOBMSG_TYPE_INT64; 1774 break; 1775 1776 default: 1777 type = BLOBMSG_TYPE_INT32; 1778 break; 1779 } 1780 1781 break; 1782 1783 case UC_DOUBLE: 1784 type = BLOBMSG_TYPE_DOUBLE; 1785 break; 1786 1787 case UC_ARRAY: 1788 type = BLOBMSG_TYPE_ARRAY; 1789 break; 1790 1791 case UC_OBJECT: 1792 type = BLOBMSG_TYPE_TABLE; 1793 break; 1794 1795 default: 1796 type = BLOBMSG_TYPE_STRING; 1797 break; 1798 } 1799 1800 policy = (struct blobmsg_policy *)&method->policy[method->n_policy++]; 1801 policy->type = type; 1802 policy->name = strdup(ubus_argument_name); 1803 1804 if (!policy->name) 1805 return false; 1806 } 1807 1808 return true; 1809 } 1810 1811 static uc_ubus_object_t * 1812 uc_ubus_object_register(uc_vm_t *vm, uc_ubus_connection_t *c, const char *ubus_object_name, 1813 uc_value_t *ubus_object_methods) 1814 { 1815 struct ubus_context *ctx = &c->ctx; 1816 const struct blobmsg_policy *policy; 1817 uc_ubus_object_t *uuobj = NULL; 1818 int rv = UBUS_STATUS_UNKNOWN_ERROR; 1819 char *tnptr, *onptr; 1820 struct ubus_method *method; 1821 struct ubus_object *obj; 1822 size_t len, typelen, namelen, methodlen; 1823 uc_value_t *args, *res; 1824 1825 namelen = strlen(ubus_object_name); 1826 typelen = strlen("ucode-ubus-") + namelen; 1827 methodlen = ucv_object_length(ubus_object_methods) * sizeof(struct ubus_method); 1828 len = sizeof(*uuobj) + methodlen + namelen + 1 + typelen + 1; 1829 1830 res = ucv_resource_create_ex(vm, "ubus.object", (void **)&uuobj, __OBJ_RES_MAX, len); 1831 1832 if (!uuobj) 1833 err_return(rv, "Out of memory"); 1834 1835 method = uuobj->methods; 1836 1837 obj = &uuobj->obj; 1838 obj->methods = method; 1839 1840 if (ubus_object_methods) { 1841 ucv_object_foreach(ubus_object_methods, ubus_method_name, ubus_method_definition) { 1842 args = ucv_object_get(ubus_method_definition, "args", NULL); 1843 1844 if (!uc_ubus_object_method_register(&method[obj->n_methods++], ubus_method_name, args)) 1845 goto out; 1846 } 1847 } 1848 1849 onptr = (char *)&uuobj->methods[obj->n_methods]; 1850 tnptr = onptr + namelen + 1; 1851 1852 snprintf(tnptr, typelen, "ucode-ubus-%s", ubus_object_name); 1853 obj->name = memcpy(onptr, ubus_object_name, namelen); 1854 1855 obj->type = (struct ubus_object_type *)&uuobj->type; 1856 obj->type->name = tnptr; 1857 obj->type->methods = obj->methods; 1858 obj->type->n_methods = obj->n_methods; 1859 1860 rv = ubus_add_object(ctx, obj); 1861 1862 if (rv != UBUS_STATUS_OK) 1863 goto out; 1864 1865 uuobj->vm = vm; 1866 uuobj->ctx = ctx; 1867 uuobj->res = ucv_get(res); 1868 ucv_resource_persistent_set(res, true); 1869 ucv_resource_value_set(res, OBJ_RES_CONN, ucv_get(c->res)); 1870 ucv_resource_value_set(res, OBJ_RES_METHODS, ucv_get(ubus_object_methods)); 1871 1872 return uuobj; 1873 1874 out: 1875 for (; obj->n_methods > 0; method++, obj->n_methods--) { 1876 for (policy = method->policy; method->n_policy > 0; policy++, method->n_policy--) 1877 free((char *)policy->name); 1878 1879 free((char *)method->name); 1880 free((char *)method->policy); 1881 } 1882 1883 ucv_put(res); 1884 1885 err_return(rv, "Unable to add ubus object"); 1886 } 1887 1888 static uc_value_t * 1889 uc_ubus_publish(uc_vm_t *vm, size_t nargs) 1890 { 1891 uc_value_t *objname, *methods, *subscribecb; 1892 uc_ubus_connection_t *c; 1893 uc_ubus_object_t *uuobj; 1894 1895 conn_get(vm, &c); 1896 1897 args_get(vm, nargs, 1898 "object name", UC_STRING, false, &objname, 1899 "object methods", UC_OBJECT, true, &methods, 1900 "subscribe callback", UC_CLOSURE, true, &subscribecb); 1901 1902 if (!methods && !subscribecb) 1903 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either methods or subscribe callback required"); 1904 1905 if (methods && !uc_ubus_object_methods_validate(methods)) 1906 return NULL; 1907 1908 uuobj = uc_ubus_object_register(vm, c, ucv_string_get(objname), methods); 1909 1910 if (!uuobj) 1911 return NULL; 1912 1913 if (subscribecb) { 1914 uuobj->obj.subscribe_cb = uc_ubus_object_subscribe_cb; 1915 ucv_resource_value_set(uuobj->res, OBJ_RES_SUB_CB, ucv_get(subscribecb)); 1916 } 1917 1918 ok_return(uuobj->res); 1919 } 1920 1921 1922 /* 1923 * ubus events 1924 * -------------------------------------------------------------------------- 1925 */ 1926 1927 static int 1928 uc_ubus_listener_remove_common(uc_ubus_listener_t *uul) 1929 { 1930 int rv = ubus_unregister_event_handler(uul->ctx, &uul->ev); 1931 1932 if (rv == UBUS_STATUS_OK) 1933 uc_ubus_put_res(&uul->res); 1934 1935 return rv; 1936 } 1937 1938 static uc_value_t * 1939 uc_ubus_listener_remove(uc_vm_t *vm, size_t nargs) 1940 { 1941 uc_ubus_listener_t *uul = uc_fn_thisval("ubus.listener"); 1942 int rv; 1943 1944 rv = uc_ubus_listener_remove_common(uul); 1945 1946 if (rv != UBUS_STATUS_OK) 1947 err_return(rv, "Failed to remove listener object"); 1948 1949 ok_return(ucv_boolean_new(true)); 1950 } 1951 1952 static void 1953 uc_ubus_listener_cb(struct ubus_context *ctx, struct ubus_event_handler *ev, 1954 const char *type, struct blob_attr *msg) 1955 { 1956 uc_ubus_listener_t *uul = (uc_ubus_listener_t *)ev; 1957 uc_value_t *this, *func; 1958 uc_vm_t *vm = uul->vm; 1959 1960 this = uul->res; 1961 func = ucv_resource_value_get(this, 0); 1962 1963 uc_vm_stack_push(vm, ucv_get(this)); 1964 uc_vm_stack_push(vm, ucv_get(func)); 1965 uc_vm_stack_push(vm, ucv_string_new(type)); 1966 uc_vm_stack_push(vm, blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true)); 1967 1968 if (uc_ubus_vm_call(vm, true, 2)) 1969 ucv_put(uc_vm_stack_pop(vm)); 1970 } 1971 1972 static uc_value_t * 1973 uc_ubus_listener(uc_vm_t *vm, size_t nargs) 1974 { 1975 uc_value_t *cb, *pattern; 1976 uc_ubus_connection_t *c; 1977 uc_ubus_listener_t *uul = NULL; 1978 uc_value_t *res; 1979 int rv; 1980 1981 conn_get(vm, &c); 1982 1983 args_get(vm, nargs, 1984 "event type pattern", UC_STRING, false, &pattern, 1985 "event callback", UC_CLOSURE, false, &cb); 1986 1987 res = ucv_resource_create_ex(vm, "ubus.listener", (void **)&uul, 1, sizeof(*uul)); 1988 1989 if (!uul) 1990 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory"); 1991 1992 uul->vm = vm; 1993 uul->ctx = &c->ctx; 1994 uul->res = res; 1995 uul->ev.cb = uc_ubus_listener_cb; 1996 1997 rv = ubus_register_event_handler(&c->ctx, &uul->ev, 1998 ucv_string_get(pattern)); 1999 2000 if (rv != UBUS_STATUS_OK) { 2001 ucv_put(res); 2002 err_return(rv, "Failed to register listener object"); 2003 } 2004 2005 ucv_resource_persistent_set(res, true); 2006 ucv_resource_value_set(res, 0, ucv_get(cb)); 2007 2008 ok_return(ucv_get(res)); 2009 } 2010 2011 static uc_value_t * 2012 uc_ubus_event(uc_vm_t *vm, size_t nargs) 2013 { 2014 uc_value_t *eventtype, *eventdata; 2015 uc_ubus_connection_t *c; 2016 int rv; 2017 2018 conn_get(vm, &c); 2019 2020 args_get(vm, nargs, 2021 "event id", UC_STRING, false, &eventtype, 2022 "event data", UC_OBJECT, true, &eventdata); 2023 2024 blob_buf_init(&buf, 0); 2025 2026 if (eventdata) 2027 ucv_object_to_blob(eventdata, &buf); 2028 2029 rv = ubus_send_event(&c->ctx, ucv_string_get(eventtype), buf.head); 2030 2031 if (rv != UBUS_STATUS_OK) 2032 err_return(rv, "Unable to send event"); 2033 2034 ok_return(ucv_boolean_new(true)); 2035 } 2036 2037 2038 /* 2039 * ubus subscriptions 2040 * -------------------------------------------------------------------------- 2041 */ 2042 2043 static int 2044 uc_ubus_subscriber_notify_cb(struct ubus_context *ctx, struct ubus_object *obj, 2045 struct ubus_request_data *req, const char *method, 2046 struct blob_attr *msg) 2047 { 2048 struct ubus_subscriber *sub = container_of(obj, struct ubus_subscriber, obj); 2049 uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub); 2050 uc_value_t *this, *func, *reqproto; 2051 2052 this = uusub->res; 2053 func = ucv_resource_value_get(this, SUB_RES_NOTIFY_CB); 2054 2055 if (!ucv_is_callable(func)) 2056 return UBUS_STATUS_METHOD_NOT_FOUND; 2057 2058 reqproto = ucv_object_new(uusub->vm); 2059 2060 ucv_object_add(reqproto, "type", ucv_string_new(method)); 2061 2062 ucv_object_add(reqproto, "data", 2063 blob_array_to_ucv(uusub->vm, blob_data(msg), blob_len(msg), true)); 2064 2065 ucv_object_add(reqproto, "info", 2066 uc_ubus_object_call_info(uusub->vm, ctx, req, obj, NULL)); 2067 2068 return uc_ubus_handle_reply_common(ctx, req, uusub->vm, this, func, reqproto); 2069 } 2070 2071 static void 2072 uc_ubus_subscriber_remove_cb(struct ubus_context *ctx, 2073 struct ubus_subscriber *sub, uint32_t id) 2074 { 2075 uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub); 2076 uc_value_t *this, *func; 2077 uc_vm_t *vm = uusub->vm; 2078 2079 this = uusub->res; 2080 func = ucv_resource_value_get(this, SUB_RES_REMOVE_CB); 2081 2082 if (!ucv_is_callable(func)) 2083 return; 2084 2085 uc_vm_stack_push(vm, ucv_get(this)); 2086 uc_vm_stack_push(vm, ucv_get(func)); 2087 uc_vm_stack_push(vm, ucv_uint64_new(id)); 2088 2089 if (uc_ubus_vm_call(vm, true, 1)) 2090 ucv_put(uc_vm_stack_pop(vm)); 2091 } 2092 2093 static uc_value_t * 2094 uc_ubus_subscriber_subunsub_common(uc_vm_t *vm, size_t nargs, bool subscribe) 2095 { 2096 uc_ubus_subscriber_t *uusub = uc_fn_thisval("ubus.subscriber"); 2097 uc_value_t *objname; 2098 uint32_t id; 2099 int rv; 2100 2101 if (!uusub) 2102 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context"); 2103 2104 args_get(vm, nargs, 2105 "object name", UC_STRING, false, &objname); 2106 2107 rv = ubus_lookup_id(uusub->ctx, ucv_string_get(objname), &id); 2108 2109 if (rv != UBUS_STATUS_OK) 2110 err_return(rv, "Failed to resolve object name '%s'", 2111 ucv_string_get(objname)); 2112 2113 if (subscribe) 2114 rv = ubus_subscribe(uusub->ctx, &uusub->sub, id); 2115 else 2116 rv = ubus_unsubscribe(uusub->ctx, &uusub->sub, id); 2117 2118 if (rv != UBUS_STATUS_OK) 2119 err_return(rv, "Failed to %s object '%s'", 2120 subscribe ? "subscribe" : "unsubscribe", 2121 ucv_string_get(objname)); 2122 2123 ok_return(ucv_boolean_new(true)); 2124 } 2125 2126 static uc_value_t * 2127 uc_ubus_subscriber_subscribe(uc_vm_t *vm, size_t nargs) 2128 { 2129 return uc_ubus_subscriber_subunsub_common(vm, nargs, true); 2130 } 2131 2132 static uc_value_t * 2133 uc_ubus_subscriber_unsubscribe(uc_vm_t *vm, size_t nargs) 2134 { 2135 return uc_ubus_subscriber_subunsub_common(vm, nargs, false); 2136 } 2137 2138 static int 2139 uc_ubus_subscriber_remove_common(uc_ubus_subscriber_t *uusub) 2140 { 2141 int rv = ubus_unregister_subscriber(uusub->ctx, &uusub->sub); 2142 2143 if (rv == UBUS_STATUS_OK) 2144 uc_ubus_put_res(&uusub->res); 2145 2146 return rv; 2147 } 2148 2149 #ifdef HAVE_UBUS_NEW_OBJ_CB 2150 static bool 2151 uc_ubus_subscriber_new_object_cb(struct ubus_context *ctx, struct ubus_subscriber *sub, const char *path) 2152 { 2153 uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub); 2154 uc_value_t *patterns = ucv_resource_value_get(uusub->res, SUB_RES_PATTERNS); 2155 size_t len = ucv_array_length(patterns); 2156 2157 for (size_t i = 0; i < len; i++) { 2158 uc_value_t *val = ucv_array_get(patterns, i); 2159 const char *pattern; 2160 2161 if (ucv_type(val) != UC_STRING) 2162 continue; 2163 2164 pattern = ucv_string_get(val); 2165 2166 if (fnmatch(pattern, path, 0) == 0) 2167 return true; 2168 } 2169 2170 return false; 2171 } 2172 #endif 2173 2174 static uc_value_t * 2175 uc_ubus_subscriber_remove(uc_vm_t *vm, size_t nargs) 2176 { 2177 uc_ubus_subscriber_t *uusub = uc_fn_thisval("ubus.subscriber"); 2178 int rv; 2179 2180 if (!uusub) 2181 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context"); 2182 2183 rv = uc_ubus_subscriber_remove_common(uusub); 2184 2185 if (rv != UBUS_STATUS_OK) 2186 err_return(rv, "Failed to remove subscriber object"); 2187 2188 ok_return(ucv_boolean_new(true)); 2189 } 2190 2191 static uc_value_t * 2192 uc_ubus_subscriber(uc_vm_t *vm, size_t nargs) 2193 { 2194 uc_value_t *notify_cb, *remove_cb, *subscriptions; 2195 uc_ubus_subscriber_t *uusub = NULL; 2196 uc_ubus_connection_t *c; 2197 uc_value_t *res; 2198 int rv; 2199 2200 conn_get(vm, &c); 2201 2202 args_get(vm, nargs, 2203 "notify callback", UC_CLOSURE, true, ¬ify_cb, 2204 "remove callback", UC_CLOSURE, true, &remove_cb, 2205 "subscription patterns", UC_ARRAY, true, &subscriptions); 2206 2207 if (!notify_cb && !remove_cb) 2208 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either notify or remove callback required"); 2209 2210 res = ucv_resource_create_ex(vm, "ubus.subscriber", (void **)&uusub, __SUB_RES_MAX, sizeof(*uusub)); 2211 2212 if (!uusub) 2213 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Out of memory"); 2214 2215 uusub->vm = vm; 2216 uusub->ctx = &c->ctx; 2217 uusub->res = ucv_get(res); 2218 2219 ucv_resource_value_set(res, SUB_RES_NOTIFY_CB, ucv_get(notify_cb)); 2220 ucv_resource_value_set(res, SUB_RES_REMOVE_CB, ucv_get(remove_cb)); 2221 ucv_resource_value_set(res, SUB_RES_PATTERNS, ucv_get(subscriptions)); 2222 2223 #ifdef HAVE_UBUS_NEW_OBJ_CB 2224 if (subscriptions) 2225 uusub->sub.new_obj_cb = uc_ubus_subscriber_new_object_cb; 2226 #endif 2227 2228 rv = ubus_register_subscriber(&c->ctx, &uusub->sub); 2229 2230 if (rv != UBUS_STATUS_OK) { 2231 ucv_put(uusub->res); 2232 ucv_put(res); 2233 err_return(rv, "Failed to register subscriber object"); 2234 } 2235 2236 if (notify_cb) 2237 uusub->sub.cb = uc_ubus_subscriber_notify_cb; 2238 2239 if (remove_cb) 2240 uusub->sub.remove_cb = uc_ubus_subscriber_remove_cb; 2241 2242 ucv_resource_persistent_set(res, true); 2243 2244 ok_return(res); 2245 } 2246 2247 2248 /* 2249 * connection methods 2250 * -------------------------------------------------------------------------- 2251 */ 2252 2253 static uc_value_t * 2254 uc_ubus_remove(uc_vm_t *vm, size_t nargs) 2255 { 2256 uc_ubus_subscriber_t **uusub; 2257 uc_ubus_connection_t *c; 2258 uc_ubus_object_t *uuobj; 2259 uc_ubus_listener_t **uul; 2260 int rv; 2261 2262 conn_get(vm, &c); 2263 2264 uusub = (uc_ubus_subscriber_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.subscriber"); 2265 uuobj = (uc_ubus_object_t *)ucv_resource_data(uc_fn_arg(0), "ubus.object"); 2266 uul = (uc_ubus_listener_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.listener"); 2267 2268 if (uusub && *uusub) { 2269 if ((*uusub)->ctx != &c->ctx) 2270 err_return(UBUS_STATUS_INVALID_ARGUMENT, 2271 "Subscriber belongs to different connection"); 2272 2273 rv = uc_ubus_subscriber_remove_common(*uusub); 2274 2275 if (rv != UBUS_STATUS_OK) 2276 err_return(rv, "Unable to remove subscriber"); 2277 } 2278 else if (uuobj) { 2279 if (uuobj->ctx != &c->ctx) 2280 err_return(UBUS_STATUS_INVALID_ARGUMENT, 2281 "Object belongs to different connection"); 2282 2283 rv = uc_ubus_object_remove_common(uuobj); 2284 2285 if (rv != UBUS_STATUS_OK) 2286 err_return(rv, "Unable to remove object"); 2287 } 2288 else if (uul && *uul) { 2289 if ((*uul)->ctx != &c->ctx) 2290 err_return(UBUS_STATUS_INVALID_ARGUMENT, 2291 "Listener belongs to different connection"); 2292 2293 rv = uc_ubus_listener_remove_common(*uul); 2294 2295 if (rv != UBUS_STATUS_OK) 2296 err_return(rv, "Unable to remove listener"); 2297 } 2298 else { 2299 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Unhandled resource type"); 2300 } 2301 2302 ok_return(ucv_boolean_new(true)); 2303 } 2304 2305 2306 static uc_value_t * 2307 uc_ubus_disconnect(uc_vm_t *vm, size_t nargs) 2308 { 2309 uc_ubus_connection_t *c; 2310 2311 conn_get(vm, &c); 2312 2313 ubus_shutdown(&c->ctx); 2314 c->ctx.sock.fd = -1; 2315 uc_ubus_put_res(&c->res); 2316 2317 ok_return(ucv_boolean_new(true)); 2318 } 2319 2320 static uc_value_t * 2321 uc_ubus_defer_completed(uc_vm_t *vm, size_t nargs) 2322 { 2323 uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred"); 2324 2325 if (!d) 2326 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context"); 2327 2328 ok_return(ucv_boolean_new(d->complete)); 2329 } 2330 2331 static uc_value_t * 2332 uc_ubus_defer_await(uc_vm_t *vm, size_t nargs) 2333 { 2334 uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred"); 2335 int64_t remaining; 2336 2337 if (!d) 2338 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context"); 2339 2340 if (d->complete) 2341 ok_return(ucv_boolean_new(false)); 2342 2343 #ifdef HAVE_ULOOP_TIMEOUT_REMAINING64 2344 remaining = uloop_timeout_remaining64(&d->timeout); 2345 #else 2346 remaining = uloop_timeout_remaining(&d->timeout); 2347 #endif 2348 2349 ubus_complete_request(d->ctx, &d->request, remaining); 2350 2351 ok_return(ucv_boolean_new(true)); 2352 } 2353 2354 static uc_value_t * 2355 uc_ubus_defer_abort(uc_vm_t *vm, size_t nargs) 2356 { 2357 uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred"); 2358 2359 if (!d) 2360 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context"); 2361 2362 if (d->complete) 2363 ok_return(ucv_boolean_new(false)); 2364 2365 ubus_abort_request(d->ctx, &d->request); 2366 uloop_timeout_cancel(&d->timeout); 2367 2368 uc_ubus_put_res(&d->res); 2369 d->complete = true; 2370 2371 ok_return(ucv_boolean_new(true)); 2372 } 2373 2374 /* 2375 * channel related methods 2376 * -------------------------------------------------------------------------- 2377 */ 2378 2379 #ifdef HAVE_UBUS_CHANNEL_SUPPORT 2380 static int 2381 uc_ubus_channel_req_cb(struct ubus_context *ctx, struct ubus_object *obj, 2382 struct ubus_request_data *req, const char *method, 2383 struct blob_attr *msg) 2384 { 2385 uc_ubus_connection_t *c = container_of(ctx, uc_ubus_connection_t, ctx); 2386 uc_value_t *func, *args, *reqproto; 2387 2388 func = ucv_resource_value_get(c->res, CONN_RES_CB); 2389 2390 if (!ucv_is_callable(func)) 2391 return UBUS_STATUS_METHOD_NOT_FOUND; 2392 2393 args = blob_array_to_ucv(c->vm, blob_data(msg), blob_len(msg), true); 2394 reqproto = ucv_object_new(c->vm); 2395 ucv_object_add(reqproto, "args", ucv_get(args)); 2396 2397 if (method) 2398 ucv_object_add(reqproto, "type", ucv_get(ucv_string_new(method))); 2399 2400 return uc_ubus_handle_reply_common(ctx, req, c->vm, c->res, func, reqproto); 2401 } 2402 2403 static void 2404 uc_ubus_channel_disconnect_cb(struct ubus_context *ctx) 2405 { 2406 uc_ubus_connection_t *c = container_of(ctx, uc_ubus_connection_t, ctx); 2407 uc_value_t *func; 2408 2409 func = ucv_resource_value_get(c->res, CONN_RES_DISCONNECT_CB); 2410 2411 if (ucv_is_callable(func)) { 2412 uc_vm_stack_push(c->vm, ucv_get(c->res)); 2413 uc_vm_stack_push(c->vm, ucv_get(func)); 2414 2415 if (uc_ubus_vm_call(c->vm, true, 0)) 2416 ucv_put(uc_vm_stack_pop(c->vm)); 2417 } 2418 2419 blob_buf_free(&c->buf); 2420 2421 if (c->ctx.sock.fd >= 0) { 2422 ubus_shutdown(&c->ctx); 2423 c->ctx.sock.fd = -1; 2424 } 2425 2426 uc_ubus_put_res(&c->res); 2427 } 2428 2429 static uc_value_t * 2430 uc_ubus_channel_add(uc_ubus_connection_t *c, uc_value_t *cb, 2431 uc_value_t *disconnect_cb, uc_value_t *fd) 2432 { 2433 ucv_resource_persistent_set(c->res, true); 2434 ucv_resource_value_set(c->res, CONN_RES_FD, ucv_get(fd)); 2435 ucv_resource_value_set(c->res, CONN_RES_CB, ucv_get(cb)); 2436 ucv_resource_value_set(c->res, CONN_RES_DISCONNECT_CB, ucv_get(disconnect_cb)); 2437 c->ctx.connection_lost = uc_ubus_channel_disconnect_cb; 2438 ubus_add_uloop(&c->ctx); 2439 2440 ok_return(ucv_get(c->res)); 2441 } 2442 2443 #endif 2444 2445 static uc_value_t * 2446 uc_ubus_request_new_channel(uc_vm_t *vm, size_t nargs) 2447 { 2448 #ifdef HAVE_UBUS_CHANNEL_SUPPORT 2449 uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request"); 2450 uc_value_t *cb, *disconnect_cb, *timeout; 2451 uc_ubus_connection_t *c; 2452 int fd; 2453 2454 if (!callctx) 2455 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context"); 2456 2457 args_get(vm, nargs, 2458 "cb", UC_CLOSURE, true, &cb, 2459 "disconnect_cb", UC_CLOSURE, true, &disconnect_cb, 2460 "timeout", UC_INTEGER, true, &timeout); 2461 2462 c = uc_ubus_conn_alloc(vm, timeout, "ubus.channel"); 2463 2464 if (!c) 2465 return NULL; 2466 2467 if (ubus_channel_create(&c->ctx, &fd, cb ? uc_ubus_channel_req_cb : NULL)) { 2468 ucv_put(c->res); 2469 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel"); 2470 } 2471 2472 ubus_request_set_fd(callctx->ctx, &callctx->req, fd); 2473 2474 return uc_ubus_channel_add(c, cb, disconnect_cb, NULL); 2475 #else 2476 err_return(UBUS_STATUS_NOT_SUPPORTED, "No ubus channel support"); 2477 #endif 2478 } 2479 2480 2481 static uc_value_t * 2482 uc_ubus_channel_connect(uc_vm_t *vm, size_t nargs) 2483 { 2484 #ifdef HAVE_UBUS_CHANNEL_SUPPORT 2485 uc_value_t *fd, *cb, *disconnect_cb, *timeout; 2486 uc_ubus_connection_t *c; 2487 int fd_val; 2488 2489 args_get(vm, nargs, 2490 "fd", UC_NULL, false, &fd, 2491 "cb", UC_CLOSURE, true, &cb, 2492 "disconnect_cb", UC_CLOSURE, true, &disconnect_cb, 2493 "timeout", UC_INTEGER, true, &timeout); 2494 2495 fd_val = get_fd(vm, fd); 2496 2497 if (fd_val < 0) 2498 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor argument"); 2499 2500 c = uc_ubus_conn_alloc(vm, timeout, "ubus.channel"); 2501 2502 if (!c) 2503 return NULL; 2504 2505 if (ubus_channel_connect(&c->ctx, fd_val, cb ? uc_ubus_channel_req_cb : NULL)) { 2506 ucv_put(c->res); 2507 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel"); 2508 } 2509 2510 return uc_ubus_channel_add(c, cb, disconnect_cb, fd); 2511 #else 2512 err_return(UBUS_STATUS_NOT_SUPPORTED, "No ubus channel support"); 2513 #endif 2514 } 2515 2516 2517 static uc_value_t * 2518 uc_ubus_guard(uc_vm_t *vm, size_t nargs) 2519 { 2520 uc_value_t *arg = uc_fn_arg(0); 2521 2522 if (!nargs) 2523 return ucv_get(uc_vm_registry_get(vm, "ubus.ex_handler")); 2524 2525 if (arg && !ucv_is_callable(arg)) 2526 return NULL; 2527 2528 uc_vm_registry_set(vm, "ubus.ex_handler", ucv_get(arg)); 2529 2530 return ucv_boolean_new(true); 2531 } 2532 2533 2534 static const uc_function_list_t global_fns[] = { 2535 { "error", uc_ubus_error }, 2536 { "connect", uc_ubus_connect }, 2537 { "open_channel", uc_ubus_channel_connect }, 2538 { "guard", uc_ubus_guard }, 2539 }; 2540 2541 static const uc_function_list_t conn_fns[] = { 2542 { "list", uc_ubus_list }, 2543 { "call", uc_ubus_call }, 2544 { "defer", uc_ubus_defer }, 2545 { "publish", uc_ubus_publish }, 2546 { "remove", uc_ubus_remove }, 2547 { "listener", uc_ubus_listener }, 2548 { "subscriber", uc_ubus_subscriber }, 2549 { "event", uc_ubus_event }, 2550 { "error", uc_ubus_error }, 2551 { "disconnect", uc_ubus_disconnect }, 2552 }; 2553 2554 static const uc_function_list_t chan_fns[] = { 2555 { "request", uc_ubus_chan_request }, 2556 { "defer", uc_ubus_chan_defer }, 2557 { "error", uc_ubus_error }, 2558 { "disconnect", uc_ubus_disconnect }, 2559 }; 2560 2561 static const uc_function_list_t defer_fns[] = { 2562 { "await", uc_ubus_defer_await }, 2563 { "completed", uc_ubus_defer_completed }, 2564 { "abort", uc_ubus_defer_abort }, 2565 }; 2566 2567 static const uc_function_list_t object_fns[] = { 2568 { "subscribed", uc_ubus_object_subscribed }, 2569 { "notify", uc_ubus_object_notify }, 2570 { "remove", uc_ubus_object_remove }, 2571 }; 2572 2573 static const uc_function_list_t request_fns[] = { 2574 { "reply", uc_ubus_request_reply }, 2575 { "error", uc_ubus_request_error }, 2576 { "defer", uc_ubus_request_defer }, 2577 { "get_fd", uc_ubus_request_get_fd }, 2578 { "set_fd", uc_ubus_request_set_fd }, 2579 { "new_channel", uc_ubus_request_new_channel }, 2580 }; 2581 2582 static const uc_function_list_t notify_fns[] = { 2583 { "completed", uc_ubus_notify_completed }, 2584 { "abort", uc_ubus_notify_abort }, 2585 }; 2586 2587 static const uc_function_list_t listener_fns[] = { 2588 { "remove", uc_ubus_listener_remove }, 2589 }; 2590 2591 static const uc_function_list_t subscriber_fns[] = { 2592 { "subscribe", uc_ubus_subscriber_subscribe }, 2593 { "unsubscribe", uc_ubus_subscriber_unsubscribe }, 2594 { "remove", uc_ubus_subscriber_remove }, 2595 }; 2596 2597 static void free_connection(void *ud) { 2598 uc_ubus_connection_t *conn = ud; 2599 2600 blob_buf_free(&conn->buf); 2601 2602 if (conn->ctx.sock.fd >= 0) 2603 ubus_shutdown(&conn->ctx); 2604 } 2605 2606 static void free_deferred(void *ud) { 2607 uc_ubus_deferred_t *defer = ud; 2608 2609 uloop_timeout_cancel(&defer->timeout); 2610 } 2611 2612 static void free_object(void *ud) { 2613 uc_ubus_object_t *uuobj = ud; 2614 struct ubus_object *obj = &uuobj->obj; 2615 int i, j; 2616 2617 for (i = 0; i < obj->n_methods; i++) { 2618 for (j = 0; j < obj->methods[i].n_policy; j++) 2619 free((char *)obj->methods[i].policy[j].name); 2620 2621 free((char *)obj->methods[i].name); 2622 free((char *)obj->methods[i].policy); 2623 } 2624 } 2625 2626 static void free_request(void *ud) { 2627 uc_ubus_request_t *callctx = ud; 2628 2629 uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT); 2630 } 2631 2632 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 2633 { 2634 uc_function_list_register(scope, global_fns); 2635 uc_function_list_register(scope, conn_fns); 2636 2637 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(UBUS_##x)) 2638 ADD_CONST(STATUS_OK); 2639 ADD_CONST(STATUS_INVALID_COMMAND); 2640 ADD_CONST(STATUS_INVALID_ARGUMENT); 2641 ADD_CONST(STATUS_METHOD_NOT_FOUND); 2642 ADD_CONST(STATUS_NOT_FOUND); 2643 ADD_CONST(STATUS_NO_DATA); 2644 ADD_CONST(STATUS_PERMISSION_DENIED); 2645 ADD_CONST(STATUS_TIMEOUT); 2646 ADD_CONST(STATUS_NOT_SUPPORTED); 2647 ADD_CONST(STATUS_UNKNOWN_ERROR); 2648 ADD_CONST(STATUS_CONNECTION_FAILED); 2649 2650 #ifdef HAVE_NEW_UBUS_STATUS_CODES 2651 ADD_CONST(STATUS_NO_MEMORY); 2652 ADD_CONST(STATUS_PARSE_ERROR); 2653 ADD_CONST(STATUS_SYSTEM_ERROR); 2654 #endif 2655 2656 /* virtual status code for reply */ 2657 #define UBUS_STATUS_CONTINUE -1 2658 ADD_CONST(STATUS_CONTINUE); 2659 2660 ADD_CONST(SYSTEM_OBJECT_ACL); 2661 2662 uc_type_declare(vm, "ubus.connection", conn_fns, free_connection); 2663 uc_type_declare(vm, "ubus.channel", chan_fns, free_connection); 2664 uc_type_declare(vm, "ubus.deferred", defer_fns, free_deferred); 2665 uc_type_declare(vm, "ubus.object", object_fns, free_object); 2666 uc_type_declare(vm, "ubus.notify", notify_fns, NULL); 2667 uc_type_declare(vm, "ubus.request", request_fns, free_request); 2668 uc_type_declare(vm, "ubus.listener", listener_fns, NULL); 2669 uc_type_declare(vm, "ubus.subscriber", subscriber_fns, NULL); 2670 } 2671
This page was automatically generated by LXR 0.3.1. • OpenWrt