+static void netifd_add_interface_errors(struct blob_buf *b, struct interface *iface)
+{
+ struct interface_error *error;
+ void *e, *e2, *e3;
+ int i;
+
+ e = blobmsg_open_array(b, "errors");
+ list_for_each_entry(error, &iface->errors, list) {
+ e2 = blobmsg_open_table(b, NULL);
+
+ blobmsg_add_string(b, "subsystem", error->subsystem);
+ blobmsg_add_string(b, "code", error->code);
+ if (error->data[0]) {
+ e3 = blobmsg_open_array(b, "data");
+ for (i = 0; error->data[i]; i++)
+ blobmsg_add_string(b, NULL, error->data[i]);
+ blobmsg_close_array(b, e3);
+ }
+
+ blobmsg_close_table(b, e2);
+ }
+ blobmsg_close_array(b, e);
+}
+
+static int netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ static const char *iface_state[] = {
+ [IFS_SETUP] = "setup",
+ [IFS_UP] = "up",
+ [IFS_TEARDOWN] = "teardown",
+ [IFS_DOWN] = "down",
+ };
+ struct interface *iface;
+
+ iface = container_of(obj, struct interface, ubus);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "state", iface_state[iface->state]);
+ blobmsg_add_u8(&b, "active", iface->active);
+ blobmsg_add_u8(&b, "autostart", iface->autostart);
+ if (iface->main_dev.dev) {
+ struct device *dev = iface->main_dev.dev;
+ const char *field;
+ void *devinfo;
+
+ /* use a different field for virtual devices */
+ if (dev->avl.key)
+ field = "device";
+ else
+ field = "link";
+
+ devinfo = blobmsg_open_table(&b, field);
+ blobmsg_add_string(&b, "name", dev->ifname);
+
+ if (dev->type->dump_status)
+ dev->type->dump_status(dev, &b);
+
+ blobmsg_close_table(&b, devinfo);
+ }
+
+ if (!list_is_empty(&iface->errors))
+ netifd_add_interface_errors(&b, iface);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+