~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to net/8021q/vlan_core.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
#include <linux/netpoll.h>
5
5
#include "vlan.h"
6
6
 
7
 
bool vlan_hwaccel_do_receive(struct sk_buff **skbp)
 
7
bool vlan_do_receive(struct sk_buff **skbp)
8
8
{
9
9
        struct sk_buff *skb = *skbp;
10
10
        u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
23
23
                return false;
24
24
 
25
25
        skb->dev = vlan_dev;
 
26
        if (skb->pkt_type == PACKET_OTHERHOST) {
 
27
                /* Our lower layer thinks this is not local, let's make sure.
 
28
                 * This allows the VLAN to have a different MAC than the
 
29
                 * underlying device, and still route correctly. */
 
30
                if (!compare_ether_addr(eth_hdr(skb)->h_dest,
 
31
                                        vlan_dev->dev_addr))
 
32
                        skb->pkt_type = PACKET_HOST;
 
33
        }
 
34
 
 
35
        if (!(vlan_dev_info(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR)) {
 
36
                unsigned int offset = skb->data - skb_mac_header(skb);
 
37
 
 
38
                /*
 
39
                 * vlan_insert_tag expect skb->data pointing to mac header.
 
40
                 * So change skb->data before calling it and change back to
 
41
                 * original position later
 
42
                 */
 
43
                skb_push(skb, offset);
 
44
                skb = *skbp = vlan_insert_tag(skb, skb->vlan_tci);
 
45
                if (!skb)
 
46
                        return false;
 
47
                skb_pull(skb, offset + VLAN_HLEN);
 
48
                skb_reset_mac_len(skb);
 
49
        }
 
50
 
26
51
        skb->priority = vlan_get_ingress_priority(vlan_dev, skb->vlan_tci);
27
52
        skb->vlan_tci = 0;
28
53
 
31
56
        u64_stats_update_begin(&rx_stats->syncp);
32
57
        rx_stats->rx_packets++;
33
58
        rx_stats->rx_bytes += skb->len;
34
 
 
35
 
        switch (skb->pkt_type) {
36
 
        case PACKET_BROADCAST:
37
 
                break;
38
 
        case PACKET_MULTICAST:
 
59
        if (skb->pkt_type == PACKET_MULTICAST)
39
60
                rx_stats->rx_multicast++;
40
 
                break;
41
 
        case PACKET_OTHERHOST:
42
 
                /* Our lower layer thinks this is not local, let's make sure.
43
 
                 * This allows the VLAN to have a different MAC than the
44
 
                 * underlying device, and still route correctly. */
45
 
                if (!compare_ether_addr(eth_hdr(skb)->h_dest,
46
 
                                        vlan_dev->dev_addr))
47
 
                        skb->pkt_type = PACKET_HOST;
48
 
                break;
49
 
        }
50
61
        u64_stats_update_end(&rx_stats->syncp);
51
62
 
52
63
        return true;
88
99
        return napi_gro_frags(napi);
89
100
}
90
101
EXPORT_SYMBOL(vlan_gro_frags);
 
102
 
 
103
static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
 
104
{
 
105
        if (skb_cow(skb, skb_headroom(skb)) < 0)
 
106
                return NULL;
 
107
        memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN);
 
108
        skb->mac_header += VLAN_HLEN;
 
109
        skb_reset_mac_len(skb);
 
110
        return skb;
 
111
}
 
112
 
 
113
static void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
 
114
{
 
115
        __be16 proto;
 
116
        unsigned char *rawp;
 
117
 
 
118
        /*
 
119
         * Was a VLAN packet, grab the encapsulated protocol, which the layer
 
120
         * three protocols care about.
 
121
         */
 
122
 
 
123
        proto = vhdr->h_vlan_encapsulated_proto;
 
124
        if (ntohs(proto) >= 1536) {
 
125
                skb->protocol = proto;
 
126
                return;
 
127
        }
 
128
 
 
129
        rawp = skb->data;
 
130
        if (*(unsigned short *) rawp == 0xFFFF)
 
131
                /*
 
132
                 * This is a magic hack to spot IPX packets. Older Novell
 
133
                 * breaks the protocol design and runs IPX over 802.3 without
 
134
                 * an 802.2 LLC layer. We look for FFFF which isn't a used
 
135
                 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
 
136
                 * but does for the rest.
 
137
                 */
 
138
                skb->protocol = htons(ETH_P_802_3);
 
139
        else
 
140
                /*
 
141
                 * Real 802.2 LLC
 
142
                 */
 
143
                skb->protocol = htons(ETH_P_802_2);
 
144
}
 
145
 
 
146
struct sk_buff *vlan_untag(struct sk_buff *skb)
 
147
{
 
148
        struct vlan_hdr *vhdr;
 
149
        u16 vlan_tci;
 
150
 
 
151
        if (unlikely(vlan_tx_tag_present(skb))) {
 
152
                /* vlan_tci is already set-up so leave this for another time */
 
153
                return skb;
 
154
        }
 
155
 
 
156
        skb = skb_share_check(skb, GFP_ATOMIC);
 
157
        if (unlikely(!skb))
 
158
                goto err_free;
 
159
 
 
160
        if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
 
161
                goto err_free;
 
162
 
 
163
        vhdr = (struct vlan_hdr *) skb->data;
 
164
        vlan_tci = ntohs(vhdr->h_vlan_TCI);
 
165
        __vlan_hwaccel_put_tag(skb, vlan_tci);
 
166
 
 
167
        skb_pull_rcsum(skb, VLAN_HLEN);
 
168
        vlan_set_encap_proto(skb, vhdr);
 
169
 
 
170
        skb = vlan_reorder_header(skb);
 
171
        if (unlikely(!skb))
 
172
                goto err_free;
 
173
 
 
174
        return skb;
 
175
 
 
176
err_free:
 
177
        kfree_skb(skb);
 
178
        return NULL;
 
179
}