bcm43xx_xmit.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*
  2. Broadcom BCM43xx wireless driver
  3. Transmission (TX/RX) related functions.
  4. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  5. Stefano Brivio <st3@riseup.net>
  6. Michael Buesch <mbuesch@freenet.de>
  7. Danny van Dyk <kugelfang@gentoo.org>
  8. Andreas Jaggi <andreas.jaggi@waterwave.ch>
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program; see the file COPYING. If not, write to
  19. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  20. Boston, MA 02110-1301, USA.
  21. */
  22. #include "bcm43xx_xmit.h"
  23. #include <linux/etherdevice.h>
  24. /* Extract the bitrate out of a CCK PLCP header. */
  25. static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
  26. {
  27. switch (plcp->raw[0]) {
  28. case 0x0A:
  29. return IEEE80211_CCK_RATE_1MB;
  30. case 0x14:
  31. return IEEE80211_CCK_RATE_2MB;
  32. case 0x37:
  33. return IEEE80211_CCK_RATE_5MB;
  34. case 0x6E:
  35. return IEEE80211_CCK_RATE_11MB;
  36. }
  37. assert(0);
  38. return 0;
  39. }
  40. /* Extract the bitrate out of an OFDM PLCP header. */
  41. static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
  42. {
  43. switch (plcp->raw[0] & 0xF) {
  44. case 0xB:
  45. return IEEE80211_OFDM_RATE_6MB;
  46. case 0xF:
  47. return IEEE80211_OFDM_RATE_9MB;
  48. case 0xA:
  49. return IEEE80211_OFDM_RATE_12MB;
  50. case 0xE:
  51. return IEEE80211_OFDM_RATE_18MB;
  52. case 0x9:
  53. return IEEE80211_OFDM_RATE_24MB;
  54. case 0xD:
  55. return IEEE80211_OFDM_RATE_36MB;
  56. case 0x8:
  57. return IEEE80211_OFDM_RATE_48MB;
  58. case 0xC:
  59. return IEEE80211_OFDM_RATE_54MB;
  60. }
  61. assert(0);
  62. return 0;
  63. }
  64. u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
  65. {
  66. switch (bitrate) {
  67. case IEEE80211_CCK_RATE_1MB:
  68. return 0x0A;
  69. case IEEE80211_CCK_RATE_2MB:
  70. return 0x14;
  71. case IEEE80211_CCK_RATE_5MB:
  72. return 0x37;
  73. case IEEE80211_CCK_RATE_11MB:
  74. return 0x6E;
  75. }
  76. assert(0);
  77. return 0;
  78. }
  79. u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
  80. {
  81. switch (bitrate) {
  82. case IEEE80211_OFDM_RATE_6MB:
  83. return 0xB;
  84. case IEEE80211_OFDM_RATE_9MB:
  85. return 0xF;
  86. case IEEE80211_OFDM_RATE_12MB:
  87. return 0xA;
  88. case IEEE80211_OFDM_RATE_18MB:
  89. return 0xE;
  90. case IEEE80211_OFDM_RATE_24MB:
  91. return 0x9;
  92. case IEEE80211_OFDM_RATE_36MB:
  93. return 0xD;
  94. case IEEE80211_OFDM_RATE_48MB:
  95. return 0x8;
  96. case IEEE80211_OFDM_RATE_54MB:
  97. return 0xC;
  98. }
  99. assert(0);
  100. return 0;
  101. }
  102. static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
  103. const u16 octets, const u8 bitrate,
  104. const int ofdm_modulation)
  105. {
  106. __le32 *data = &(plcp->data);
  107. __u8 *raw = plcp->raw;
  108. if (ofdm_modulation) {
  109. *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
  110. assert(!(octets & 0xF000));
  111. *data |= (octets << 5);
  112. *data = cpu_to_le32(*data);
  113. } else {
  114. u32 plen;
  115. plen = octets * 16 / bitrate;
  116. if ((octets * 16 % bitrate) > 0) {
  117. plen++;
  118. if ((bitrate == IEEE80211_CCK_RATE_11MB)
  119. && ((octets * 8 % 11) < 4)) {
  120. raw[1] = 0x84;
  121. } else
  122. raw[1] = 0x04;
  123. } else
  124. raw[1] = 0x04;
  125. *data |= cpu_to_le32(plen << 16);
  126. raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
  127. }
  128. }
  129. static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
  130. {
  131. switch (bitrate) {
  132. case IEEE80211_CCK_RATE_1MB:
  133. return IEEE80211_CCK_RATE_1MB;
  134. case IEEE80211_CCK_RATE_2MB:
  135. return IEEE80211_CCK_RATE_1MB;
  136. case IEEE80211_CCK_RATE_5MB:
  137. return IEEE80211_CCK_RATE_2MB;
  138. case IEEE80211_CCK_RATE_11MB:
  139. return IEEE80211_CCK_RATE_5MB;
  140. case IEEE80211_OFDM_RATE_6MB:
  141. return IEEE80211_CCK_RATE_5MB;
  142. case IEEE80211_OFDM_RATE_9MB:
  143. return IEEE80211_OFDM_RATE_6MB;
  144. case IEEE80211_OFDM_RATE_12MB:
  145. return IEEE80211_OFDM_RATE_9MB;
  146. case IEEE80211_OFDM_RATE_18MB:
  147. return IEEE80211_OFDM_RATE_12MB;
  148. case IEEE80211_OFDM_RATE_24MB:
  149. return IEEE80211_OFDM_RATE_18MB;
  150. case IEEE80211_OFDM_RATE_36MB:
  151. return IEEE80211_OFDM_RATE_24MB;
  152. case IEEE80211_OFDM_RATE_48MB:
  153. return IEEE80211_OFDM_RATE_36MB;
  154. case IEEE80211_OFDM_RATE_54MB:
  155. return IEEE80211_OFDM_RATE_48MB;
  156. }
  157. assert(0);
  158. return 0;
  159. }
  160. static
  161. __le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
  162. u8 bitrate)
  163. {
  164. const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
  165. __le16 duration_id = wireless_header->duration_id;
  166. switch (WLAN_FC_GET_TYPE(frame_ctl)) {
  167. case IEEE80211_FTYPE_DATA:
  168. case IEEE80211_FTYPE_MGMT:
  169. //TODO: Steal the code from ieee80211, once it is completed there.
  170. break;
  171. case IEEE80211_FTYPE_CTL:
  172. /* Use the original duration/id. */
  173. break;
  174. default:
  175. assert(0);
  176. }
  177. return duration_id;
  178. }
  179. static inline
  180. u16 ceiling_div(u16 dividend, u16 divisor)
  181. {
  182. return ((dividend + divisor - 1) / divisor);
  183. }
  184. static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
  185. struct bcm43xx_txhdr *txhdr,
  186. u16 *flags,
  187. u8 bitrate,
  188. const struct ieee80211_hdr_4addr *wlhdr)
  189. {
  190. u16 fctl;
  191. u16 dur;
  192. u8 fallback_bitrate;
  193. int ofdm_modulation;
  194. int fallback_ofdm_modulation;
  195. // u8 *sa, *da;
  196. u16 flen;
  197. //FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
  198. //FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
  199. fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
  200. ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
  201. fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
  202. flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
  203. bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
  204. flen, bitrate,
  205. !ieee80211_is_cck_rate(bitrate));
  206. bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
  207. flen, fallback_bitrate,
  208. !ieee80211_is_cck_rate(fallback_bitrate));
  209. fctl = IEEE80211_FTYPE_CTL;
  210. fctl |= IEEE80211_STYPE_RTS;
  211. dur = le16_to_cpu(wlhdr->duration_id);
  212. /*FIXME: should we test for dur==0 here and let it unmodified in this case?
  213. * The following assert checks for this case...
  214. */
  215. assert(dur);
  216. /*FIXME: The duration calculation is not really correct.
  217. * I am not 100% sure which bitrate to use. We use the RTS rate here,
  218. * but this is likely to be wrong.
  219. */
  220. if (phy->type == BCM43xx_PHYTYPE_A) {
  221. /* Three times SIFS */
  222. dur += 16 * 3;
  223. /* Add ACK duration. */
  224. dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
  225. bitrate * 4);
  226. /* Add CTS duration. */
  227. dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
  228. bitrate * 4);
  229. } else {
  230. /* Three times SIFS */
  231. dur += 10 * 3;
  232. /* Add ACK duration. */
  233. dur += ceiling_div(8 * (14 /*bytes*/) * 10,
  234. bitrate);
  235. /* Add CTS duration. */
  236. dur += ceiling_div(8 * (14 /*bytes*/) * 10,
  237. bitrate);
  238. }
  239. txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
  240. txhdr->rts_cts_dur = cpu_to_le16(dur);
  241. //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
  242. //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
  243. memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
  244. // memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
  245. *flags |= BCM43xx_TXHDRFLAG_RTSCTS;
  246. *flags |= BCM43xx_TXHDRFLAG_RTS;
  247. if (ofdm_modulation)
  248. *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
  249. if (fallback_ofdm_modulation)
  250. *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
  251. }
  252. void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
  253. struct bcm43xx_txhdr *txhdr,
  254. const unsigned char *fragment_data,
  255. const unsigned int fragment_len,
  256. const int is_first_fragment,
  257. const u16 cookie)
  258. {
  259. const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
  260. const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
  261. const struct ieee80211_security *secinfo = &bcm->ieee->sec;
  262. u8 bitrate;
  263. u8 fallback_bitrate;
  264. int ofdm_modulation;
  265. int fallback_ofdm_modulation;
  266. u16 plcp_fragment_len = fragment_len;
  267. u16 flags = 0;
  268. u16 control = 0;
  269. u16 wsec_rate = 0;
  270. u16 encrypt_frame;
  271. /* Now construct the TX header. */
  272. memset(txhdr, 0, sizeof(*txhdr));
  273. bitrate = bcm->softmac->txrates.default_rate;
  274. ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
  275. fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
  276. fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
  277. /* Set Frame Control from 80211 header. */
  278. txhdr->frame_control = wireless_header->frame_ctl;
  279. /* Copy address1 from 80211 header. */
  280. memcpy(txhdr->mac1, wireless_header->addr1, 6);
  281. /* Set the fallback duration ID. */
  282. txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
  283. fallback_bitrate);
  284. /* Set the cookie (used as driver internal ID for the frame) */
  285. txhdr->cookie = cpu_to_le16(cookie);
  286. /* Hardware appends FCS. */
  287. plcp_fragment_len += IEEE80211_FCS_LEN;
  288. /* Hardware encryption. */
  289. encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
  290. if (encrypt_frame && !bcm->ieee->host_encrypt) {
  291. const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
  292. memcpy(txhdr->wep_iv, hdr->payload, 4);
  293. /* Hardware appends ICV. */
  294. plcp_fragment_len += 4;
  295. wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
  296. & BCM43xx_TXHDR_WSEC_ALGO_MASK;
  297. wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
  298. & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
  299. }
  300. /* Generate the PLCP header and the fallback PLCP header. */
  301. bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
  302. plcp_fragment_len,
  303. bitrate, ofdm_modulation);
  304. bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
  305. fallback_bitrate, fallback_ofdm_modulation);
  306. /* Set the CONTROL field */
  307. if (ofdm_modulation)
  308. control |= BCM43xx_TXHDRCTL_OFDM;
  309. if (bcm->short_preamble) //FIXME: could be the other way around, please test
  310. control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
  311. control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
  312. & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
  313. /* Set the FLAGS field */
  314. if (!is_multicast_ether_addr(wireless_header->addr1) &&
  315. !is_broadcast_ether_addr(wireless_header->addr1))
  316. flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
  317. if (1 /* FIXME: PS poll?? */)
  318. flags |= 0x10; // FIXME: unknown meaning.
  319. if (fallback_ofdm_modulation)
  320. flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
  321. if (is_first_fragment)
  322. flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
  323. /* Set WSEC/RATE field */
  324. wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
  325. & BCM43xx_TXHDR_RATE_MASK;
  326. /* Generate the RTS/CTS packet, if required. */
  327. /* FIXME: We should first try with CTS-to-self,
  328. * if we are on 80211g. If we get too many
  329. * failures (hidden nodes), we should switch back to RTS/CTS.
  330. */
  331. if (0/*FIXME txctl->use_rts_cts*/) {
  332. bcm43xx_generate_rts(phy, txhdr, &flags,
  333. 0/*FIXME txctl->rts_cts_rate*/,
  334. wireless_header);
  335. }
  336. txhdr->flags = cpu_to_le16(flags);
  337. txhdr->control = cpu_to_le16(control);
  338. txhdr->wsec_rate = cpu_to_le16(wsec_rate);
  339. }
  340. static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
  341. u8 in_rssi, int ofdm,
  342. int adjust_2053, int adjust_2050)
  343. {
  344. struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
  345. struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
  346. s32 tmp;
  347. switch (radio->version) {
  348. case 0x2050:
  349. if (ofdm) {
  350. tmp = in_rssi;
  351. if (tmp > 127)
  352. tmp -= 256;
  353. tmp *= 73;
  354. tmp /= 64;
  355. if (adjust_2050)
  356. tmp += 25;
  357. else
  358. tmp -= 3;
  359. } else {
  360. if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
  361. if (in_rssi > 63)
  362. in_rssi = 63;
  363. tmp = radio->nrssi_lt[in_rssi];
  364. tmp = 31 - tmp;
  365. tmp *= -131;
  366. tmp /= 128;
  367. tmp -= 57;
  368. } else {
  369. tmp = in_rssi;
  370. tmp = 31 - tmp;
  371. tmp *= -149;
  372. tmp /= 128;
  373. tmp -= 68;
  374. }
  375. if (phy->type == BCM43xx_PHYTYPE_G &&
  376. adjust_2050)
  377. tmp += 25;
  378. }
  379. break;
  380. case 0x2060:
  381. if (in_rssi > 127)
  382. tmp = in_rssi - 256;
  383. else
  384. tmp = in_rssi;
  385. break;
  386. default:
  387. tmp = in_rssi;
  388. tmp -= 11;
  389. tmp *= 103;
  390. tmp /= 64;
  391. if (adjust_2053)
  392. tmp -= 109;
  393. else
  394. tmp -= 83;
  395. }
  396. return (s8)tmp;
  397. }
  398. //TODO
  399. #if 0
  400. static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
  401. u8 in_rssi)
  402. {
  403. struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
  404. s8 ret;
  405. if (phy->type == BCM43xx_PHYTYPE_A) {
  406. //TODO: Incomplete specs.
  407. ret = 0;
  408. } else
  409. ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
  410. return ret;
  411. }
  412. #endif
  413. int bcm43xx_rx(struct bcm43xx_private *bcm,
  414. struct sk_buff *skb,
  415. struct bcm43xx_rxhdr *rxhdr)
  416. {
  417. struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
  418. struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
  419. struct bcm43xx_plcp_hdr4 *plcp;
  420. struct ieee80211_rx_stats stats;
  421. struct ieee80211_hdr_4addr *wlhdr;
  422. u16 frame_ctl;
  423. int is_packet_for_us = 0;
  424. int err = -EINVAL;
  425. const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
  426. const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
  427. const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
  428. const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
  429. if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
  430. plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
  431. /* Skip two unknown bytes and the PLCP header. */
  432. skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
  433. } else {
  434. plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
  435. /* Skip the PLCP header. */
  436. skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
  437. }
  438. /* The SKB contains the PAYLOAD (wireless header + data)
  439. * at this point. The FCS at the end is stripped.
  440. */
  441. memset(&stats, 0, sizeof(stats));
  442. stats.mac_time = le16_to_cpu(rxhdr->mactime);
  443. stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
  444. !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
  445. !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
  446. stats.signal = rxhdr->signal_quality; //FIXME
  447. //TODO stats.noise =
  448. if (is_ofdm)
  449. stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
  450. else
  451. stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
  452. //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
  453. stats.received_channel = radio->channel;
  454. //TODO stats.control =
  455. stats.mask = IEEE80211_STATMASK_SIGNAL |
  456. //TODO IEEE80211_STATMASK_NOISE |
  457. IEEE80211_STATMASK_RATE |
  458. IEEE80211_STATMASK_RSSI;
  459. if (phy->type == BCM43xx_PHYTYPE_A)
  460. stats.freq = IEEE80211_52GHZ_BAND;
  461. else
  462. stats.freq = IEEE80211_24GHZ_BAND;
  463. stats.len = skb->len;
  464. bcm->stats.last_rx = jiffies;
  465. if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
  466. err = ieee80211_rx(bcm->ieee, skb, &stats);
  467. return (err == 0) ? -EINVAL : 0;
  468. }
  469. wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
  470. switch (bcm->ieee->iw_mode) {
  471. case IW_MODE_ADHOC:
  472. if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
  473. memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
  474. is_broadcast_ether_addr(wlhdr->addr1) ||
  475. is_multicast_ether_addr(wlhdr->addr1) ||
  476. bcm->net_dev->flags & IFF_PROMISC)
  477. is_packet_for_us = 1;
  478. break;
  479. case IW_MODE_INFRA:
  480. default:
  481. /* When receiving multicast or broadcast packets, filter out
  482. the packets we send ourself; we shouldn't see those */
  483. if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
  484. memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
  485. (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
  486. (is_broadcast_ether_addr(wlhdr->addr1) ||
  487. is_multicast_ether_addr(wlhdr->addr1) ||
  488. bcm->net_dev->flags & IFF_PROMISC)))
  489. is_packet_for_us = 1;
  490. break;
  491. }
  492. frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
  493. if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
  494. frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
  495. wlhdr->frame_ctl = cpu_to_le16(frame_ctl);
  496. /* trim IV and ICV */
  497. /* FIXME: this must be done only for WEP encrypted packets */
  498. if (skb->len < 32) {
  499. dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
  500. "set and length < 32)\n");
  501. return -EINVAL;
  502. } else {
  503. memmove(skb->data + 4, skb->data, 24);
  504. skb_pull(skb, 4);
  505. skb_trim(skb, skb->len - 4);
  506. stats.len -= 8;
  507. }
  508. wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
  509. }
  510. switch (WLAN_FC_GET_TYPE(frame_ctl)) {
  511. case IEEE80211_FTYPE_MGMT:
  512. ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
  513. break;
  514. case IEEE80211_FTYPE_DATA:
  515. if (is_packet_for_us) {
  516. err = ieee80211_rx(bcm->ieee, skb, &stats);
  517. err = (err == 0) ? -EINVAL : 0;
  518. }
  519. break;
  520. case IEEE80211_FTYPE_CTL:
  521. break;
  522. default:
  523. assert(0);
  524. return -EINVAL;
  525. }
  526. return err;
  527. }