mirror of https://github.com/hak5/openwrt-owl.git
parent
71e356029e
commit
552cffd97a
|
@ -212,75 +212,6 @@ ar8216_read_port_link(struct ar8216_priv *priv, int port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
|
||||||
struct switch_val *val)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
priv->vlan = !!val->value.i;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
|
||||||
struct switch_val *val)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
val->value.i = priv->vlan;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
|
|
||||||
/* make sure no invalid PVIDs get set */
|
|
||||||
|
|
||||||
if (vlan >= dev->vlans)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
priv->pvid[port] = vlan;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
*vlan = priv->pvid[port];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
|
||||||
struct switch_val *val)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
priv->vlan_id[val->port_vlan] = val->value.i;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
|
||||||
struct switch_val *val)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
val->value.i = priv->vlan_id[val->port_vlan];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_get_port_link(struct switch_dev *dev, int port,
|
|
||||||
struct switch_port_link *link)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
|
|
||||||
ar8216_read_port_link(priv, port, link);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8216_mangle_tx(struct sk_buff *skb, struct net_device *dev)
|
ar8216_mangle_tx(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -377,88 +308,6 @@ ar8216_netif_receive_skb(struct sk_buff *skb)
|
||||||
return ar8216_mangle_rx(skb, 1);
|
return ar8216_mangle_rx(skb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct switch_attr ar8216_globals[] = {
|
|
||||||
{
|
|
||||||
.type = SWITCH_TYPE_INT,
|
|
||||||
.name = "enable_vlan",
|
|
||||||
.description = "Enable VLAN mode",
|
|
||||||
.set = ar8216_sw_set_vlan,
|
|
||||||
.get = ar8216_sw_get_vlan,
|
|
||||||
.max = 1
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct switch_attr ar8216_port[] = {
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct switch_attr ar8216_vlan[] = {
|
|
||||||
{
|
|
||||||
.type = SWITCH_TYPE_INT,
|
|
||||||
.name = "vid",
|
|
||||||
.description = "VLAN ID (0-4094)",
|
|
||||||
.set = ar8216_sw_set_vid,
|
|
||||||
.get = ar8216_sw_get_vid,
|
|
||||||
.max = 4094,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
u8 ports = priv->vlan_table[val->port_vlan];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
val->len = 0;
|
|
||||||
for (i = 0; i < dev->ports; i++) {
|
|
||||||
struct switch_port *p;
|
|
||||||
|
|
||||||
if (!(ports & (1 << i)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
p = &val->value.ports[val->len++];
|
|
||||||
p->id = i;
|
|
||||||
if (priv->vlan_tagged & (1 << i))
|
|
||||||
p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
|
|
||||||
else
|
|
||||||
p->flags = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
u8 *vt = &priv->vlan_table[val->port_vlan];
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
*vt = 0;
|
|
||||||
for (i = 0; i < val->len; i++) {
|
|
||||||
struct switch_port *p = &val->value.ports[i];
|
|
||||||
|
|
||||||
if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
|
|
||||||
priv->vlan_tagged |= (1 << p->id);
|
|
||||||
} else {
|
|
||||||
priv->vlan_tagged &= ~(1 << p->id);
|
|
||||||
priv->pvid[p->id] = val->port_vlan;
|
|
||||||
|
|
||||||
/* make sure that an untagged port does not
|
|
||||||
* appear in other vlans */
|
|
||||||
for (j = 0; j < AR8X16_MAX_VLANS; j++) {
|
|
||||||
if (j == val->port_vlan)
|
|
||||||
continue;
|
|
||||||
priv->vlan_table[j] &= ~(1 << p->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*vt |= 1 << p->id;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val)
|
ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val)
|
||||||
{
|
{
|
||||||
|
@ -578,73 +427,6 @@ ar8236_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress,
|
||||||
(members << AR8236_PORT_VLAN2_MEMBER_S));
|
(members << AR8236_PORT_VLAN2_MEMBER_S));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
ar8216_sw_hw_apply(struct switch_dev *dev)
|
|
||||||
{
|
|
||||||
struct ar8216_priv *priv = to_ar8216(dev);
|
|
||||||
u8 portmask[AR8216_NUM_PORTS];
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
mutex_lock(&priv->reg_mutex);
|
|
||||||
/* flush all vlan translation unit entries */
|
|
||||||
priv->chip->vtu_flush(priv);
|
|
||||||
|
|
||||||
memset(portmask, 0, sizeof(portmask));
|
|
||||||
if (!priv->init) {
|
|
||||||
/* calculate the port destination masks and load vlans
|
|
||||||
* into the vlan translation unit */
|
|
||||||
for (j = 0; j < AR8X16_MAX_VLANS; j++) {
|
|
||||||
u8 vp = priv->vlan_table[j];
|
|
||||||
|
|
||||||
if (!vp)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (i = 0; i < dev->ports; i++) {
|
|
||||||
u8 mask = (1 << i);
|
|
||||||
if (vp & mask)
|
|
||||||
portmask[i] |= vp & ~mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->chip->vtu_load_vlan(priv, priv->vlan_id[j],
|
|
||||||
priv->vlan_table[j]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* vlan disabled:
|
|
||||||
* isolate all ports, but connect them to the cpu port */
|
|
||||||
for (i = 0; i < dev->ports; i++) {
|
|
||||||
if (i == AR8216_PORT_CPU)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
portmask[i] = 1 << AR8216_PORT_CPU;
|
|
||||||
portmask[AR8216_PORT_CPU] |= (1 << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update the port destination mask registers and tag settings */
|
|
||||||
for (i = 0; i < dev->ports; i++) {
|
|
||||||
int egress, ingress;
|
|
||||||
int pvid;
|
|
||||||
|
|
||||||
if (priv->vlan) {
|
|
||||||
pvid = priv->vlan_id[priv->pvid[i]];
|
|
||||||
if (priv->vlan_tagged & (1 << i))
|
|
||||||
egress = AR8216_OUT_ADD_VLAN;
|
|
||||||
else
|
|
||||||
egress = AR8216_OUT_STRIP_VLAN;
|
|
||||||
ingress = AR8216_IN_SECURE;
|
|
||||||
} else {
|
|
||||||
pvid = i;
|
|
||||||
egress = AR8216_OUT_KEEP;
|
|
||||||
ingress = AR8216_IN_PORT_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
|
|
||||||
pvid);
|
|
||||||
}
|
|
||||||
mutex_unlock(&priv->reg_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8216_hw_init(struct ar8216_priv *priv)
|
ar8216_hw_init(struct ar8216_priv *priv)
|
||||||
{
|
{
|
||||||
|
@ -826,6 +608,197 @@ static const struct ar8xxx_chip ar8316_chip = {
|
||||||
.vtu_load_vlan = ar8216_vtu_load_vlan,
|
.vtu_load_vlan = ar8216_vtu_load_vlan,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
priv->vlan = !!val->value.i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
val->value.i = priv->vlan;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
|
||||||
|
/* make sure no invalid PVIDs get set */
|
||||||
|
|
||||||
|
if (vlan >= dev->vlans)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
priv->pvid[port] = vlan;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
*vlan = priv->pvid[port];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
priv->vlan_id[val->port_vlan] = val->value.i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
val->value.i = priv->vlan_id[val->port_vlan];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_get_port_link(struct switch_dev *dev, int port,
|
||||||
|
struct switch_port_link *link)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
|
||||||
|
ar8216_read_port_link(priv, port, link);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
u8 ports = priv->vlan_table[val->port_vlan];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
val->len = 0;
|
||||||
|
for (i = 0; i < dev->ports; i++) {
|
||||||
|
struct switch_port *p;
|
||||||
|
|
||||||
|
if (!(ports & (1 << i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
p = &val->value.ports[val->len++];
|
||||||
|
p->id = i;
|
||||||
|
if (priv->vlan_tagged & (1 << i))
|
||||||
|
p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
|
||||||
|
else
|
||||||
|
p->flags = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
u8 *vt = &priv->vlan_table[val->port_vlan];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
*vt = 0;
|
||||||
|
for (i = 0; i < val->len; i++) {
|
||||||
|
struct switch_port *p = &val->value.ports[i];
|
||||||
|
|
||||||
|
if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
|
||||||
|
priv->vlan_tagged |= (1 << p->id);
|
||||||
|
} else {
|
||||||
|
priv->vlan_tagged &= ~(1 << p->id);
|
||||||
|
priv->pvid[p->id] = val->port_vlan;
|
||||||
|
|
||||||
|
/* make sure that an untagged port does not
|
||||||
|
* appear in other vlans */
|
||||||
|
for (j = 0; j < AR8X16_MAX_VLANS; j++) {
|
||||||
|
if (j == val->port_vlan)
|
||||||
|
continue;
|
||||||
|
priv->vlan_table[j] &= ~(1 << p->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*vt |= 1 << p->id;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8216_sw_hw_apply(struct switch_dev *dev)
|
||||||
|
{
|
||||||
|
struct ar8216_priv *priv = to_ar8216(dev);
|
||||||
|
u8 portmask[AR8216_NUM_PORTS];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
mutex_lock(&priv->reg_mutex);
|
||||||
|
/* flush all vlan translation unit entries */
|
||||||
|
priv->chip->vtu_flush(priv);
|
||||||
|
|
||||||
|
memset(portmask, 0, sizeof(portmask));
|
||||||
|
if (!priv->init) {
|
||||||
|
/* calculate the port destination masks and load vlans
|
||||||
|
* into the vlan translation unit */
|
||||||
|
for (j = 0; j < AR8X16_MAX_VLANS; j++) {
|
||||||
|
u8 vp = priv->vlan_table[j];
|
||||||
|
|
||||||
|
if (!vp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; i < dev->ports; i++) {
|
||||||
|
u8 mask = (1 << i);
|
||||||
|
if (vp & mask)
|
||||||
|
portmask[i] |= vp & ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->chip->vtu_load_vlan(priv, priv->vlan_id[j],
|
||||||
|
priv->vlan_table[j]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* vlan disabled:
|
||||||
|
* isolate all ports, but connect them to the cpu port */
|
||||||
|
for (i = 0; i < dev->ports; i++) {
|
||||||
|
if (i == AR8216_PORT_CPU)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
portmask[i] = 1 << AR8216_PORT_CPU;
|
||||||
|
portmask[AR8216_PORT_CPU] |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update the port destination mask registers and tag settings */
|
||||||
|
for (i = 0; i < dev->ports; i++) {
|
||||||
|
int egress, ingress;
|
||||||
|
int pvid;
|
||||||
|
|
||||||
|
if (priv->vlan) {
|
||||||
|
pvid = priv->vlan_id[priv->pvid[i]];
|
||||||
|
if (priv->vlan_tagged & (1 << i))
|
||||||
|
egress = AR8216_OUT_ADD_VLAN;
|
||||||
|
else
|
||||||
|
egress = AR8216_OUT_STRIP_VLAN;
|
||||||
|
ingress = AR8216_IN_SECURE;
|
||||||
|
} else {
|
||||||
|
pvid = i;
|
||||||
|
egress = AR8216_OUT_KEEP;
|
||||||
|
ingress = AR8216_IN_PORT_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
|
||||||
|
pvid);
|
||||||
|
}
|
||||||
|
mutex_unlock(&priv->reg_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8216_sw_reset_switch(struct switch_dev *dev)
|
ar8216_sw_reset_switch(struct switch_dev *dev)
|
||||||
{
|
{
|
||||||
|
@ -849,6 +822,31 @@ ar8216_sw_reset_switch(struct switch_dev *dev)
|
||||||
return ar8216_sw_hw_apply(dev);
|
return ar8216_sw_hw_apply(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct switch_attr ar8216_globals[] = {
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "enable_vlan",
|
||||||
|
.description = "Enable VLAN mode",
|
||||||
|
.set = ar8216_sw_set_vlan,
|
||||||
|
.get = ar8216_sw_get_vlan,
|
||||||
|
.max = 1
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct switch_attr ar8216_port[] = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct switch_attr ar8216_vlan[] = {
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "vid",
|
||||||
|
.description = "VLAN ID (0-4094)",
|
||||||
|
.set = ar8216_sw_set_vid,
|
||||||
|
.get = ar8216_sw_get_vid,
|
||||||
|
.max = 4094,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const struct switch_dev_ops ar8216_sw_ops = {
|
static const struct switch_dev_ops ar8216_sw_ops = {
|
||||||
.attr_global = {
|
.attr_global = {
|
||||||
.attr = ar8216_globals,
|
.attr = ar8216_globals,
|
||||||
|
|
Loading…
Reference in New Issue