+static int
+ar8216_mangle_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ar8216_priv *priv = dev->phy_ptr;
+ unsigned char *buf;
+
+ if (unlikely(!priv))
+ goto error;
+
+ if (!priv->vlan)
+ goto send;
+
+ if (unlikely(skb_headroom(skb) < 2)) {
+ if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0)
+ goto error;
+ }
+
+ buf = skb_push(skb, 2);
+ buf[0] = 0x10;
+ buf[1] = 0x80;
+
+send:
+ return priv->hardstart(skb, dev);
+
+error:
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
+static int
+ar8216_mangle_rx(struct sk_buff *skb, int napi)
+{
+ struct ar8216_priv *priv;
+ struct net_device *dev;
+ unsigned char *buf;
+ int port, vlan;
+
+ dev = skb->dev;
+ if (!dev)
+ goto error;
+
+ priv = dev->phy_ptr;
+ if (!priv)
+ goto error;
+
+ /* don't strip the header if vlan mode is disabled */
+ if (!priv->vlan)
+ goto recv;
+
+ /* strip header, get vlan id */
+ buf = skb->data;
+ skb_pull(skb, 2);
+
+ /* check for vlan header presence */
+ if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00))
+ goto recv;
+
+ port = buf[0] & 0xf;
+
+ /* no need to fix up packets coming from a tagged source */
+ if (priv->vlan_tagged & (1 << port))
+ goto recv;
+
+ /* lookup port vid from local table, the switch passes an invalid vlan id */
+ vlan = priv->pvid[port];
+
+ buf[14 + 2] &= 0xf0;
+ buf[14 + 2] |= vlan >> 8;
+ buf[15 + 2] = vlan & 0xff;
+
+recv:
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ if (napi)
+ return netif_receive_skb(skb);
+ else
+ return netif_rx(skb);
+
+error:
+ /* no vlan? eat the packet! */
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
+static int
+ar8216_netif_rx(struct sk_buff *skb)
+{
+ return ar8216_mangle_rx(skb, 0);
+}
+
+static int
+ar8216_netif_receive_skb(struct sk_buff *skb)
+{
+ return ar8216_mangle_rx(skb, 1);
+}
+
+