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;
static void
__set_interface_down(struct interface *iface)
{
+ clear_interface_errors(iface);
+
if (!iface->up)
return;
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;
{
iface->autostart = true;
+ if (!iface->active) {
+ interface_add_error(iface, "interface", "NO_DEVICE", NULL, 0);
+ return -1;
+ }
+
if (iface->up || !iface->active)
return -1;
set_interface_down(struct interface *iface)
{
iface->autostart = false;
-
- if (!iface->up)
- return -1;
-
__set_interface_down(iface);
return 0;
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
*/
/* 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;
};
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
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)
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;