1 /* 2 * netifd - network interface daemon 3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 7 * as published by the Free Software Foundation 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 #define _GNU_SOURCE 15 16 #include <string.h> 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <signal.h> 20 21 #include <arpa/inet.h> 22 #include <netinet/in.h> 23 24 25 #include "netifd.h" 26 #include "interface.h" 27 #include "interface-ip.h" 28 #include "proto.h" 29 #include "system.h" 30 #include "handler.h" 31 32 static int proto_fd = -1; 33 34 enum proto_shell_sm { 35 S_IDLE, 36 S_SETUP, 37 S_SETUP_ABORT, 38 S_TEARDOWN, 39 }; 40 41 struct proto_shell_handler { 42 struct list_head list; 43 struct proto_handler proto; 44 char *config_buf; 45 char *script_name; 46 bool init_available; 47 48 struct uci_blob_param_list config; 49 }; 50 51 struct proto_shell_dependency { 52 struct list_head list; 53 54 struct proto_shell_state *proto; 55 struct interface_user dep; 56 57 union if_addr host; 58 bool v6; 59 bool any; 60 61 char interface[]; 62 }; 63 64 struct proto_shell_state { 65 struct interface_proto_state proto; 66 struct proto_shell_handler *handler; 67 struct blob_attr *config; 68 69 struct uloop_timeout teardown_timeout; 70 71 /* 72 * Teardown and setup interface again if it is still not up (IFS_UP) 73 * after checkup_interval seconds since previous attempt. This check 74 * will be disabled when the config option "checkup_interval" is 75 * missing or has a negative value 76 */ 77 int checkup_interval; 78 struct uloop_timeout checkup_timeout; 79 80 struct netifd_process script_task; 81 struct netifd_process proto_task; 82 83 enum proto_shell_sm sm; 84 bool proto_task_killed; 85 bool renew_pending; 86 87 int last_error; 88 89 struct list_head deps; 90 }; 91 92 static void 93 proto_shell_check_dependencies(struct proto_shell_state *state) 94 { 95 struct proto_shell_dependency *dep; 96 bool available = true; 97 98 list_for_each_entry(dep, &state->deps, list) { 99 if (dep->dep.iface) 100 continue; 101 102 available = false; 103 break; 104 } 105 106 interface_set_available(state->proto.iface, available); 107 } 108 109 static void 110 proto_shell_if_up_cb(struct interface_user *dep, struct interface *iface, 111 enum interface_event ev); 112 static void 113 proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface, 114 enum interface_event ev); 115 116 static void 117 proto_shell_update_host_dep(struct proto_shell_dependency *dep) 118 { 119 struct interface *iface = NULL; 120 121 if (dep->dep.iface) 122 goto out; 123 124 if (dep->interface[0]) { 125 iface = vlist_find(&interfaces, dep->interface, iface, node); 126 127 if (!iface || iface->state != IFS_UP) 128 goto out; 129 } 130 131 if (!dep->any) 132 iface = interface_ip_add_target_route(&dep->host, dep->v6, iface, false); 133 134 if (!iface) 135 goto out; 136 137 interface_remove_user(&dep->dep); 138 dep->dep.cb = proto_shell_if_down_cb; 139 interface_add_user(&dep->dep, iface); 140 141 out: 142 proto_shell_check_dependencies(dep->proto); 143 } 144 145 static void 146 proto_shell_clear_host_dep(struct proto_shell_state *state) 147 { 148 struct proto_shell_dependency *dep, *tmp; 149 150 list_for_each_entry_safe(dep, tmp, &state->deps, list) { 151 interface_remove_user(&dep->dep); 152 list_del(&dep->list); 153 free(dep); 154 } 155 } 156 157 static int 158 proto_shell_handler(struct interface_proto_state *proto, 159 enum interface_proto_cmd cmd, bool force) 160 { 161 struct proto_shell_state *state; 162 struct proto_shell_handler *handler; 163 struct netifd_process *proc; 164 static char error_buf[32]; 165 const char *argv[7]; 166 char *envp[2]; 167 const char *action; 168 char *config; 169 int ret, i = 0, j = 0; 170 171 state = container_of(proto, struct proto_shell_state, proto); 172 handler = state->handler; 173 proc = &state->script_task; 174 175 if (cmd == PROTO_CMD_SETUP) { 176 switch (state->sm) { 177 case S_IDLE: 178 action = "setup"; 179 state->last_error = -1; 180 proto_shell_clear_host_dep(state); 181 state->sm = S_SETUP; 182 break; 183 184 default: 185 return -1; 186 } 187 } else if (cmd == PROTO_CMD_RENEW) { 188 if (!(handler->proto.flags & PROTO_FLAG_RENEW_AVAILABLE)) 189 return 0; 190 191 if (state->script_task.uloop.pending) { 192 state->renew_pending = true; 193 return 0; 194 } 195 196 state->renew_pending = false; 197 action = "renew"; 198 } else { 199 switch (state->sm) { 200 case S_SETUP: 201 if (state->script_task.uloop.pending) { 202 uloop_timeout_set(&state->teardown_timeout, 1000); 203 kill(state->script_task.uloop.pid, SIGTERM); 204 if (state->proto_task.uloop.pending) 205 kill(state->proto_task.uloop.pid, SIGTERM); 206 state->renew_pending = false; 207 state->sm = S_SETUP_ABORT; 208 return 0; 209 } 210 /* if no script task is running */ 211 fallthrough; 212 case S_IDLE: 213 action = "teardown"; 214 state->renew_pending = false; 215 state->sm = S_TEARDOWN; 216 if (state->last_error >= 0) { 217 snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error); 218 envp[j++] = error_buf; 219 } 220 uloop_timeout_set(&state->teardown_timeout, 5000); 221 break; 222 223 case S_TEARDOWN: 224 return 0; 225 226 default: 227 return -1; 228 } 229 } 230 231 D(INTERFACE, "run %s for interface '%s'", action, proto->iface->name); 232 config = blobmsg_format_json(state->config, true); 233 if (!config) 234 return -1; 235 236 argv[i++] = handler->script_name; 237 argv[i++] = handler->proto.name; 238 argv[i++] = action; 239 argv[i++] = proto->iface->name; 240 argv[i++] = config; 241 if (proto->iface->main_dev.dev) 242 argv[i++] = proto->iface->main_dev.dev->ifname; 243 argv[i] = NULL; 244 envp[j] = NULL; 245 246 ret = netifd_start_process(argv, envp, proc); 247 free(config); 248 249 return ret; 250 } 251 252 static void 253 proto_shell_if_up_cb(struct interface_user *dep, struct interface *iface, 254 enum interface_event ev) 255 { 256 struct proto_shell_dependency *pdep; 257 258 if (ev != IFEV_UP && ev != IFEV_UPDATE) 259 return; 260 261 pdep = container_of(dep, struct proto_shell_dependency, dep); 262 proto_shell_update_host_dep(pdep); 263 } 264 265 static void 266 proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface, 267 enum interface_event ev) 268 { 269 struct proto_shell_dependency *pdep; 270 struct proto_shell_state *state; 271 272 if (ev == IFEV_UP || ev == IFEV_UPDATE) 273 return; 274 275 pdep = container_of(dep, struct proto_shell_dependency, dep); 276 interface_remove_user(dep); 277 dep->cb = proto_shell_if_up_cb; 278 interface_add_user(dep, NULL); 279 280 state = pdep->proto; 281 if (state->sm == S_IDLE) { 282 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 283 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false); 284 } 285 } 286 287 static void 288 proto_shell_task_finish(struct proto_shell_state *state, 289 struct netifd_process *task) 290 { 291 switch (state->sm) { 292 case S_IDLE: 293 if (task == &state->proto_task) 294 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 295 fallthrough; 296 case S_SETUP: 297 if (task == &state->proto_task) 298 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, 299 false); 300 else if (task == &state->script_task) { 301 if (state->renew_pending) 302 proto_shell_handler(&state->proto, 303 PROTO_CMD_RENEW, false); 304 else if (!(state->handler->proto.flags & PROTO_FLAG_NO_TASK) && 305 !state->proto_task.uloop.pending && 306 state->sm == S_SETUP) 307 proto_shell_handler(&state->proto, 308 PROTO_CMD_TEARDOWN, 309 false); 310 311 /* check up status after setup attempt by this script_task */ 312 if (state->sm == S_SETUP && state->checkup_interval > 0) { 313 uloop_timeout_set(&state->checkup_timeout, 314 state->checkup_interval * 1000); 315 } 316 } 317 break; 318 319 case S_SETUP_ABORT: 320 if (state->script_task.uloop.pending || 321 state->proto_task.uloop.pending) 322 break; 323 324 /* completed aborting all tasks, now idle */ 325 uloop_timeout_cancel(&state->teardown_timeout); 326 uloop_timeout_cancel(&state->checkup_timeout); 327 state->sm = S_IDLE; 328 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false); 329 break; 330 331 case S_TEARDOWN: 332 if (state->script_task.uloop.pending) 333 break; 334 335 if (state->proto_task.uloop.pending) { 336 if (!state->proto_task_killed) 337 kill(state->proto_task.uloop.pid, SIGTERM); 338 break; 339 } 340 341 /* completed tearing down all tasks, now idle */ 342 uloop_timeout_cancel(&state->teardown_timeout); 343 uloop_timeout_cancel(&state->checkup_timeout); 344 state->sm = S_IDLE; 345 state->proto.proto_event(&state->proto, IFPEV_DOWN); 346 break; 347 } 348 } 349 350 static void 351 proto_shell_teardown_timeout_cb(struct uloop_timeout *timeout) 352 { 353 struct proto_shell_state *state; 354 355 state = container_of(timeout, struct proto_shell_state, teardown_timeout); 356 357 netifd_kill_process(&state->script_task); 358 netifd_kill_process(&state->proto_task); 359 proto_shell_task_finish(state, NULL); 360 } 361 362 static void 363 proto_shell_script_cb(struct netifd_process *p, int ret) 364 { 365 struct proto_shell_state *state; 366 367 state = container_of(p, struct proto_shell_state, script_task); 368 proto_shell_task_finish(state, p); 369 } 370 371 static void 372 proto_shell_task_cb(struct netifd_process *p, int ret) 373 { 374 struct proto_shell_state *state; 375 376 state = container_of(p, struct proto_shell_state, proto_task); 377 378 if (state->sm == S_IDLE || state->sm == S_SETUP) 379 state->last_error = WEXITSTATUS(ret); 380 381 proto_shell_task_finish(state, p); 382 } 383 384 static void 385 proto_shell_free(struct interface_proto_state *proto) 386 { 387 struct proto_shell_state *state; 388 389 state = container_of(proto, struct proto_shell_state, proto); 390 uloop_timeout_cancel(&state->teardown_timeout); 391 uloop_timeout_cancel(&state->checkup_timeout); 392 proto_shell_clear_host_dep(state); 393 netifd_kill_process(&state->script_task); 394 netifd_kill_process(&state->proto_task); 395 free(state->config); 396 free(state); 397 } 398 399 static void 400 proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr, 401 bool v6) 402 { 403 struct blob_attr *cur; 404 size_t rem; 405 406 blobmsg_for_each_attr(cur, attr, rem) { 407 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) { 408 D(INTERFACE, "Ignore wrong route type: %d", blobmsg_type(cur)); 409 continue; 410 } 411 412 interface_ip_add_route(iface, cur, v6); 413 } 414 } 415 416 static void 417 proto_shell_parse_neighbor_list(struct interface *iface, struct blob_attr *attr, 418 bool v6) 419 { 420 struct blob_attr *cur; 421 size_t rem; 422 423 blobmsg_for_each_attr(cur, attr, rem) { 424 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) { 425 D(INTERFACE, "Ignore wrong neighbor type: %d", blobmsg_type(cur)); 426 continue; 427 } 428 429 interface_ip_add_neighbor(iface, cur, v6); 430 } 431 } 432 433 static void 434 proto_shell_parse_data(struct interface *iface, struct blob_attr *attr) 435 { 436 struct blob_attr *cur; 437 size_t rem; 438 439 blobmsg_for_each_attr(cur, attr, rem) 440 interface_add_data(iface, cur); 441 } 442 443 static struct device * 444 proto_shell_create_tunnel(const char *name, struct blob_attr *attr) 445 { 446 struct device *dev; 447 struct blob_buf b; 448 449 memset(&b, 0, sizeof(b)); 450 blob_buf_init(&b, 0); 451 blob_put(&b, 0, blobmsg_data(attr), blobmsg_data_len(attr)); 452 dev = device_create(name, &tunnel_device_type, blob_data(b.head)); 453 blob_buf_free(&b); 454 455 return dev; 456 } 457 458 enum { 459 NOTIFY_ACTION, 460 NOTIFY_ERROR, 461 NOTIFY_COMMAND, 462 NOTIFY_ENV, 463 NOTIFY_SIGNAL, 464 NOTIFY_AVAILABLE, 465 NOTIFY_LINK_UP, 466 NOTIFY_IFNAME, 467 NOTIFY_ADDR_EXT, 468 NOTIFY_ROUTES, 469 NOTIFY_ROUTES6, 470 NOTIFY_TUNNEL, 471 NOTIFY_DATA, 472 NOTIFY_KEEP, 473 NOTIFY_HOST, 474 NOTIFY_DNS, 475 NOTIFY_DNS_SEARCH, 476 NOTIFY_NEIGHBORS, 477 NOTIFY_NEIGHBORS6, 478 __NOTIFY_LAST 479 }; 480 481 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = { 482 [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 }, 483 [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY }, 484 [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY }, 485 [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY }, 486 [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 }, 487 [NOTIFY_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL }, 488 [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL }, 489 [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, 490 [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL }, 491 [NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY }, 492 [NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY }, 493 [NOTIFY_TUNNEL] = { .name = "tunnel", .type = BLOBMSG_TYPE_TABLE }, 494 [NOTIFY_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 495 [NOTIFY_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, 496 [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING }, 497 [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY }, 498 [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY }, 499 [NOTIFY_NEIGHBORS]= {.name = "neighbor", .type = BLOBMSG_TYPE_ARRAY}, 500 [NOTIFY_NEIGHBORS6]= {.name = "neighbor6", .type = BLOBMSG_TYPE_ARRAY}, 501 }; 502 503 static int 504 proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, struct blob_attr **tb) 505 { 506 struct interface *iface = state->proto.iface; 507 struct blob_attr *cur; 508 struct device *dev; 509 const char *devname; 510 int dev_create = 1; 511 bool addr_ext = false; 512 bool keep = false; 513 bool up; 514 515 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 516 return UBUS_STATUS_PERMISSION_DENIED; 517 518 if (!tb[NOTIFY_LINK_UP]) 519 return UBUS_STATUS_INVALID_ARGUMENT; 520 521 up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]); 522 if (!up) { 523 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 524 return 0; 525 } 526 527 if ((cur = tb[NOTIFY_KEEP]) != NULL) 528 keep = blobmsg_get_bool(cur); 529 530 if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) { 531 addr_ext = blobmsg_get_bool(cur); 532 if (addr_ext) 533 dev_create = 2; 534 } 535 536 if (iface->state != IFS_UP || !iface->l3_dev.dev) 537 keep = false; 538 539 if (!keep) { 540 dev = iface->main_dev.dev; 541 if (tb[NOTIFY_IFNAME]) { 542 keep = false; 543 devname = blobmsg_data(tb[NOTIFY_IFNAME]); 544 if (tb[NOTIFY_TUNNEL]) 545 dev = proto_shell_create_tunnel(devname, tb[NOTIFY_TUNNEL]); 546 else 547 dev = device_get(devname, dev_create); 548 } 549 550 if (!dev) 551 return UBUS_STATUS_INVALID_ARGUMENT; 552 553 interface_set_l3_dev(iface, dev); 554 if (device_claim(&iface->l3_dev) < 0) 555 return UBUS_STATUS_UNKNOWN_ERROR; 556 557 device_set_present(dev, true); 558 } 559 560 interface_update_start(iface, keep); 561 562 proto_apply_ip_settings(iface, data, addr_ext); 563 564 if ((cur = tb[NOTIFY_ROUTES]) != NULL) 565 proto_shell_parse_route_list(state->proto.iface, cur, false); 566 567 if ((cur = tb[NOTIFY_ROUTES6]) != NULL) 568 proto_shell_parse_route_list(state->proto.iface, cur, true); 569 570 if ((cur = tb[NOTIFY_NEIGHBORS]) != NULL) 571 proto_shell_parse_neighbor_list(state->proto.iface, cur, false); 572 573 if ((cur = tb[NOTIFY_NEIGHBORS6]) != NULL) 574 proto_shell_parse_neighbor_list(state->proto.iface, cur, true); 575 576 if ((cur = tb[NOTIFY_DNS])) 577 interface_add_dns_server_list(&iface->proto_ip, cur); 578 579 if ((cur = tb[NOTIFY_DNS_SEARCH])) 580 interface_add_dns_search_list(&iface->proto_ip, cur); 581 582 if ((cur = tb[NOTIFY_DATA])) 583 proto_shell_parse_data(state->proto.iface, cur); 584 585 interface_update_complete(state->proto.iface); 586 587 if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) { 588 state->proto.proto_event(&state->proto, IFPEV_UP); 589 state->sm = S_IDLE; 590 } 591 592 return 0; 593 } 594 595 static bool 596 fill_string_list(struct blob_attr *attr, char **argv, int max) 597 { 598 struct blob_attr *cur; 599 int argc = 0; 600 size_t rem; 601 602 if (!attr) 603 goto out; 604 605 blobmsg_for_each_attr(cur, attr, rem) { 606 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 607 return false; 608 609 if (!blobmsg_check_attr(cur, false)) 610 return false; 611 612 argv[argc++] = blobmsg_data(cur); 613 if (argc == max - 1) 614 return false; 615 } 616 617 out: 618 argv[argc] = NULL; 619 return true; 620 } 621 622 static int 623 proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb) 624 { 625 static char *argv[64]; 626 static char *env[32]; 627 628 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 629 return UBUS_STATUS_PERMISSION_DENIED; 630 631 if (!tb[NOTIFY_COMMAND]) 632 goto error; 633 634 if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv))) 635 goto error; 636 637 if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env))) 638 goto error; 639 640 netifd_start_process((const char **) argv, (char **) env, &state->proto_task); 641 642 return 0; 643 644 error: 645 return UBUS_STATUS_INVALID_ARGUMENT; 646 } 647 648 static int 649 proto_shell_kill_command(struct proto_shell_state *state, struct blob_attr **tb) 650 { 651 unsigned int signal = ~0; 652 653 if (tb[NOTIFY_SIGNAL]) 654 signal = blobmsg_get_u32(tb[NOTIFY_SIGNAL]); 655 656 if (signal > 31) 657 signal = SIGTERM; 658 659 if (state->proto_task.uloop.pending) { 660 if (signal == SIGTERM || signal == SIGKILL) 661 state->proto_task_killed = true; 662 kill(state->proto_task.uloop.pid, signal); 663 } 664 665 return 0; 666 } 667 668 static int 669 proto_shell_notify_error(struct proto_shell_state *state, struct blob_attr **tb) 670 { 671 struct blob_attr *cur; 672 char *data[16]; 673 int n_data = 0; 674 size_t rem; 675 676 if (!tb[NOTIFY_ERROR]) 677 return UBUS_STATUS_INVALID_ARGUMENT; 678 679 blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) { 680 if (n_data + 1 == ARRAY_SIZE(data)) 681 goto error; 682 683 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 684 goto error; 685 686 if (!blobmsg_check_attr(cur, false)) 687 goto error; 688 689 data[n_data++] = blobmsg_data(cur); 690 } 691 692 if (!n_data) 693 goto error; 694 695 interface_add_error(state->proto.iface, state->handler->proto.name, 696 data[0], (const char **) &data[1], n_data - 1); 697 698 return 0; 699 700 error: 701 return UBUS_STATUS_INVALID_ARGUMENT; 702 } 703 704 static int 705 proto_shell_block_restart(struct proto_shell_state *state, struct blob_attr **tb) 706 { 707 state->proto.iface->autostart = false; 708 return 0; 709 } 710 711 static int 712 proto_shell_set_available(struct proto_shell_state *state, struct blob_attr **tb) 713 { 714 if (!tb[NOTIFY_AVAILABLE]) 715 return UBUS_STATUS_INVALID_ARGUMENT; 716 717 interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE])); 718 return 0; 719 } 720 721 static int 722 proto_shell_add_host_dependency(struct proto_shell_state *state, struct blob_attr **tb) 723 { 724 struct proto_shell_dependency *dep; 725 const char *ifname = tb[NOTIFY_IFNAME] ? blobmsg_data(tb[NOTIFY_IFNAME]) : ""; 726 const char *host = tb[NOTIFY_HOST] ? blobmsg_data(tb[NOTIFY_HOST]) : ""; 727 728 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 729 return UBUS_STATUS_PERMISSION_DENIED; 730 731 dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1); 732 if (!dep) 733 return UBUS_STATUS_UNKNOWN_ERROR; 734 735 if (!host[0] && ifname[0]) { 736 dep->any = true; 737 } else if (inet_pton(AF_INET, host, &dep->host) < 1) { 738 if (inet_pton(AF_INET6, host, &dep->host) < 1) { 739 free(dep); 740 return UBUS_STATUS_INVALID_ARGUMENT; 741 } else { 742 dep->v6 = true; 743 } 744 } 745 746 dep->proto = state; 747 strcpy(dep->interface, ifname); 748 749 dep->dep.cb = proto_shell_if_up_cb; 750 interface_add_user(&dep->dep, NULL); 751 list_add(&dep->list, &state->deps); 752 proto_shell_update_host_dep(dep); 753 if (!dep->dep.iface) 754 return UBUS_STATUS_NOT_FOUND; 755 756 return 0; 757 } 758 759 static int 760 proto_shell_setup_failed(struct proto_shell_state *state) 761 { 762 int ret = 0; 763 764 switch (state->sm) { 765 case S_IDLE: 766 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 767 fallthrough; 768 case S_SETUP: 769 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false); 770 break; 771 case S_SETUP_ABORT: 772 case S_TEARDOWN: 773 default: 774 ret = UBUS_STATUS_PERMISSION_DENIED; 775 break; 776 } 777 return ret; 778 } 779 780 static int 781 proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr) 782 { 783 struct proto_shell_state *state; 784 struct blob_attr *tb[__NOTIFY_LAST]; 785 786 state = container_of(proto, struct proto_shell_state, proto); 787 788 blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr)); 789 if (!tb[NOTIFY_ACTION]) 790 return UBUS_STATUS_INVALID_ARGUMENT; 791 792 switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) { 793 case 0: 794 return proto_shell_update_link(state, attr, tb); 795 case 1: 796 return proto_shell_run_command(state, tb); 797 case 2: 798 return proto_shell_kill_command(state, tb); 799 case 3: 800 return proto_shell_notify_error(state, tb); 801 case 4: 802 return proto_shell_block_restart(state, tb); 803 case 5: 804 return proto_shell_set_available(state, tb); 805 case 6: 806 return proto_shell_add_host_dependency(state, tb); 807 case 7: 808 return proto_shell_setup_failed(state); 809 default: 810 return UBUS_STATUS_INVALID_ARGUMENT; 811 } 812 } 813 814 static void 815 proto_shell_checkup_timeout_cb(struct uloop_timeout *timeout) 816 { 817 struct proto_shell_state *state = container_of(timeout, struct 818 proto_shell_state, checkup_timeout); 819 struct interface_proto_state *proto = &state->proto; 820 struct interface *iface = proto->iface; 821 822 if (!iface->autostart) 823 return; 824 825 if (iface->state == IFS_UP) 826 return; 827 828 D(INTERFACE, "Interface '%s' is not up after %d sec", 829 iface->name, state->checkup_interval); 830 proto_shell_handler(proto, PROTO_CMD_TEARDOWN, false); 831 } 832 833 static void 834 proto_shell_checkup_attach(struct proto_shell_state *state, 835 const struct blob_attr *attr) 836 { 837 struct blob_attr *tb; 838 struct blobmsg_policy checkup_policy = { 839 .name = "checkup_interval", 840 .type = BLOBMSG_TYPE_INT32 841 }; 842 843 blobmsg_parse(&checkup_policy, 1, &tb, blob_data(attr), blob_len(attr)); 844 if (!tb) { 845 state->checkup_interval = -1; 846 state->checkup_timeout.cb = NULL; 847 } else { 848 state->checkup_interval = blobmsg_get_u32(tb); 849 state->checkup_timeout.cb = proto_shell_checkup_timeout_cb; 850 } 851 } 852 853 static struct interface_proto_state * 854 proto_shell_attach(const struct proto_handler *h, struct interface *iface, 855 struct blob_attr *attr) 856 { 857 struct proto_shell_state *state; 858 859 state = calloc(1, sizeof(*state)); 860 if (!state) 861 return NULL; 862 863 INIT_LIST_HEAD(&state->deps); 864 865 state->config = malloc(blob_pad_len(attr)); 866 if (!state->config) 867 goto error; 868 869 memcpy(state->config, attr, blob_pad_len(attr)); 870 proto_shell_checkup_attach(state, state->config); 871 state->proto.free = proto_shell_free; 872 state->proto.notify = proto_shell_notify; 873 state->proto.cb = proto_shell_handler; 874 state->teardown_timeout.cb = proto_shell_teardown_timeout_cb; 875 state->script_task.cb = proto_shell_script_cb; 876 state->script_task.dir_fd = proto_fd; 877 state->script_task.log_prefix = iface->name; 878 state->proto_task.cb = proto_shell_task_cb; 879 state->proto_task.dir_fd = proto_fd; 880 state->proto_task.log_prefix = iface->name; 881 state->handler = container_of(h, struct proto_shell_handler, proto); 882 883 return &state->proto; 884 885 error: 886 free(state); 887 return NULL; 888 } 889 890 static void 891 proto_shell_add_handler(const char *script, const char *name, json_object *obj) 892 { 893 struct proto_shell_handler *handler; 894 struct proto_handler *proto; 895 json_object *config, *tmp; 896 char *proto_name, *script_name; 897 898 handler = calloc_a(sizeof(*handler), 899 &proto_name, strlen(name) + 1, 900 &script_name, strlen(script) + 1); 901 if (!handler) 902 return; 903 904 handler->script_name = strcpy(script_name, script); 905 906 proto = &handler->proto; 907 proto->name = strcpy(proto_name, name); 908 proto->config_params = &handler->config; 909 proto->attach = proto_shell_attach; 910 911 tmp = json_get_field(obj, "no-device", json_type_boolean); 912 if (tmp && json_object_get_boolean(tmp)) 913 handler->proto.flags |= PROTO_FLAG_NODEV; 914 915 tmp = json_get_field(obj, "no-device-config", json_type_boolean); 916 if (tmp && json_object_get_boolean(tmp)) 917 handler->proto.flags |= PROTO_FLAG_NODEV_CONFIG; 918 919 tmp = json_get_field(obj, "no-proto-task", json_type_boolean); 920 if (tmp && json_object_get_boolean(tmp)) 921 handler->proto.flags |= PROTO_FLAG_NO_TASK; 922 923 tmp = json_get_field(obj, "available", json_type_boolean); 924 if (tmp && json_object_get_boolean(tmp)) 925 handler->proto.flags |= PROTO_FLAG_INIT_AVAILABLE; 926 927 tmp = json_get_field(obj, "renew-handler", json_type_boolean); 928 if (tmp && json_object_get_boolean(tmp)) 929 handler->proto.flags |= PROTO_FLAG_RENEW_AVAILABLE; 930 931 tmp = json_get_field(obj, "lasterror", json_type_boolean); 932 if (tmp && json_object_get_boolean(tmp)) 933 handler->proto.flags |= PROTO_FLAG_LASTERROR; 934 935 tmp = json_get_field(obj, "teardown-on-l3-link-down", json_type_boolean); 936 if (tmp && json_object_get_boolean(tmp)) 937 handler->proto.flags |= PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN; 938 939 config = json_get_field(obj, "config", json_type_array); 940 if (config) 941 handler->config_buf = netifd_handler_parse_config(&handler->config, config); 942 943 D(INTERFACE, "Add handler for script %s: %s", script, proto->name); 944 add_proto_handler(proto); 945 } 946 947 void proto_shell_init(void) 948 { 949 proto_fd = netifd_open_subdir("proto"); 950 if (proto_fd < 0) 951 return; 952 953 netifd_init_script_handlers(proto_fd, proto_shell_add_handler); 954 } 955
This page was automatically generated by LXR 0.3.1. • OpenWrt