+proto_shell_notify_error(struct proto_shell_state *state, struct blob_attr **tb)
+{
+ struct blob_attr *cur;
+ char *data[16];
+ int n_data = 0;
+ int rem;
+
+ if (!tb[NOTIFY_ERROR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) {
+ if (n_data + 1 == ARRAY_SIZE(data))
+ goto error;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ goto error;
+
+ if (!blobmsg_check_attr(cur, NULL))
+ goto error;
+
+ data[n_data++] = blobmsg_data(cur);
+ }
+
+ if (!n_data)
+ goto error;
+
+ interface_add_error(state->proto.iface, state->handler->proto.name,
+ data[0], (const char **) &data[1], n_data - 1);
+
+ return 0;
+
+error:
+ return UBUS_STATUS_INVALID_ARGUMENT;
+}
+
+static int
+proto_shell_block_restart(struct proto_shell_state *state, struct blob_attr **tb)
+{
+ state->proto.iface->autostart = false;
+ return 0;
+}
+
+static int
+proto_shell_set_available(struct proto_shell_state *state, struct blob_attr **tb)
+{
+ if (!tb[NOTIFY_AVAILABLE])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE]));
+ return 0;
+}
+
+static int
+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];
+
+ if (!host)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ dep = calloc(1, sizeof(*dep));
+ if (!inet_pton(AF_INET, blobmsg_data(host), &dep->host)) {
+ free(dep);
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ dep->proto = state;
+ dep->dep.cb = proto_shell_if_up_cb;
+ interface_add_user(&dep->dep, NULL);
+ list_add(&dep->list, &state->deps);
+ proto_shell_update_host_dep(dep);
+ if (!dep->dep.iface)
+ return UBUS_STATUS_NOT_FOUND;
+
+ 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