X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=proto-shell.c;h=ef56aa808fc33e39fdf95a8bee50ecc35ec49316;hb=91810ecc13239f3b18c8299de265b4f3531c0017;hp=e2e765f5e398c1d108f5b86957155e8f76e10647;hpb=5cf30b59baa03db2448570c78e7e92873555d2ec;p=oweals%2Fnetifd.git diff --git a/proto-shell.c b/proto-shell.c index e2e765f..ef56aa8 100644 --- a/proto-shell.c +++ b/proto-shell.c @@ -44,7 +44,6 @@ struct proto_shell_handler { char *config_buf; char *script_name; bool init_available; - bool no_proto_task; struct uci_blob_param_list config; }; @@ -69,6 +68,15 @@ struct proto_shell_state { struct uloop_timeout teardown_timeout; + /* + * Teardown and setup interface again if it is still not up (IFS_UP) + * after checkup_interval seconds since previous attempt. This check + * will be disabled when the config option "checkup_interval" is + * missing or has a negative value + */ + int checkup_interval; + struct uloop_timeout checkup_timeout; + struct netifd_process script_task; struct netifd_process proto_task; @@ -297,12 +305,18 @@ proto_shell_task_finish(struct proto_shell_state *state, if (state->renew_pending) proto_shell_handler(&state->proto, PROTO_CMD_RENEW, false); - else if (!state->handler->no_proto_task && + else if (!(state->handler->proto.flags & PROTO_FLAG_NO_TASK) && !state->proto_task.uloop.pending && state->sm == S_SETUP) proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false); + + /* check up status after setup attempt by this script_task */ + if (state->sm == S_SETUP && state->checkup_interval > 0) { + uloop_timeout_set(&state->checkup_timeout, + state->checkup_interval * 1000); + } } break; @@ -311,7 +325,9 @@ proto_shell_task_finish(struct proto_shell_state *state, state->proto_task.uloop.pending) break; + /* completed aborting all tasks, now idle */ uloop_timeout_cancel(&state->teardown_timeout); + uloop_timeout_cancel(&state->checkup_timeout); state->sm = S_IDLE; proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false); break; @@ -326,7 +342,9 @@ proto_shell_task_finish(struct proto_shell_state *state, break; } + /* completed tearing down all tasks, now idle */ uloop_timeout_cancel(&state->teardown_timeout); + uloop_timeout_cancel(&state->checkup_timeout); state->sm = S_IDLE; state->proto.proto_event(&state->proto, IFPEV_DOWN); break; @@ -374,6 +392,7 @@ proto_shell_free(struct interface_proto_state *proto) state = container_of(proto, struct proto_shell_state, proto); uloop_timeout_cancel(&state->teardown_timeout); + uloop_timeout_cancel(&state->checkup_timeout); proto_shell_clear_host_dep(state); netifd_kill_process(&state->script_task); netifd_kill_process(&state->proto_task); @@ -519,10 +538,10 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, return UBUS_STATUS_UNKNOWN_ERROR; device_set_present(dev, true); - - interface_update_start(iface); } + interface_update_start(iface, keep); + proto_apply_ip_settings(iface, data, addr_ext); if ((cur = tb[NOTIFY_ROUTES]) != NULL) @@ -543,8 +562,7 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, interface_update_complete(state->proto.iface); if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) { - if (!keep) - state->proto.proto_event(&state->proto, IFPEV_UP); + state->proto.proto_event(&state->proto, IFPEV_UP); state->sm = S_IDLE; } @@ -688,6 +706,8 @@ proto_shell_add_host_dependency(struct proto_shell_state *state, struct blob_att return UBUS_STATUS_PERMISSION_DENIED; dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1); + if (!dep) + return UBUS_STATUS_UNKNOWN_ERROR; if (!host[0] && ifname[0]) { dep->any = true; @@ -768,6 +788,45 @@ proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr) } } +static void +proto_shell_checkup_timeout_cb(struct uloop_timeout *timeout) +{ + struct proto_shell_state *state = container_of(timeout, struct + proto_shell_state, checkup_timeout); + struct interface_proto_state *proto = &state->proto; + struct interface *iface = proto->iface; + + if (!iface->autostart) + return; + + if (iface->state == IFS_UP) + return; + + D(INTERFACE, "Interface '%s' is not up after %d sec\n", + iface->name, state->checkup_interval); + proto_shell_handler(proto, PROTO_CMD_TEARDOWN, false); +} + +static void +proto_shell_checkup_attach(struct proto_shell_state *state, + const struct blob_attr *attr) +{ + struct blob_attr *tb; + struct blobmsg_policy checkup_policy = { + .name = "checkup_interval", + .type = BLOBMSG_TYPE_INT32 + }; + + blobmsg_parse(&checkup_policy, 1, &tb, blob_data(attr), blob_len(attr)); + if (!tb) { + state->checkup_interval = -1; + state->checkup_timeout.cb = NULL; + } else { + state->checkup_interval = blobmsg_get_u32(tb); + state->checkup_timeout.cb = proto_shell_checkup_timeout_cb; + } +} + static struct interface_proto_state * proto_shell_attach(const struct proto_handler *h, struct interface *iface, struct blob_attr *attr) @@ -775,6 +834,9 @@ proto_shell_attach(const struct proto_handler *h, struct interface *iface, struct proto_shell_state *state; state = calloc(1, sizeof(*state)); + if (!state) + return NULL; + INIT_LIST_HEAD(&state->deps); state->config = malloc(blob_pad_len(attr)); @@ -782,6 +844,7 @@ proto_shell_attach(const struct proto_handler *h, struct interface *iface, goto error; memcpy(state->config, attr, blob_pad_len(attr)); + proto_shell_checkup_attach(state, state->config); state->proto.free = proto_shell_free; state->proto.notify = proto_shell_notify; state->proto.cb = proto_shell_handler; @@ -827,7 +890,8 @@ proto_shell_add_handler(const char *script, const char *name, json_object *obj) handler->proto.flags |= PROTO_FLAG_NODEV; tmp = json_get_field(obj, "no-proto-task", json_type_boolean); - handler->no_proto_task = tmp && json_object_get_boolean(tmp); + if (tmp && json_object_get_boolean(tmp)) + handler->proto.flags |= PROTO_FLAG_NO_TASK; tmp = json_get_field(obj, "available", json_type_boolean); if (tmp && json_object_get_boolean(tmp)) @@ -841,6 +905,10 @@ proto_shell_add_handler(const char *script, const char *name, json_object *obj) if (tmp && json_object_get_boolean(tmp)) handler->proto.flags |= PROTO_FLAG_LASTERROR; + tmp = json_get_field(obj, "teardown-on-l3-link-down", json_type_boolean); + if (tmp && json_object_get_boolean(tmp)) + handler->proto.flags |= PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN; + config = json_get_field(obj, "config", json_type_array); if (config) handler->config_buf = netifd_handler_parse_config(&handler->config, config);