Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
0002 /*
0003  *
0004  * Ether/802.11 conversions and packet buffer routines
0005  *
0006  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
0007  * --------------------------------------------------------------------
0008  *
0009  * linux-wlan
0010  *
0011  *   The contents of this file are subject to the Mozilla Public
0012  *   License Version 1.1 (the "License"); you may not use this file
0013  *   except in compliance with the License. You may obtain a copy of
0014  *   the License at http://www.mozilla.org/MPL/
0015  *
0016  *   Software distributed under the License is distributed on an "AS
0017  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0018  *   implied. See the License for the specific language governing
0019  *   rights and limitations under the License.
0020  *
0021  *   Alternatively, the contents of this file may be used under the
0022  *   terms of the GNU Public License version 2 (the "GPL"), in which
0023  *   case the provisions of the GPL are applicable instead of the
0024  *   above.  If you wish to allow the use of your version of this file
0025  *   only under the terms of the GPL and not to allow others to use
0026  *   your version of this file under the MPL, indicate your decision
0027  *   by deleting the provisions above and replace them with the notice
0028  *   and other provisions required by the GPL.  If you do not delete
0029  *   the provisions above, a recipient may use your version of this
0030  *   file under either the MPL or the GPL.
0031  *
0032  * --------------------------------------------------------------------
0033  *
0034  * Inquiries regarding the linux-wlan Open Source project can be
0035  * made directly to:
0036  *
0037  * AbsoluteValue Systems Inc.
0038  * info@linux-wlan.com
0039  * http://www.linux-wlan.com
0040  *
0041  * --------------------------------------------------------------------
0042  *
0043  * Portions of the development of this software were funded by
0044  * Intersil Corporation as part of PRISM(R) chipset product development.
0045  *
0046  * --------------------------------------------------------------------
0047  *
0048  * This file defines the functions that perform Ethernet to/from
0049  * 802.11 frame conversions.
0050  *
0051  * --------------------------------------------------------------------
0052  *
0053  *================================================================
0054  */
0055 
0056 #include <linux/module.h>
0057 #include <linux/kernel.h>
0058 #include <linux/sched.h>
0059 #include <linux/types.h>
0060 #include <linux/skbuff.h>
0061 #include <linux/slab.h>
0062 #include <linux/wireless.h>
0063 #include <linux/netdevice.h>
0064 #include <linux/etherdevice.h>
0065 #include <linux/if_ether.h>
0066 #include <linux/byteorder/generic.h>
0067 
0068 #include <asm/byteorder.h>
0069 
0070 #include "p80211types.h"
0071 #include "p80211hdr.h"
0072 #include "p80211conv.h"
0073 #include "p80211mgmt.h"
0074 #include "p80211msg.h"
0075 #include "p80211netdev.h"
0076 #include "p80211ioctl.h"
0077 #include "p80211req.h"
0078 
0079 static const u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
0080 static const u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
0081 
0082 /*----------------------------------------------------------------
0083  * p80211pb_ether_to_80211
0084  *
0085  * Uses the contents of the ether frame and the etherconv setting
0086  * to build the elements of the 802.11 frame.
0087  *
0088  * We don't actually set
0089  * up the frame header here.  That's the MAC's job.  We're only handling
0090  * conversion of DIXII or 802.3+LLC frames to something that works
0091  * with 802.11.
0092  *
0093  * Note -- 802.11 header is NOT part of the skb.  Likewise, the 802.11
0094  *         FCS is also not present and will need to be added elsewhere.
0095  *
0096  * Arguments:
0097  *  ethconv     Conversion type to perform
0098  *  skb     skbuff containing the ether frame
0099  *       p80211_hdr      802.11 header
0100  *
0101  * Returns:
0102  *  0 on success, non-zero otherwise
0103  *
0104  * Call context:
0105  *  May be called in interrupt or non-interrupt context
0106  *----------------------------------------------------------------
0107  */
0108 int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv,
0109             struct sk_buff *skb, struct p80211_hdr *p80211_hdr,
0110             struct p80211_metawep *p80211_wep)
0111 {
0112     __le16 fc;
0113     u16 proto;
0114     struct wlan_ethhdr e_hdr;
0115     struct wlan_llc *e_llc;
0116     struct wlan_snap *e_snap;
0117     int foo;
0118 
0119     memcpy(&e_hdr, skb->data, sizeof(e_hdr));
0120 
0121     if (skb->len <= 0) {
0122         pr_debug("zero-length skb!\n");
0123         return 1;
0124     }
0125 
0126     if (ethconv == WLAN_ETHCONV_ENCAP) {    /* simplest case */
0127         pr_debug("ENCAP len: %d\n", skb->len);
0128         /* here, we don't care what kind of ether frm. Just stick it */
0129         /*  in the 80211 payload */
0130         /* which is to say, leave the skb alone. */
0131     } else {
0132         /* step 1: classify ether frame, DIX or 802.3? */
0133         proto = ntohs(e_hdr.type);
0134         if (proto <= ETH_DATA_LEN) {
0135             pr_debug("802.3 len: %d\n", skb->len);
0136             /* codes <= 1500 reserved for 802.3 lengths */
0137             /* it's 802.3, pass ether payload unchanged,  */
0138 
0139             /* trim off ethernet header */
0140             skb_pull(skb, ETH_HLEN);
0141 
0142             /*   leave off any PAD octets.  */
0143             skb_trim(skb, proto);
0144         } else {
0145             pr_debug("DIXII len: %d\n", skb->len);
0146             /* it's DIXII, time for some conversion */
0147 
0148             /* trim off ethernet header */
0149             skb_pull(skb, ETH_HLEN);
0150 
0151             /* tack on SNAP */
0152             e_snap = skb_push(skb, sizeof(struct wlan_snap));
0153             e_snap->type = htons(proto);
0154             if (ethconv == WLAN_ETHCONV_8021h &&
0155                 p80211_stt_findproto(proto)) {
0156                 memcpy(e_snap->oui, oui_8021h,
0157                        WLAN_IEEE_OUI_LEN);
0158             } else {
0159                 memcpy(e_snap->oui, oui_rfc1042,
0160                        WLAN_IEEE_OUI_LEN);
0161             }
0162 
0163             /* tack on llc */
0164             e_llc = skb_push(skb, sizeof(struct wlan_llc));
0165             e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
0166             e_llc->ssap = 0xAA;
0167             e_llc->ctl = 0x03;
0168         }
0169     }
0170 
0171     /* Set up the 802.11 header */
0172     /* It's a data frame */
0173     fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
0174              WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
0175 
0176     switch (wlandev->macmode) {
0177     case WLAN_MACMODE_IBSS_STA:
0178         memcpy(p80211_hdr->address1, &e_hdr.daddr, ETH_ALEN);
0179         memcpy(p80211_hdr->address2, wlandev->netdev->dev_addr, ETH_ALEN);
0180         memcpy(p80211_hdr->address3, wlandev->bssid, ETH_ALEN);
0181         break;
0182     case WLAN_MACMODE_ESS_STA:
0183         fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
0184         memcpy(p80211_hdr->address1, wlandev->bssid, ETH_ALEN);
0185         memcpy(p80211_hdr->address2, wlandev->netdev->dev_addr, ETH_ALEN);
0186         memcpy(p80211_hdr->address3, &e_hdr.daddr, ETH_ALEN);
0187         break;
0188     case WLAN_MACMODE_ESS_AP:
0189         fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
0190         memcpy(p80211_hdr->address1, &e_hdr.daddr, ETH_ALEN);
0191         memcpy(p80211_hdr->address2, wlandev->bssid, ETH_ALEN);
0192         memcpy(p80211_hdr->address3, &e_hdr.saddr, ETH_ALEN);
0193         break;
0194     default:
0195         netdev_err(wlandev->netdev,
0196                "Error: Converting eth to wlan in unknown mode.\n");
0197         return 1;
0198     }
0199 
0200     p80211_wep->data = NULL;
0201 
0202     if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) &&
0203         (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
0204         /* XXXX need to pick keynum other than default? */
0205 
0206         p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
0207         if (!p80211_wep->data)
0208             return -ENOMEM;
0209         foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
0210                   skb->len,
0211                   wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK,
0212                   p80211_wep->iv, p80211_wep->icv);
0213         if (foo) {
0214             netdev_warn(wlandev->netdev,
0215                     "Host en-WEP failed, dropping frame (%d).\n",
0216                     foo);
0217             kfree(p80211_wep->data);
0218             return 2;
0219         }
0220         fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
0221     }
0222 
0223     /*      skb->nh.raw = skb->data; */
0224 
0225     p80211_hdr->frame_control = fc;
0226     p80211_hdr->duration_id = 0;
0227     p80211_hdr->sequence_control = 0;
0228 
0229     return 0;
0230 }
0231 
0232 /* jkriegl: from orinoco, modified */
0233 static void orinoco_spy_gather(struct wlandevice *wlandev, char *mac,
0234                    struct p80211_rxmeta *rxmeta)
0235 {
0236     int i;
0237 
0238     /* Gather wireless spy statistics: for each packet, compare the
0239      * source address with out list, and if match, get the stats...
0240      */
0241 
0242     for (i = 0; i < wlandev->spy_number; i++) {
0243         if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
0244             wlandev->spy_stat[i].level = rxmeta->signal;
0245             wlandev->spy_stat[i].noise = rxmeta->noise;
0246             wlandev->spy_stat[i].qual =
0247                 (rxmeta->signal >
0248                  rxmeta->noise) ? (rxmeta->signal -
0249                            rxmeta->noise) : 0;
0250             wlandev->spy_stat[i].updated = 0x7;
0251         }
0252     }
0253 }
0254 
0255 /*----------------------------------------------------------------
0256  * p80211pb_80211_to_ether
0257  *
0258  * Uses the contents of a received 802.11 frame and the etherconv
0259  * setting to build an ether frame.
0260  *
0261  * This function extracts the src and dest address from the 802.11
0262  * frame to use in the construction of the eth frame.
0263  *
0264  * Arguments:
0265  *  ethconv     Conversion type to perform
0266  *  skb     Packet buffer containing the 802.11 frame
0267  *
0268  * Returns:
0269  *  0 on success, non-zero otherwise
0270  *
0271  * Call context:
0272  *  May be called in interrupt or non-interrupt context
0273  *----------------------------------------------------------------
0274  */
0275 int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv,
0276             struct sk_buff *skb)
0277 {
0278     struct net_device *netdev = wlandev->netdev;
0279     u16 fc;
0280     unsigned int payload_length;
0281     unsigned int payload_offset;
0282     u8 daddr[ETH_ALEN];
0283     u8 saddr[ETH_ALEN];
0284     struct p80211_hdr *w_hdr;
0285     struct wlan_ethhdr *e_hdr;
0286     struct wlan_llc *e_llc;
0287     struct wlan_snap *e_snap;
0288 
0289     int foo;
0290 
0291     payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
0292     payload_offset = WLAN_HDR_A3_LEN;
0293 
0294     w_hdr = (struct p80211_hdr *)skb->data;
0295 
0296     /* setup some vars for convenience */
0297     fc = le16_to_cpu(w_hdr->frame_control);
0298     if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
0299         ether_addr_copy(daddr, w_hdr->address1);
0300         ether_addr_copy(saddr, w_hdr->address2);
0301     } else if ((WLAN_GET_FC_TODS(fc) == 0) &&
0302            (WLAN_GET_FC_FROMDS(fc) == 1)) {
0303         ether_addr_copy(daddr, w_hdr->address1);
0304         ether_addr_copy(saddr, w_hdr->address3);
0305     } else if ((WLAN_GET_FC_TODS(fc) == 1) &&
0306            (WLAN_GET_FC_FROMDS(fc) == 0)) {
0307         ether_addr_copy(daddr, w_hdr->address3);
0308         ether_addr_copy(saddr, w_hdr->address2);
0309     } else {
0310         payload_offset = WLAN_HDR_A4_LEN;
0311         if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
0312             netdev_err(netdev, "A4 frame too short!\n");
0313             return 1;
0314         }
0315         payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
0316         ether_addr_copy(daddr, w_hdr->address3);
0317         ether_addr_copy(saddr, w_hdr->address4);
0318     }
0319 
0320     /* perform de-wep if necessary.. */
0321     if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) &&
0322         WLAN_GET_FC_ISWEP(fc) &&
0323         (wlandev->hostwep & HOSTWEP_DECRYPT)) {
0324         if (payload_length <= 8) {
0325             netdev_err(netdev,
0326                    "WEP frame too short (%u).\n", skb->len);
0327             return 1;
0328         }
0329         foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
0330                   payload_length - 8, -1,
0331                   skb->data + payload_offset,
0332                   skb->data + payload_offset +
0333                   payload_length - 4);
0334         if (foo) {
0335             /* de-wep failed, drop skb. */
0336             pr_debug("Host de-WEP failed, dropping frame (%d).\n",
0337                  foo);
0338             wlandev->rx.decrypt_err++;
0339             return 2;
0340         }
0341 
0342         /* subtract the IV+ICV length off the payload */
0343         payload_length -= 8;
0344         /* chop off the IV */
0345         skb_pull(skb, 4);
0346         /* chop off the ICV. */
0347         skb_trim(skb, skb->len - 4);
0348 
0349         wlandev->rx.decrypt++;
0350     }
0351 
0352     e_hdr = (struct wlan_ethhdr *)(skb->data + payload_offset);
0353 
0354     e_llc = (struct wlan_llc *)(skb->data + payload_offset);
0355     e_snap =
0356         (struct wlan_snap *)(skb->data + payload_offset +
0357         sizeof(struct wlan_llc));
0358 
0359     /* Test for the various encodings */
0360     if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
0361         (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
0362         ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) ||
0363          (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) {
0364         pr_debug("802.3 ENCAP len: %d\n", payload_length);
0365         /* 802.3 Encapsulated */
0366         /* Test for an overlength frame */
0367         if (payload_length > (netdev->mtu + ETH_HLEN)) {
0368             /* A bogus length ethfrm has been encap'd. */
0369             /* Is someone trying an oflow attack? */
0370             netdev_err(netdev, "ENCAP frame too large (%d > %d)\n",
0371                    payload_length, netdev->mtu + ETH_HLEN);
0372             return 1;
0373         }
0374 
0375         /* Chop off the 802.11 header.  it's already sane. */
0376         skb_pull(skb, payload_offset);
0377         /* chop off the 802.11 CRC */
0378         skb_trim(skb, skb->len - WLAN_CRC_LEN);
0379 
0380     } else if ((payload_length >= sizeof(struct wlan_llc) +
0381         sizeof(struct wlan_snap)) &&
0382         (e_llc->dsap == 0xaa) &&
0383         (e_llc->ssap == 0xaa) &&
0384         (e_llc->ctl == 0x03) &&
0385            (((memcmp(e_snap->oui, oui_rfc1042,
0386            WLAN_IEEE_OUI_LEN) == 0) &&
0387            (ethconv == WLAN_ETHCONV_8021h) &&
0388            (p80211_stt_findproto(be16_to_cpu(e_snap->type)))) ||
0389            (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) !=
0390             0))) {
0391         pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
0392         /* it's a SNAP + RFC1042 frame && protocol is in STT */
0393         /* build 802.3 + RFC1042 */
0394 
0395         /* Test for an overlength frame */
0396         if (payload_length > netdev->mtu) {
0397             /* A bogus length ethfrm has been sent. */
0398             /* Is someone trying an oflow attack? */
0399             netdev_err(netdev, "SNAP frame too large (%d > %d)\n",
0400                    payload_length, netdev->mtu);
0401             return 1;
0402         }
0403 
0404         /* chop 802.11 header from skb. */
0405         skb_pull(skb, payload_offset);
0406 
0407         /* create 802.3 header at beginning of skb. */
0408         e_hdr = skb_push(skb, ETH_HLEN);
0409         ether_addr_copy(e_hdr->daddr, daddr);
0410         ether_addr_copy(e_hdr->saddr, saddr);
0411         e_hdr->type = htons(payload_length);
0412 
0413         /* chop off the 802.11 CRC */
0414         skb_trim(skb, skb->len - WLAN_CRC_LEN);
0415 
0416     } else if ((payload_length >= sizeof(struct wlan_llc) +
0417         sizeof(struct wlan_snap)) &&
0418         (e_llc->dsap == 0xaa) &&
0419         (e_llc->ssap == 0xaa) &&
0420         (e_llc->ctl == 0x03)) {
0421         pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
0422         /* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
0423          * build a DIXII + RFC894
0424          */
0425 
0426         /* Test for an overlength frame */
0427         if ((payload_length - sizeof(struct wlan_llc) -
0428             sizeof(struct wlan_snap))
0429             > netdev->mtu) {
0430             /* A bogus length ethfrm has been sent. */
0431             /* Is someone trying an oflow attack? */
0432             netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
0433                    (long)(payload_length -
0434                    sizeof(struct wlan_llc) -
0435                    sizeof(struct wlan_snap)), netdev->mtu);
0436             return 1;
0437         }
0438 
0439         /* chop 802.11 header from skb. */
0440         skb_pull(skb, payload_offset);
0441 
0442         /* chop llc header from skb. */
0443         skb_pull(skb, sizeof(struct wlan_llc));
0444 
0445         /* chop snap header from skb. */
0446         skb_pull(skb, sizeof(struct wlan_snap));
0447 
0448         /* create 802.3 header at beginning of skb. */
0449         e_hdr = skb_push(skb, ETH_HLEN);
0450         e_hdr->type = e_snap->type;
0451         ether_addr_copy(e_hdr->daddr, daddr);
0452         ether_addr_copy(e_hdr->saddr, saddr);
0453 
0454         /* chop off the 802.11 CRC */
0455         skb_trim(skb, skb->len - WLAN_CRC_LEN);
0456     } else {
0457         pr_debug("NON-ENCAP len: %d\n", payload_length);
0458         /* any NON-ENCAP */
0459         /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
0460         /*  build an 802.3 frame */
0461         /* allocate space and setup hostbuf */
0462 
0463         /* Test for an overlength frame */
0464         if (payload_length > netdev->mtu) {
0465             /* A bogus length ethfrm has been sent. */
0466             /* Is someone trying an oflow attack? */
0467             netdev_err(netdev, "OTHER frame too large (%d > %d)\n",
0468                    payload_length, netdev->mtu);
0469             return 1;
0470         }
0471 
0472         /* Chop off the 802.11 header. */
0473         skb_pull(skb, payload_offset);
0474 
0475         /* create 802.3 header at beginning of skb. */
0476         e_hdr = skb_push(skb, ETH_HLEN);
0477         ether_addr_copy(e_hdr->daddr, daddr);
0478         ether_addr_copy(e_hdr->saddr, saddr);
0479         e_hdr->type = htons(payload_length);
0480 
0481         /* chop off the 802.11 CRC */
0482         skb_trim(skb, skb->len - WLAN_CRC_LEN);
0483     }
0484 
0485     /*
0486      * Note that eth_type_trans() expects an skb w/ skb->data pointing
0487      * at the MAC header, it then sets the following skb members:
0488      * skb->mac_header,
0489      * skb->data, and
0490      * skb->pkt_type.
0491      * It then _returns_ the value that _we're_ supposed to stuff in
0492      * skb->protocol.  This is nuts.
0493      */
0494     skb->protocol = eth_type_trans(skb, netdev);
0495 
0496     /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
0497     /* jkriegl: only process signal/noise if requested by iwspy */
0498     if (wlandev->spy_number)
0499         orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
0500                    p80211skb_rxmeta(skb));
0501 
0502     /* Free the metadata */
0503     p80211skb_rxmeta_detach(skb);
0504 
0505     return 0;
0506 }
0507 
0508 /*----------------------------------------------------------------
0509  * p80211_stt_findproto
0510  *
0511  * Searches the 802.1h Selective Translation Table for a given
0512  * protocol.
0513  *
0514  * Arguments:
0515  *  proto   protocol number (in host order) to search for.
0516  *
0517  * Returns:
0518  *  1 - if the table is empty or a match is found.
0519  *  0 - if the table is non-empty and a match is not found.
0520  *
0521  * Call context:
0522  *  May be called in interrupt or non-interrupt context
0523  *----------------------------------------------------------------
0524  */
0525 int p80211_stt_findproto(u16 proto)
0526 {
0527     /* Always return found for now.  This is the behavior used by the */
0528     /* Zoom Win95 driver when 802.1h mode is selected */
0529     /* TODO: If necessary, add an actual search we'll probably
0530      * need this to match the CMAC's way of doing things.
0531      * Need to do some testing to confirm.
0532      */
0533 
0534     if (proto == ETH_P_AARP)    /* APPLETALK */
0535         return 1;
0536 
0537     return 0;
0538 }
0539 
0540 /*----------------------------------------------------------------
0541  * p80211skb_rxmeta_detach
0542  *
0543  * Disconnects the frmmeta and rxmeta from an skb.
0544  *
0545  * Arguments:
0546  *  wlandev     The wlandev this skb belongs to.
0547  *  skb     The skb we're attaching to.
0548  *
0549  * Returns:
0550  *  0 on success, non-zero otherwise
0551  *
0552  * Call context:
0553  *  May be called in interrupt or non-interrupt context
0554  *----------------------------------------------------------------
0555  */
0556 void p80211skb_rxmeta_detach(struct sk_buff *skb)
0557 {
0558     struct p80211_rxmeta *rxmeta;
0559     struct p80211_frmmeta *frmmeta;
0560 
0561     /* Sanity checks */
0562     if (!skb) { /* bad skb */
0563         pr_debug("Called w/ null skb.\n");
0564         return;
0565     }
0566     frmmeta = p80211skb_frmmeta(skb);
0567     if (!frmmeta) { /* no magic */
0568         pr_debug("Called w/ bad frmmeta magic.\n");
0569         return;
0570     }
0571     rxmeta = frmmeta->rx;
0572     if (!rxmeta) {  /* bad meta ptr */
0573         pr_debug("Called w/ bad rxmeta ptr.\n");
0574         return;
0575     }
0576 
0577     /* Free rxmeta */
0578     kfree(rxmeta);
0579 
0580     /* Clear skb->cb */
0581     memset(skb->cb, 0, sizeof(skb->cb));
0582 }
0583 
0584 /*----------------------------------------------------------------
0585  * p80211skb_rxmeta_attach
0586  *
0587  * Allocates a p80211rxmeta structure, initializes it, and attaches
0588  * it to an skb.
0589  *
0590  * Arguments:
0591  *  wlandev     The wlandev this skb belongs to.
0592  *  skb     The skb we're attaching to.
0593  *
0594  * Returns:
0595  *  0 on success, non-zero otherwise
0596  *
0597  * Call context:
0598  *  May be called in interrupt or non-interrupt context
0599  *----------------------------------------------------------------
0600  */
0601 int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
0602 {
0603     int result = 0;
0604     struct p80211_rxmeta *rxmeta;
0605     struct p80211_frmmeta *frmmeta;
0606 
0607     /* If these already have metadata, we error out! */
0608     if (p80211skb_rxmeta(skb)) {
0609         netdev_err(wlandev->netdev,
0610                "%s: RXmeta already attached!\n", wlandev->name);
0611         result = 0;
0612         goto exit;
0613     }
0614 
0615     /* Allocate the rxmeta */
0616     rxmeta = kzalloc(sizeof(*rxmeta), GFP_ATOMIC);
0617 
0618     if (!rxmeta) {
0619         result = 1;
0620         goto exit;
0621     }
0622 
0623     /* Initialize the rxmeta */
0624     rxmeta->wlandev = wlandev;
0625     rxmeta->hosttime = jiffies;
0626 
0627     /* Overlay a frmmeta_t onto skb->cb */
0628     memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
0629     frmmeta = (struct p80211_frmmeta *)(skb->cb);
0630     frmmeta->magic = P80211_FRMMETA_MAGIC;
0631     frmmeta->rx = rxmeta;
0632 exit:
0633     return result;
0634 }
0635 
0636 /*----------------------------------------------------------------
0637  * p80211skb_free
0638  *
0639  * Frees an entire p80211skb by checking and freeing the meta struct
0640  * and then freeing the skb.
0641  *
0642  * Arguments:
0643  *  wlandev     The wlandev this skb belongs to.
0644  *  skb     The skb we're attaching to.
0645  *
0646  * Returns:
0647  *  0 on success, non-zero otherwise
0648  *
0649  * Call context:
0650  *  May be called in interrupt or non-interrupt context
0651  *----------------------------------------------------------------
0652  */
0653 void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
0654 {
0655     struct p80211_frmmeta *meta;
0656 
0657     meta = p80211skb_frmmeta(skb);
0658     if (meta && meta->rx)
0659         p80211skb_rxmeta_detach(skb);
0660     else
0661         netdev_err(wlandev->netdev,
0662                "Freeing an skb (%p) w/ no frmmeta.\n", skb);
0663     dev_kfree_skb(skb);
0664 }