+#define _GNU_SOURCE
+
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
struct uloop_process setup_task;
struct uloop_process teardown_task;
bool teardown_pending;
+
+ struct uloop_process proto_task;
};
+static void
+kill_process(struct uloop_process *proc)
+{
+ if (!proc->pending)
+ return;
+
+ kill(proc->pid, SIGTERM);
+ uloop_process_delete(proc);
+}
+
static int
-run_script(const char **argv, struct uloop_process *proc)
+start_process(const char **argv, struct uloop_process *proc)
{
int pid;
+ kill_process(proc);
+
if ((pid = fork()) < 0)
return -1;
argv[i++] = proto->iface->main_dev.dev->ifname;
argv[i] = NULL;
- ret = run_script(argv, proc);
+ ret = start_process(argv, proc);
free(config);
return ret;
struct proto_shell_state *state;
state = container_of(p, struct proto_shell_state, teardown_task);
- state->proto.proto_event(&state->proto, IFPEV_DOWN);
+
+ kill_process(&state->proto_task);
+
if (state->l3_dev.dev)
device_remove_user(&state->l3_dev);
+
+ state->proto.proto_event(&state->proto, IFPEV_DOWN);
+}
+
+static void
+proto_shell_task_cb(struct uloop_process *p, int ret)
+{
+ struct proto_shell_state *state;
+
+ state = container_of(p, struct proto_shell_state, proto_task);
+ if (state->teardown_pending || state->teardown_task.pending)
+ return;
+
+ state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
+ proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
}
static void
enum {
+ NOTIFY_ACTION,
+ NOTIFY_COMMAND,
NOTIFY_LINK_UP,
NOTIFY_IFNAME,
NOTIFY_ADDR_EXT,
NOTIFY_IP6ADDR,
NOTIFY_ROUTES,
NOTIFY_ROUTES6,
+ NOTIFY_DNS,
__NOTIFY_LAST
};
static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
+ [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 },
+ [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY },
[NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL },
[NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
[NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL },
[NOTIFY_IP6ADDR] = { .name = "ip6addr", .type = BLOBMSG_TYPE_ARRAY },
[NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY },
[NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY },
+ [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
};
static int
-proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr)
+proto_shell_update_link(struct proto_shell_state *state, struct blob_attr **tb)
{
- struct proto_shell_state *state;
- struct blob_attr *tb[__NOTIFY_LAST], *cur;
+ struct blob_attr *cur;
bool addr_ext = false;
bool up;
- state = container_of(proto, struct proto_shell_state, proto);
-
- blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr));
if (!tb[NOTIFY_LINK_UP])
return UBUS_STATUS_INVALID_ARGUMENT;
if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
proto_shell_parse_route_list(state->proto.iface, cur, true);
+ if ((cur = tb[NOTIFY_DNS]) != NULL)
+ interface_add_dns_server_list(state->proto.iface, cur);
+
+ return 0;
+}
+
+static int
+proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb)
+{
+ struct blob_attr *cur;
+ char *argv[64];
+ int argc = 0;
+ int rem;
+
+ if (!tb[NOTIFY_COMMAND])
+ goto error;
+
+ blobmsg_for_each_attr(cur, tb[NOTIFY_COMMAND], rem) {
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ goto error;
+
+ if (!blobmsg_check_attr(cur, NULL))
+ goto error;
+
+ argv[argc++] = blobmsg_data(cur);
+ if (argc == ARRAY_SIZE(argv) - 1)
+ goto error;
+ }
+ argv[argc] = NULL;
+ start_process((const char **) argv, &state->proto_task);
+
return 0;
+
+error:
+ return UBUS_STATUS_INVALID_ARGUMENT;
+}
+
+static int
+proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr)
+{
+ struct proto_shell_state *state;
+ struct blob_attr *tb[__NOTIFY_LAST];
+
+ state = container_of(proto, struct proto_shell_state, proto);
+
+ blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr));
+ if (!tb[NOTIFY_ACTION])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
+ case 0:
+ return proto_shell_update_link(state, tb);
+ case 1:
+ return proto_shell_run_command(state, tb);
+ default:
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
}
struct interface_proto_state *
state->setup_timeout.cb = proto_shell_setup_timeout_cb;
state->setup_task.cb = proto_shell_setup_cb;
state->teardown_task.cb = proto_shell_teardown_cb;
+ state->proto_task.cb = proto_shell_task_cb;
state->handler = container_of(h, struct proto_shell_handler, proto);
return &state->proto;
if (attrs[i].type > BLOBMSG_TYPE_LAST)
goto error;
- str_len += strlen(attrs[i].name + 1);
+ str_len += strlen(attrs[i].name) + 1;
}
str_buf = malloc(str_len);