blob: 724f3de77e21335d637eea4a6bc034eb80146280 [file] [log] [blame]
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -07001/* src/p80211/p80211conv.c
2*
3* Ether/802.11 conversions and packet buffer routines
4*
5* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
6* --------------------------------------------------------------------
7*
8* linux-wlan
9*
10* The contents of this file are subject to the Mozilla Public
11* License Version 1.1 (the "License"); you may not use this file
12* except in compliance with the License. You may obtain a copy of
13* the License at http://www.mozilla.org/MPL/
14*
15* Software distributed under the License is distributed on an "AS
16* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17* implied. See the License for the specific language governing
18* rights and limitations under the License.
19*
20* Alternatively, the contents of this file may be used under the
21* terms of the GNU Public License version 2 (the "GPL"), in which
22* case the provisions of the GPL are applicable instead of the
23* above. If you wish to allow the use of your version of this file
24* only under the terms of the GPL and not to allow others to use
25* your version of this file under the MPL, indicate your decision
26* by deleting the provisions above and replace them with the notice
27* and other provisions required by the GPL. If you do not delete
28* the provisions above, a recipient may use your version of this
29* file under either the MPL or the GPL.
30*
31* --------------------------------------------------------------------
32*
33* Inquiries regarding the linux-wlan Open Source project can be
34* made directly to:
35*
36* AbsoluteValue Systems Inc.
37* info@linux-wlan.com
38* http://www.linux-wlan.com
39*
40* --------------------------------------------------------------------
41*
42* Portions of the development of this software were funded by
43* Intersil Corporation as part of PRISM(R) chipset product development.
44*
45* --------------------------------------------------------------------
46*
47* This file defines the functions that perform Ethernet to/from
48* 802.11 frame conversions.
49*
50* --------------------------------------------------------------------
51*/
52/*================================================================*/
53/* System Includes */
54
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070055
56#include <linux/module.h>
57#include <linux/kernel.h>
58#include <linux/sched.h>
59#include <linux/types.h>
60#include <linux/skbuff.h>
61#include <linux/slab.h>
62#include <linux/wireless.h>
63#include <linux/netdevice.h>
64#include <linux/etherdevice.h>
65#include <linux/if_ether.h>
Moritz Muehlenhoffae262302009-01-21 22:00:45 +010066#include <linux/byteorder/generic.h>
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070067
68#include <asm/byteorder.h>
69
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070070#include "wlan_compat.h"
71
72/*================================================================*/
73/* Project Includes */
74
75#include "p80211types.h"
76#include "p80211hdr.h"
77#include "p80211conv.h"
78#include "p80211mgmt.h"
79#include "p80211msg.h"
80#include "p80211netdev.h"
81#include "p80211ioctl.h"
82#include "p80211req.h"
83
84
85/*================================================================*/
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070086/* Local Static Definitions */
87
Solomon Peachyaaad4302008-10-29 10:42:53 -040088static u8 oui_rfc1042[] = {0x00, 0x00, 0x00};
89static u8 oui_8021h[] = {0x00, 0x00, 0xf8};
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070090
91/*================================================================*/
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070092/* Function Definitions */
93
94/*----------------------------------------------------------------
95* p80211pb_ether_to_80211
96*
97* Uses the contents of the ether frame and the etherconv setting
98* to build the elements of the 802.11 frame.
99*
100* We don't actually set
101* up the frame header here. That's the MAC's job. We're only handling
102* conversion of DIXII or 802.3+LLC frames to something that works
103* with 802.11.
104*
105* Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11
106* FCS is also not present and will need to be added elsewhere.
107*
108* Arguments:
109* ethconv Conversion type to perform
110* skb skbuff containing the ether frame
111* p80211_hdr 802.11 header
112*
113* Returns:
114* 0 on success, non-zero otherwise
115*
116* Call context:
117* May be called in interrupt or non-interrupt context
118----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400119int skb_ether_to_p80211( wlandevice_t *wlandev, u32 ethconv, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700120{
121
Solomon Peachyaaad4302008-10-29 10:42:53 -0400122 u16 fc;
123 u16 proto;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700124 wlan_ethhdr_t e_hdr;
125 wlan_llc_t *e_llc;
126 wlan_snap_t *e_snap;
127 int foo;
128
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700129 memcpy(&e_hdr, skb->data, sizeof(e_hdr));
130
131 if (skb->len <= 0) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100132 pr_debug("zero-length skb!\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700133 return 1;
134 }
135
136 if ( ethconv == WLAN_ETHCONV_ENCAP ) { /* simplest case */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100137 pr_debug("ENCAP len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700138 /* here, we don't care what kind of ether frm. Just stick it */
139 /* in the 80211 payload */
140 /* which is to say, leave the skb alone. */
141 } else {
142 /* step 1: classify ether frame, DIX or 802.3? */
143 proto = ntohs(e_hdr.type);
144 if ( proto <= 1500 ) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100145 pr_debug("802.3 len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700146 /* codes <= 1500 reserved for 802.3 lengths */
147 /* it's 802.3, pass ether payload unchanged, */
148
149 /* trim off ethernet header */
150 skb_pull(skb, WLAN_ETHHDR_LEN);
151
152 /* leave off any PAD octets. */
153 skb_trim(skb, proto);
154 } else {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100155 pr_debug("DIXII len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700156 /* it's DIXII, time for some conversion */
157
158 /* trim off ethernet header */
159 skb_pull(skb, WLAN_ETHHDR_LEN);
160
161 /* tack on SNAP */
162 e_snap = (wlan_snap_t *) skb_push(skb, sizeof(wlan_snap_t));
163 e_snap->type = htons(proto);
164 if ( ethconv == WLAN_ETHCONV_8021h && p80211_stt_findproto(proto) ) {
165 memcpy( e_snap->oui, oui_8021h, WLAN_IEEE_OUI_LEN);
166 } else {
167 memcpy( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN);
168 }
169
170 /* tack on llc */
171 e_llc = (wlan_llc_t *) skb_push(skb, sizeof(wlan_llc_t));
172 e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
173 e_llc->ssap = 0xAA;
174 e_llc->ctl = 0x03;
175
176 }
177 }
178
179 /* Set up the 802.11 header */
180 /* It's a data frame */
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100181 fc = cpu_to_le16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700182 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
183
184 switch ( wlandev->macmode ) {
185 case WLAN_MACMODE_IBSS_STA:
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100186 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
187 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
188 memcpy(p80211_hdr->a3.a3, wlandev->bssid, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700189 break;
190 case WLAN_MACMODE_ESS_STA:
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100191 fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100192 memcpy(p80211_hdr->a3.a1, wlandev->bssid, ETH_ALEN);
193 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
194 memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700195 break;
196 case WLAN_MACMODE_ESS_AP:
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100197 fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100198 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
199 memcpy(p80211_hdr->a3.a2, wlandev->bssid, ETH_ALEN);
200 memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700201 break;
202 default:
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100203 printk(KERN_ERR "Error: Converting eth to wlan in unknown mode.\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700204 return 1;
205 break;
206 }
207
208 p80211_wep->data = NULL;
209
210 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
211 // XXXX need to pick keynum other than default?
212
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700213 p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700214
215 if ((foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
216 skb->len,
217 (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
218 p80211_wep->iv, p80211_wep->icv))) {
Moritz Muehlenhoff9b9556e2009-01-25 21:55:01 +0100219 printk(KERN_WARNING "Host en-WEP failed, dropping frame (%d).\n", foo);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700220 return 2;
221 }
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100222 fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700223 }
224
225
226 // skb->nh.raw = skb->data;
227
228 p80211_hdr->a3.fc = fc;
229 p80211_hdr->a3.dur = 0;
230 p80211_hdr->a3.seq = 0;
231
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700232 return 0;
233}
234
235/* jkriegl: from orinoco, modified */
236static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
237 p80211_rxmeta_t *rxmeta)
238{
239 int i;
240
241 /* Gather wireless spy statistics: for each packet, compare the
242 * source address with out list, and if match, get the stats... */
243
244 for (i = 0; i < wlandev->spy_number; i++) {
245
246 if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
247 memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
248 wlandev->spy_stat[i].level = rxmeta->signal;
249 wlandev->spy_stat[i].noise = rxmeta->noise;
250 wlandev->spy_stat[i].qual = (rxmeta->signal > rxmeta->noise) ? \
251 (rxmeta->signal - rxmeta->noise) : 0;
252 wlandev->spy_stat[i].updated = 0x7;
253 }
254 }
255}
256
257/*----------------------------------------------------------------
258* p80211pb_80211_to_ether
259*
260* Uses the contents of a received 802.11 frame and the etherconv
261* setting to build an ether frame.
262*
263* This function extracts the src and dest address from the 802.11
264* frame to use in the construction of the eth frame.
265*
266* Arguments:
267* ethconv Conversion type to perform
268* skb Packet buffer containing the 802.11 frame
269*
270* Returns:
271* 0 on success, non-zero otherwise
272*
273* Call context:
274* May be called in interrupt or non-interrupt context
275----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400276int skb_p80211_to_ether( wlandevice_t *wlandev, u32 ethconv, struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700277{
278 netdevice_t *netdev = wlandev->netdev;
Solomon Peachyaaad4302008-10-29 10:42:53 -0400279 u16 fc;
280 unsigned int payload_length;
281 unsigned int payload_offset;
282 u8 daddr[WLAN_ETHADDR_LEN];
283 u8 saddr[WLAN_ETHADDR_LEN];
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700284 p80211_hdr_t *w_hdr;
285 wlan_ethhdr_t *e_hdr;
286 wlan_llc_t *e_llc;
287 wlan_snap_t *e_snap;
288
289 int foo;
290
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700291 payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
292 payload_offset = WLAN_HDR_A3_LEN;
293
294 w_hdr = (p80211_hdr_t *) skb->data;
295
296 /* setup some vars for convenience */
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100297 fc = le16_to_cpu(w_hdr->a3.fc);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700298 if ( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0) ) {
299 memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
300 memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
301 } else if( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1) ) {
302 memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
303 memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
304 } else if( (WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0) ) {
305 memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
306 memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
307 } else {
308 payload_offset = WLAN_HDR_A4_LEN;
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100309 if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100310 printk(KERN_ERR "A4 frame too short!\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700311 return 1;
312 }
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100313 payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700314 memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN);
315 memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN);
316 }
317
318 /* perform de-wep if necessary.. */
319 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc) && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
320 if (payload_length <= 8) {
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100321 printk(KERN_ERR "WEP frame too short (%u).\n",
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700322 skb->len);
323 return 1;
324 }
325 if ((foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
326 payload_length - 8, -1,
327 skb->data + payload_offset,
328 skb->data + payload_offset + payload_length - 4))) {
329 /* de-wep failed, drop skb. */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100330 pr_debug("Host de-WEP failed, dropping frame (%d).\n", foo);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700331 wlandev->rx.decrypt_err++;
332 return 2;
333 }
334
335 /* subtract the IV+ICV length off the payload */
336 payload_length -= 8;
337 /* chop off the IV */
338 skb_pull(skb, 4);
339 /* chop off the ICV. */
340 skb_trim(skb, skb->len - 4);
341
342 wlandev->rx.decrypt++;
343 }
344
345 e_hdr = (wlan_ethhdr_t *) (skb->data + payload_offset);
346
347 e_llc = (wlan_llc_t *) (skb->data + payload_offset);
348 e_snap = (wlan_snap_t *) (skb->data + payload_offset + sizeof(wlan_llc_t));
349
350 /* Test for the various encodings */
351 if ( (payload_length >= sizeof(wlan_ethhdr_t)) &&
352 ( e_llc->dsap != 0xaa || e_llc->ssap != 0xaa ) &&
353 ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) ||
354 (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100355 pr_debug("802.3 ENCAP len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700356 /* 802.3 Encapsulated */
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000357 /* Test for an overlength frame */
358 if ( payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) {
359 /* A bogus length ethfrm has been encap'd. */
360 /* Is someone trying an oflow attack? */
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100361 printk(KERN_ERR "ENCAP frame too large (%d > %d)\n",
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000362 payload_length, netdev->mtu + WLAN_ETHHDR_LEN);
363 return 1;
364 }
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700365
366 /* Chop off the 802.11 header. it's already sane. */
367 skb_pull(skb, payload_offset);
368 /* chop off the 802.11 CRC */
369 skb_trim(skb, skb->len - WLAN_CRC_LEN);
370
371 } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) &&
372 (e_llc->dsap == 0xaa) &&
373 (e_llc->ssap == 0xaa) &&
374 (e_llc->ctl == 0x03) &&
375 (((memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)==0) &&
376 (ethconv == WLAN_ETHCONV_8021h) &&
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100377 (p80211_stt_findproto(le16_to_cpu(e_snap->type)))) ||
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700378 (memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)!=0)))
379 {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100380 pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700381 /* it's a SNAP + RFC1042 frame && protocol is in STT */
382 /* build 802.3 + RFC1042 */
383
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000384 /* Test for an overlength frame */
385 if ( payload_length > netdev->mtu ) {
386 /* A bogus length ethfrm has been sent. */
387 /* Is someone trying an oflow attack? */
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100388 printk(KERN_ERR "SNAP frame too large (%d > %d)\n",
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000389 payload_length, netdev->mtu);
390 return 1;
391 }
392
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700393 /* chop 802.11 header from skb. */
394 skb_pull(skb, payload_offset);
395
396 /* create 802.3 header at beginning of skb. */
397 e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
398 memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
399 memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
400 e_hdr->type = htons(payload_length);
401
402 /* chop off the 802.11 CRC */
403 skb_trim(skb, skb->len - WLAN_CRC_LEN);
404
405 } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) &&
406 (e_llc->dsap == 0xaa) &&
407 (e_llc->ssap == 0xaa) &&
408 (e_llc->ctl == 0x03) ) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100409 pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700410 /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */
411 /* build a DIXII + RFC894 */
412
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000413 /* Test for an overlength frame */
414 if ((payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t))
415 > netdev->mtu) {
416 /* A bogus length ethfrm has been sent. */
417 /* Is someone trying an oflow attack? */
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100418 printk(KERN_ERR "DIXII frame too large (%ld > %d)\n",
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000419 (long int) (payload_length - sizeof(wlan_llc_t) -
420 sizeof(wlan_snap_t)),
421 netdev->mtu);
422 return 1;
423 }
424
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700425 /* chop 802.11 header from skb. */
426 skb_pull(skb, payload_offset);
427
428 /* chop llc header from skb. */
429 skb_pull(skb, sizeof(wlan_llc_t));
430
431 /* chop snap header from skb. */
432 skb_pull(skb, sizeof(wlan_snap_t));
433
434 /* create 802.3 header at beginning of skb. */
435 e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
436 e_hdr->type = e_snap->type;
437 memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
438 memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
439
440 /* chop off the 802.11 CRC */
441 skb_trim(skb, skb->len - WLAN_CRC_LEN);
442 } else {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100443 pr_debug("NON-ENCAP len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700444 /* any NON-ENCAP */
445 /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
446 /* build an 802.3 frame */
447 /* allocate space and setup hostbuf */
448
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000449 /* Test for an overlength frame */
450 if ( payload_length > netdev->mtu ) {
451 /* A bogus length ethfrm has been sent. */
452 /* Is someone trying an oflow attack? */
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100453 printk(KERN_ERR "OTHER frame too large (%d > %d)\n",
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000454 payload_length,
455 netdev->mtu);
456 return 1;
457 }
458
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700459 /* Chop off the 802.11 header. */
460 skb_pull(skb, payload_offset);
461
462 /* create 802.3 header at beginning of skb. */
463 e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
464 memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
465 memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
466 e_hdr->type = htons(payload_length);
467
468 /* chop off the 802.11 CRC */
469 skb_trim(skb, skb->len - WLAN_CRC_LEN);
470
471 }
472
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000473 /*
474 * Note that eth_type_trans() expects an skb w/ skb->data pointing
475 * at the MAC header, it then sets the following skb members:
476 * skb->mac_header,
477 * skb->data, and
478 * skb->pkt_type.
479 * It then _returns_ the value that _we're_ supposed to stuff in
480 * skb->protocol. This is nuts.
481 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700482 skb->protocol = eth_type_trans(skb, netdev);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700483
484 /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
485 /* jkriegl: only process signal/noise if requested by iwspy */
486 if (wlandev->spy_number)
487 orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source, P80211SKB_RXMETA(skb));
488
489 /* Free the metadata */
490 p80211skb_rxmeta_detach(skb);
491
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700492 return 0;
493}
494
495/*----------------------------------------------------------------
496* p80211_stt_findproto
497*
498* Searches the 802.1h Selective Translation Table for a given
499* protocol.
500*
501* Arguments:
502* proto protocl number (in host order) to search for.
503*
504* Returns:
505* 1 - if the table is empty or a match is found.
506* 0 - if the table is non-empty and a match is not found.
507*
508* Call context:
509* May be called in interrupt or non-interrupt context
510----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400511int p80211_stt_findproto(u16 proto)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700512{
513 /* Always return found for now. This is the behavior used by the */
514 /* Zoom Win95 driver when 802.1h mode is selected */
515 /* TODO: If necessary, add an actual search we'll probably
516 need this to match the CMAC's way of doing things.
517 Need to do some testing to confirm.
518 */
519
520 if (proto == 0x80f3) /* APPLETALK */
521 return 1;
522
523 return 0;
524}
525
526/*----------------------------------------------------------------
527* p80211skb_rxmeta_detach
528*
529* Disconnects the frmmeta and rxmeta from an skb.
530*
531* Arguments:
532* wlandev The wlandev this skb belongs to.
533* skb The skb we're attaching to.
534*
535* Returns:
536* 0 on success, non-zero otherwise
537*
538* Call context:
539* May be called in interrupt or non-interrupt context
540----------------------------------------------------------------*/
541void
542p80211skb_rxmeta_detach(struct sk_buff *skb)
543{
544 p80211_rxmeta_t *rxmeta;
545 p80211_frmmeta_t *frmmeta;
546
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700547 /* Sanity checks */
548 if ( skb==NULL ) { /* bad skb */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100549 pr_debug("Called w/ null skb.\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700550 goto exit;
551 }
552 frmmeta = P80211SKB_FRMMETA(skb);
553 if ( frmmeta == NULL ) { /* no magic */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100554 pr_debug("Called w/ bad frmmeta magic.\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700555 goto exit;
556 }
557 rxmeta = frmmeta->rx;
558 if ( rxmeta == NULL ) { /* bad meta ptr */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100559 pr_debug("Called w/ bad rxmeta ptr.\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700560 goto exit;
561 }
562
563 /* Free rxmeta */
564 kfree(rxmeta);
565
566 /* Clear skb->cb */
567 memset(skb->cb, 0, sizeof(skb->cb));
568exit:
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700569 return;
570}
571
572/*----------------------------------------------------------------
573* p80211skb_rxmeta_attach
574*
575* Allocates a p80211rxmeta structure, initializes it, and attaches
576* it to an skb.
577*
578* Arguments:
579* wlandev The wlandev this skb belongs to.
580* skb The skb we're attaching to.
581*
582* Returns:
583* 0 on success, non-zero otherwise
584*
585* Call context:
586* May be called in interrupt or non-interrupt context
587----------------------------------------------------------------*/
588int
589p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
590{
591 int result = 0;
592 p80211_rxmeta_t *rxmeta;
593 p80211_frmmeta_t *frmmeta;
594
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700595 /* If these already have metadata, we error out! */
596 if (P80211SKB_RXMETA(skb) != NULL) {
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100597 printk(KERN_ERR "%s: RXmeta already attached!\n",
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700598 wlandev->name);
599 result = 0;
600 goto exit;
601 }
602
603 /* Allocate the rxmeta */
604 rxmeta = kmalloc(sizeof(p80211_rxmeta_t), GFP_ATOMIC);
605
606 if ( rxmeta == NULL ) {
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100607 printk(KERN_ERR "%s: Failed to allocate rxmeta.\n",
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700608 wlandev->name);
609 result = 1;
610 goto exit;
611 }
612
613 /* Initialize the rxmeta */
614 memset(rxmeta, 0, sizeof(p80211_rxmeta_t));
615 rxmeta->wlandev = wlandev;
616 rxmeta->hosttime = jiffies;
617
618 /* Overlay a frmmeta_t onto skb->cb */
619 memset(skb->cb, 0, sizeof(p80211_frmmeta_t));
620 frmmeta = (p80211_frmmeta_t*)(skb->cb);
621 frmmeta->magic = P80211_FRMMETA_MAGIC;
622 frmmeta->rx = rxmeta;
623exit:
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700624 return result;
625}
626
627/*----------------------------------------------------------------
628* p80211skb_free
629*
630* Frees an entire p80211skb by checking and freeing the meta struct
631* and then freeing the skb.
632*
633* Arguments:
634* wlandev The wlandev this skb belongs to.
635* skb The skb we're attaching to.
636*
637* Returns:
638* 0 on success, non-zero otherwise
639*
640* Call context:
641* May be called in interrupt or non-interrupt context
642----------------------------------------------------------------*/
643void
644p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
645{
646 p80211_frmmeta_t *meta;
Moritz Muehlenhoff8a251b52009-01-21 22:00:44 +0100647
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700648 meta = P80211SKB_FRMMETA(skb);
649 if ( meta && meta->rx) {
650 p80211skb_rxmeta_detach(skb);
651 } else {
Moritz Muehlenhoffedbd6062009-01-25 21:55:00 +0100652 printk(KERN_ERR "Freeing an skb (%p) w/ no frmmeta.\n", skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700653 }
654
655 dev_kfree_skb(skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700656 return;
657}