Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
p80211conv.c
Go to the documentation of this file.
1 /* 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.
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 
54 #include <linux/module.h>
55 #include <linux/kernel.h>
56 #include <linux/sched.h>
57 #include <linux/types.h>
58 #include <linux/skbuff.h>
59 #include <linux/slab.h>
60 #include <linux/wireless.h>
61 #include <linux/netdevice.h>
62 #include <linux/etherdevice.h>
63 #include <linux/if_ether.h>
65 
66 #include <asm/byteorder.h>
67 
68 #include "p80211types.h"
69 #include "p80211hdr.h"
70 #include "p80211conv.h"
71 #include "p80211mgmt.h"
72 #include "p80211msg.h"
73 #include "p80211netdev.h"
74 #include "p80211ioctl.h"
75 #include "p80211req.h"
76 
77 static u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
78 static u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
79 
80 /*----------------------------------------------------------------
81 * p80211pb_ether_to_80211
82 *
83 * Uses the contents of the ether frame and the etherconv setting
84 * to build the elements of the 802.11 frame.
85 *
86 * We don't actually set
87 * up the frame header here. That's the MAC's job. We're only handling
88 * conversion of DIXII or 802.3+LLC frames to something that works
89 * with 802.11.
90 *
91 * Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11
92 * FCS is also not present and will need to be added elsewhere.
93 *
94 * Arguments:
95 * ethconv Conversion type to perform
96 * skb skbuff containing the ether frame
97 * p80211_hdr 802.11 header
98 *
99 * Returns:
100 * 0 on success, non-zero otherwise
101 *
102 * Call context:
103 * May be called in interrupt or non-interrupt context
104 ----------------------------------------------------------------*/
105 int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
106  struct sk_buff *skb, union p80211_hdr *p80211_hdr,
107  struct p80211_metawep *p80211_wep)
108 {
109 
110  u16 fc;
111  u16 proto;
112  struct wlan_ethhdr e_hdr;
113  struct wlan_llc *e_llc;
114  struct wlan_snap *e_snap;
115  int foo;
116 
117  memcpy(&e_hdr, skb->data, sizeof(e_hdr));
118 
119  if (skb->len <= 0) {
120  pr_debug("zero-length skb!\n");
121  return 1;
122  }
123 
124  if (ethconv == WLAN_ETHCONV_ENCAP) { /* simplest case */
125  pr_debug("ENCAP len: %d\n", skb->len);
126  /* here, we don't care what kind of ether frm. Just stick it */
127  /* in the 80211 payload */
128  /* which is to say, leave the skb alone. */
129  } else {
130  /* step 1: classify ether frame, DIX or 802.3? */
131  proto = ntohs(e_hdr.type);
132  if (proto <= 1500) {
133  pr_debug("802.3 len: %d\n", skb->len);
134  /* codes <= 1500 reserved for 802.3 lengths */
135  /* it's 802.3, pass ether payload unchanged, */
136 
137  /* trim off ethernet header */
139 
140  /* leave off any PAD octets. */
141  skb_trim(skb, proto);
142  } else {
143  pr_debug("DIXII len: %d\n", skb->len);
144  /* it's DIXII, time for some conversion */
145 
146  /* trim off ethernet header */
148 
149  /* tack on SNAP */
150  e_snap =
151  (struct wlan_snap *) skb_push(skb,
152  sizeof(struct wlan_snap));
153  e_snap->type = htons(proto);
154  if (ethconv == WLAN_ETHCONV_8021h
155  && p80211_stt_findproto(proto)) {
156  memcpy(e_snap->oui, oui_8021h,
158  } else {
159  memcpy(e_snap->oui, oui_rfc1042,
161  }
162 
163  /* tack on llc */
164  e_llc =
165  (struct wlan_llc *) skb_push(skb,
166  sizeof(struct wlan_llc));
167  e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
168  e_llc->ssap = 0xAA;
169  e_llc->ctl = 0x03;
170 
171  }
172  }
173 
174  /* Set up the 802.11 header */
175  /* It's a data frame */
178 
179  switch (wlandev->macmode) {
181  memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
182  memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
183  memcpy(p80211_hdr->a3.a3, wlandev->bssid, ETH_ALEN);
184  break;
186  fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
187  memcpy(p80211_hdr->a3.a1, wlandev->bssid, ETH_ALEN);
188  memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
189  memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, ETH_ALEN);
190  break;
191  case WLAN_MACMODE_ESS_AP:
193  memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
194  memcpy(p80211_hdr->a3.a2, wlandev->bssid, ETH_ALEN);
195  memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, ETH_ALEN);
196  break;
197  default:
199  "Error: Converting eth to wlan in unknown mode.\n");
200  return 1;
201  break;
202  }
203 
204  p80211_wep->data = NULL;
205 
206  if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
207  && (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
208  /* XXXX need to pick keynum other than default? */
209 
210  p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
211  foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
212  skb->len,
213  (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
214  p80211_wep->iv, p80211_wep->icv);
215  if (foo) {
217  "Host en-WEP failed, dropping frame (%d).\n",
218  foo);
219  return 2;
220  }
221  fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
222  }
223 
224  /* skb->nh.raw = skb->data; */
225 
226  p80211_hdr->a3.fc = fc;
227  p80211_hdr->a3.dur = 0;
228  p80211_hdr->a3.seq = 0;
229 
230  return 0;
231 }
232 
233 /* jkriegl: from orinoco, modified */
234 static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
235  struct p80211_rxmeta *rxmeta)
236 {
237  int i;
238 
239  /* Gather wireless spy statistics: for each packet, compare the
240  * source address with out list, and if match, get the stats... */
241 
242  for (i = 0; i < wlandev->spy_number; i++) {
243 
244  if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
245  memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
246  wlandev->spy_stat[i].level = rxmeta->signal;
247  wlandev->spy_stat[i].noise = rxmeta->noise;
248  wlandev->spy_stat[i].qual =
249  (rxmeta->signal >
250  rxmeta->noise) ? (rxmeta->signal -
251  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 ----------------------------------------------------------------*/
276 int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
277  struct sk_buff *skb)
278 {
279  netdevice_t *netdev = wlandev->netdev;
280  u16 fc;
281  unsigned int payload_length;
282  unsigned int payload_offset;
285  union p80211_hdr *w_hdr;
286  struct wlan_ethhdr *e_hdr;
287  struct wlan_llc *e_llc;
288  struct wlan_snap *e_snap;
289 
290  int foo;
291 
292  payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
293  payload_offset = WLAN_HDR_A3_LEN;
294 
295  w_hdr = (union p80211_hdr *) skb->data;
296 
297  /* setup some vars for convenience */
298  fc = le16_to_cpu(w_hdr->a3.fc);
299  if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
300  memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
301  memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
302  } else if ((WLAN_GET_FC_TODS(fc) == 0)
303  && (WLAN_GET_FC_FROMDS(fc) == 1)) {
304  memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
305  memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
306  } else if ((WLAN_GET_FC_TODS(fc) == 1)
307  && (WLAN_GET_FC_FROMDS(fc) == 0)) {
308  memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
309  memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
310  } else {
311  payload_offset = WLAN_HDR_A4_LEN;
312  if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
313  printk(KERN_ERR "A4 frame too short!\n");
314  return 1;
315  }
316  payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
317  memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN);
318  memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN);
319  }
320 
321  /* perform de-wep if necessary.. */
322  if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc)
323  && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
324  if (payload_length <= 8) {
325  printk(KERN_ERR "WEP frame too short (%u).\n",
326  skb->len);
327  return 1;
328  }
329  foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
330  payload_length - 8, -1,
331  skb->data + payload_offset,
332  skb->data + payload_offset +
333  payload_length - 4);
334  if (foo) {
335  /* de-wep failed, drop skb. */
336  pr_debug("Host de-WEP failed, dropping frame (%d).\n",
337  foo);
338  wlandev->rx.decrypt_err++;
339  return 2;
340  }
341 
342  /* subtract the IV+ICV length off the payload */
343  payload_length -= 8;
344  /* chop off the IV */
345  skb_pull(skb, 4);
346  /* chop off the ICV. */
347  skb_trim(skb, skb->len - 4);
348 
349  wlandev->rx.decrypt++;
350  }
351 
352  e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);
353 
354  e_llc = (struct wlan_llc *) (skb->data + payload_offset);
355  e_snap =
356  (struct wlan_snap *) (skb->data + payload_offset +
357  sizeof(struct wlan_llc));
358 
359  /* Test for the various encodings */
360  if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
361  (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
362  ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) ||
363  (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) {
364  pr_debug("802.3 ENCAP len: %d\n", payload_length);
365  /* 802.3 Encapsulated */
366  /* Test for an overlength frame */
367  if (payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) {
368  /* A bogus length ethfrm has been encap'd. */
369  /* Is someone trying an oflow attack? */
370  printk(KERN_ERR "ENCAP frame too large (%d > %d)\n",
371  payload_length, netdev->mtu + WLAN_ETHHDR_LEN);
372  return 1;
373  }
374 
375  /* Chop off the 802.11 header. it's already sane. */
376  skb_pull(skb, payload_offset);
377  /* chop off the 802.11 CRC */
378  skb_trim(skb, skb->len - WLAN_CRC_LEN);
379 
380  } else if ((payload_length >= sizeof(struct wlan_llc) +
381  sizeof(struct wlan_snap))
382  && (e_llc->dsap == 0xaa)
383  && (e_llc->ssap == 0xaa)
384  && (e_llc->ctl == 0x03)
385  &&
386  (((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0)
387  && (ethconv == WLAN_ETHCONV_8021h)
388  && (p80211_stt_findproto(le16_to_cpu(e_snap->type))))
389  || (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) !=
390  0))) {
391  pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
392  /* it's a SNAP + RFC1042 frame && protocol is in STT */
393  /* build 802.3 + RFC1042 */
394 
395  /* Test for an overlength frame */
396  if (payload_length > netdev->mtu) {
397  /* A bogus length ethfrm has been sent. */
398  /* Is someone trying an oflow attack? */
399  printk(KERN_ERR "SNAP frame too large (%d > %d)\n",
400  payload_length, netdev->mtu);
401  return 1;
402  }
403 
404  /* chop 802.11 header from skb. */
405  skb_pull(skb, payload_offset);
406 
407  /* create 802.3 header at beginning of skb. */
408  e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
409  memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
410  memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
411  e_hdr->type = htons(payload_length);
412 
413  /* chop off the 802.11 CRC */
414  skb_trim(skb, skb->len - WLAN_CRC_LEN);
415 
416  } else if ((payload_length >= sizeof(struct wlan_llc) +
417  sizeof(struct wlan_snap))
418  && (e_llc->dsap == 0xaa)
419  && (e_llc->ssap == 0xaa)
420  && (e_llc->ctl == 0x03)) {
421  pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
422  /* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
423  build a DIXII + RFC894 */
424 
425  /* Test for an overlength frame */
426  if ((payload_length - sizeof(struct wlan_llc) -
427  sizeof(struct wlan_snap))
428  > netdev->mtu) {
429  /* A bogus length ethfrm has been sent. */
430  /* Is someone trying an oflow attack? */
431  printk(KERN_ERR "DIXII frame too large (%ld > %d)\n",
432  (long int)(payload_length -
433  sizeof(struct wlan_llc) -
434  sizeof(struct wlan_snap)), netdev->mtu);
435  return 1;
436  }
437 
438  /* chop 802.11 header from skb. */
439  skb_pull(skb, payload_offset);
440 
441  /* chop llc header from skb. */
442  skb_pull(skb, sizeof(struct wlan_llc));
443 
444  /* chop snap header from skb. */
445  skb_pull(skb, sizeof(struct wlan_snap));
446 
447  /* create 802.3 header at beginning of skb. */
448  e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
449  e_hdr->type = e_snap->type;
450  memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
451  memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
452 
453  /* chop off the 802.11 CRC */
454  skb_trim(skb, skb->len - WLAN_CRC_LEN);
455  } else {
456  pr_debug("NON-ENCAP len: %d\n", payload_length);
457  /* any NON-ENCAP */
458  /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
459  /* build an 802.3 frame */
460  /* allocate space and setup hostbuf */
461 
462  /* Test for an overlength frame */
463  if (payload_length > netdev->mtu) {
464  /* A bogus length ethfrm has been sent. */
465  /* Is someone trying an oflow attack? */
466  printk(KERN_ERR "OTHER frame too large (%d > %d)\n",
467  payload_length, netdev->mtu);
468  return 1;
469  }
470 
471  /* Chop off the 802.11 header. */
472  skb_pull(skb, payload_offset);
473 
474  /* create 802.3 header at beginning of skb. */
475  e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
476  memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
477  memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
478  e_hdr->type = htons(payload_length);
479 
480  /* chop off the 802.11 CRC */
481  skb_trim(skb, skb->len - WLAN_CRC_LEN);
482 
483  }
484 
485  /*
486  * Note that eth_type_trans() expects an skb w/ skb->data pointing
487  * at the MAC header, it then sets the following skb members:
488  * skb->mac_header,
489  * skb->data, and
490  * skb->pkt_type.
491  * It then _returns_ the value that _we're_ supposed to stuff in
492  * skb->protocol. This is nuts.
493  */
494  skb->protocol = eth_type_trans(skb, netdev);
495 
496  /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
497  /* jkriegl: only process signal/noise if requested by iwspy */
498  if (wlandev->spy_number)
499  orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
500  P80211SKB_RXMETA(skb));
501 
502  /* Free the metadata */
504 
505  return 0;
506 }
507 
508 /*----------------------------------------------------------------
509 * p80211_stt_findproto
510 *
511 * Searches the 802.1h Selective Translation Table for a given
512 * protocol.
513 *
514 * Arguments:
515 * proto protocl number (in host order) to search for.
516 *
517 * Returns:
518 * 1 - if the table is empty or a match is found.
519 * 0 - if the table is non-empty and a match is not found.
520 *
521 * Call context:
522 * May be called in interrupt or non-interrupt context
523 ----------------------------------------------------------------*/
525 {
526  /* Always return found for now. This is the behavior used by the */
527  /* Zoom Win95 driver when 802.1h mode is selected */
528  /* TODO: If necessary, add an actual search we'll probably
529  need this to match the CMAC's way of doing things.
530  Need to do some testing to confirm.
531  */
532 
533  if (proto == 0x80f3) /* APPLETALK */
534  return 1;
535 
536  return 0;
537 }
538 
539 /*----------------------------------------------------------------
540 * p80211skb_rxmeta_detach
541 *
542 * Disconnects the frmmeta and rxmeta from an skb.
543 *
544 * Arguments:
545 * wlandev The wlandev this skb belongs to.
546 * skb The skb we're attaching to.
547 *
548 * Returns:
549 * 0 on success, non-zero otherwise
550 *
551 * Call context:
552 * May be called in interrupt or non-interrupt context
553 ----------------------------------------------------------------*/
555 {
556  struct p80211_rxmeta *rxmeta;
557  struct p80211_frmmeta *frmmeta;
558 
559  /* Sanity checks */
560  if (skb == NULL) { /* bad skb */
561  pr_debug("Called w/ null skb.\n");
562  return;
563  }
564  frmmeta = P80211SKB_FRMMETA(skb);
565  if (frmmeta == NULL) { /* no magic */
566  pr_debug("Called w/ bad frmmeta magic.\n");
567  return;
568  }
569  rxmeta = frmmeta->rx;
570  if (rxmeta == NULL) { /* bad meta ptr */
571  pr_debug("Called w/ bad rxmeta ptr.\n");
572  return;
573  }
574 
575  /* Free rxmeta */
576  kfree(rxmeta);
577 
578  /* Clear skb->cb */
579  memset(skb->cb, 0, sizeof(skb->cb));
580 }
581 
582 /*----------------------------------------------------------------
583 * p80211skb_rxmeta_attach
584 *
585 * Allocates a p80211rxmeta structure, initializes it, and attaches
586 * it to an skb.
587 *
588 * Arguments:
589 * wlandev The wlandev this skb belongs to.
590 * skb The skb we're attaching to.
591 *
592 * Returns:
593 * 0 on success, non-zero otherwise
594 *
595 * Call context:
596 * May be called in interrupt or non-interrupt context
597 ----------------------------------------------------------------*/
598 int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
599 {
600  int result = 0;
601  struct p80211_rxmeta *rxmeta;
602  struct p80211_frmmeta *frmmeta;
603 
604  /* If these already have metadata, we error out! */
605  if (P80211SKB_RXMETA(skb) != NULL) {
606  printk(KERN_ERR "%s: RXmeta already attached!\n",
607  wlandev->name);
608  result = 0;
609  goto exit;
610  }
611 
612  /* Allocate the rxmeta */
613  rxmeta = kzalloc(sizeof(struct p80211_rxmeta), GFP_ATOMIC);
614 
615  if (rxmeta == NULL) {
616  printk(KERN_ERR "%s: Failed to allocate rxmeta.\n",
617  wlandev->name);
618  result = 1;
619  goto exit;
620  }
621 
622  /* Initialize the rxmeta */
623  rxmeta->wlandev = wlandev;
624  rxmeta->hosttime = jiffies;
625 
626  /* Overlay a frmmeta_t onto skb->cb */
627  memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
628  frmmeta = (struct p80211_frmmeta *) (skb->cb);
629  frmmeta->magic = P80211_FRMMETA_MAGIC;
630  frmmeta->rx = rxmeta;
631 exit:
632  return result;
633 }
634 
635 /*----------------------------------------------------------------
636 * p80211skb_free
637 *
638 * Frees an entire p80211skb by checking and freeing the meta struct
639 * and then freeing the skb.
640 *
641 * Arguments:
642 * wlandev The wlandev this skb belongs to.
643 * skb The skb we're attaching to.
644 *
645 * Returns:
646 * 0 on success, non-zero otherwise
647 *
648 * Call context:
649 * May be called in interrupt or non-interrupt context
650 ----------------------------------------------------------------*/
651 void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
652 {
653  struct p80211_frmmeta *meta;
654 
655  meta = P80211SKB_FRMMETA(skb);
656  if (meta && meta->rx)
658  else
659  printk(KERN_ERR "Freeing an skb (%p) w/ no frmmeta.\n", skb);
660  dev_kfree_skb(skb);
661 }