p80211conv.c 19 KB

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