p80211conv.c (19697B)
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 * 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 79static const u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 }; 80static 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 */ 108int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, 109 struct sk_buff *skb, struct 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->address1, &e_hdr.daddr, ETH_ALEN); 179 memcpy(p80211_hdr->address2, wlandev->netdev->dev_addr, ETH_ALEN); 180 memcpy(p80211_hdr->address3, 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->address1, wlandev->bssid, ETH_ALEN); 185 memcpy(p80211_hdr->address2, wlandev->netdev->dev_addr, ETH_ALEN); 186 memcpy(p80211_hdr->address3, &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->address1, &e_hdr.daddr, ETH_ALEN); 191 memcpy(p80211_hdr->address2, wlandev->bssid, ETH_ALEN); 192 memcpy(p80211_hdr->address3, &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->frame_control = fc; 226 p80211_hdr->duration_id = 0; 227 p80211_hdr->sequence_control = 0; 228 229 return 0; 230} 231 232/* jkriegl: from orinoco, modified */ 233static 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 */ 275int 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 struct 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 = (struct p80211_hdr *)skb->data; 295 296 /* setup some vars for convenience */ 297 fc = le16_to_cpu(w_hdr->frame_control); 298 if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) { 299 ether_addr_copy(daddr, w_hdr->address1); 300 ether_addr_copy(saddr, w_hdr->address2); 301 } else if ((WLAN_GET_FC_TODS(fc) == 0) && 302 (WLAN_GET_FC_FROMDS(fc) == 1)) { 303 ether_addr_copy(daddr, w_hdr->address1); 304 ether_addr_copy(saddr, w_hdr->address3); 305 } else if ((WLAN_GET_FC_TODS(fc) == 1) && 306 (WLAN_GET_FC_FROMDS(fc) == 0)) { 307 ether_addr_copy(daddr, w_hdr->address3); 308 ether_addr_copy(saddr, w_hdr->address2); 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->address3); 317 ether_addr_copy(saddr, w_hdr->address4); 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 */ 525int 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 */ 556void 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 */ 601int 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; 632exit: 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 */ 653void 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}