p80211conv.c 19 KB

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