vlan/macvlan: propagate transmission state to upper layers
[safe/jmp/linux-2.6] / net / 8021q / vlan_dev.c
index 6e695ac..9159659 100644 (file)
@@ -288,10 +288,14 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
        return rc;
 }
 
-static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
+                                           struct net_device *dev)
 {
-       struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+       int i = skb_get_queue_mapping(skb);
+       struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
+       unsigned int len;
+       int ret;
 
        /* Handle non-VLAN frames if they are sent to us, for example by DHCP.
         *
@@ -317,30 +321,44 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        vlan_dev_info(dev)->cnt_inc_headroom_on_tx++;
        }
 
-       txq->tx_packets++;
-       txq->tx_bytes += skb->len;
 
        skb->dev = vlan_dev_info(dev)->real_dev;
-       dev_queue_xmit(skb);
-       return NETDEV_TX_OK;
+       len = skb->len;
+       ret = dev_queue_xmit(skb);
+
+       if (likely(ret == NET_XMIT_SUCCESS)) {
+               txq->tx_packets++;
+               txq->tx_bytes += len;
+       } else
+               txq->tx_dropped++;
+
+       return ret;
 }
 
-static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
-                                           struct net_device *dev)
+static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
+                                                   struct net_device *dev)
 {
-       struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+       int i = skb_get_queue_mapping(skb);
+       struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
        u16 vlan_tci;
+       unsigned int len;
+       int ret;
 
        vlan_tci = vlan_dev_info(dev)->vlan_id;
        vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
        skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
 
-       txq->tx_packets++;
-       txq->tx_bytes += skb->len;
-
        skb->dev = vlan_dev_info(dev)->real_dev;
-       dev_queue_xmit(skb);
-       return NETDEV_TX_OK;
+       len = skb->len;
+       ret = dev_queue_xmit(skb);
+
+       if (likely(ret == NET_XMIT_SUCCESS)) {
+               txq->tx_packets++;
+               txq->tx_bytes += len;
+       } else
+               txq->tx_dropped++;
+
+       return ret;
 }
 
 static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
@@ -375,7 +393,7 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
        struct vlan_dev_info *vlan = vlan_dev_info(dev);
        struct vlan_priority_tci_mapping *mp = NULL;
        struct vlan_priority_tci_mapping *np;
-       u32 vlan_qos = (vlan_prio << 13) & 0xE000;
+       u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
 
        /* See if a priority mapping exists.. */
        mp = vlan->egress_priority_map[skb_prio & 0xF];
@@ -586,6 +604,39 @@ static int vlan_dev_fcoe_ddp_done(struct net_device *dev, u16 xid)
 
        return len;
 }
+
+static int vlan_dev_fcoe_enable(struct net_device *dev)
+{
+       struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+       const struct net_device_ops *ops = real_dev->netdev_ops;
+       int rc = -EINVAL;
+
+       if (ops->ndo_fcoe_enable)
+               rc = ops->ndo_fcoe_enable(real_dev);
+       return rc;
+}
+
+static int vlan_dev_fcoe_disable(struct net_device *dev)
+{
+       struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+       const struct net_device_ops *ops = real_dev->netdev_ops;
+       int rc = -EINVAL;
+
+       if (ops->ndo_fcoe_disable)
+               rc = ops->ndo_fcoe_disable(real_dev);
+       return rc;
+}
+
+static int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type)
+{
+       struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+       const struct net_device_ops *ops = real_dev->netdev_ops;
+       int rc = -EINVAL;
+
+       if (ops->ndo_fcoe_get_wwn)
+               rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type);
+       return rc;
+}
 #endif
 
 static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
@@ -749,6 +800,9 @@ static const struct net_device_ops vlan_netdev_ops = {
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
        .ndo_fcoe_ddp_setup     = vlan_dev_fcoe_ddp_setup,
        .ndo_fcoe_ddp_done      = vlan_dev_fcoe_ddp_done,
+       .ndo_fcoe_enable        = vlan_dev_fcoe_enable,
+       .ndo_fcoe_disable       = vlan_dev_fcoe_disable,
+       .ndo_fcoe_get_wwn       = vlan_dev_fcoe_get_wwn,
 #endif
 };
 
@@ -769,6 +823,9 @@ static const struct net_device_ops vlan_netdev_accel_ops = {
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
        .ndo_fcoe_ddp_setup     = vlan_dev_fcoe_ddp_setup,
        .ndo_fcoe_ddp_done      = vlan_dev_fcoe_ddp_done,
+       .ndo_fcoe_enable        = vlan_dev_fcoe_enable,
+       .ndo_fcoe_disable       = vlan_dev_fcoe_disable,
+       .ndo_fcoe_get_wwn       = vlan_dev_fcoe_get_wwn,
 #endif
 };