From 52196955dfe288cd3e8cf6e68d1f9b843b1636b1 Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Mon, 20 Apr 2009 21:26:39 +0000
Subject: [PATCH] swconfig: add a generic method for setting the port primary
 vlan id (used for transparently fixing up pvid for untagged port when setting
 vlan ports)

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@15307 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 .../files/drivers/net/phy/swconfig.c          | 47 ++++++++++++++++---
 .../generic-2.6/files/include/linux/switch.h  |  2 +
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c b/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c
index 83da094ee..8bae66708 100644
--- a/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c
+++ b/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c
@@ -75,6 +75,7 @@ swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
 static int
 swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
 {
+	struct switch_port *ports = val->value.ports;
 	int i;
 
 	if (val->port_vlan >= dev->vlans)
@@ -84,15 +85,42 @@ swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
 	if (val->len > dev->ports)
 		return -EINVAL;
 
+	if (!dev->set_vlan_ports)
+		return -EOPNOTSUPP;
+
 	for (i = 0; i < val->len; i++) {
-		if (val->value.ports[i].id >= dev->ports)
+		if (ports[i].id >= dev->ports)
 			return -EINVAL;
+
+		if (dev->set_port_pvid && !(ports[i].flags & SWITCH_PORT_FLAG_TAGGED))
+			dev->set_port_pvid(dev, ports[i].id, val->port_vlan);
 	}
 
-	if (!dev->set_vlan_ports)
+	return dev->set_vlan_ports(dev, val);
+}
+
+static int
+swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->set_port_pvid)
 		return -EOPNOTSUPP;
 
-	return dev->set_vlan_ports(dev, val);
+	return dev->set_port_pvid(dev, val->port_vlan, val->value.i);
+}
+
+static int
+swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->get_port_pvid)
+		return -EOPNOTSUPP;
+
+	return dev->get_port_pvid(dev, val->port_vlan, &val->value.i);
 }
 
 static int
@@ -115,7 +143,7 @@ enum vlan_defaults {
 };
 
 enum port_defaults {
-	PORT_LINK,
+	PORT_PVID,
 };
 
 static struct switch_attr default_global[] = {
@@ -128,10 +156,12 @@ static struct switch_attr default_global[] = {
 };
 
 static struct switch_attr default_port[] = {
-	[PORT_LINK] = {
+	[PORT_PVID] = {
 		.type = SWITCH_TYPE_INT,
-		.name = "link",
-		.description = "Current link speed",
+		.name = "pvid",
+		.description = "Primary VLAN ID",
+		.set = swconfig_set_pvid,
+		.get = swconfig_get_pvid,
 	}
 };
 
@@ -155,6 +185,9 @@ static void swconfig_defaults_init(struct switch_dev *dev)
 	if (dev->get_vlan_ports || dev->set_vlan_ports)
 		set_bit(VLAN_PORTS, &dev->def_vlan);
 
+	if (dev->get_port_pvid || dev->set_port_pvid)
+		set_bit(PORT_PVID, &dev->def_port);
+
 	/* always present, can be no-op */
 	set_bit(GLOBAL_APPLY, &dev->def_global);
 }
diff --git a/target/linux/generic-2.6/files/include/linux/switch.h b/target/linux/generic-2.6/files/include/linux/switch.h
index ef6b8f2ea..75c7dcfa9 100644
--- a/target/linux/generic-2.6/files/include/linux/switch.h
+++ b/target/linux/generic-2.6/files/include/linux/switch.h
@@ -129,6 +129,8 @@ struct switch_dev {
 
 	int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
 	int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
+	int (*get_port_pvid)(struct switch_dev *dev, int port, int *val);
+	int (*set_port_pvid)(struct switch_dev *dev, int port, int val);
 	int (*apply_config)(struct switch_dev *dev);
 };
 
-- 
2.20.1