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