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->restart_pending) 143 state->proto.cb(&state->proto, 144 PROTO_CMD_RESTART, false); 145 else if (state->renew_pending) 146 state->proto.cb(&state->proto, 147 PROTO_CMD_RENEW, false); 148 else if (!(state->proto.handler->flags & PROTO_FLAG_NO_TASK) && 149 !state->proto_task.uloop.pending && 150 state->sm == S_SETUP) 151 state->proto.cb(&state->proto, 152 PROTO_CMD_TEARDOWN, 153 false); 154 155 if (state->sm == S_SETUP && state->checkup_interval > 0) { 156 uloop_timeout_set(&state->checkup_timeout, 157 state->checkup_interval * 1000); 158 } 159 } 160 break; 161 162 case S_SETUP_ABORT: 163 if (state->script_task.uloop.pending || 164 state->proto_task.uloop.pending) 165 break; 166 167 uloop_timeout_cancel(&state->teardown_timeout); 168 uloop_timeout_cancel(&state->checkup_timeout); 169 state->sm = S_IDLE; 170 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false); 171 break; 172 173 case S_TEARDOWN: 174 if (state->script_task.uloop.pending) 175 break; 176 177 if (state->proto_task.uloop.pending) { 178 if (!state->proto_task_killed) 179 kill(state->proto_task.uloop.pid, SIGTERM); 180 break; 181 } 182 183 uloop_timeout_cancel(&state->teardown_timeout); 184 uloop_timeout_cancel(&state->checkup_timeout); 185 state->sm = S_IDLE; 186 state->proto.proto_event(&state->proto, IFPEV_DOWN); 187 break; 188 } 189 } 190 191 static void 192 proto_ext_teardown_timeout_cb(struct uloop_timeout *timeout) 193 { 194 struct proto_ext_state *state; 195 196 state = container_of(timeout, struct proto_ext_state, teardown_timeout); 197 198 netifd_kill_process(&state->script_task); 199 netifd_kill_process(&state->proto_task); 200 proto_ext_task_finish(state, NULL); 201 } 202 203 static void 204 proto_ext_script_cb(struct netifd_process *p, int ret) 205 { 206 struct proto_ext_state *state; 207 208 state = container_of(p, struct proto_ext_state, script_task); 209 proto_ext_task_finish(state, p); 210 } 211 212 static void 213 proto_ext_task_cb(struct netifd_process *p, int ret) 214 { 215 struct proto_ext_state *state; 216 217 state = container_of(p, struct proto_ext_state, proto_task); 218 219 if (state->sm == S_IDLE || state->sm == S_SETUP) 220 state->last_error = WEXITSTATUS(ret); 221 222 proto_ext_task_finish(state, p); 223 } 224 225 void 226 proto_ext_free(struct interface_proto_state *proto) 227 { 228 struct proto_ext_state *state; 229 230 state = container_of(proto, struct proto_ext_state, proto); 231 uloop_timeout_cancel(&state->teardown_timeout); 232 uloop_timeout_cancel(&state->checkup_timeout); 233 proto_ext_clear_host_dep(state); 234 netifd_kill_process(&state->script_task); 235 netifd_kill_process(&state->proto_task); 236 free(state->config); 237 free(state); 238 } 239 240 static void 241 proto_ext_parse_route_list(struct interface *iface, struct blob_attr *attr, 242 bool v6) 243 { 244 struct blob_attr *cur; 245 size_t rem; 246 247 blobmsg_for_each_attr(cur, attr, rem) { 248 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) { 249 D(INTERFACE, "Ignore wrong route type: %d", blobmsg_type(cur)); 250 continue; 251 } 252 253 interface_ip_add_route(iface, cur, v6); 254 } 255 } 256 257 static void 258 proto_ext_parse_neighbor_list(struct interface *iface, struct blob_attr *attr, 259 bool v6) 260 { 261 struct blob_attr *cur; 262 size_t rem; 263 264 blobmsg_for_each_attr(cur, attr, rem) { 265 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) { 266 D(INTERFACE, "Ignore wrong neighbor type: %d", blobmsg_type(cur)); 267 continue; 268 } 269 270 interface_ip_add_neighbor(iface, cur, v6); 271 } 272 } 273 274 static void 275 proto_ext_parse_data(struct interface *iface, struct blob_attr *attr) 276 { 277 struct blob_attr *cur; 278 size_t rem; 279 280 blobmsg_for_each_attr(cur, attr, rem) 281 interface_add_data(iface, cur); 282 } 283 284 static struct device * 285 proto_ext_create_tunnel(const char *name, struct blob_attr *attr) 286 { 287 struct device *dev; 288 struct blob_buf b; 289 290 memset(&b, 0, sizeof(b)); 291 blob_buf_init(&b, 0); 292 blob_put(&b, 0, blobmsg_data(attr), blobmsg_data_len(attr)); 293 dev = device_create(name, &tunnel_device_type, blob_data(b.head)); 294 blob_buf_free(&b); 295 296 return dev; 297 } 298 299 enum { 300 NOTIFY_ACTION, 301 NOTIFY_ERROR, 302 NOTIFY_COMMAND, 303 NOTIFY_ENV, 304 NOTIFY_SIGNAL, 305 NOTIFY_AVAILABLE, 306 NOTIFY_LINK_UP, 307 NOTIFY_IFNAME, 308 NOTIFY_ADDR_EXT, 309 NOTIFY_ROUTES, 310 NOTIFY_ROUTES6, 311 NOTIFY_TUNNEL, 312 NOTIFY_DATA, 313 NOTIFY_KEEP, 314 NOTIFY_HOST, 315 NOTIFY_DNS, 316 NOTIFY_DNS_SEARCH, 317 NOTIFY_NEIGHBORS, 318 NOTIFY_NEIGHBORS6, 319 __NOTIFY_LAST 320 }; 321 322 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = { 323 [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 }, 324 [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY }, 325 [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY }, 326 [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY }, 327 [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 }, 328 [NOTIFY_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL }, 329 [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL }, 330 [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, 331 [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL }, 332 [NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY }, 333 [NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY }, 334 [NOTIFY_TUNNEL] = { .name = "tunnel", .type = BLOBMSG_TYPE_TABLE }, 335 [NOTIFY_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 336 [NOTIFY_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, 337 [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING }, 338 [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY }, 339 [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY }, 340 [NOTIFY_NEIGHBORS]= {.name = "neighbor", .type = BLOBMSG_TYPE_ARRAY}, 341 [NOTIFY_NEIGHBORS6]= {.name = "neighbor6", .type = BLOBMSG_TYPE_ARRAY}, 342 }; 343 344 static int 345 proto_ext_update_link(struct proto_ext_state *state, struct blob_attr *data, struct blob_attr **tb) 346 { 347 struct interface *iface = state->proto.iface; 348 struct blob_attr *cur; 349 struct device *dev; 350 const char *devname; 351 int dev_create = 1; 352 bool addr_ext = false; 353 bool keep = false; 354 bool up; 355 356 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 357 return UBUS_STATUS_PERMISSION_DENIED; 358 359 if (!tb[NOTIFY_LINK_UP]) 360 return UBUS_STATUS_INVALID_ARGUMENT; 361 362 up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]); 363 if (!up) { 364 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 365 return 0; 366 } 367 368 if ((cur = tb[NOTIFY_KEEP]) != NULL) 369 keep = blobmsg_get_bool(cur); 370 371 if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) { 372 addr_ext = blobmsg_get_bool(cur); 373 if (addr_ext) 374 dev_create = 2; 375 } 376 377 if (iface->state != IFS_UP || !iface->l3_dev.dev) 378 keep = false; 379 380 if (!keep) { 381 dev = iface->main_dev.dev; 382 if (tb[NOTIFY_IFNAME]) { 383 keep = false; 384 devname = blobmsg_data(tb[NOTIFY_IFNAME]); 385 if (tb[NOTIFY_TUNNEL]) 386 dev = proto_ext_create_tunnel(devname, tb[NOTIFY_TUNNEL]); 387 else 388 dev = device_get(devname, dev_create); 389 } 390 391 if (!dev) 392 return UBUS_STATUS_INVALID_ARGUMENT; 393 394 interface_set_l3_dev(iface, dev); 395 if (device_claim(&iface->l3_dev) < 0) 396 return UBUS_STATUS_UNKNOWN_ERROR; 397 398 device_set_present(dev, true); 399 } 400 401 interface_update_start(iface, keep); 402 403 proto_apply_ip_settings(iface, data, addr_ext); 404 405 if ((cur = tb[NOTIFY_ROUTES]) != NULL) 406 proto_ext_parse_route_list(state->proto.iface, cur, false); 407 408 if ((cur = tb[NOTIFY_ROUTES6]) != NULL) 409 proto_ext_parse_route_list(state->proto.iface, cur, true); 410 411 if ((cur = tb[NOTIFY_NEIGHBORS]) != NULL) 412 proto_ext_parse_neighbor_list(state->proto.iface, cur, false); 413 414 if ((cur = tb[NOTIFY_NEIGHBORS6]) != NULL) 415 proto_ext_parse_neighbor_list(state->proto.iface, cur, true); 416 417 if ((cur = tb[NOTIFY_DNS])) 418 interface_add_dns_server_list(&iface->proto_ip, cur); 419 420 if ((cur = tb[NOTIFY_DNS_SEARCH])) 421 interface_add_dns_search_list(&iface->proto_ip, cur); 422 423 if ((cur = tb[NOTIFY_DATA])) 424 proto_ext_parse_data(state->proto.iface, cur); 425 426 interface_update_complete(state->proto.iface); 427 428 if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) { 429 state->proto.proto_event(&state->proto, IFPEV_UP); 430 state->sm = S_IDLE; 431 } 432 433 return 0; 434 } 435 436 static bool 437 fill_string_list(struct blob_attr *attr, char **argv, int max) 438 { 439 struct blob_attr *cur; 440 int argc = 0; 441 size_t rem; 442 443 if (!attr) 444 goto out; 445 446 blobmsg_for_each_attr(cur, attr, rem) { 447 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 448 return false; 449 450 if (!blobmsg_check_attr(cur, false)) 451 return false; 452 453 argv[argc++] = blobmsg_data(cur); 454 if (argc == max - 1) 455 return false; 456 } 457 458 out: 459 argv[argc] = NULL; 460 return true; 461 } 462 463 static int 464 proto_ext_run_command(struct proto_ext_state *state, struct blob_attr **tb) 465 { 466 static char *argv[64]; 467 static char *env[32]; 468 469 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 470 return UBUS_STATUS_PERMISSION_DENIED; 471 472 if (!tb[NOTIFY_COMMAND]) 473 goto error; 474 475 if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv))) 476 goto error; 477 478 if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env))) 479 goto error; 480 481 state->proto_task_killed = false; 482 netifd_start_process((const char **) argv, (char **) env, &state->proto_task); 483 484 return 0; 485 486 error: 487 return UBUS_STATUS_INVALID_ARGUMENT; 488 } 489 490 static int 491 proto_ext_kill_command(struct proto_ext_state *state, struct blob_attr **tb) 492 { 493 unsigned int signal = ~0; 494 495 if (tb[NOTIFY_SIGNAL]) 496 signal = blobmsg_get_u32(tb[NOTIFY_SIGNAL]); 497 498 if (signal > 31) 499 signal = SIGTERM; 500 501 if (state->proto_task.uloop.pending) { 502 if (signal == SIGTERM || signal == SIGKILL) 503 state->proto_task_killed = true; 504 kill(state->proto_task.uloop.pid, signal); 505 } 506 507 return 0; 508 } 509 510 static int 511 proto_ext_notify_error(struct proto_ext_state *state, struct blob_attr **tb) 512 { 513 struct blob_attr *cur; 514 char *data[16]; 515 int n_data = 0; 516 size_t rem; 517 518 if (!tb[NOTIFY_ERROR]) 519 return UBUS_STATUS_INVALID_ARGUMENT; 520 521 blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) { 522 if (n_data + 1 == ARRAY_SIZE(data)) 523 goto error; 524 525 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 526 goto error; 527 528 if (!blobmsg_check_attr(cur, false)) 529 goto error; 530 531 data[n_data++] = blobmsg_data(cur); 532 } 533 534 if (!n_data) 535 goto error; 536 537 interface_add_error(state->proto.iface, state->proto.handler->name, 538 data[0], (const char **) &data[1], n_data - 1); 539 540 return 0; 541 542 error: 543 return UBUS_STATUS_INVALID_ARGUMENT; 544 } 545 546 static int 547 proto_ext_block_restart(struct proto_ext_state *state, struct blob_attr **tb) 548 { 549 state->proto.iface->autostart = false; 550 return 0; 551 } 552 553 static int 554 proto_ext_set_available(struct proto_ext_state *state, struct blob_attr **tb) 555 { 556 if (!tb[NOTIFY_AVAILABLE]) 557 return UBUS_STATUS_INVALID_ARGUMENT; 558 559 interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE])); 560 return 0; 561 } 562 563 static int 564 proto_ext_add_host_dependency(struct proto_ext_state *state, struct blob_attr **tb) 565 { 566 struct proto_ext_dep *dep; 567 const char *ifname = tb[NOTIFY_IFNAME] ? blobmsg_data(tb[NOTIFY_IFNAME]) : ""; 568 const char *host = tb[NOTIFY_HOST] ? blobmsg_data(tb[NOTIFY_HOST]) : ""; 569 570 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 571 return UBUS_STATUS_PERMISSION_DENIED; 572 573 dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1); 574 if (!dep) 575 return UBUS_STATUS_UNKNOWN_ERROR; 576 577 if (!host[0] && ifname[0]) { 578 dep->any = true; 579 } else if (inet_pton(AF_INET, host, &dep->host) < 1) { 580 if (inet_pton(AF_INET6, host, &dep->host) < 1) { 581 free(dep); 582 return UBUS_STATUS_INVALID_ARGUMENT; 583 } else { 584 dep->v6 = true; 585 } 586 } 587 588 dep->proto = state; 589 strcpy(dep->interface, ifname); 590 591 dep->dep.cb = proto_ext_if_up_cb; 592 interface_add_user(&dep->dep, NULL); 593 list_add(&dep->list, &state->deps); 594 proto_ext_update_host_dep(dep); 595 if (!dep->dep.iface) 596 return UBUS_STATUS_NOT_FOUND; 597 598 return 0; 599 } 600 601 static int 602 proto_ext_setup_failed(struct proto_ext_state *state) 603 { 604 int ret = 0; 605 606 switch (state->sm) { 607 case S_IDLE: 608 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); 609 fallthrough; 610 case S_SETUP: 611 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false); 612 break; 613 case S_SETUP_ABORT: 614 case S_TEARDOWN: 615 default: 616 ret = UBUS_STATUS_PERMISSION_DENIED; 617 break; 618 } 619 return ret; 620 } 621 622 int 623 proto_ext_notify(struct interface_proto_state *proto, struct blob_attr *attr) 624 { 625 struct proto_ext_state *state; 626 struct blob_attr *tb[__NOTIFY_LAST]; 627 628 state = container_of(proto, struct proto_ext_state, proto); 629 630 blobmsg_parse_attr(notify_attr, __NOTIFY_LAST, tb, attr); 631 if (!tb[NOTIFY_ACTION]) 632 return UBUS_STATUS_INVALID_ARGUMENT; 633 634 switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) { 635 case 0: 636 return proto_ext_update_link(state, attr, tb); 637 case 1: 638 return proto_ext_run_command(state, tb); 639 case 2: 640 return proto_ext_kill_command(state, tb); 641 case 3: 642 return proto_ext_notify_error(state, tb); 643 case 4: 644 return proto_ext_block_restart(state, tb); 645 case 5: 646 return proto_ext_set_available(state, tb); 647 case 6: 648 return proto_ext_add_host_dependency(state, tb); 649 case 7: 650 return proto_ext_setup_failed(state); 651 default: 652 return UBUS_STATUS_INVALID_ARGUMENT; 653 } 654 } 655 656 static void 657 proto_ext_checkup_timeout_cb(struct uloop_timeout *timeout) 658 { 659 struct proto_ext_state *state = container_of(timeout, struct 660 proto_ext_state, checkup_timeout); 661 struct interface_proto_state *proto = &state->proto; 662 struct interface *iface = proto->iface; 663 664 if (!iface->autostart) 665 return; 666 667 if (iface->state == IFS_UP) 668 return; 669 670 D(INTERFACE, "Interface '%s' is not up after %d sec", 671 iface->name, state->checkup_interval); 672 state->proto.cb(proto, PROTO_CMD_TEARDOWN, false); 673 } 674 675 static void 676 proto_ext_checkup_attach(struct proto_ext_state *state, 677 const struct blob_attr *attr) 678 { 679 struct blob_attr *tb; 680 struct blobmsg_policy checkup_policy = { 681 .name = "checkup_interval", 682 .type = BLOBMSG_TYPE_INT32 683 }; 684 685 blobmsg_parse_attr(&checkup_policy, 1, &tb, (struct blob_attr *)attr); 686 if (!tb) { 687 state->checkup_interval = -1; 688 state->checkup_timeout.cb = NULL; 689 } else { 690 state->checkup_interval = blobmsg_get_u32(tb); 691 state->checkup_timeout.cb = proto_ext_checkup_timeout_cb; 692 } 693 } 694 695 void 696 proto_ext_state_init(struct proto_ext_state *state, 697 struct interface *iface, struct blob_attr *attr, 698 int dir_fd) 699 { 700 INIT_LIST_HEAD(&state->deps); 701 702 state->config = malloc(blob_pad_len(attr)); 703 if (!state->config) 704 return; 705 706 memcpy(state->config, attr, blob_pad_len(attr)); 707 proto_ext_checkup_attach(state, state->config); 708 state->proto.free = proto_ext_free; 709 state->proto.notify = proto_ext_notify; 710 state->teardown_timeout.cb = proto_ext_teardown_timeout_cb; 711 state->script_task.cb = proto_ext_script_cb; 712 state->script_task.dir_fd = dir_fd; 713 state->script_task.log_prefix = iface->name; 714 state->proto_task.cb = proto_ext_task_cb; 715 state->proto_task.dir_fd = dir_fd; 716 state->proto_task.log_prefix = iface->name; 717 } 718 719 int 720 proto_ext_run(struct proto_ext_state *state, 721 enum interface_proto_cmd cmd, bool force, 722 proto_ext_handler_cb start_cb) 723 { 724 struct interface_proto_state *proto = &state->proto; 725 static char error_buf[32]; 726 char *envp[2]; 727 const char *action; 728 char *config; 729 int ret, j = 0; 730 731 if (cmd == PROTO_CMD_SETUP) { 732 switch (state->sm) { 733 case S_IDLE: 734 action = "setup"; 735 state->last_error = -1; 736 proto_ext_clear_host_dep(state); 737 state->sm = S_SETUP; 738 break; 739 740 default: 741 return -1; 742 } 743 } else if (cmd == PROTO_CMD_RENEW) { 744 if (!(proto->handler->flags & PROTO_FLAG_RENEW_AVAILABLE)) 745 return 0; 746 747 /* 748 * A teardown is already in progress and its completion paths do 749 * not consume pending flags; a flag queued here would go stale 750 * and fire against the freshly started client after the next 751 * setup. The client is being bounced anyway, so drop the 752 * request. 753 */ 754 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 755 return 0; 756 757 if (state->script_task.uloop.pending) { 758 state->renew_pending = true; 759 return 0; 760 } 761 762 state->renew_pending = false; 763 action = "renew"; 764 } else if (cmd == PROTO_CMD_RESTART) { 765 if (!(proto->handler->flags & PROTO_FLAG_RESTART_AVAILABLE)) 766 return 0; 767 768 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT) 769 return 0; 770 771 if (state->script_task.uloop.pending) { 772 state->restart_pending = true; 773 return 0; 774 } 775 776 state->restart_pending = false; 777 action = "restart"; 778 } else { 779 switch (state->sm) { 780 case S_SETUP: 781 if (state->script_task.uloop.pending) { 782 uloop_timeout_set(&state->teardown_timeout, 1000); 783 kill(state->script_task.uloop.pid, SIGTERM); 784 if (state->proto_task.uloop.pending) 785 kill(state->proto_task.uloop.pid, SIGTERM); 786 state->renew_pending = false; 787 state->restart_pending = false; 788 state->sm = S_SETUP_ABORT; 789 return 0; 790 } 791 fallthrough; 792 case S_IDLE: 793 action = "teardown"; 794 state->renew_pending = false; 795 state->restart_pending = false; 796 state->sm = S_TEARDOWN; 797 if (state->last_error >= 0) { 798 snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error); 799 envp[j++] = error_buf; 800 } 801 uloop_timeout_set(&state->teardown_timeout, 5000); 802 break; 803 804 case S_TEARDOWN: 805 return 0; 806 807 default: 808 return -1; 809 } 810 } 811 812 D(INTERFACE, "run %s for interface '%s'", action, proto->iface->name); 813 config = blobmsg_format_json(state->config, true); 814 if (!config) { 815 ret = -1; 816 goto error; 817 } 818 819 envp[j] = NULL; 820 821 ret = start_cb(state, action, config, envp); 822 free(config); 823 if (ret) 824 goto error; 825 826 return 0; 827 828 error: 829 /* 830 * Roll back the setup transition: nothing is running that could 831 * advance the state machine, and teardown on an interface that never 832 * came up does not reach the proto handler, so a stuck S_SETUP would 833 * block every future setup attempt 834 */ 835 if (cmd == PROTO_CMD_SETUP) 836 state->sm = S_IDLE; 837 838 return ret; 839 } 840
This page was automatically generated by LXR 0.3.1. • OpenWrt