p80211conv.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  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. __le16 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 <= ETH_DATA_LEN) {
  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, ETH_HLEN);
  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, ETH_HLEN);
  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. if (!p80211_wep->data)
  191. return -ENOMEM;
  192. foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
  193. skb->len,
  194. (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
  195. p80211_wep->iv, p80211_wep->icv);
  196. if (foo) {
  197. netdev_warn(wlandev->netdev,
  198. "Host en-WEP failed, dropping frame (%d).\n",
  199. foo);
  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(wlandevice_t *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. for (i = 0; i < wlandev->spy_number; i++) {
  218. if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
  219. memcpy(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. int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
  250. struct sk_buff *skb)
  251. {
  252. netdevice_t *netdev = wlandev->netdev;
  253. u16 fc;
  254. unsigned int payload_length;
  255. unsigned int payload_offset;
  256. u8 daddr[ETH_ALEN];
  257. u8 saddr[ETH_ALEN];
  258. union p80211_hdr *w_hdr;
  259. struct wlan_ethhdr *e_hdr;
  260. struct wlan_llc *e_llc;
  261. struct wlan_snap *e_snap;
  262. int foo;
  263. payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
  264. payload_offset = WLAN_HDR_A3_LEN;
  265. w_hdr = (union p80211_hdr *) skb->data;
  266. /* setup some vars for convenience */
  267. fc = le16_to_cpu(w_hdr->a3.fc);
  268. if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
  269. ether_addr_copy(daddr, w_hdr->a3.a1);
  270. ether_addr_copy(saddr, w_hdr->a3.a2);
  271. } else if ((WLAN_GET_FC_TODS(fc) == 0)
  272. && (WLAN_GET_FC_FROMDS(fc) == 1)) {
  273. ether_addr_copy(daddr, w_hdr->a3.a1);
  274. ether_addr_copy(saddr, w_hdr->a3.a3);
  275. } else if ((WLAN_GET_FC_TODS(fc) == 1)
  276. && (WLAN_GET_FC_FROMDS(fc) == 0)) {
  277. ether_addr_copy(daddr, w_hdr->a3.a3);
  278. ether_addr_copy(saddr, w_hdr->a3.a2);
  279. } else {
  280. payload_offset = WLAN_HDR_A4_LEN;
  281. if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
  282. netdev_err(netdev, "A4 frame too short!\n");
  283. return 1;
  284. }
  285. payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
  286. ether_addr_copy(daddr, w_hdr->a4.a3);
  287. ether_addr_copy(saddr, w_hdr->a4.a4);
  288. }
  289. /* perform de-wep if necessary.. */
  290. if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc)
  291. && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
  292. if (payload_length <= 8) {
  293. netdev_err(netdev,
  294. "WEP frame too short (%u).\n", skb->len);
  295. return 1;
  296. }
  297. foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
  298. payload_length - 8, -1,
  299. skb->data + payload_offset,
  300. skb->data + payload_offset +
  301. payload_length - 4);
  302. if (foo) {
  303. /* de-wep failed, drop skb. */
  304. pr_debug("Host de-WEP failed, dropping frame (%d).\n",
  305. foo);
  306. wlandev->rx.decrypt_err++;
  307. return 2;
  308. }
  309. /* subtract the IV+ICV length off the payload */
  310. payload_length -= 8;
  311. /* chop off the IV */
  312. skb_pull(skb, 4);
  313. /* chop off the ICV. */
  314. skb_trim(skb, skb->len - 4);
  315. wlandev->rx.decrypt++;
  316. }
  317. e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);
  318. e_llc = (struct wlan_llc *) (skb->data + payload_offset);
  319. e_snap =
  320. (struct wlan_snap *) (skb->data + payload_offset +
  321. sizeof(struct wlan_llc));
  322. /* Test for the various encodings */
  323. if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
  324. (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
  325. ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) ||
  326. (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) {
  327. pr_debug("802.3 ENCAP len: %d\n", payload_length);
  328. /* 802.3 Encapsulated */
  329. /* Test for an overlength frame */
  330. if (payload_length > (netdev->mtu + ETH_HLEN)) {
  331. /* A bogus length ethfrm has been encap'd. */
  332. /* Is someone trying an oflow attack? */
  333. netdev_err(netdev, "ENCAP frame too large (%d > %d)\n",
  334. payload_length, netdev->mtu + ETH_HLEN);
  335. return 1;
  336. }
  337. /* Chop off the 802.11 header. it's already sane. */
  338. skb_pull(skb, payload_offset);
  339. /* chop off the 802.11 CRC */
  340. skb_trim(skb, skb->len - WLAN_CRC_LEN);
  341. } else if ((payload_length >= sizeof(struct wlan_llc) +
  342. sizeof(struct wlan_snap))
  343. && (e_llc->dsap == 0xaa)
  344. && (e_llc->ssap == 0xaa)
  345. && (e_llc->ctl == 0x03)
  346. &&
  347. (((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0)
  348. && (ethconv == WLAN_ETHCONV_8021h)
  349. && (p80211_stt_findproto(le16_to_cpu(e_snap->type))))
  350. || (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) !=
  351. 0))) {
  352. pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
  353. /* it's a SNAP + RFC1042 frame && protocol is in STT */
  354. /* build 802.3 + RFC1042 */
  355. /* Test for an overlength frame */
  356. if (payload_length > netdev->mtu) {
  357. /* A bogus length ethfrm has been sent. */
  358. /* Is someone trying an oflow attack? */
  359. netdev_err(netdev, "SNAP frame too large (%d > %d)\n",
  360. payload_length, netdev->mtu);
  361. return 1;
  362. }
  363. /* chop 802.11 header from skb. */
  364. skb_pull(skb, payload_offset);
  365. /* create 802.3 header at beginning of skb. */
  366. e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
  367. ether_addr_copy(e_hdr->daddr, daddr);
  368. ether_addr_copy(e_hdr->saddr, saddr);
  369. e_hdr->type = htons(payload_length);
  370. /* chop off the 802.11 CRC */
  371. skb_trim(skb, skb->len - WLAN_CRC_LEN);
  372. } else if ((payload_length >= sizeof(struct wlan_llc) +
  373. sizeof(struct wlan_snap))
  374. && (e_llc->dsap == 0xaa)
  375. && (e_llc->ssap == 0xaa)
  376. && (e_llc->ctl == 0x03)) {
  377. pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
  378. /* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
  379. build a DIXII + RFC894 */
  380. /* Test for an overlength frame */
  381. if ((payload_length - sizeof(struct wlan_llc) -
  382. sizeof(struct wlan_snap))
  383. > netdev->mtu) {
  384. /* A bogus length ethfrm has been sent. */
  385. /* Is someone trying an oflow attack? */
  386. netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
  387. (long int)(payload_length -
  388. sizeof(struct wlan_llc) -
  389. sizeof(struct wlan_snap)), netdev->mtu);
  390. return 1;
  391. }
  392. /* chop 802.11 header from skb. */
  393. skb_pull(skb, payload_offset);
  394. /* chop llc header from skb. */
  395. skb_pull(skb, sizeof(struct wlan_llc));
  396. /* chop snap header from skb. */
  397. skb_pull(skb, sizeof(struct wlan_snap));
  398. /* create 802.3 header at beginning of skb. */
  399. e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
  400. e_hdr->type = e_snap->type;
  401. ether_addr_copy(e_hdr->daddr, daddr);
  402. ether_addr_copy(e_hdr->saddr, saddr);
  403. /* chop off the 802.11 CRC */
  404. skb_trim(skb, skb->len - WLAN_CRC_LEN);
  405. } else {
  406. pr_debug("NON-ENCAP len: %d\n", payload_length);
  407. /* any NON-ENCAP */
  408. /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
  409. /* build an 802.3 frame */
  410. /* allocate space and setup hostbuf */
  411. /* Test for an overlength frame */
  412. if (payload_length > netdev->mtu) {
  413. /* A bogus length ethfrm has been sent. */
  414. /* Is someone trying an oflow attack? */
  415. netdev_err(netdev, "OTHER frame too large (%d > %d)\n",
  416. payload_length, netdev->mtu);
  417. return 1;
  418. }
  419. /* Chop off the 802.11 header. */
  420. skb_pull(skb, payload_offset);
  421. /* create 802.3 header at beginning of skb. */
  422. e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
  423. ether_addr_copy(e_hdr->daddr, daddr);
  424. ether_addr_copy(e_hdr->saddr, saddr);
  425. e_hdr->type = htons(payload_length);
  426. /* chop off the 802.11 CRC */
  427. skb_trim(skb, skb->len - WLAN_CRC_LEN);
  428. }
  429. /*
  430. * Note that eth_type_trans() expects an skb w/ skb->data pointing
  431. * at the MAC header, it then sets the following skb members:
  432. * skb->mac_header,
  433. * skb->data, and
  434. * skb->pkt_type.
  435. * It then _returns_ the value that _we're_ supposed to stuff in
  436. * skb->protocol. This is nuts.
  437. */
  438. skb->protocol = eth_type_trans(skb, netdev);
  439. /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
  440. /* jkriegl: only process signal/noise if requested by iwspy */
  441. if (wlandev->spy_number)
  442. orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
  443. P80211SKB_RXMETA(skb));
  444. /* Free the metadata */
  445. p80211skb_rxmeta_detach(skb);
  446. return 0;
  447. }
  448. /*----------------------------------------------------------------
  449. * p80211_stt_findproto
  450. *
  451. * Searches the 802.1h Selective Translation Table for a given
  452. * protocol.
  453. *
  454. * Arguments:
  455. * proto protocol number (in host order) to search for.
  456. *
  457. * Returns:
  458. * 1 - if the table is empty or a match is found.
  459. * 0 - if the table is non-empty and a match is not found.
  460. *
  461. * Call context:
  462. * May be called in interrupt or non-interrupt context
  463. ----------------------------------------------------------------*/
  464. int p80211_stt_findproto(u16 proto)
  465. {
  466. /* Always return found for now. This is the behavior used by the */
  467. /* Zoom Win95 driver when 802.1h mode is selected */
  468. /* TODO: If necessary, add an actual search we'll probably
  469. need this to match the CMAC's way of doing things.
  470. Need to do some testing to confirm.
  471. */
  472. if (proto == ETH_P_AARP) /* APPLETALK */
  473. return 1;
  474. return 0;
  475. }
  476. /*----------------------------------------------------------------
  477. * p80211skb_rxmeta_detach
  478. *
  479. * Disconnects the frmmeta and rxmeta from an skb.
  480. *
  481. * Arguments:
  482. * wlandev The wlandev this skb belongs to.
  483. * skb The skb we're attaching to.
  484. *
  485. * Returns:
  486. * 0 on success, non-zero otherwise
  487. *
  488. * Call context:
  489. * May be called in interrupt or non-interrupt context
  490. ----------------------------------------------------------------*/
  491. void p80211skb_rxmeta_detach(struct sk_buff *skb)
  492. {
  493. struct p80211_rxmeta *rxmeta;
  494. struct p80211_frmmeta *frmmeta;
  495. /* Sanity checks */
  496. if (skb == NULL) { /* bad skb */
  497. pr_debug("Called w/ null skb.\n");
  498. return;
  499. }
  500. frmmeta = P80211SKB_FRMMETA(skb);
  501. if (frmmeta == NULL) { /* no magic */
  502. pr_debug("Called w/ bad frmmeta magic.\n");
  503. return;
  504. }
  505. rxmeta = frmmeta->rx;
  506. if (rxmeta == NULL) { /* bad meta ptr */
  507. pr_debug("Called w/ bad rxmeta ptr.\n");
  508. return;
  509. }
  510. /* Free rxmeta */
  511. kfree(rxmeta);
  512. /* Clear skb->cb */
  513. memset(skb->cb, 0, sizeof(skb->cb));
  514. }
  515. /*----------------------------------------------------------------
  516. * p80211skb_rxmeta_attach
  517. *
  518. * Allocates a p80211rxmeta structure, initializes it, and attaches
  519. * it to an skb.
  520. *
  521. * Arguments:
  522. * wlandev The wlandev this skb belongs to.
  523. * skb The skb we're attaching to.
  524. *
  525. * Returns:
  526. * 0 on success, non-zero otherwise
  527. *
  528. * Call context:
  529. * May be called in interrupt or non-interrupt context
  530. ----------------------------------------------------------------*/
  531. int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
  532. {
  533. int result = 0;
  534. struct p80211_rxmeta *rxmeta;
  535. struct p80211_frmmeta *frmmeta;
  536. /* If these already have metadata, we error out! */
  537. if (P80211SKB_RXMETA(skb) != NULL) {
  538. netdev_err(wlandev->netdev,
  539. "%s: RXmeta already attached!\n", wlandev->name);
  540. result = 0;
  541. goto exit;
  542. }
  543. /* Allocate the rxmeta */
  544. rxmeta = kzalloc(sizeof(struct p80211_rxmeta), GFP_ATOMIC);
  545. if (rxmeta == NULL) {
  546. netdev_err(wlandev->netdev,
  547. "%s: Failed to allocate rxmeta.\n", wlandev->name);
  548. result = 1;
  549. goto exit;
  550. }
  551. /* Initialize the rxmeta */
  552. rxmeta->wlandev = wlandev;
  553. rxmeta->hosttime = jiffies;
  554. /* Overlay a frmmeta_t onto skb->cb */
  555. memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
  556. frmmeta = (struct p80211_frmmeta *) (skb->cb);
  557. frmmeta->magic = P80211_FRMMETA_MAGIC;
  558. frmmeta->rx = rxmeta;
  559. exit:
  560. return result;
  561. }
  562. /*----------------------------------------------------------------
  563. * p80211skb_free
  564. *
  565. * Frees an entire p80211skb by checking and freeing the meta struct
  566. * and then freeing the skb.
  567. *
  568. * Arguments:
  569. * wlandev The wlandev this skb belongs to.
  570. * skb The skb we're attaching to.
  571. *
  572. * Returns:
  573. * 0 on success, non-zero otherwise
  574. *
  575. * Call context:
  576. * May be called in interrupt or non-interrupt context
  577. ----------------------------------------------------------------*/
  578. void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
  579. {
  580. struct p80211_frmmeta *meta;
  581. meta = P80211SKB_FRMMETA(skb);
  582. if (meta && meta->rx)
  583. p80211skb_rxmeta_detach(skb);
  584. else
  585. netdev_err(wlandev->netdev,
  586. "Freeing an skb (%p) w/ no frmmeta.\n", skb);
  587. dev_kfree_skb(skb);
  588. }