add error reporting support
authorFelix Fietkau <nbd@openwrt.org>
Sun, 27 Mar 2011 22:17:51 +0000 (00:17 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 27 Mar 2011 22:17:51 +0000 (00:17 +0200)
interface.c
interface.h
ubus.c

index d45f2d5..52d30fc 100644 (file)
@@ -7,7 +7,53 @@
 
 LIST_HEAD(interfaces);
 
 
 LIST_HEAD(interfaces);
 
-static int interface_event(struct interface *iface, enum interface_event ev)
+static void
+clear_interface_errors(struct interface *iface)
+{
+       struct interface_error *error, *tmp;
+
+       list_for_each_entry_safe(error, tmp, &iface->errors, list) {
+               list_del(&error->list);
+               free(error);
+       }
+}
+
+void interface_add_error(struct interface *iface, const char *subsystem,
+                        const char *code, const char **data, int n_data)
+{
+       struct interface_error *error;
+       int i, len = 0;
+       int *datalen;
+       char *dest;
+
+       if (n_data) {
+               len = n_data * sizeof(char *);
+               datalen = alloca(len);
+               for (i = 0; i < n_data; i++) {
+                       datalen[i] = strlen(data[i]) + 1;
+                       len += datalen[i];
+               }
+       }
+
+       error = calloc(1, sizeof(*error) + sizeof(char *) + len);
+       if (!error)
+               return;
+
+       list_add_tail(&error->list, &iface->errors);
+       error->subsystem = subsystem;
+       error->code = code;
+
+       dest = (char *) &error->data[n_data + 1];
+       for (i = 0; i < n_data; i++) {
+               error->data[i] = dest;
+               memcpy(dest, data[i], datalen[i]);
+               dest += datalen[i];
+       }
+       error->data[n_data] = NULL;
+}
+
+static int
+interface_event(struct interface *iface, enum interface_event ev)
 {
        if (!iface->state || !iface->state->event)
                return 0;
 {
        if (!iface->state || !iface->state->event)
                return 0;
@@ -35,6 +81,8 @@ __set_interface_up(struct interface *iface)
 static void
 __set_interface_down(struct interface *iface)
 {
 static void
 __set_interface_down(struct interface *iface)
 {
+       clear_interface_errors(iface);
+
        if (!iface->up)
                return;
 
        if (!iface->up)
                return;
 
@@ -87,6 +135,8 @@ alloc_interface(const char *name)
        iface->l3_iface = &iface->main_dev;
        strncpy(iface->name, name, sizeof(iface->name) - 1);
        list_add(&iface->list, &interfaces);
        iface->l3_iface = &iface->main_dev;
        strncpy(iface->name, name, sizeof(iface->name) - 1);
        list_add(&iface->list, &interfaces);
+       INIT_LIST_HEAD(&iface->errors);
+
        netifd_ubus_add_interface(iface);
 
        return iface;
        netifd_ubus_add_interface(iface);
 
        return iface;
@@ -148,6 +198,11 @@ set_interface_up(struct interface *iface)
 {
        iface->autostart = true;
 
 {
        iface->autostart = true;
 
+       if (!iface->active) {
+               interface_add_error(iface, "interface", "NO_DEVICE", NULL, 0);
+               return -1;
+       }
+
        if (iface->up || !iface->active)
                return -1;
 
        if (iface->up || !iface->active)
                return -1;
 
@@ -159,10 +214,6 @@ int
 set_interface_down(struct interface *iface)
 {
        iface->autostart = false;
 set_interface_down(struct interface *iface)
 {
        iface->autostart = false;
-
-       if (!iface->up)
-               return -1;
-
        __set_interface_down(iface);
 
        return 0;
        __set_interface_down(iface);
 
        return 0;
index 0fd70d7..b3a86f2 100644 (file)
@@ -19,6 +19,14 @@ struct interface_proto_state {
        void (*free)(struct interface *, struct interface_proto_state *);
 };
 
        void (*free)(struct interface *, struct interface_proto_state *);
 };
 
+struct interface_error {
+       struct list_head list;
+
+       const char *subsystem;
+       const char *code;
+       const char *data[];
+};
+
 /*
  * interface configuration
  */
 /*
  * interface configuration
  */
@@ -45,6 +53,9 @@ struct interface {
        /* primary protocol state */
        struct interface_proto_state *state;
 
        /* primary protocol state */
        struct interface_proto_state *state;
 
+       /* errors/warnings while trying to bring up the interface */
+       struct list_head errors;
+
        struct ubus_object ubus;
 };
 
        struct ubus_object ubus;
 };
 
@@ -58,6 +69,9 @@ int set_interface_down(struct interface *iface);
 int interface_add_link(struct interface *iface, struct device *llif);
 void interface_remove_link(struct interface *iface, struct device *llif);
 
 int interface_add_link(struct interface *iface, struct device *llif);
 void interface_remove_link(struct interface *iface, struct device *llif);
 
+void interface_add_error(struct interface *iface, const char *subsystem,
+                        const char *code, const char **data, int n_data);
+
 int interface_attach_bridge(struct interface *iface, struct uci_section *s);
 
 #endif
 int interface_attach_bridge(struct interface *iface, struct uci_section *s);
 
 #endif
diff --git a/ubus.c b/ubus.c
index cdd1ff0..159d5f5 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -110,6 +110,30 @@ static int netifd_handle_down(struct ubus_context *ctx, struct ubus_object *obj,
        return 0;
 }
 
        return 0;
 }
 
+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 int netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj,
                                struct ubus_request_data *req, const char *method,
                                struct blob_attr *msg)
@@ -142,6 +166,9 @@ static int netifd_handle_status(struct ubus_context *ctx, struct ubus_object *ob
                blobmsg_close_table(&b, devinfo);
        }
 
                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;
        ubus_send_reply(ctx, req, b.head);
 
        return 0;