blob: 53b17c3b1ed05bae299994c6fbc89f3308db9d69 [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>
66
67#include <asm/byteorder.h>
68
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070069#include "wlan_compat.h"
70
71/*================================================================*/
72/* Project Includes */
73
74#include "p80211types.h"
75#include "p80211hdr.h"
76#include "p80211conv.h"
77#include "p80211mgmt.h"
78#include "p80211msg.h"
79#include "p80211netdev.h"
80#include "p80211ioctl.h"
81#include "p80211req.h"
82
83
84/*================================================================*/
85/* Local Constants */
86
87/*================================================================*/
88/* Local Macros */
89
90
91/*================================================================*/
92/* Local Types */
93
94
95/*================================================================*/
96/* Local Static Definitions */
97
Solomon Peachyaaad4302008-10-29 10:42:53 -040098static u8 oui_rfc1042[] = {0x00, 0x00, 0x00};
99static u8 oui_8021h[] = {0x00, 0x00, 0xf8};
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700100
101/*================================================================*/
102/* Local Function Declarations */
103
104
105/*================================================================*/
106/* Function Definitions */
107
108/*----------------------------------------------------------------
109* p80211pb_ether_to_80211
110*
111* Uses the contents of the ether frame and the etherconv setting
112* to build the elements of the 802.11 frame.
113*
114* We don't actually set
115* up the frame header here. That's the MAC's job. We're only handling
116* conversion of DIXII or 802.3+LLC frames to something that works
117* with 802.11.
118*
119* Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11
120* FCS is also not present and will need to be added elsewhere.
121*
122* Arguments:
123* ethconv Conversion type to perform
124* skb skbuff containing the ether frame
125* p80211_hdr 802.11 header
126*
127* Returns:
128* 0 on success, non-zero otherwise
129*
130* Call context:
131* May be called in interrupt or non-interrupt context
132----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400133int 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 -0700134{
135
Solomon Peachyaaad4302008-10-29 10:42:53 -0400136 u16 fc;
137 u16 proto;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700138 wlan_ethhdr_t e_hdr;
139 wlan_llc_t *e_llc;
140 wlan_snap_t *e_snap;
141 int foo;
142
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700143 memcpy(&e_hdr, skb->data, sizeof(e_hdr));
144
145 if (skb->len <= 0) {
146 WLAN_LOG_DEBUG(1, "zero-length skb!\n");
147 return 1;
148 }
149
150 if ( ethconv == WLAN_ETHCONV_ENCAP ) { /* simplest case */
151 WLAN_LOG_DEBUG(3, "ENCAP len: %d\n", skb->len);
152 /* here, we don't care what kind of ether frm. Just stick it */
153 /* in the 80211 payload */
154 /* which is to say, leave the skb alone. */
155 } else {
156 /* step 1: classify ether frame, DIX or 802.3? */
157 proto = ntohs(e_hdr.type);
158 if ( proto <= 1500 ) {
159 WLAN_LOG_DEBUG(3, "802.3 len: %d\n", skb->len);
160 /* codes <= 1500 reserved for 802.3 lengths */
161 /* it's 802.3, pass ether payload unchanged, */
162
163 /* trim off ethernet header */
164 skb_pull(skb, WLAN_ETHHDR_LEN);
165
166 /* leave off any PAD octets. */
167 skb_trim(skb, proto);
168 } else {
169 WLAN_LOG_DEBUG(3, "DIXII len: %d\n", skb->len);
170 /* it's DIXII, time for some conversion */
171
172 /* trim off ethernet header */
173 skb_pull(skb, WLAN_ETHHDR_LEN);
174
175 /* tack on SNAP */
176 e_snap = (wlan_snap_t *) skb_push(skb, sizeof(wlan_snap_t));
177 e_snap->type = htons(proto);
178 if ( ethconv == WLAN_ETHCONV_8021h && p80211_stt_findproto(proto) ) {
179 memcpy( e_snap->oui, oui_8021h, WLAN_IEEE_OUI_LEN);
180 } else {
181 memcpy( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN);
182 }
183
184 /* tack on llc */
185 e_llc = (wlan_llc_t *) skb_push(skb, sizeof(wlan_llc_t));
186 e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
187 e_llc->ssap = 0xAA;
188 e_llc->ctl = 0x03;
189
190 }
191 }
192
193 /* Set up the 802.11 header */
194 /* It's a data frame */
195 fc = host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
196 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
197
198 switch ( wlandev->macmode ) {
199 case WLAN_MACMODE_IBSS_STA:
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100200 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
201 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
202 memcpy(p80211_hdr->a3.a3, wlandev->bssid, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700203 break;
204 case WLAN_MACMODE_ESS_STA:
205 fc |= host2ieee16(WLAN_SET_FC_TODS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100206 memcpy(p80211_hdr->a3.a1, wlandev->bssid, ETH_ALEN);
207 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
208 memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700209 break;
210 case WLAN_MACMODE_ESS_AP:
211 fc |= host2ieee16(WLAN_SET_FC_FROMDS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100212 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
213 memcpy(p80211_hdr->a3.a2, wlandev->bssid, ETH_ALEN);
214 memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700215 break;
216 default:
217 WLAN_LOG_ERROR("Error: Converting eth to wlan in unknown mode.\n");
218 return 1;
219 break;
220 }
221
222 p80211_wep->data = NULL;
223
224 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
225 // XXXX need to pick keynum other than default?
226
227#if 1
228 p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
229#else
230 p80211_wep->data = skb->data;
231#endif
232
233 if ((foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
234 skb->len,
235 (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
236 p80211_wep->iv, p80211_wep->icv))) {
237 WLAN_LOG_WARNING("Host en-WEP failed, dropping frame (%d).\n", foo);
238 return 2;
239 }
240 fc |= host2ieee16(WLAN_SET_FC_ISWEP(1));
241 }
242
243
244 // skb->nh.raw = skb->data;
245
246 p80211_hdr->a3.fc = fc;
247 p80211_hdr->a3.dur = 0;
248 p80211_hdr->a3.seq = 0;
249
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700250 return 0;
251}
252
253/* jkriegl: from orinoco, modified */
254static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
255 p80211_rxmeta_t *rxmeta)
256{
257 int i;
258
259 /* Gather wireless spy statistics: for each packet, compare the
260 * source address with out list, and if match, get the stats... */
261
262 for (i = 0; i < wlandev->spy_number; i++) {
263
264 if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
265 memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
266 wlandev->spy_stat[i].level = rxmeta->signal;
267 wlandev->spy_stat[i].noise = rxmeta->noise;
268 wlandev->spy_stat[i].qual = (rxmeta->signal > rxmeta->noise) ? \
269 (rxmeta->signal - rxmeta->noise) : 0;
270 wlandev->spy_stat[i].updated = 0x7;
271 }
272 }
273}
274
275/*----------------------------------------------------------------
276* p80211pb_80211_to_ether
277*
278* Uses the contents of a received 802.11 frame and the etherconv
279* setting to build an ether frame.
280*
281* This function extracts the src and dest address from the 802.11
282* frame to use in the construction of the eth frame.
283*
284* Arguments:
285* ethconv Conversion type to perform
286* skb Packet buffer containing the 802.11 frame
287*
288* Returns:
289* 0 on success, non-zero otherwise
290*
291* Call context:
292* May be called in interrupt or non-interrupt context
293----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400294int skb_p80211_to_ether( wlandevice_t *wlandev, u32 ethconv, struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700295{
296 netdevice_t *netdev = wlandev->netdev;
Solomon Peachyaaad4302008-10-29 10:42:53 -0400297 u16 fc;
298 unsigned int payload_length;
299 unsigned int payload_offset;
300 u8 daddr[WLAN_ETHADDR_LEN];
301 u8 saddr[WLAN_ETHADDR_LEN];
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700302 p80211_hdr_t *w_hdr;
303 wlan_ethhdr_t *e_hdr;
304 wlan_llc_t *e_llc;
305 wlan_snap_t *e_snap;
306
307 int foo;
308
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700309 payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
310 payload_offset = WLAN_HDR_A3_LEN;
311
312 w_hdr = (p80211_hdr_t *) skb->data;
313
314 /* setup some vars for convenience */
315 fc = ieee2host16(w_hdr->a3.fc);
316 if ( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0) ) {
317 memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
318 memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
319 } else if( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1) ) {
320 memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
321 memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
322 } else if( (WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0) ) {
323 memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
324 memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
325 } else {
326 payload_offset = WLAN_HDR_A4_LEN;
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100327 if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700328 WLAN_LOG_ERROR("A4 frame too short!\n");
329 return 1;
330 }
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100331 payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700332 memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN);
333 memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN);
334 }
335
336 /* perform de-wep if necessary.. */
337 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc) && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
338 if (payload_length <= 8) {
339 WLAN_LOG_ERROR("WEP frame too short (%u).\n",
340 skb->len);
341 return 1;
342 }
343 if ((foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
344 payload_length - 8, -1,
345 skb->data + payload_offset,
346 skb->data + payload_offset + payload_length - 4))) {
347 /* de-wep failed, drop skb. */
348 WLAN_LOG_DEBUG(1, "Host de-WEP failed, dropping frame (%d).\n", foo);
349 wlandev->rx.decrypt_err++;
350 return 2;
351 }
352
353 /* subtract the IV+ICV length off the payload */
354 payload_length -= 8;
355 /* chop off the IV */
356 skb_pull(skb, 4);
357 /* chop off the ICV. */
358 skb_trim(skb, skb->len - 4);
359
360 wlandev->rx.decrypt++;
361 }
362
363 e_hdr = (wlan_ethhdr_t *) (skb->data + payload_offset);
364
365 e_llc = (wlan_llc_t *) (skb->data + payload_offset);
366 e_snap = (wlan_snap_t *) (skb->data + payload_offset + sizeof(wlan_llc_t));
367
368 /* Test for the various encodings */
369 if ( (payload_length >= sizeof(wlan_ethhdr_t)) &&
370 ( e_llc->dsap != 0xaa || e_llc->ssap != 0xaa ) &&
371 ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) ||
372 (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) {
373 WLAN_LOG_DEBUG(3, "802.3 ENCAP len: %d\n", payload_length);
374 /* 802.3 Encapsulated */
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000375 /* Test for an overlength frame */
376 if ( payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) {
377 /* A bogus length ethfrm has been encap'd. */
378 /* Is someone trying an oflow attack? */
379 WLAN_LOG_ERROR("ENCAP frame too large (%d > %d)\n",
380 payload_length, netdev->mtu + WLAN_ETHHDR_LEN);
381 return 1;
382 }
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700383
384 /* Chop off the 802.11 header. it's already sane. */
385 skb_pull(skb, payload_offset);
386 /* chop off the 802.11 CRC */
387 skb_trim(skb, skb->len - WLAN_CRC_LEN);
388
389 } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) &&
390 (e_llc->dsap == 0xaa) &&
391 (e_llc->ssap == 0xaa) &&
392 (e_llc->ctl == 0x03) &&
393 (((memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)==0) &&
394 (ethconv == WLAN_ETHCONV_8021h) &&
395 (p80211_stt_findproto(ieee2host16(e_snap->type)))) ||
396 (memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)!=0)))
397 {
398 WLAN_LOG_DEBUG(3, "SNAP+RFC1042 len: %d\n", payload_length);
399 /* it's a SNAP + RFC1042 frame && protocol is in STT */
400 /* build 802.3 + RFC1042 */
401
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000402 /* Test for an overlength frame */
403 if ( payload_length > netdev->mtu ) {
404 /* A bogus length ethfrm has been sent. */
405 /* Is someone trying an oflow attack? */
406 WLAN_LOG_ERROR("SNAP frame too large (%d > %d)\n",
407 payload_length, netdev->mtu);
408 return 1;
409 }
410
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700411 /* chop 802.11 header from skb. */
412 skb_pull(skb, payload_offset);
413
414 /* create 802.3 header at beginning of skb. */
415 e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
416 memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
417 memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
418 e_hdr->type = htons(payload_length);
419
420 /* chop off the 802.11 CRC */
421 skb_trim(skb, skb->len - WLAN_CRC_LEN);
422
423 } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) &&
424 (e_llc->dsap == 0xaa) &&
425 (e_llc->ssap == 0xaa) &&
426 (e_llc->ctl == 0x03) ) {
427 WLAN_LOG_DEBUG(3, "802.1h/RFC1042 len: %d\n", payload_length);
428 /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */
429 /* build a DIXII + RFC894 */
430
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000431 /* Test for an overlength frame */
432 if ((payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t))
433 > netdev->mtu) {
434 /* A bogus length ethfrm has been sent. */
435 /* Is someone trying an oflow attack? */
436 WLAN_LOG_ERROR("DIXII frame too large (%ld > %d)\n",
437 (long int) (payload_length - sizeof(wlan_llc_t) -
438 sizeof(wlan_snap_t)),
439 netdev->mtu);
440 return 1;
441 }
442
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700443 /* chop 802.11 header from skb. */
444 skb_pull(skb, payload_offset);
445
446 /* chop llc header from skb. */
447 skb_pull(skb, sizeof(wlan_llc_t));
448
449 /* chop snap header from skb. */
450 skb_pull(skb, sizeof(wlan_snap_t));
451
452 /* create 802.3 header at beginning of skb. */
453 e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
454 e_hdr->type = e_snap->type;
455 memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
456 memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
457
458 /* chop off the 802.11 CRC */
459 skb_trim(skb, skb->len - WLAN_CRC_LEN);
460 } else {
461 WLAN_LOG_DEBUG(3, "NON-ENCAP len: %d\n", payload_length);
462 /* any NON-ENCAP */
463 /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
464 /* build an 802.3 frame */
465 /* allocate space and setup hostbuf */
466
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000467 /* Test for an overlength frame */
468 if ( payload_length > netdev->mtu ) {
469 /* A bogus length ethfrm has been sent. */
470 /* Is someone trying an oflow attack? */
471 WLAN_LOG_ERROR("OTHER frame too large (%d > %d)\n",
472 payload_length,
473 netdev->mtu);
474 return 1;
475 }
476
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700477 /* Chop off the 802.11 header. */
478 skb_pull(skb, payload_offset);
479
480 /* create 802.3 header at beginning of skb. */
481 e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
482 memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
483 memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
484 e_hdr->type = htons(payload_length);
485
486 /* chop off the 802.11 CRC */
487 skb_trim(skb, skb->len - WLAN_CRC_LEN);
488
489 }
490
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000491 /*
492 * Note that eth_type_trans() expects an skb w/ skb->data pointing
493 * at the MAC header, it then sets the following skb members:
494 * skb->mac_header,
495 * skb->data, and
496 * skb->pkt_type.
497 * It then _returns_ the value that _we're_ supposed to stuff in
498 * skb->protocol. This is nuts.
499 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700500 skb->protocol = eth_type_trans(skb, netdev);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700501
502 /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
503 /* jkriegl: only process signal/noise if requested by iwspy */
504 if (wlandev->spy_number)
505 orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source, P80211SKB_RXMETA(skb));
506
507 /* Free the metadata */
508 p80211skb_rxmeta_detach(skb);
509
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700510 return 0;
511}
512
513/*----------------------------------------------------------------
514* p80211_stt_findproto
515*
516* Searches the 802.1h Selective Translation Table for a given
517* protocol.
518*
519* Arguments:
520* proto protocl number (in host order) to search for.
521*
522* Returns:
523* 1 - if the table is empty or a match is found.
524* 0 - if the table is non-empty and a match is not found.
525*
526* Call context:
527* May be called in interrupt or non-interrupt context
528----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400529int p80211_stt_findproto(u16 proto)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700530{
531 /* Always return found for now. This is the behavior used by the */
532 /* Zoom Win95 driver when 802.1h mode is selected */
533 /* TODO: If necessary, add an actual search we'll probably
534 need this to match the CMAC's way of doing things.
535 Need to do some testing to confirm.
536 */
537
538 if (proto == 0x80f3) /* APPLETALK */
539 return 1;
540
541 return 0;
542}
543
544/*----------------------------------------------------------------
545* p80211skb_rxmeta_detach
546*
547* Disconnects the frmmeta and rxmeta from an skb.
548*
549* Arguments:
550* wlandev The wlandev this skb belongs to.
551* skb The skb we're attaching to.
552*
553* Returns:
554* 0 on success, non-zero otherwise
555*
556* Call context:
557* May be called in interrupt or non-interrupt context
558----------------------------------------------------------------*/
559void
560p80211skb_rxmeta_detach(struct sk_buff *skb)
561{
562 p80211_rxmeta_t *rxmeta;
563 p80211_frmmeta_t *frmmeta;
564
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700565 /* Sanity checks */
566 if ( skb==NULL ) { /* bad skb */
567 WLAN_LOG_DEBUG(1, "Called w/ null skb.\n");
568 goto exit;
569 }
570 frmmeta = P80211SKB_FRMMETA(skb);
571 if ( frmmeta == NULL ) { /* no magic */
572 WLAN_LOG_DEBUG(1, "Called w/ bad frmmeta magic.\n");
573 goto exit;
574 }
575 rxmeta = frmmeta->rx;
576 if ( rxmeta == NULL ) { /* bad meta ptr */
577 WLAN_LOG_DEBUG(1, "Called w/ bad rxmeta ptr.\n");
578 goto exit;
579 }
580
581 /* Free rxmeta */
582 kfree(rxmeta);
583
584 /* Clear skb->cb */
585 memset(skb->cb, 0, sizeof(skb->cb));
586exit:
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700587 return;
588}
589
590/*----------------------------------------------------------------
591* p80211skb_rxmeta_attach
592*
593* Allocates a p80211rxmeta structure, initializes it, and attaches
594* it to an skb.
595*
596* Arguments:
597* wlandev The wlandev this skb belongs to.
598* skb The skb we're attaching to.
599*
600* Returns:
601* 0 on success, non-zero otherwise
602*
603* Call context:
604* May be called in interrupt or non-interrupt context
605----------------------------------------------------------------*/
606int
607p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
608{
609 int result = 0;
610 p80211_rxmeta_t *rxmeta;
611 p80211_frmmeta_t *frmmeta;
612
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700613 /* If these already have metadata, we error out! */
614 if (P80211SKB_RXMETA(skb) != NULL) {
615 WLAN_LOG_ERROR("%s: RXmeta already attached!\n",
616 wlandev->name);
617 result = 0;
618 goto exit;
619 }
620
621 /* Allocate the rxmeta */
622 rxmeta = kmalloc(sizeof(p80211_rxmeta_t), GFP_ATOMIC);
623
624 if ( rxmeta == NULL ) {
625 WLAN_LOG_ERROR("%s: Failed to allocate rxmeta.\n",
626 wlandev->name);
627 result = 1;
628 goto exit;
629 }
630
631 /* Initialize the rxmeta */
632 memset(rxmeta, 0, sizeof(p80211_rxmeta_t));
633 rxmeta->wlandev = wlandev;
634 rxmeta->hosttime = jiffies;
635
636 /* Overlay a frmmeta_t onto skb->cb */
637 memset(skb->cb, 0, sizeof(p80211_frmmeta_t));
638 frmmeta = (p80211_frmmeta_t*)(skb->cb);
639 frmmeta->magic = P80211_FRMMETA_MAGIC;
640 frmmeta->rx = rxmeta;
641exit:
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700642 return result;
643}
644
645/*----------------------------------------------------------------
646* p80211skb_free
647*
648* Frees an entire p80211skb by checking and freeing the meta struct
649* and then freeing the skb.
650*
651* Arguments:
652* wlandev The wlandev this skb belongs to.
653* skb The skb we're attaching to.
654*
655* Returns:
656* 0 on success, non-zero otherwise
657*
658* Call context:
659* May be called in interrupt or non-interrupt context
660----------------------------------------------------------------*/
661void
662p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
663{
664 p80211_frmmeta_t *meta;
Moritz Muehlenhoff8a251b52009-01-21 22:00:44 +0100665
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700666 meta = P80211SKB_FRMMETA(skb);
667 if ( meta && meta->rx) {
668 p80211skb_rxmeta_detach(skb);
669 } else {
670 WLAN_LOG_ERROR("Freeing an skb (%p) w/ no frmmeta.\n", skb);
671 }
672
673 dev_kfree_skb(skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700674 return;
675}