Skip to content

Commit

Permalink
bnx2: Reinsert VLAN tag when necessary.
Browse files Browse the repository at this point in the history
In certain cases when ASF or other management firmware is running, the
chip may be configured to always strip out the VLAN tag even when
VLAN acceleration is not enabled.  This causes some VLAN tagged
packets to be received by the host stack without any knowledge that
the original packet was VLAN tagged.

We fix this by re-inserting the VLAN tag into the packet when necessary.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael Chan authored and David S. Miller committed Aug 14, 2008
1 parent 729b85c commit f22828e
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions drivers/net/bnx2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2876,6 +2876,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
struct sw_bd *rx_buf;
struct sk_buff *skb;
dma_addr_t dma_addr;
u16 vtag = 0;
int hw_vlan __maybe_unused = 0;

sw_ring_cons = RX_RING_IDX(sw_cons);
sw_ring_prod = RX_RING_IDX(sw_prod);
Expand Down Expand Up @@ -2919,7 +2921,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
if (len <= bp->rx_copy_thresh) {
struct sk_buff *new_skb;

new_skb = netdev_alloc_skb(bp->dev, len + 2);
new_skb = netdev_alloc_skb(bp->dev, len + 6);
if (new_skb == NULL) {
bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
sw_ring_prod);
Expand All @@ -2928,9 +2930,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)

/* aligned copy */
skb_copy_from_linear_data_offset(skb,
BNX2_RX_OFFSET - 2,
new_skb->data, len + 2);
skb_reserve(new_skb, 2);
BNX2_RX_OFFSET - 6,
new_skb->data, len + 6);
skb_reserve(new_skb, 6);
skb_put(new_skb, len);

bnx2_reuse_rx_skb(bp, rxr, skb,
Expand All @@ -2941,6 +2943,25 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
goto next_rx;

if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
vtag = rx_hdr->l2_fhdr_vlan_tag;
#ifdef BCM_VLAN
if (bp->vlgrp)
hw_vlan = 1;
else
#endif
{
struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
__skb_push(skb, 4);

memmove(ve, skb->data + 4, ETH_ALEN * 2);
ve->h_vlan_proto = htons(ETH_P_8021Q);
ve->h_vlan_TCI = htons(vtag);
len += 4;
}
}

skb->protocol = eth_type_trans(skb, bp->dev);

if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Expand All @@ -2962,10 +2983,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
}

#ifdef BCM_VLAN
if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && bp->vlgrp) {
vlan_hwaccel_receive_skb(skb, bp->vlgrp,
rx_hdr->l2_fhdr_vlan_tag);
}
if (hw_vlan)
vlan_hwaccel_receive_skb(skb, bp->vlgrp, vtag);
else
#endif
netif_receive_skb(skb);
Expand Down

0 comments on commit f22828e

Please sign in to comment.