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 #include "proto-ext.h" 25 #include "system.h" 26 #include "handler.h" 27 28 static void 29 proto_ext_check_dependencies(struct proto_ext_state *state) 30 { 31 struct proto_ext_dep *dep; 32 bool available = true; 33 34 list_for_each_entry(dep, &state->deps, list) { 35 if (dep->dep.iface) 36 continue; 37 38 available = false; 39 break; 40 } 41 42 interface_set_available(state->proto.iface, available); 43 } 44 45 static void 46 proto_ext_if_up_cb(struct interface_user *dep, struct interface *iface, 47 enum interface_event ev); 48 static void 49 proto_ext_if_down_cb(struct interface_user *dep, struct interface *iface, 50 enum interface_event ev); 51 52 static void 53 proto_ext_update_host_dep(struct proto_ext_dep *dep) 54 { 55 struct interface *iface = NULL; 56 57 if (dep->dep.iface) 58 goto out; 59 60 if (dep->interface[0]) { 61 iface = vlist_find(&interfaces, dep->interface, iface, node); 62 63 if (!iface || iface->state != IFS_UP) 64 goto out; 65 } 66 67 if (!dep->any) 68 iface = interface_ip_add_target_route(&dep->host, dep->v6, iface, false); 69 70 if (!iface) 71 goto out; 72 73 interface_remove_user(&dep->dep); 74 dep->dep.cb = proto_ext_if_down_cb; 75 interface_add_user(&dep->dep, iface); 76 77 out: 78 proto_ext_check_dependencies(dep->proto); 79 } 80 81 static void 82 proto_ext_clear_host_dep(struct proto_ext_state *state) 83 { 84 struct proto_ext_dep *dep, *tmp; 85 86 list_for_each_entry_safe(dep, tmp, &state->deps, list) { 87 interface_remove_user(&dep->dep); 88 list_del(&dep->list); 89 free(dep); 90 } 91 } 92 93 static void 94 proto_ext_if_up_cb(struct interface_user *dep, struct interface *iface, 95 enum interface_event ev) 96 { 97 struct proto_ext_dep *pdep; 98 99 if (ev != IFEV_UP && ev != IFEV_UPDATE) 100 return; 101 102 pdep = container_of(dep, struct proto_ext_dep, dep); 103 proto_ext_update_host_dep(pdep); 104 } 105 106 static void 107 proto_ext_if_down_cb(struct interface_user *dep, struct interface *iface, 108 enum interface_event ev) 109 { 110 struct proto_ext_dep *pdep; 111 struct proto_ext_state *state; 112 113 if (ev != IFEV_UP_FAILED && ev != IFEV_DOWN && ev != IFEV_FREE) 114 return; 115 116 pdep = container_of(dep, struct proto_ext_dep, dep); 117 interface_remove_user(dep); 118 dep->cb = proto_ext_if_up_cb; 119 interface_add_user(dep, NULL); 120 121 state = pdep->proto; 122 if (state->sm == S_IDLE) { 123 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 124 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false); 125 } 126 } 127 128 static void 129 proto_ext_task_finish(struct proto_ext_state *state, 130 struct netifd_process *task) 131 { 132 switch (state->sm) { 133 case S_IDLE: 134 if (task == &state->proto_task) 135 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 136 fallthrough; 137 case S_SETUP: 138 if (task == &state->proto_task) 139 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, 140 false); 141 else if (task == &state->script_task) { 142 if (state->renew_pending) 143 state->proto.cb(&state->proto, 144 PROTO_CMD_RENEW, false); 145 else if (!(state->proto.handler->flags & PROTO_FLAG_NO_TASK) && 146 !state->proto_task.uloop.pending && 147 state->sm == S_SETUP) 148 state->proto.cb(&state->proto, 149 PROTO_CMD_TEARDOWN, 150 false); 151 152 if (state->sm == S_SETUP && state->checkup_interval > 0) { 153 uloop_timeout_set(&state->checkup_timeout, 154 state->checkup_interval * 1000); 155 } 156 } 157 break; 158 159 case S_SETUP_ABORT: 160 if (state->script_task.uloop.pending || 161 state->proto_task.uloop.pending) 162 break; 163 164 uloop_timeout_cancel(&state->teardown_timeout); 165 uloop_timeout_cancel(&state->checkup_timeout); 166 state->sm = S_IDLE; 167 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false); 168 break; 169 170 case S_TEARDOWN: 171 if (state->script_task.uloop.pending) 172 break; 173 174 if (state->proto_task.uloop.pending) { 175 if (!state->proto_task_killed) 176 kill(state->proto_task.uloop.pid, SIGTERM); 177 break; 178 } 179 180 uloop_timeout_cancel(&state->teardown_timeout); 181 uloop_timeout_cancel(&state->checkup_timeout); 182 state->sm = S_IDLE; 183 state->proto.proto_event(&state->proto, IFPEV_DOWN); 184 break; 185 } 186 } 187 188 static void 189 proto_ext_teardown_timeout_cb(struct uloop_timeout *timeout) 190 { 191 struct proto_ext_state *state; 192 193 state = container_of(timeout, struct proto_ext_state, teardown_timeout); 194 195 netifd_kill_process(&state->script_task); 196 netifd_kill_process(&state->proto_task); 197 proto_ext_task_finish(state, NULL); 198 } 199 200 static void 201 proto_ext_script_cb(struct netifd_process *p, int ret) 202 { 203 struct proto_ext_state *state; 204 205 state = container_of(p, struct proto_ext_state, script_task); 206 proto_ext_task_finish(state, p); 207 } 208 209 static void 210 proto_ext_task_cb(struct netifd_process *p, int ret) 211 { 212 struct proto_ext_state *state; 213 214 state = container_of(p, struct proto_ext_state, proto_task); 215 216 if (state->sm == S_IDLE || state->sm == S_SETUP) 217 state->last_error = WEXITSTATUS(ret); 218 219 proto_ext_task_finish(state, p); 220 } 221 222 void 223 proto_ext_free(struct interface_proto_state *proto) 224 { 225 struct proto_ext_state *state; 226 227 state = container_of(proto, struct proto_ext_state, proto); 228 uloop_timeout_cancel(&state->teardown_timeout); 229 uloop_timeout_cancel(&state->checkup_timeout); 230 proto_ext_clear_host_dep(state); 231 netifd_kill_process(&state->script_task); 232 netifd_kill_process(&state->proto_task); 233 free(state->config); 234 free(state); 235 } 236 237 static void 238 proto_ext_parse_route_list(struct interface *iface, struct blob_attr *attr, 239 bool v6) 240 { 241 struct blob_attr *cur; 242 size_t rem; 243 244 blobmsg_for_each_attr(cur, attr, rem) { 245 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) { 246 D(INTERFACE, "Ignore wrong route type: %d", blobmsg_type(cur)); 247 continue; 248 } 249 250 interface_ip_add_route(iface, cur, v6); 251 } 252 } 253 254 static void 255 proto_ext_parse_neighbor_list(struct interface *iface, struct blob_attr *attr, 256 bool v6) 257 { 258 struct blob_attr *cur; 259 size_t rem; 260 261 blobmsg_for_each_attr(cur, attr, rem) { 262 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) { 263 D(INTERFACE, "Ignore wrong neighbor type: %d", blobmsg_type(cur)); 264 continue; 265 } 266 267 interface_ip_add_neighbor(iface, cur, v6); 268 } 269 } 270 271 static void 272 proto_ext_parse_data(struct interface *iface, struct blob_attr *attr) 273 { 274 struct blob_attr *cur; 275 size_t rem; 276 277 blobmsg_for_each_attr(cur, attr, rem) 278 interface_add_data(iface, cur); 279 } 280 281 static struct device * 282 proto_ext_create_tunnel(const char *name, struct blob_attr *attr) 283 { 284 struct device *dev; 285 struct blob_buf b; 286 287 memset(&b, 0, sizeof(b)); 288 blob_buf_init(&b, 0); 289 blob_put(&b, 0, blobmsg_data(attr), blobmsg_data_len(attr)); 290 dev = device_create(name, &tunnel_device_type, blob_data(b.head)); 291 blob_buf_free(&b); 292 293 return dev; 294 } 295 296 enum { 297 NOTIFY_ACTION, 298 NOTIFY_ERROR, 299 NOTIFY_COMMAND, 300 NOTIFY_ENV, 301 NOTIFY_SIGNAL, 302 NOTIFY_AVAILABLE, 303 NOTIFY_LINK_UP, 304 NOTIFY_IFNAME, 305 NOTIFY_ADDR_EXT, 306 NOTIFY_ROUTES, 307 NOTIFY_ROUTES6, 308 NOTIFY_TUNNEL, 309 NOTIFY_DATA, 310 NOTIFY_KEEP, 311 NOTIFY_HOST, 312 NOTIFY_DNS, 313 NOTIFY_DNS_SEARCH, 314 NOTIFY_NEIGHBORS, 315 NOTIFY_NEIGHBORS6, 316 __NOTIFY_LAST 317 }; 318 319 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = { 320 [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 }, 321 [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY }, 322 [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY }, 323 [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY }, 324 [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 }, 325 [NOTIFY_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL }, 326 [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL }, 327 [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, 328 [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL }, 329 [NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY }, 330 [NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY }, 331 [NOTIFY_TUNNEL] = { .name = "tunnel", .type = BLOBMSG_TYPE_TABLE }, 332 [NOTIFY_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 333 [NOTIFY_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, 334 [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING }, 335 [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY }, 336 [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY }, 337 [NOTIFY_NEIGHBORS]= {.name = "neighbor", .type = BLOBMSG_TYPE_ARRAY}, 338 [NOTIFY_NEIGHBORS6]= {.name = "neighbor6", .type = BLOBMSG_TYPE_ARRAY}, 339 }; 340 341 static int 342 proto_ext_update_link(struct proto_ext_state *state, struct blob_attr *data, struct blob_attr **tb) 343 { 344 struct interface *iface = state->proto.iface; 345 struct blob_attr *cur; 346 struct device *dev; 347 const char *devname; 348 int dev_create = 1; 349 bool addr_ext = false; 350 bool keep = false; 351 bool up; 352 353 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 354 return UBUS_STATUS_PERMISSION_DENIED; 355 356 if (!tb[NOTIFY_LINK_UP]) 357 return UBUS_STATUS_INVALID_ARGUMENT; 358 359 up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]); 360 if (!up) { 361 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 362 return 0; 363 } 364 365 if ((cur = tb[NOTIFY_KEEP]) != NULL) 366 keep = blobmsg_get_bool(cur); 367 368 if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) { 369 addr_ext = blobmsg_get_bool(cur); 370 if (addr_ext) 371 dev_create = 2; 372 } 373 374 if (iface->state != IFS_UP || !iface->l3_dev.dev) 375 keep = false; 376 377 if (!keep) { 378 dev = iface->main_dev.dev; 379 if (tb[NOTIFY_IFNAME]) { 380 keep = false; 381 devname = blobmsg_data(tb[NOTIFY_IFNAME]); 382 if (tb[NOTIFY_TUNNEL]) 383 dev = proto_ext_create_tunnel(devname, tb[NOTIFY_TUNNEL]); 384 else 385 dev = device_get(devname, dev_create); 386 } 387 388 if (!dev) 389 return UBUS_STATUS_INVALID_ARGUMENT; 390 391 interface_set_l3_dev(iface, dev); 392 if (device_claim(&iface->l3_dev) < 0) 393 return UBUS_STATUS_UNKNOWN_ERROR; 394 395 device_set_present(dev, true); 396 } 397 398 interface_update_start(iface, keep); 399 400 proto_apply_ip_settings(iface, data, addr_ext); 401 402 if ((cur = tb[NOTIFY_ROUTES]) != NULL) 403 proto_ext_parse_route_list(state->proto.iface, cur, false); 404 405 if ((cur = tb[NOTIFY_ROUTES6]) != NULL) 406 proto_ext_parse_route_list(state->proto.iface, cur, true); 407 408 if ((cur = tb[NOTIFY_NEIGHBORS]) != NULL) 409 proto_ext_parse_neighbor_list(state->proto.iface, cur, false); 410 411 if ((cur = tb[NOTIFY_NEIGHBORS6]) != NULL) 412 proto_ext_parse_neighbor_list(state->proto.iface, cur, true); 413 414 if ((cur = tb[NOTIFY_DNS])) 415 interface_add_dns_server_list(&iface->proto_ip, cur); 416 417 if ((cur = tb[NOTIFY_DNS_SEARCH])) 418 interface_add_dns_search_list(&iface->proto_ip, cur); 419 420 if ((cur = tb[NOTIFY_DATA])) 421 proto_ext_parse_data(state->proto.iface, cur); 422 423 interface_update_complete(state->proto.iface); 424 425 if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) { 426 state->proto.proto_event(&state->proto, IFPEV_UP); 427 state->sm = S_IDLE; 428 } 429 430 return 0; 431 } 432 433 static bool 434 fill_string_list(struct blob_attr *attr, char **argv, int max) 435 { 436 struct blob_attr *cur; 437 int argc = 0; 438 size_t rem; 439 440 if (!attr) 441 goto out; 442 443 blobmsg_for_each_attr(cur, attr, rem) { 444 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 445 return false; 446 447 if (!blobmsg_check_attr(cur, false)) 448 return false; 449 450 argv[argc++] = blobmsg_data(cur); 451 if (argc == max - 1) 452 return false; 453 } 454 455 out: 456 argv[argc] = NULL; 457 return true; 458 } 459 460 static int 461 proto_ext_run_command(struct proto_ext_state *state, struct blob_attr **tb) 462 { 463 static char *argv[64]; 464 static char *env[32]; 465 466 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 467 return UBUS_STATUS_PERMISSION_DENIED; 468 469 if (!tb[NOTIFY_COMMAND]) 470 goto error; 471 472 if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv))) 473 goto error; 474 475 if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env))) 476 goto error; 477 478 netifd_start_process((const char **) argv, (char **) env, &state->proto_task); 479 480 return 0; 481 482 error: 483 return UBUS_STATUS_INVALID_ARGUMENT; 484 } 485 486 static int 487 proto_ext_kill_command(struct proto_ext_state *state, struct blob_attr **tb) 488 { 489 unsigned int signal = ~0; 490 491 if (tb[NOTIFY_SIGNAL]) 492 signal = blobmsg_get_u32(tb[NOTIFY_SIGNAL]); 493 494 if (signal > 31) 495 signal = SIGTERM; 496 497 if (state->proto_task.uloop.pending) { 498 if (signal == SIGTERM || signal == SIGKILL) 499 state->proto_task_killed = true; 500 kill(state->proto_task.uloop.pid, signal); 501 } 502 503 return 0; 504 } 505 506 static int 507 proto_ext_notify_error(struct proto_ext_state *state, struct blob_attr **tb) 508 { 509 struct blob_attr *cur; 510 char *data[16]; 511 int n_data = 0; 512 size_t rem; 513 514 if (!tb[NOTIFY_ERROR]) 515 return UBUS_STATUS_INVALID_ARGUMENT; 516 517 blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) { 518 if (n_data + 1 == ARRAY_SIZE(data)) 519 goto error; 520 521 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 522 goto error; 523 524 if (!blobmsg_check_attr(cur, false)) 525 goto error; 526 527 data[n_data++] = blobmsg_data(cur); 528 } 529 530 if (!n_data) 531 goto error; 532 533 interface_add_error(state->proto.iface, state->proto.handler->name, 534 data[0], (const char **) &data[1], n_data - 1); 535 536 return 0; 537 538 error: 539 return UBUS_STATUS_INVALID_ARGUMENT; 540 } 541 542 static int 543 proto_ext_block_restart(struct proto_ext_state *state, struct blob_attr **tb) 544 { 545 state->proto.iface->autostart = false; 546 return 0; 547 } 548 549 static int 550 proto_ext_set_available(struct proto_ext_state *state, struct blob_attr **tb) 551 { 552 if (!tb[NOTIFY_AVAILABLE]) 553 return UBUS_STATUS_INVALID_ARGUMENT; 554 555 interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE])); 556 return 0; 557 } 558 559 static int 560 proto_ext_add_host_dependency(struct proto_ext_state *state, struct blob_attr **tb) 561 { 562 struct proto_ext_dep *dep; 563 const char *ifname = tb[NOTIFY_IFNAME] ? blobmsg_data(tb[NOTIFY_IFNAME]) : ""; 564 const char *host = tb[NOTIFY_HOST] ? blobmsg_data(tb[NOTIFY_HOST]) : ""; 565 566 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 567 return UBUS_STATUS_PERMISSION_DENIED; 568 569 dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1); 570 if (!dep) 571 return UBUS_STATUS_UNKNOWN_ERROR; 572 573 if (!host[0] && ifname[0]) { 574 dep->any = true; 575 } else if (inet_pton(AF_INET, host, &dep->host) < 1) { 576 if (inet_pton(AF_INET6, host, &dep->host) < 1) { 577 free(dep); 578 return UBUS_STATUS_INVALID_ARGUMENT; 579 } else { 580 dep->v6 = true; 581 } 582 } 583 584 dep->proto = state; 585 strcpy(dep->interface, ifname); 586 587 dep->dep.cb = proto_ext_if_up_cb; 588 interface_add_user(&dep->dep, NULL); 589 list_add(&dep->list, &state->deps); 590 proto_ext_update_host_dep(dep); 591 if (!dep->dep.iface) 592 return UBUS_STATUS_NOT_FOUND; 593 594 return 0; 595 } 596 597 static int 598 proto_ext_setup_failed(struct proto_ext_state *state) 599 { 600 int ret = 0; 601 602 switch (state->sm) { 603 case S_IDLE: 604 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 605 fallthrough; 606 case S_SETUP: 607 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false); 608 break; 609 case S_SETUP_ABORT: 610 case S_TEARDOWN: 611 default: 612 ret = UBUS_STATUS_PERMISSION_DENIED; 613 break; 614 } 615 return ret; 616 } 617 618 int 619 proto_ext_notify(struct interface_proto_state *proto, struct blob_attr *attr) 620 { 621 struct proto_ext_state *state; 622 struct blob_attr *tb[__NOTIFY_LAST]; 623 624 state = container_of(proto, struct proto_ext_state, proto); 625 626 blobmsg_parse_attr(notify_attr, __NOTIFY_LAST, tb, attr); 627 if (!tb[NOTIFY_ACTION]) 628 return UBUS_STATUS_INVALID_ARGUMENT; 629 630 switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) { 631 case 0: 632 return proto_ext_update_link(state, attr, tb); 633 case 1: 634 return proto_ext_run_command(state, tb); 635 case 2: 636 return proto_ext_kill_command(state, tb); 637 case 3: 638 return proto_ext_notify_error(state, tb); 639 case 4: 640 return proto_ext_block_restart(state, tb); 641 case 5: 642 return proto_ext_set_available(state, tb); 643 case 6: 644 return proto_ext_add_host_dependency(state, tb); 645 case 7: 646 return proto_ext_setup_failed(state); 647 default: 648 return UBUS_STATUS_INVALID_ARGUMENT; 649 } 650 } 651 652 static void 653 proto_ext_checkup_timeout_cb(struct uloop_timeout *timeout) 654 { 655 struct proto_ext_state *state = container_of(timeout, struct 656 proto_ext_state, checkup_timeout); 657 struct interface_proto_state *proto = &state->proto; 658 struct interface *iface = proto->iface; 659 660 if (!iface->autostart) 661 return; 662 663 if (iface->state == IFS_UP) 664 return; 665 666 D(INTERFACE, "Interface '%s' is not up after %d sec", 667 iface->name, state->checkup_interval); 668 state->proto.cb(proto, PROTO_CMD_TEARDOWN, false); 669 } 670 671 static void 672 proto_ext_checkup_attach(struct proto_ext_state *state, 673 const struct blob_attr *attr) 674 { 675 struct blob_attr *tb; 676 struct blobmsg_policy checkup_policy = { 677 .name = "checkup_interval", 678 .type = BLOBMSG_TYPE_INT32 679 }; 680 681 blobmsg_parse_attr(&checkup_policy, 1, &tb, (struct blob_attr *)attr); 682 if (!tb) { 683 state->checkup_interval = -1; 684 state->checkup_timeout.cb = NULL; 685 } else { 686 state->checkup_interval = blobmsg_get_u32(tb); 687 state->checkup_timeout.cb = proto_ext_checkup_timeout_cb; 688 } 689 } 690 691 void 692 proto_ext_state_init(struct proto_ext_state *state, 693 struct interface *iface, struct blob_attr *attr, 694 int dir_fd) 695 { 696 INIT_LIST_HEAD(&state->deps); 697 698 state->config = malloc(blob_pad_len(attr)); 699 if (!state->config) 700 return; 701 702 memcpy(state->config, attr, blob_pad_len(attr)); 703 proto_ext_checkup_attach(state, state->config); 704 state->proto.free = proto_ext_free; 705 state->proto.notify = proto_ext_notify; 706 state->teardown_timeout.cb = proto_ext_teardown_timeout_cb; 707 state->script_task.cb = proto_ext_script_cb; 708 state->script_task.dir_fd = dir_fd; 709 state->script_task.log_prefix = iface->name; 710 state->proto_task.cb = proto_ext_task_cb; 711 state->proto_task.dir_fd = dir_fd; 712 state->proto_task.log_prefix = iface->name; 713 } 714 715 int 716 proto_ext_run(struct proto_ext_state *state, 717 enum interface_proto_cmd cmd, bool force, 718 proto_ext_handler_cb start_cb) 719 { 720 struct interface_proto_state *proto = &state->proto; 721 static char error_buf[32]; 722 char *envp[2]; 723 const char *action; 724 char *config; 725 int ret, j = 0; 726 727 if (cmd == PROTO_CMD_SETUP) { 728 switch (state->sm) { 729 case S_IDLE: 730 action = "setup"; 731 state->last_error = -1; 732 proto_ext_clear_host_dep(state); 733 state->sm = S_SETUP; 734 break; 735 736 default: 737 return -1; 738 } 739 } else if (cmd == PROTO_CMD_RENEW) { 740 if (!(proto->handler->flags & PROTO_FLAG_RENEW_AVAILABLE)) 741 return 0; 742 743 if (state->script_task.uloop.pending) { 744 state->renew_pending = true; 745 return 0; 746 } 747 748 state->renew_pending = false; 749 action = "renew"; 750 } else { 751 switch (state->sm) { 752 case S_SETUP: 753 if (state->script_task.uloop.pending) { 754 uloop_timeout_set(&state->teardown_timeout, 1000); 755 kill(state->script_task.uloop.pid, SIGTERM); 756 if (state->proto_task.uloop.pending) 757 kill(state->proto_task.uloop.pid, SIGTERM); 758 state->renew_pending = false; 759 state->sm = S_SETUP_ABORT; 760 return 0; 761 } 762 fallthrough; 763 case S_IDLE: 764 action = "teardown"; 765 state->renew_pending = false; 766 state->sm = S_TEARDOWN; 767 if (state->last_error >= 0) { 768 snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error); 769 envp[j++] = error_buf; 770 } 771 uloop_timeout_set(&state->teardown_timeout, 5000); 772 break; 773 774 case S_TEARDOWN: 775 return 0; 776 777 default: 778 return -1; 779 } 780 } 781 782 D(INTERFACE, "run %s for interface '%s'", action, proto->iface->name); 783 config = blobmsg_format_json(state->config, true); 784 if (!config) 785 return -1; 786 787 envp[j] = NULL; 788 789 ret = start_cb(state, action, config, envp); 790 free(config); 791 792 return ret; 793 } 794
This page was automatically generated by LXR 0.3.1. • OpenWrt