diff options
-rw-r--r-- | net/8021q/vlan_dev.c | 113 |
1 files changed, 24 insertions, 89 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e19e49184ae5..57799af51088 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -114,77 +114,49 @@ static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) | |||
114 | int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | 114 | int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, |
115 | struct packet_type *ptype, struct net_device *orig_dev) | 115 | struct packet_type *ptype, struct net_device *orig_dev) |
116 | { | 116 | { |
117 | unsigned char *rawp = NULL; | 117 | unsigned char *rawp; |
118 | struct vlan_hdr *vhdr; | 118 | struct vlan_hdr *vhdr; |
119 | unsigned short vid; | 119 | unsigned short vid; |
120 | struct net_device_stats *stats; | 120 | struct net_device_stats *stats; |
121 | unsigned short vlan_TCI; | 121 | unsigned short vlan_TCI; |
122 | __be16 proto; | 122 | __be16 proto; |
123 | 123 | ||
124 | if (dev->nd_net != &init_net) { | 124 | if (dev->nd_net != &init_net) |
125 | kfree_skb(skb); | 125 | goto err_free; |
126 | return -1; | ||
127 | } | ||
128 | 126 | ||
129 | skb = skb_share_check(skb, GFP_ATOMIC); | 127 | skb = skb_share_check(skb, GFP_ATOMIC); |
130 | if (skb == NULL) | 128 | if (skb == NULL) |
131 | return -1; | 129 | goto err_free; |
132 | |||
133 | if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) { | ||
134 | kfree_skb(skb); | ||
135 | return -1; | ||
136 | } | ||
137 | 130 | ||
138 | vhdr = (struct vlan_hdr *)(skb->data); | 131 | if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) |
132 | goto err_free; | ||
139 | 133 | ||
140 | /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */ | 134 | vhdr = (struct vlan_hdr *)skb->data; |
141 | vlan_TCI = ntohs(vhdr->h_vlan_TCI); | 135 | vlan_TCI = ntohs(vhdr->h_vlan_TCI); |
142 | |||
143 | vid = (vlan_TCI & VLAN_VID_MASK); | 136 | vid = (vlan_TCI & VLAN_VID_MASK); |
144 | 137 | ||
145 | /* Ok, we will find the correct VLAN device, strip the header, | ||
146 | * and then go on as usual. | ||
147 | */ | ||
148 | |||
149 | /* We have 12 bits of vlan ID. | ||
150 | * | ||
151 | * We must not drop allow preempt until we hold a | ||
152 | * reference to the device (netif_rx does that) or we | ||
153 | * fail. | ||
154 | */ | ||
155 | |||
156 | rcu_read_lock(); | 138 | rcu_read_lock(); |
157 | skb->dev = __find_vlan_dev(dev, vid); | 139 | skb->dev = __find_vlan_dev(dev, vid); |
158 | if (!skb->dev) { | 140 | if (!skb->dev) { |
159 | rcu_read_unlock(); | ||
160 | pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", | 141 | pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", |
161 | __FUNCTION__, (unsigned int)vid, dev->name); | 142 | __FUNCTION__, (unsigned int)vid, dev->name); |
162 | kfree_skb(skb); | 143 | goto err_unlock; |
163 | return -1; | ||
164 | } | 144 | } |
165 | 145 | ||
166 | skb->dev->last_rx = jiffies; | 146 | skb->dev->last_rx = jiffies; |
167 | 147 | ||
168 | /* Bump the rx counters for the VLAN device. */ | ||
169 | stats = &skb->dev->stats; | 148 | stats = &skb->dev->stats; |
170 | stats->rx_packets++; | 149 | stats->rx_packets++; |
171 | stats->rx_bytes += skb->len; | 150 | stats->rx_bytes += skb->len; |
172 | 151 | ||
173 | /* Take off the VLAN header (4 bytes currently) */ | ||
174 | skb_pull_rcsum(skb, VLAN_HLEN); | 152 | skb_pull_rcsum(skb, VLAN_HLEN); |
175 | 153 | ||
176 | /* | ||
177 | * Deal with ingress priority mapping. | ||
178 | */ | ||
179 | skb->priority = vlan_get_ingress_priority(skb->dev, | 154 | skb->priority = vlan_get_ingress_priority(skb->dev, |
180 | ntohs(vhdr->h_vlan_TCI)); | 155 | ntohs(vhdr->h_vlan_TCI)); |
181 | 156 | ||
182 | pr_debug("%s: priority: %u for TCI: %hu\n", | 157 | pr_debug("%s: priority: %u for TCI: %hu\n", |
183 | __FUNCTION__, skb->priority, ntohs(vhdr->h_vlan_TCI)); | 158 | __FUNCTION__, skb->priority, ntohs(vhdr->h_vlan_TCI)); |
184 | 159 | ||
185 | /* The ethernet driver already did the pkt_type calculations | ||
186 | * for us... | ||
187 | */ | ||
188 | switch (skb->pkt_type) { | 160 | switch (skb->pkt_type) { |
189 | case PACKET_BROADCAST: /* Yeah, stats collect these together.. */ | 161 | case PACKET_BROADCAST: /* Yeah, stats collect these together.. */ |
190 | /* stats->broadcast ++; // no such counter :-( */ | 162 | /* stats->broadcast ++; // no such counter :-( */ |
@@ -201,7 +173,6 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
201 | */ | 173 | */ |
202 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, | 174 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, |
203 | skb->dev->dev_addr)) | 175 | skb->dev->dev_addr)) |
204 | /* It is for our (changed) MAC-address! */ | ||
205 | skb->pkt_type = PACKET_HOST; | 176 | skb->pkt_type = PACKET_HOST; |
206 | break; | 177 | break; |
207 | default: | 178 | default: |
@@ -211,81 +182,45 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
211 | /* Was a VLAN packet, grab the encapsulated protocol, which the layer | 182 | /* Was a VLAN packet, grab the encapsulated protocol, which the layer |
212 | * three protocols care about. | 183 | * three protocols care about. |
213 | */ | 184 | */ |
214 | /* proto = get_unaligned(&vhdr->h_vlan_encapsulated_proto); */ | ||
215 | proto = vhdr->h_vlan_encapsulated_proto; | 185 | proto = vhdr->h_vlan_encapsulated_proto; |
216 | |||
217 | skb->protocol = proto; | ||
218 | if (ntohs(proto) >= 1536) { | 186 | if (ntohs(proto) >= 1536) { |
219 | /* place it back on the queue to be handled by | 187 | skb->protocol = proto; |
220 | * true layer 3 protocols. | 188 | goto recv; |
221 | */ | ||
222 | |||
223 | /* See if we are configured to re-write the VLAN header | ||
224 | * to make it look like ethernet... | ||
225 | */ | ||
226 | skb = vlan_check_reorder_header(skb); | ||
227 | |||
228 | /* Can be null if skb-clone fails when re-ordering */ | ||
229 | if (skb) { | ||
230 | netif_rx(skb); | ||
231 | } else { | ||
232 | /* TODO: Add a more specific counter here. */ | ||
233 | stats->rx_errors++; | ||
234 | } | ||
235 | rcu_read_unlock(); | ||
236 | return 0; | ||
237 | } | 189 | } |
238 | 190 | ||
239 | rawp = skb->data; | ||
240 | |||
241 | /* | 191 | /* |
242 | * This is a magic hack to spot IPX packets. Older Novell breaks | 192 | * This is a magic hack to spot IPX packets. Older Novell breaks |
243 | * the protocol design and runs IPX over 802.3 without an 802.2 LLC | 193 | * the protocol design and runs IPX over 802.3 without an 802.2 LLC |
244 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This | 194 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This |
245 | * won't work for fault tolerant netware but does for the rest. | 195 | * won't work for fault tolerant netware but does for the rest. |
246 | */ | 196 | */ |
197 | rawp = skb->data; | ||
247 | if (*(unsigned short *)rawp == 0xFFFF) { | 198 | if (*(unsigned short *)rawp == 0xFFFF) { |
248 | skb->protocol = htons(ETH_P_802_3); | 199 | skb->protocol = htons(ETH_P_802_3); |
249 | /* place it back on the queue to be handled by true layer 3 | 200 | goto recv; |
250 | * protocols. */ | ||
251 | |||
252 | /* See if we are configured to re-write the VLAN header | ||
253 | * to make it look like ethernet... | ||
254 | */ | ||
255 | skb = vlan_check_reorder_header(skb); | ||
256 | |||
257 | /* Can be null if skb-clone fails when re-ordering */ | ||
258 | if (skb) { | ||
259 | netif_rx(skb); | ||
260 | } else { | ||
261 | /* TODO: Add a more specific counter here. */ | ||
262 | stats->rx_errors++; | ||
263 | } | ||
264 | rcu_read_unlock(); | ||
265 | return 0; | ||
266 | } | 201 | } |
267 | 202 | ||
268 | /* | 203 | /* |
269 | * Real 802.2 LLC | 204 | * Real 802.2 LLC |
270 | */ | 205 | */ |
271 | skb->protocol = htons(ETH_P_802_2); | 206 | skb->protocol = htons(ETH_P_802_2); |
272 | /* place it back on the queue to be handled by upper layer protocols. | ||
273 | */ | ||
274 | 207 | ||
275 | /* See if we are configured to re-write the VLAN header | 208 | recv: |
276 | * to make it look like ethernet... | ||
277 | */ | ||
278 | skb = vlan_check_reorder_header(skb); | 209 | skb = vlan_check_reorder_header(skb); |
279 | 210 | if (!skb) { | |
280 | /* Can be null if skb-clone fails when re-ordering */ | ||
281 | if (skb) { | ||
282 | netif_rx(skb); | ||
283 | } else { | ||
284 | /* TODO: Add a more specific counter here. */ | ||
285 | stats->rx_errors++; | 211 | stats->rx_errors++; |
212 | goto err_unlock; | ||
286 | } | 213 | } |
214 | |||
215 | netif_rx(skb); | ||
287 | rcu_read_unlock(); | 216 | rcu_read_unlock(); |
288 | return 0; | 217 | return NET_RX_SUCCESS; |
218 | |||
219 | err_unlock: | ||
220 | rcu_read_unlock(); | ||
221 | err_free: | ||
222 | kfree_skb(skb); | ||
223 | return NET_RX_DROP; | ||
289 | } | 224 | } |
290 | 225 | ||
291 | static inline unsigned short | 226 | static inline unsigned short |