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