char *config_buf;
char *script_name;
bool init_available;
+ bool no_proto_task;
struct uci_blob_param_list config;
};
struct proto_shell_dependency {
struct list_head list;
- char *interface;
struct proto_shell_state *proto;
struct interface_user dep;
union if_addr host;
bool v6;
+ bool any;
+
+ char interface[];
};
struct proto_shell_state {
if (dep->dep.iface)
goto out;
- if (dep->interface[0])
+ if (dep->interface[0]) {
iface = vlist_find(&interfaces, dep->interface, iface, node);
- iface = interface_ip_add_target_route(&dep->host, dep->v6, iface);
+ if (!iface || iface->state != IFS_UP)
+ goto out;
+ }
+
+ if (!dep->any)
+ iface = interface_ip_add_target_route(&dep->host, dep->v6, iface);
+
if (!iface)
goto out;
state->renew_pending = false;
action = "renew";
} else {
- if (state->sm == S_TEARDOWN)
- return 0;
-
- state->renew_pending = false;
- if (state->script_task.uloop.pending) {
- if (state->sm != S_SETUP_ABORT) {
+ switch (state->sm) {
+ case S_SETUP:
+ if (state->script_task.uloop.pending) {
uloop_timeout_set(&state->teardown_timeout, 1000);
kill(state->script_task.uloop.pid, SIGTERM);
if (state->proto_task.uloop.pending)
kill(state->proto_task.uloop.pid, SIGTERM);
+ state->renew_pending = false;
state->sm = S_SETUP_ABORT;
+ return 0;
+ }
+ /* fall through if no script task is running */
+ case S_IDLE:
+ action = "teardown";
+ state->renew_pending = false;
+ state->sm = S_TEARDOWN;
+ if (state->last_error >= 0) {
+ snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error);
+ envp[j++] = error_buf;
}
+ uloop_timeout_set(&state->teardown_timeout, 5000);
+ break;
+
+ case S_TEARDOWN:
return 0;
- }
- action = "teardown";
- state->sm = S_TEARDOWN;
- if (state->last_error >= 0) {
- snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error);
- envp[j++] = error_buf;
+ default:
+ return -1;
}
- uloop_timeout_set(&state->teardown_timeout, 5000);
}
D(INTERFACE, "run %s for interface '%s'\n", action, proto->iface->name);
if (task == &state->proto_task)
proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN,
false);
- if (task == &state->script_task && state->renew_pending)
- proto_shell_handler(&state->proto, PROTO_CMD_RENEW,
- false);
+ else if (task == &state->script_task) {
+ if (state->renew_pending)
+ proto_shell_handler(&state->proto,
+ PROTO_CMD_RENEW, false);
+ else if (!state->handler->no_proto_task &&
+ !state->proto_task.uloop.pending &&
+ state->sm == S_SETUP)
+ proto_shell_handler(&state->proto,
+ PROTO_CMD_TEARDOWN,
+ false);
+ }
break;
case S_SETUP_ABORT:
proto_shell_add_host_dependency(struct proto_shell_state *state, struct blob_attr **tb)
{
struct proto_shell_dependency *dep;
- struct blob_attr *host = tb[NOTIFY_HOST];
- struct blob_attr *ifname_a = tb[NOTIFY_IFNAME];
- const char *ifname_str = ifname_a ? blobmsg_data(ifname_a) : "";
- char *ifname;
+ const char *ifname = tb[NOTIFY_IFNAME] ? blobmsg_data(tb[NOTIFY_IFNAME]) : "";
+ const char *host = tb[NOTIFY_HOST] ? blobmsg_data(tb[NOTIFY_HOST]) : "";
if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
return UBUS_STATUS_PERMISSION_DENIED;
- if (!host)
- return UBUS_STATUS_INVALID_ARGUMENT;
+ dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1);
- dep = calloc_a(sizeof(*dep), &ifname, strlen(ifname_str) + 1);
- if (inet_pton(AF_INET, blobmsg_data(host), &dep->host) < 1) {
- if (inet_pton(AF_INET6, blobmsg_data(host), &dep->host) < 1) {
+ if (!host[0] && ifname[0]) {
+ dep->any = true;
+ } else if (inet_pton(AF_INET, host, &dep->host) < 1) {
+ if (inet_pton(AF_INET6, host, &dep->host) < 1) {
free(dep);
return UBUS_STATUS_INVALID_ARGUMENT;
} else {
}
dep->proto = state;
- dep->interface = strcpy(ifname, ifname_str);
+ strcpy(dep->interface, ifname);
dep->dep.cb = proto_shell_if_up_cb;
interface_add_user(&dep->dep, NULL);
if (tmp && json_object_get_boolean(tmp))
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);
+
tmp = json_get_field(obj, "available", json_type_boolean);
if (tmp && json_object_get_boolean(tmp))
handler->proto.flags |= PROTO_FLAG_INIT_AVAILABLE;
if (tmp && json_object_get_boolean(tmp))
handler->proto.flags |= PROTO_FLAG_RENEW_AVAILABLE;
+ tmp = json_get_field(obj, "lasterror", json_type_boolean);
+ if (tmp && json_object_get_boolean(tmp))
+ handler->proto.flags |= PROTO_FLAG_LASTERROR;
+
config = json_get_field(obj, "config", json_type_array);
if (config)
handler->config_buf = netifd_handler_parse_config(&handler->config, config);