root/drivers/staging/wlan-ng/p80211conv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. skb_ether_to_p80211
  2. orinoco_spy_gather
  3. skb_p80211_to_ether
  4. p80211_stt_findproto
  5. p80211skb_rxmeta_detach
  6. p80211skb_rxmeta_attach
  7. p80211skb_free

   1 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
   2 /* src/p80211/p80211conv.c
   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  *   The contents of this file are subject to the Mozilla Public
  12  *   License Version 1.1 (the "License"); you may not use this file
  13  *   except in compliance with the License. You may obtain a copy of
  14  *   the License at http://www.mozilla.org/MPL/
  15  *
  16  *   Software distributed under the License is distributed on an "AS
  17  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  18  *   implied. See the License for the specific language governing
  19  *   rights and limitations under the License.
  20  *
  21  *   Alternatively, the contents of this file may be used under the
  22  *   terms of the GNU Public License version 2 (the "GPL"), in which
  23  *   case the provisions of the GPL are applicable instead of the
  24  *   above.  If you wish to allow the use of your version of this file
  25  *   only under the terms of the GPL and not to allow others to use
  26  *   your version of this file under the MPL, indicate your decision
  27  *   by deleting the provisions above and replace them with the notice
  28  *   and other provisions required by the GPL.  If you do not delete
  29  *   the provisions above, a recipient may use your version of this
  30  *   file under either the MPL or the GPL.
  31  *
  32  * --------------------------------------------------------------------
  33  *
  34  * Inquiries regarding the linux-wlan Open Source project can be
  35  * made directly to:
  36  *
  37  * AbsoluteValue Systems Inc.
  38  * info@linux-wlan.com
  39  * http://www.linux-wlan.com
  40  *
  41  * --------------------------------------------------------------------
  42  *
  43  * Portions of the development of this software were funded by
  44  * Intersil Corporation as part of PRISM(R) chipset product development.
  45  *
  46  * --------------------------------------------------------------------
  47  *
  48  * This file defines the functions that perform Ethernet to/from
  49  * 802.11 frame conversions.
  50  *
  51  * --------------------------------------------------------------------
  52  *
  53  *================================================================
  54  */
  55 
  56 #include <linux/module.h>
  57 #include <linux/kernel.h>
  58 #include <linux/sched.h>
  59 #include <linux/types.h>
  60 #include <linux/skbuff.h>
  61 #include <linux/slab.h>
  62 #include <linux/wireless.h>
  63 #include <linux/netdevice.h>
  64 #include <linux/etherdevice.h>
  65 #include <linux/if_ether.h>
  66 #include <linux/byteorder/generic.h>
  67 
  68 #include <asm/byteorder.h>
  69 
  70 #include "p80211types.h"
  71 #include "p80211hdr.h"
  72 #include "p80211conv.h"
  73 #include "p80211mgmt.h"
  74 #include "p80211msg.h"
  75 #include "p80211netdev.h"
  76 #include "p80211ioctl.h"
  77 #include "p80211req.h"
  78 
  79 static const u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
  80 static const u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
  81 
  82 /*----------------------------------------------------------------
  83  * p80211pb_ether_to_80211
  84  *
  85  * Uses the contents of the ether frame and the etherconv setting
  86  * to build the elements of the 802.11 frame.
  87  *
  88  * We don't actually set
  89  * up the frame header here.  That's the MAC's job.  We're only handling
  90  * conversion of DIXII or 802.3+LLC frames to something that works
  91  * with 802.11.
  92  *
  93  * Note -- 802.11 header is NOT part of the skb.  Likewise, the 802.11
  94  *         FCS is also not present and will need to be added elsewhere.
  95  *
  96  * Arguments:
  97  *      ethconv         Conversion type to perform
  98  *      skb             skbuff containing the ether frame
  99  *       p80211_hdr      802.11 header
 100  *
 101  * Returns:
 102  *      0 on success, non-zero otherwise
 103  *
 104  * Call context:
 105  *      May be called in interrupt or non-interrupt context
 106  *----------------------------------------------------------------
 107  */
 108 int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv,
 109                         struct sk_buff *skb, union p80211_hdr *p80211_hdr,
 110                         struct p80211_metawep *p80211_wep)
 111 {
 112         __le16 fc;
 113         u16 proto;
 114         struct wlan_ethhdr e_hdr;
 115         struct wlan_llc *e_llc;
 116         struct wlan_snap *e_snap;
 117         int foo;
 118 
 119         memcpy(&e_hdr, skb->data, sizeof(e_hdr));
 120 
 121         if (skb->len <= 0) {
 122                 pr_debug("zero-length skb!\n");
 123                 return 1;
 124         }
 125 
 126         if (ethconv == WLAN_ETHCONV_ENCAP) {    /* simplest case */
 127                 pr_debug("ENCAP len: %d\n", skb->len);
 128                 /* here, we don't care what kind of ether frm. Just stick it */
 129                 /*  in the 80211 payload */
 130                 /* which is to say, leave the skb alone. */
 131         } else {
 132                 /* step 1: classify ether frame, DIX or 802.3? */
 133                 proto = ntohs(e_hdr.type);
 134                 if (proto <= ETH_DATA_LEN) {
 135                         pr_debug("802.3 len: %d\n", skb->len);
 136                         /* codes <= 1500 reserved for 802.3 lengths */
 137                         /* it's 802.3, pass ether payload unchanged,  */
 138 
 139                         /* trim off ethernet header */
 140                         skb_pull(skb, ETH_HLEN);
 141 
 142                         /*   leave off any PAD octets.  */
 143                         skb_trim(skb, proto);
 144                 } else {
 145                         pr_debug("DIXII len: %d\n", skb->len);
 146                         /* it's DIXII, time for some conversion */
 147 
 148                         /* trim off ethernet header */
 149                         skb_pull(skb, ETH_HLEN);
 150 
 151                         /* tack on SNAP */
 152                         e_snap = skb_push(skb, 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 = skb_push(skb, sizeof(struct wlan_llc));
 165                         e_llc->dsap = 0xAA;     /* SNAP, see IEEE 802 */
 166                         e_llc->ssap = 0xAA;
 167                         e_llc->ctl = 0x03;
 168                 }
 169         }
 170 
 171         /* Set up the 802.11 header */
 172         /* It's a data frame */
 173         fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
 174                          WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
 175 
 176         switch (wlandev->macmode) {
 177         case WLAN_MACMODE_IBSS_STA:
 178                 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
 179                 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
 180                 memcpy(p80211_hdr->a3.a3, wlandev->bssid, ETH_ALEN);
 181                 break;
 182         case WLAN_MACMODE_ESS_STA:
 183                 fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
 184                 memcpy(p80211_hdr->a3.a1, wlandev->bssid, ETH_ALEN);
 185                 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
 186                 memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, ETH_ALEN);
 187                 break;
 188         case WLAN_MACMODE_ESS_AP:
 189                 fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
 190                 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
 191                 memcpy(p80211_hdr->a3.a2, wlandev->bssid, ETH_ALEN);
 192                 memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, ETH_ALEN);
 193                 break;
 194         default:
 195                 netdev_err(wlandev->netdev,
 196                            "Error: Converting eth to wlan in unknown mode.\n");
 197                 return 1;
 198         }
 199 
 200         p80211_wep->data = NULL;
 201 
 202         if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) &&
 203             (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
 204                 /* XXXX need to pick keynum other than default? */
 205 
 206                 p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
 207                 if (!p80211_wep->data)
 208                         return -ENOMEM;
 209                 foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
 210                                   skb->len,
 211                                   wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK,
 212                                   p80211_wep->iv, p80211_wep->icv);
 213                 if (foo) {
 214                         netdev_warn(wlandev->netdev,
 215                                     "Host en-WEP failed, dropping frame (%d).\n",
 216                                     foo);
 217                         kfree(p80211_wep->data);
 218                         return 2;
 219                 }
 220                 fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
 221         }
 222 
 223         /*      skb->nh.raw = skb->data; */
 224 
 225         p80211_hdr->a3.fc = fc;
 226         p80211_hdr->a3.dur = 0;
 227         p80211_hdr->a3.seq = 0;
 228 
 229         return 0;
 230 }
 231 
 232 /* jkriegl: from orinoco, modified */
 233 static void orinoco_spy_gather(struct wlandevice *wlandev, char *mac,
 234                                struct p80211_rxmeta *rxmeta)
 235 {
 236         int i;
 237 
 238         /* Gather wireless spy statistics: for each packet, compare the
 239          * source address with out list, and if match, get the stats...
 240          */
 241 
 242         for (i = 0; i < wlandev->spy_number; i++) {
 243                 if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
 244                         wlandev->spy_stat[i].level = rxmeta->signal;
 245                         wlandev->spy_stat[i].noise = rxmeta->noise;
 246                         wlandev->spy_stat[i].qual =
 247                             (rxmeta->signal >
 248                              rxmeta->noise) ? (rxmeta->signal -
 249                                                rxmeta->noise) : 0;
 250                         wlandev->spy_stat[i].updated = 0x7;
 251                 }
 252         }
 253 }
 254 
 255 /*----------------------------------------------------------------
 256  * p80211pb_80211_to_ether
 257  *
 258  * Uses the contents of a received 802.11 frame and the etherconv
 259  * setting to build an ether frame.
 260  *
 261  * This function extracts the src and dest address from the 802.11
 262  * frame to use in the construction of the eth frame.
 263  *
 264  * Arguments:
 265  *      ethconv         Conversion type to perform
 266  *      skb             Packet buffer containing the 802.11 frame
 267  *
 268  * Returns:
 269  *      0 on success, non-zero otherwise
 270  *
 271  * Call context:
 272  *      May be called in interrupt or non-interrupt context
 273  *----------------------------------------------------------------
 274  */
 275 int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv,
 276                         struct sk_buff *skb)
 277 {
 278         struct net_device *netdev = wlandev->netdev;
 279         u16 fc;
 280         unsigned int payload_length;
 281         unsigned int payload_offset;
 282         u8 daddr[ETH_ALEN];
 283         u8 saddr[ETH_ALEN];
 284         union p80211_hdr *w_hdr;
 285         struct wlan_ethhdr *e_hdr;
 286         struct wlan_llc *e_llc;
 287         struct wlan_snap *e_snap;
 288 
 289         int foo;
 290 
 291         payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
 292         payload_offset = WLAN_HDR_A3_LEN;
 293 
 294         w_hdr = (union p80211_hdr *)skb->data;
 295 
 296         /* setup some vars for convenience */
 297         fc = le16_to_cpu(w_hdr->a3.fc);
 298         if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
 299                 ether_addr_copy(daddr, w_hdr->a3.a1);
 300                 ether_addr_copy(saddr, w_hdr->a3.a2);
 301         } else if ((WLAN_GET_FC_TODS(fc) == 0) &&
 302                    (WLAN_GET_FC_FROMDS(fc) == 1)) {
 303                 ether_addr_copy(daddr, w_hdr->a3.a1);
 304                 ether_addr_copy(saddr, w_hdr->a3.a3);
 305         } else if ((WLAN_GET_FC_TODS(fc) == 1) &&
 306                    (WLAN_GET_FC_FROMDS(fc) == 0)) {
 307                 ether_addr_copy(daddr, w_hdr->a3.a3);
 308                 ether_addr_copy(saddr, w_hdr->a3.a2);
 309         } else {
 310                 payload_offset = WLAN_HDR_A4_LEN;
 311                 if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
 312                         netdev_err(netdev, "A4 frame too short!\n");
 313                         return 1;
 314                 }
 315                 payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
 316                 ether_addr_copy(daddr, w_hdr->a4.a3);
 317                 ether_addr_copy(saddr, w_hdr->a4.a4);
 318         }
 319 
 320         /* perform de-wep if necessary.. */
 321         if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) &&
 322             WLAN_GET_FC_ISWEP(fc) &&
 323             (wlandev->hostwep & HOSTWEP_DECRYPT)) {
 324                 if (payload_length <= 8) {
 325                         netdev_err(netdev,
 326                                    "WEP frame too short (%u).\n", 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             ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) ||
 363              (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) {
 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 + ETH_HLEN)) {
 368                         /* A bogus length ethfrm has been encap'd. */
 369                         /* Is someone trying an oflow attack? */
 370                         netdev_err(netdev, "ENCAP frame too large (%d > %d)\n",
 371                                    payload_length, netdev->mtu + ETH_HLEN);
 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                    (((memcmp(e_snap->oui, oui_rfc1042,
 386                    WLAN_IEEE_OUI_LEN) == 0) &&
 387                    (ethconv == WLAN_ETHCONV_8021h) &&
 388                    (p80211_stt_findproto(be16_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                         netdev_err(netdev, "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 = skb_push(skb, ETH_HLEN);
 409                 ether_addr_copy(e_hdr->daddr, daddr);
 410                 ether_addr_copy(e_hdr->saddr, saddr);
 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 
 426                 /* Test for an overlength frame */
 427                 if ((payload_length - sizeof(struct wlan_llc) -
 428                         sizeof(struct wlan_snap))
 429                         > netdev->mtu) {
 430                         /* A bogus length ethfrm has been sent. */
 431                         /* Is someone trying an oflow attack? */
 432                         netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
 433                                    (long)(payload_length -
 434                                    sizeof(struct wlan_llc) -
 435                                    sizeof(struct wlan_snap)), netdev->mtu);
 436                         return 1;
 437                 }
 438 
 439                 /* chop 802.11 header from skb. */
 440                 skb_pull(skb, payload_offset);
 441 
 442                 /* chop llc header from skb. */
 443                 skb_pull(skb, sizeof(struct wlan_llc));
 444 
 445                 /* chop snap header from skb. */
 446                 skb_pull(skb, sizeof(struct wlan_snap));
 447 
 448                 /* create 802.3 header at beginning of skb. */
 449                 e_hdr = skb_push(skb, ETH_HLEN);
 450                 e_hdr->type = e_snap->type;
 451                 ether_addr_copy(e_hdr->daddr, daddr);
 452                 ether_addr_copy(e_hdr->saddr, saddr);
 453 
 454                 /* chop off the 802.11 CRC */
 455                 skb_trim(skb, skb->len - WLAN_CRC_LEN);
 456         } else {
 457                 pr_debug("NON-ENCAP len: %d\n", payload_length);
 458                 /* any NON-ENCAP */
 459                 /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
 460                 /*  build an 802.3 frame */
 461                 /* allocate space and setup hostbuf */
 462 
 463                 /* Test for an overlength frame */
 464                 if (payload_length > netdev->mtu) {
 465                         /* A bogus length ethfrm has been sent. */
 466                         /* Is someone trying an oflow attack? */
 467                         netdev_err(netdev, "OTHER frame too large (%d > %d)\n",
 468                                    payload_length, netdev->mtu);
 469                         return 1;
 470                 }
 471 
 472                 /* Chop off the 802.11 header. */
 473                 skb_pull(skb, payload_offset);
 474 
 475                 /* create 802.3 header at beginning of skb. */
 476                 e_hdr = skb_push(skb, ETH_HLEN);
 477                 ether_addr_copy(e_hdr->daddr, daddr);
 478                 ether_addr_copy(e_hdr->saddr, saddr);
 479                 e_hdr->type = htons(payload_length);
 480 
 481                 /* chop off the 802.11 CRC */
 482                 skb_trim(skb, skb->len - WLAN_CRC_LEN);
 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   protocol 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  *----------------------------------------------------------------
 524  */
 525 int p80211_stt_findproto(u16 proto)
 526 {
 527         /* Always return found for now.  This is the behavior used by the */
 528         /* Zoom Win95 driver when 802.1h mode is selected */
 529         /* TODO: If necessary, add an actual search we'll probably
 530          * need this to match the CMAC's way of doing things.
 531          * Need to do some testing to confirm.
 532          */
 533 
 534         if (proto == ETH_P_AARP)        /* APPLETALK */
 535                 return 1;
 536 
 537         return 0;
 538 }
 539 
 540 /*----------------------------------------------------------------
 541  * p80211skb_rxmeta_detach
 542  *
 543  * Disconnects the frmmeta and rxmeta from an skb.
 544  *
 545  * Arguments:
 546  *      wlandev         The wlandev this skb belongs to.
 547  *      skb             The skb we're attaching to.
 548  *
 549  * Returns:
 550  *      0 on success, non-zero otherwise
 551  *
 552  * Call context:
 553  *      May be called in interrupt or non-interrupt context
 554  *----------------------------------------------------------------
 555  */
 556 void p80211skb_rxmeta_detach(struct sk_buff *skb)
 557 {
 558         struct p80211_rxmeta *rxmeta;
 559         struct p80211_frmmeta *frmmeta;
 560 
 561         /* Sanity checks */
 562         if (!skb) {     /* bad skb */
 563                 pr_debug("Called w/ null skb.\n");
 564                 return;
 565         }
 566         frmmeta = p80211skb_frmmeta(skb);
 567         if (!frmmeta) { /* no magic */
 568                 pr_debug("Called w/ bad frmmeta magic.\n");
 569                 return;
 570         }
 571         rxmeta = frmmeta->rx;
 572         if (!rxmeta) {  /* bad meta ptr */
 573                 pr_debug("Called w/ bad rxmeta ptr.\n");
 574                 return;
 575         }
 576 
 577         /* Free rxmeta */
 578         kfree(rxmeta);
 579 
 580         /* Clear skb->cb */
 581         memset(skb->cb, 0, sizeof(skb->cb));
 582 }
 583 
 584 /*----------------------------------------------------------------
 585  * p80211skb_rxmeta_attach
 586  *
 587  * Allocates a p80211rxmeta structure, initializes it, and attaches
 588  * it to an skb.
 589  *
 590  * Arguments:
 591  *      wlandev         The wlandev this skb belongs to.
 592  *      skb             The skb we're attaching to.
 593  *
 594  * Returns:
 595  *      0 on success, non-zero otherwise
 596  *
 597  * Call context:
 598  *      May be called in interrupt or non-interrupt context
 599  *----------------------------------------------------------------
 600  */
 601 int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
 602 {
 603         int result = 0;
 604         struct p80211_rxmeta *rxmeta;
 605         struct p80211_frmmeta *frmmeta;
 606 
 607         /* If these already have metadata, we error out! */
 608         if (p80211skb_rxmeta(skb)) {
 609                 netdev_err(wlandev->netdev,
 610                            "%s: RXmeta already attached!\n", wlandev->name);
 611                 result = 0;
 612                 goto exit;
 613         }
 614 
 615         /* Allocate the rxmeta */
 616         rxmeta = kzalloc(sizeof(*rxmeta), GFP_ATOMIC);
 617 
 618         if (!rxmeta) {
 619                 result = 1;
 620                 goto exit;
 621         }
 622 
 623         /* Initialize the rxmeta */
 624         rxmeta->wlandev = wlandev;
 625         rxmeta->hosttime = jiffies;
 626 
 627         /* Overlay a frmmeta_t onto skb->cb */
 628         memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
 629         frmmeta = (struct p80211_frmmeta *)(skb->cb);
 630         frmmeta->magic = P80211_FRMMETA_MAGIC;
 631         frmmeta->rx = rxmeta;
 632 exit:
 633         return result;
 634 }
 635 
 636 /*----------------------------------------------------------------
 637  * p80211skb_free
 638  *
 639  * Frees an entire p80211skb by checking and freeing the meta struct
 640  * and then freeing the skb.
 641  *
 642  * Arguments:
 643  *      wlandev         The wlandev this skb belongs to.
 644  *      skb             The skb we're attaching to.
 645  *
 646  * Returns:
 647  *      0 on success, non-zero otherwise
 648  *
 649  * Call context:
 650  *      May be called in interrupt or non-interrupt context
 651  *----------------------------------------------------------------
 652  */
 653 void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
 654 {
 655         struct p80211_frmmeta *meta;
 656 
 657         meta = p80211skb_frmmeta(skb);
 658         if (meta && meta->rx)
 659                 p80211skb_rxmeta_detach(skb);
 660         else
 661                 netdev_err(wlandev->netdev,
 662                            "Freeing an skb (%p) w/ no frmmeta.\n", skb);
 663         dev_kfree_skb(skb);
 664 }

/* [<][>][^][v][top][bottom][index][help] */