+ return 0;
+}
+
+static int
+proto_shell_setup_failed(struct proto_shell_state *state)
+{
+ switch (state->sm) {
+ case S_IDLE:
+ state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
+ /* fall through */
+ case S_SETUP:
+ proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+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, attr, tb);
+ case 1:
+ return proto_shell_run_command(state, tb);
+ case 2:
+ return proto_shell_kill_command(state, tb);
+ case 3:
+ return proto_shell_notify_error(state, tb);
+ case 4:
+ return proto_shell_block_restart(state, tb);
+ case 5:
+ return proto_shell_set_available(state, tb);
+ case 6:
+ return proto_shell_add_host_dependency(state, tb);
+ case 7:
+ return proto_shell_setup_failed(state);
+ default:
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+}
+
+static struct interface_proto_state *
+proto_shell_attach(const struct proto_handler *h, struct interface *iface,
+ struct blob_attr *attr)
+{
+ struct proto_shell_state *state;
+
+ state = calloc(1, sizeof(*state));
+ INIT_LIST_HEAD(&state->deps);
+
+ state->config = malloc(blob_pad_len(attr));
+ if (!state->config)
+ goto error;
+
+ memcpy(state->config, attr, blob_pad_len(attr));
+ state->proto.free = proto_shell_free;
+ state->proto.notify = proto_shell_notify;
+ state->proto.cb = proto_shell_handler;
+ state->teardown_timeout.cb = proto_shell_teardown_timeout_cb;
+ state->script_task.cb = proto_shell_script_cb;
+ state->script_task.dir_fd = proto_fd;
+ state->script_task.log_prefix = iface->name;
+ state->proto_task.cb = proto_shell_task_cb;
+ state->proto_task.dir_fd = proto_fd;
+ state->proto_task.log_prefix = iface->name;
+ state->handler = container_of(h, struct proto_shell_handler, proto);