p80211conv.c 19 KB

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