device: prevent callbacks to device users that have been cleaned up already
[project/netifd.git] / device.c
index e635b05..feeb290 100644 (file)
--- a/device.c
+++ b/device.c
 static struct avl_tree devices;
 
 static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
-       [DEV_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING },
-       [DEV_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY },
-       [DEV_ATTR_MTU] = { "mtu", BLOBMSG_TYPE_INT32 },
-       [DEV_ATTR_MACADDR] = { "macaddr", BLOBMSG_TYPE_STRING },
-       [DEV_ATTR_TXQUEUELEN] = { "txqueuelen", BLOBMSG_TYPE_INT32 },
-       [DEV_ATTR_ENABLED] = { "enabled", BLOBMSG_TYPE_BOOL },
+       [DEV_ATTR_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
+       [DEV_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_ARRAY },
+       [DEV_ATTR_MTU] = { .name = "mtu", .type = BLOBMSG_TYPE_INT32 },
+       [DEV_ATTR_MACADDR] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
+       [DEV_ATTR_TXQUEUELEN] = { .name = "txqueuelen", .type = BLOBMSG_TYPE_INT32 },
+       [DEV_ATTR_ENABLED] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL },
 };
 
 const struct uci_blob_param_list device_attr_list = {
@@ -185,6 +185,10 @@ static int device_broadcast_cb(void *ctx, struct safe_list *list)
        struct device_user *dep = container_of(list, struct device_user, list);
        int *ev = ctx;
 
+       /* device might have been removed by an earlier callback */
+       if (!dep->dev)
+               return 0;
+
        if (dep->cb)
                dep->cb(dep, *ev);
        return 0;
@@ -216,7 +220,7 @@ int device_claim(struct device_user *dep)
        if (ret == 0)
                device_broadcast_event(dev, DEV_EVENT_UP);
        else {
-               D(DEVICE, "claim device %s failed: %d\n", dev->ifname, ret);
+               D(DEVICE, "claim %s %s failed: %d\n", dev->type->name, dev->ifname, ret);
                dev->active = 0;
                dep->claimed = false;
        }
@@ -408,6 +412,9 @@ void device_add_user(struct device_user *dep, struct device *dev)
 {
        struct safe_list *head;
 
+       if (dep->dev == dev)
+               return;
+
        if (dep->dev)
                device_remove_user(dep);