3 Broadcom BCM43xx wireless driver
5 Transmission (TX/RX) related functions.
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>
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.
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.
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.
30 #include "bcm43xx_xmit.h"
32 #include <linux/etherdevice.h>
35 /* Extract the bitrate out of a CCK PLCP header. */
36 static u8
bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4
*plcp
)
38 switch (plcp
->raw
[0]) {
40 return IEEE80211_CCK_RATE_1MB
;
42 return IEEE80211_CCK_RATE_2MB
;
44 return IEEE80211_CCK_RATE_5MB
;
46 return IEEE80211_CCK_RATE_11MB
;
52 /* Extract the bitrate out of an OFDM PLCP header. */
53 static u8
bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4
*plcp
)
55 switch (plcp
->raw
[0] & 0xF) {
57 return IEEE80211_OFDM_RATE_6MB
;
59 return IEEE80211_OFDM_RATE_9MB
;
61 return IEEE80211_OFDM_RATE_12MB
;
63 return IEEE80211_OFDM_RATE_18MB
;
65 return IEEE80211_OFDM_RATE_24MB
;
67 return IEEE80211_OFDM_RATE_36MB
;
69 return IEEE80211_OFDM_RATE_48MB
;
71 return IEEE80211_OFDM_RATE_54MB
;
77 u8
bcm43xx_plcp_get_ratecode_cck(const u8 bitrate
)
80 case IEEE80211_CCK_RATE_1MB
:
82 case IEEE80211_CCK_RATE_2MB
:
84 case IEEE80211_CCK_RATE_5MB
:
86 case IEEE80211_CCK_RATE_11MB
:
93 u8
bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate
)
96 case IEEE80211_OFDM_RATE_6MB
:
98 case IEEE80211_OFDM_RATE_9MB
:
100 case IEEE80211_OFDM_RATE_12MB
:
102 case IEEE80211_OFDM_RATE_18MB
:
104 case IEEE80211_OFDM_RATE_24MB
:
106 case IEEE80211_OFDM_RATE_36MB
:
108 case IEEE80211_OFDM_RATE_48MB
:
110 case IEEE80211_OFDM_RATE_54MB
:
117 static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4
*plcp
,
118 const u16 octets
, const u8 bitrate
,
119 const int ofdm_modulation
)
121 __le32
*data
= &(plcp
->data
);
122 __u8
*raw
= plcp
->raw
;
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
);
132 plen
= octets
* 16 / bitrate
;
133 if ((octets
* 16 % bitrate
) > 0) {
135 if ((bitrate
== IEEE80211_CCK_RATE_11MB
)
136 && ((octets
* 8 % 11) < 4)) {
142 *data
|= cpu_to_le32(plen
<< 16);
143 raw
[0] = bcm43xx_plcp_get_ratecode_cck(bitrate
);
147 static u8
bcm43xx_calc_fallback_rate(u8 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
;
180 __le16
bcm43xx_calc_duration_id(const struct ieee80211_hdr
*wireless_header
,
183 const u16 frame_ctl
= le16_to_cpu(wireless_header
->frame_ctl
);
184 __le16 duration_id
= wireless_header
->duration_id
;
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.
191 case IEEE80211_FTYPE_CTL
:
192 /* Use the original duration/id. */
202 u16
ceiling_div(u16 dividend
, u16 divisor
)
204 return ((dividend
+ divisor
- 1) / divisor
);
207 static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo
*phy
,
208 struct bcm43xx_txhdr
*txhdr
,
211 const struct ieee80211_hdr_4addr
*wlhdr
)
217 int fallback_ofdm_modulation
;
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
));
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
),
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...
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.
245 if (phy
->type
== BCM43xx_PHYTYPE_A
) {
246 /* Three times SIFS */
248 /* Add ACK duration. */
249 dur
+= ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
251 /* Add CTS duration. */
252 dur
+= ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
255 /* Three times SIFS */
257 /* Add ACK duration. */
258 dur
+= ceiling_div(8 * (14 /*bytes*/) * 10,
260 /* Add CTS duration. */
261 dur
+= ceiling_div(8 * (14 /*bytes*/) * 10,
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
);
272 *flags
|= BCM43xx_TXHDRFLAG_RTSCTS
;
273 *flags
|= BCM43xx_TXHDRFLAG_RTS
;
275 *flags
|= BCM43xx_TXHDRFLAG_RTSCTS_OFDM
;
276 if (fallback_ofdm_modulation
)
277 *flags
|= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM
;
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
,
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
;
293 int fallback_ofdm_modulation
;
294 u16 plcp_fragment_len
= fragment_len
;
300 /* Now construct the TX header. */
301 memset(txhdr
, 0, sizeof(*txhdr
));
303 bitrate
= bcm
->softmac
->txrates
.default_rate
;
304 ofdm_modulation
= !(ieee80211_is_cck_rate(bitrate
));
305 fallback_bitrate
= bcm43xx_calc_fallback_rate(bitrate
);
306 fallback_ofdm_modulation
= !(ieee80211_is_cck_rate(fallback_bitrate
));
308 /* Set Frame Control from 80211 header. */
309 txhdr
->frame_control
= wireless_header
->frame_ctl
;
310 /* Copy address1 from 80211 header. */
311 memcpy(txhdr
->mac1
, wireless_header
->addr1
, 6);
312 /* Set the fallback duration ID. */
313 txhdr
->fallback_dur_id
= bcm43xx_calc_duration_id((const struct ieee80211_hdr
*)wireless_header
,
315 /* Set the cookie (used as driver internal ID for the frame) */
316 txhdr
->cookie
= cpu_to_le16(cookie
);
318 /* Hardware appends FCS. */
319 plcp_fragment_len
+= IEEE80211_FCS_LEN
;
321 /* Hardware encryption. */
322 encrypt_frame
= le16_to_cpup(&wireless_header
->frame_ctl
) & IEEE80211_FCTL_PROTECTED
;
323 if (encrypt_frame
&& !bcm
->ieee
->host_encrypt
) {
324 const struct ieee80211_hdr_3addr
*hdr
= (struct ieee80211_hdr_3addr
*)wireless_header
;
325 memcpy(txhdr
->wep_iv
, hdr
->payload
, 4);
326 /* Hardware appends ICV. */
327 plcp_fragment_len
+= 4;
329 wsec_rate
|= (bcm
->key
[secinfo
->active_key
].algorithm
<< BCM43xx_TXHDR_WSEC_ALGO_SHIFT
)
330 & BCM43xx_TXHDR_WSEC_ALGO_MASK
;
331 wsec_rate
|= (secinfo
->active_key
<< BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT
)
332 & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK
;
335 /* Generate the PLCP header and the fallback PLCP header. */
336 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4
*)(&txhdr
->plcp
),
338 bitrate
, ofdm_modulation
);
339 bcm43xx_generate_plcp_hdr(&txhdr
->fallback_plcp
, plcp_fragment_len
,
340 fallback_bitrate
, fallback_ofdm_modulation
);
342 /* Set the CONTROL field */
344 control
|= BCM43xx_TXHDRCTL_OFDM
;
345 if (bcm
->short_preamble
) //FIXME: could be the other way around, please test
346 control
|= BCM43xx_TXHDRCTL_SHORT_PREAMBLE
;
347 control
|= (phy
->antenna_diversity
<< BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT
)
348 & BCM43xx_TXHDRCTL_ANTENNADIV_MASK
;
350 /* Set the FLAGS field */
351 if (!is_multicast_ether_addr(wireless_header
->addr1
) &&
352 !is_broadcast_ether_addr(wireless_header
->addr1
))
353 flags
|= BCM43xx_TXHDRFLAG_EXPECTACK
;
354 if (1 /* FIXME: PS poll?? */)
355 flags
|= 0x10; // FIXME: unknown meaning.
356 if (fallback_ofdm_modulation
)
357 flags
|= BCM43xx_TXHDRFLAG_FALLBACKOFDM
;
358 if (is_first_fragment
)
359 flags
|= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT
;
361 /* Set WSEC/RATE field */
362 wsec_rate
|= (txhdr
->plcp
.raw
[0] << BCM43xx_TXHDR_RATE_SHIFT
)
363 & BCM43xx_TXHDR_RATE_MASK
;
365 /* Generate the RTS/CTS packet, if required. */
366 /* FIXME: We should first try with CTS-to-self,
367 * if we are on 80211g. If we get too many
368 * failures (hidden nodes), we should switch back to RTS/CTS.
370 if (0/*FIXME txctl->use_rts_cts*/) {
371 bcm43xx_generate_rts(phy
, txhdr
, &flags
,
372 0/*FIXME txctl->rts_cts_rate*/,
376 txhdr
->flags
= cpu_to_le16(flags
);
377 txhdr
->control
= cpu_to_le16(control
);
378 txhdr
->wsec_rate
= cpu_to_le16(wsec_rate
);
381 static s8
bcm43xx_rssi_postprocess(struct bcm43xx_private
*bcm
,
382 u8 in_rssi
, int ofdm
,
383 int adjust_2053
, int adjust_2050
)
385 struct bcm43xx_radioinfo
*radio
= bcm43xx_current_radio(bcm
);
386 struct bcm43xx_phyinfo
*phy
= bcm43xx_current_phy(bcm
);
389 switch (radio
->version
) {
402 if (bcm
->sprom
.boardflags
& BCM43xx_BFL_RSSI
) {
405 tmp
= radio
->nrssi_lt
[in_rssi
];
417 if (phy
->type
== BCM43xx_PHYTYPE_G
&&
442 static s8
bcm43xx_rssinoise_postprocess(struct bcm43xx_private
*bcm
,
445 struct bcm43xx_phyinfo
*phy
= bcm43xx_current_phy(bcm
);
448 if (phy
->type
== BCM43xx_PHYTYPE_A
) {
449 //TODO: Incomplete specs.
452 ret
= bcm43xx_rssi_postprocess(bcm
, in_rssi
, 0, 1, 1);
457 int bcm43xx_rx(struct bcm43xx_private
*bcm
,
459 struct bcm43xx_rxhdr
*rxhdr
)
461 struct bcm43xx_radioinfo
*radio
= bcm43xx_current_radio(bcm
);
462 struct bcm43xx_phyinfo
*phy
= bcm43xx_current_phy(bcm
);
463 struct bcm43xx_plcp_hdr4
*plcp
;
464 struct ieee80211_rx_stats stats
;
465 struct ieee80211_hdr_4addr
*wlhdr
;
467 int is_packet_for_us
= 0;
469 const u16 rxflags1
= le16_to_cpu(rxhdr
->flags1
);
470 const u16 rxflags2
= le16_to_cpu(rxhdr
->flags2
);
471 const u16 rxflags3
= le16_to_cpu(rxhdr
->flags3
);
472 const int is_ofdm
= !!(rxflags1
& BCM43xx_RXHDR_FLAGS1_OFDM
);
474 if (rxflags2
& BCM43xx_RXHDR_FLAGS2_TYPE2FRAME
) {
475 plcp
= (struct bcm43xx_plcp_hdr4
*)(skb
->data
+ 2);
476 /* Skip two unknown bytes and the PLCP header. */
477 skb_pull(skb
, 2 + sizeof(struct bcm43xx_plcp_hdr6
));
479 plcp
= (struct bcm43xx_plcp_hdr4
*)(skb
->data
);
480 /* Skip the PLCP header. */
481 skb_pull(skb
, sizeof(struct bcm43xx_plcp_hdr6
));
483 /* The SKB contains the PAYLOAD (wireless header + data)
484 * at this point. The FCS at the end is stripped.
487 memset(&stats
, 0, sizeof(stats
));
488 stats
.mac_time
= le16_to_cpu(rxhdr
->mactime
);
489 stats
.rssi
= bcm43xx_rssi_postprocess(bcm
, rxhdr
->rssi
, is_ofdm
,
490 !!(rxflags1
& BCM43xx_RXHDR_FLAGS1_2053RSSIADJ
),
491 !!(rxflags3
& BCM43xx_RXHDR_FLAGS3_2050RSSIADJ
));
492 stats
.signal
= rxhdr
->signal_quality
; //FIXME
495 stats
.rate
= bcm43xx_plcp_get_bitrate_ofdm(plcp
);
497 stats
.rate
= bcm43xx_plcp_get_bitrate_cck(plcp
);
498 //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
499 stats
.received_channel
= radio
->channel
;
500 //TODO stats.control =
501 stats
.mask
= IEEE80211_STATMASK_SIGNAL
|
502 //TODO IEEE80211_STATMASK_NOISE |
503 IEEE80211_STATMASK_RATE
|
504 IEEE80211_STATMASK_RSSI
;
505 if (phy
->type
== BCM43xx_PHYTYPE_A
)
506 stats
.freq
= IEEE80211_52GHZ_BAND
;
508 stats
.freq
= IEEE80211_24GHZ_BAND
;
509 stats
.len
= skb
->len
;
511 bcm
->stats
.last_rx
= jiffies
;
512 if (bcm
->ieee
->iw_mode
== IW_MODE_MONITOR
) {
513 err
= ieee80211_rx(bcm
->ieee
, skb
, &stats
);
514 return (err
== 0) ? -EINVAL
: 0;
517 wlhdr
= (struct ieee80211_hdr_4addr
*)(skb
->data
);
519 switch (bcm
->ieee
->iw_mode
) {
521 if (memcmp(wlhdr
->addr1
, bcm
->net_dev
->dev_addr
, ETH_ALEN
) == 0 ||
522 memcmp(wlhdr
->addr3
, bcm
->ieee
->bssid
, ETH_ALEN
) == 0 ||
523 is_broadcast_ether_addr(wlhdr
->addr1
) ||
524 is_multicast_ether_addr(wlhdr
->addr1
) ||
525 bcm
->net_dev
->flags
& IFF_PROMISC
)
526 is_packet_for_us
= 1;
530 /* When receiving multicast or broadcast packets, filter out
531 the packets we send ourself; we shouldn't see those */
532 if (memcmp(wlhdr
->addr3
, bcm
->ieee
->bssid
, ETH_ALEN
) == 0 ||
533 memcmp(wlhdr
->addr1
, bcm
->net_dev
->dev_addr
, ETH_ALEN
) == 0 ||
534 (memcmp(wlhdr
->addr3
, bcm
->net_dev
->dev_addr
, ETH_ALEN
) &&
535 (is_broadcast_ether_addr(wlhdr
->addr1
) ||
536 is_multicast_ether_addr(wlhdr
->addr1
) ||
537 bcm
->net_dev
->flags
& IFF_PROMISC
)))
538 is_packet_for_us
= 1;
542 frame_ctl
= le16_to_cpu(wlhdr
->frame_ctl
);
543 if ((frame_ctl
& IEEE80211_FCTL_PROTECTED
) && !bcm
->ieee
->host_decrypt
) {
544 frame_ctl
&= ~IEEE80211_FCTL_PROTECTED
;
545 wlhdr
->frame_ctl
= cpu_to_le16(frame_ctl
);
546 /* trim IV and ICV */
547 /* FIXME: this must be done only for WEP encrypted packets */
549 dprintkl(KERN_ERR PFX
"RX packet dropped (PROTECTED flag "
550 "set and length < 32)\n");
553 memmove(skb
->data
+ 4, skb
->data
, 24);
555 skb_trim(skb
, skb
->len
- 4);
558 wlhdr
= (struct ieee80211_hdr_4addr
*)(skb
->data
);
561 switch (WLAN_FC_GET_TYPE(frame_ctl
)) {
562 case IEEE80211_FTYPE_MGMT
:
563 ieee80211_rx_mgt(bcm
->ieee
, wlhdr
, &stats
);
565 case IEEE80211_FTYPE_DATA
:
566 if (is_packet_for_us
) {
567 err
= ieee80211_rx(bcm
->ieee
, skb
, &stats
);
568 err
= (err
== 0) ? -EINVAL
: 0;
571 case IEEE80211_FTYPE_CTL
:
581 /* vim: set ts=8 sw=8 sts=8: */