summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2020-08-07 14:33:33 +0200
committerFelix Fietkau <nbd@nbd.name>2020-10-28 04:49:11 +0100
commitd59f3ddcbaf0784a01aa8534cdcb20554748e6e5 (patch)
tree85c87a5e30606dc06cecf41f95553ab6fae42b79
parenta3016c4512487a9673d13a4b09ba05e774df1e73 (diff)
vlandev: add pass-through hotplug ops that pass the VLAN info to the bridge
Only used for 802.1q devices Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--vlandev.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/vlandev.c b/vlandev.c
index 10b78e2..7efb5f4 100644
--- a/vlandev.c
+++ b/vlandev.c
@@ -45,6 +45,7 @@ static const struct uci_blob_param_list vlandev_attr_list = {
};
static struct device_type vlan8021q_device_type;
+static struct blob_buf b;
struct vlandev_device {
struct device dev;
@@ -57,6 +58,67 @@ struct vlandev_device {
struct vlandev_config config;
};
+static int
+vlandev_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan)
+{
+ struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev);
+ void *a;
+
+ dev = mvdev->parent.dev;
+ if (!dev || !dev->hotplug_ops)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ blob_buf_init(&b, 0);
+ a = blobmsg_open_array(&b, "vlans");
+ blobmsg_printf(&b, NULL, "%d", mvdev->config.vid);
+ blobmsg_close_array(&b, a);
+
+ return dev->hotplug_ops->add(dev, member, blobmsg_data(b.head));
+}
+
+static int
+vlandev_hotplug_del(struct device *dev, struct device *member)
+{
+ struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev);
+
+ dev = mvdev->parent.dev;
+ if (!dev || !dev->hotplug_ops)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return dev->hotplug_ops->del(dev, member);
+}
+
+static int
+vlandev_hotplug_prepare(struct device *dev)
+{
+ struct vlandev_device *mvdev = container_of(dev, struct vlandev_device, dev);
+
+ dev = mvdev->parent.dev;
+ if (!dev || !dev->hotplug_ops)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return dev->hotplug_ops->prepare(dev);
+}
+
+static void vlandev_hotplug_check(struct vlandev_device *mvdev)
+{
+ static const struct device_hotplug_ops hotplug_ops = {
+ .prepare = vlandev_hotplug_prepare,
+ .add = vlandev_hotplug_add,
+ .del = vlandev_hotplug_del
+ };
+ struct device *dev = mvdev->parent.dev;
+
+ if (!dev || !dev->hotplug_ops || avl_is_empty(&dev->vlans.avl) ||
+ dev->type != &vlan8021q_device_type) {
+ mvdev->dev.hotplug_ops = NULL;
+ return;
+ }
+
+ mvdev->dev.hotplug_ops = &hotplug_ops;
+}
+
+
static void
vlandev_base_cb(struct device_user *dev, enum device_event ev)
{
@@ -69,6 +131,9 @@ vlandev_base_cb(struct device_user *dev, enum device_event ev)
case DEV_EVENT_REMOVE:
device_set_present(&mvdev->dev, false);
break;
+ case DEV_EVENT_UPDATE_IFNAME:
+ vlandev_hotplug_check(mvdev);
+ break;
default:
return;
}
@@ -179,6 +244,7 @@ vlandev_config_init(struct device *dev)
basedev = device_get(blobmsg_data(mvdev->ifname), true);
device_add_user(&mvdev->parent, basedev);
+ vlandev_hotplug_check(mvdev);
}
static void vlandev_qos_mapping_list_apply(struct vlist_simple_tree *qos_mapping_li, struct blob_attr *list)