linux/drivers/staging/wlan-ng/p80211conv.c
<<
>>
Prefs
   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.
  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
  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>
  64#include <linux/byteorder/generic.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
  77static u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
  78static 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----------------------------------------------------------------*/
 105int 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 */
 138                        skb_pull(skb, WLAN_ETHHDR_LEN);
 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 */
 147                        skb_pull(skb, WLAN_ETHHDR_LEN);
 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,
 157                                       WLAN_IEEE_OUI_LEN);
 158                        } else {
 159                                memcpy(e_snap->oui, oui_rfc1042,
 160                                       WLAN_IEEE_OUI_LEN);
 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 */
 176        fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
 177                         WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
 178
 179        switch (wlandev->macmode) {
 180        case WLAN_MACMODE_IBSS_STA:
 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;
 185        case WLAN_MACMODE_ESS_STA:
 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:
 192                fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
 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:
 198                printk(KERN_ERR
 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) {
 216                        printk(KERN_WARNING
 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 */
 234static 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----------------------------------------------------------------*/
 276int 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;
 283        u8 daddr[WLAN_ETHADDR_LEN];
 284        u8 saddr[WLAN_ETHADDR_LEN];
 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 */
 503        p80211skb_rxmeta_detach(skb);
 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----------------------------------------------------------------*/
 524int p80211_stt_findproto(u16 proto)
 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----------------------------------------------------------------*/
 554void p80211skb_rxmeta_detach(struct sk_buff *skb)
 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----------------------------------------------------------------*/
 598int 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;
 631exit:
 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----------------------------------------------------------------*/
 651void 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)
 657                p80211skb_rxmeta_detach(skb);
 658        else
 659                printk(KERN_ERR "Freeing an skb (%p) w/ no frmmeta.\n", skb);
 660        dev_kfree_skb(skb);
 661}
 662