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