summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_xmit.c')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c565
1 files changed, 0 insertions, 565 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
deleted file mode 100644
index f79fe11f9e8..00000000000
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
-
- Broadcom BCM43xx wireless driver
-
- Transmission (TX/RX) related functions.
-
- Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
- Stefano Brivio <st3@riseup.net>
- Michael Buesch <mbuesch@freenet.de>
- Danny van Dyk <kugelfang@gentoo.org>
- Andreas Jaggi <andreas.jaggi@waterwave.ch>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
-*/
-
-#include "bcm43xx_xmit.h"
-
-#include <linux/etherdevice.h>
-
-
-/* Extract the bitrate out of a CCK PLCP header. */
-static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
-{
- switch (plcp->raw[0]) {
- case 0x0A:
- return IEEE80211_CCK_RATE_1MB;
- case 0x14:
- return IEEE80211_CCK_RATE_2MB;
- case 0x37:
- return IEEE80211_CCK_RATE_5MB;
- case 0x6E:
- return IEEE80211_CCK_RATE_11MB;
- }
- assert(0);
- return 0;
-}
-
-/* Extract the bitrate out of an OFDM PLCP header. */
-static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
-{
- switch (plcp->raw[0] & 0xF) {
- case 0xB:
- return IEEE80211_OFDM_RATE_6MB;
- case 0xF:
- return IEEE80211_OFDM_RATE_9MB;
- case 0xA:
- return IEEE80211_OFDM_RATE_12MB;
- case 0xE:
- return IEEE80211_OFDM_RATE_18MB;
- case 0x9:
- return IEEE80211_OFDM_RATE_24MB;
- case 0xD:
- return IEEE80211_OFDM_RATE_36MB;
- case 0x8:
- return IEEE80211_OFDM_RATE_48MB;
- case 0xC:
- return IEEE80211_OFDM_RATE_54MB;
- }
- assert(0);
- return 0;
-}
-
-u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
-{
- switch (bitrate) {
- case IEEE80211_CCK_RATE_1MB:
- return 0x0A;
- case IEEE80211_CCK_RATE_2MB:
- return 0x14;
- case IEEE80211_CCK_RATE_5MB:
- return 0x37;
- case IEEE80211_CCK_RATE_11MB:
- return 0x6E;
- }
- assert(0);
- return 0;
-}
-
-u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
-{
- switch (bitrate) {
- case IEEE80211_OFDM_RATE_6MB:
- return 0xB;
- case IEEE80211_OFDM_RATE_9MB:
- return 0xF;
- case IEEE80211_OFDM_RATE_12MB:
- return 0xA;
- case IEEE80211_OFDM_RATE_18MB:
- return 0xE;
- case IEEE80211_OFDM_RATE_24MB:
- return 0x9;
- case IEEE80211_OFDM_RATE_36MB:
- return 0xD;
- case IEEE80211_OFDM_RATE_48MB:
- return 0x8;
- case IEEE80211_OFDM_RATE_54MB:
- return 0xC;
- }
- assert(0);
- return 0;
-}
-
-static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
- const u16 octets, const u8 bitrate,
- const int ofdm_modulation)
-{
- __le32 *data = &(plcp->data);
- __u8 *raw = plcp->raw;
-
- if (ofdm_modulation) {
- u32 val = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
- assert(!(octets & 0xF000));
- val |= (octets << 5);
- *data = cpu_to_le32(val);
- } else {
- u32 plen;
-
- plen = octets * 16 / bitrate;
- if ((octets * 16 % bitrate) > 0) {
- plen++;
- if ((bitrate == IEEE80211_CCK_RATE_11MB)
- && ((octets * 8 % 11) < 4)) {
- raw[1] = 0x84;
- } else
- raw[1] = 0x04;
- } else
- raw[1] = 0x04;
- *data |= cpu_to_le32(plen << 16);
- raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
- }
-}
-
-static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
-{
- switch (bitrate) {
- case IEEE80211_CCK_RATE_1MB:
- return IEEE80211_CCK_RATE_1MB;
- case IEEE80211_CCK_RATE_2MB:
- return IEEE80211_CCK_RATE_1MB;
- case IEEE80211_CCK_RATE_5MB:
- return IEEE80211_CCK_RATE_2MB;
- case IEEE80211_CCK_RATE_11MB:
- return IEEE80211_CCK_RATE_5MB;
- case IEEE80211_OFDM_RATE_6MB:
- return IEEE80211_CCK_RATE_5MB;
- case IEEE80211_OFDM_RATE_9MB:
- return IEEE80211_OFDM_RATE_6MB;
- case IEEE80211_OFDM_RATE_12MB:
- return IEEE80211_OFDM_RATE_9MB;
- case IEEE80211_OFDM_RATE_18MB:
- return IEEE80211_OFDM_RATE_12MB;
- case IEEE80211_OFDM_RATE_24MB:
- return IEEE80211_OFDM_RATE_18MB;
- case IEEE80211_OFDM_RATE_36MB:
- return IEEE80211_OFDM_RATE_24MB;
- case IEEE80211_OFDM_RATE_48MB:
- return IEEE80211_OFDM_RATE_36MB;
- case IEEE80211_OFDM_RATE_54MB:
- return IEEE80211_OFDM_RATE_48MB;
- }
- assert(0);
- return 0;
-}
-
-static
-__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
- u8 bitrate)
-{
- const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
- __le16 duration_id = wireless_header->duration_id;
-
- switch (WLAN_FC_GET_TYPE(frame_ctl)) {
- case IEEE80211_FTYPE_DATA:
- case IEEE80211_FTYPE_MGMT:
- //TODO: Steal the code from ieee80211, once it is completed there.
- break;
- case IEEE80211_FTYPE_CTL:
- /* Use the original duration/id. */
- break;
- default:
- assert(0);
- }
-
- return duration_id;
-}
-
-static inline
-u16 ceiling_div(u16 dividend, u16 divisor)
-{
- return ((dividend + divisor - 1) / divisor);
-}
-
-static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
- struct bcm43xx_txhdr *txhdr,
- u16 *flags,
- u8 bitrate,
- const struct ieee80211_hdr_4addr *wlhdr)
-{
- u16 fctl;
- u16 dur;
- u8 fallback_bitrate;
- int ofdm_modulation;
- int fallback_ofdm_modulation;
-// u8 *sa, *da;
- u16 flen;
-
-//FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
-//FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
- fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
- ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
- fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
-
- flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
- bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
- flen, bitrate,
- !ieee80211_is_cck_rate(bitrate));
- bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
- flen, fallback_bitrate,
- !ieee80211_is_cck_rate(fallback_bitrate));
- fctl = IEEE80211_FTYPE_CTL;
- fctl |= IEEE80211_STYPE_RTS;
- dur = le16_to_cpu(wlhdr->duration_id);
-/*FIXME: should we test for dur==0 here and let it unmodified in this case?
- * The following assert checks for this case...
- */
-assert(dur);
-/*FIXME: The duration calculation is not really correct.
- * I am not 100% sure which bitrate to use. We use the RTS rate here,
- * but this is likely to be wrong.
- */
- if (phy->type == BCM43xx_PHYTYPE_A) {
- /* Three times SIFS */
- dur += 16 * 3;
- /* Add ACK duration. */
- dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
- bitrate * 4);
- /* Add CTS duration. */
- dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
- bitrate * 4);
- } else {
- /* Three times SIFS */
- dur += 10 * 3;
- /* Add ACK duration. */
- dur += ceiling_div(8 * (14 /*bytes*/) * 10,
- bitrate);
- /* Add CTS duration. */
- dur += ceiling_div(8 * (14 /*bytes*/) * 10,
- bitrate);
- }
-
- txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
- txhdr->rts_cts_dur = cpu_to_le16(dur);
-//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
-//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
- memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
-// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
-
- *flags |= BCM43xx_TXHDRFLAG_RTSCTS;
- *flags |= BCM43xx_TXHDRFLAG_RTS;
- if (ofdm_modulation)
- *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
- if (fallback_ofdm_modulation)
- *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
-}
-
-void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
- struct bcm43xx_txhdr *txhdr,
- const unsigned char *fragment_data,
- const unsigned int fragment_len,
- const int is_first_fragment,
- const u16 cookie)
-{
- const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
- const struct ieee80211_security *secinfo = &bcm->ieee->sec;
- u8 bitrate;
- u8 fallback_bitrate;
- int ofdm_modulation;
- int fallback_ofdm_modulation;
- u16 plcp_fragment_len = fragment_len;
- u16 flags = 0;
- u16 control = 0;
- u16 wsec_rate = 0;
- u16 encrypt_frame;
- const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
- const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
-
- /* Now construct the TX header. */
- memset(txhdr, 0, sizeof(*txhdr));
-
- bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
- is_multicast_ether_addr(wireless_header->addr1), is_mgt);
- ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
- fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
- fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
-
- /* Set Frame Control from 80211 header. */
- txhdr->frame_control = wireless_header->frame_ctl;
- /* Copy address1 from 80211 header. */
- memcpy(txhdr->mac1, wireless_header->addr1, 6);
- /* Set the fallback duration ID. */
- txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
- fallback_bitrate);
- /* Set the cookie (used as driver internal ID for the frame) */
- txhdr->cookie = cpu_to_le16(cookie);
-
- /* Hardware appends FCS. */
- plcp_fragment_len += IEEE80211_FCS_LEN;
-
- /* Hardware encryption. */
- encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
- if (encrypt_frame && !bcm->ieee->host_encrypt) {
- const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
- memcpy(txhdr->wep_iv, hdr->payload, 4);
- /* Hardware appends ICV. */
- plcp_fragment_len += 4;
-
- wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
- & BCM43xx_TXHDR_WSEC_ALGO_MASK;
- wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
- & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
- }
-
- /* Generate the PLCP header and the fallback PLCP header. */
- bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
- plcp_fragment_len,
- bitrate, ofdm_modulation);
- bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
- fallback_bitrate, fallback_ofdm_modulation);
-
- /* Set the CONTROL field */
- if (ofdm_modulation)
- control |= BCM43xx_TXHDRCTL_OFDM;
- if (bcm->short_preamble) //FIXME: could be the other way around, please test
- control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
- control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
- & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
-
- /* Set the FLAGS field */
- if (!is_multicast_ether_addr(wireless_header->addr1) &&
- !is_broadcast_ether_addr(wireless_header->addr1))
- flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
- if (1 /* FIXME: PS poll?? */)
- flags |= 0x10; // FIXME: unknown meaning.
- if (fallback_ofdm_modulation)
- flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
- if (is_first_fragment)
- flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
-
- /* Set WSEC/RATE field */
- wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
- & BCM43xx_TXHDR_RATE_MASK;
-
- /* Generate the RTS/CTS packet, if required. */
- /* FIXME: We should first try with CTS-to-self,
- * if we are on 80211g. If we get too many
- * failures (hidden nodes), we should switch back to RTS/CTS.
- */
- if (0/*FIXME txctl->use_rts_cts*/) {
- bcm43xx_generate_rts(phy, txhdr, &flags,
- 0/*FIXME txctl->rts_cts_rate*/,
- wireless_header);
- }
-
- txhdr->flags = cpu_to_le16(flags);
- txhdr->control = cpu_to_le16(control);
- txhdr->wsec_rate = cpu_to_le16(wsec_rate);
-}
-
-static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
- u8 in_rssi, int ofdm,
- int adjust_2053, int adjust_2050)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- s32 tmp;
-
- switch (radio->version) {
- case 0x2050:
- if (ofdm) {
- tmp = in_rssi;
- if (tmp > 127)
- tmp -= 256;
- tmp *= 73;
- tmp /= 64;
- if (adjust_2050)
- tmp += 25;
- else
- tmp -= 3;
- } else {
- if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
- if (in_rssi > 63)
- in_rssi = 63;
- tmp = radio->nrssi_lt[in_rssi];
- tmp = 31 - tmp;
- tmp *= -131;
- tmp /= 128;
- tmp -= 57;
- } else {
- tmp = in_rssi;
- tmp = 31 - tmp;
- tmp *= -149;
- tmp /= 128;
- tmp -= 68;
- }
- if (phy->type == BCM43xx_PHYTYPE_G &&
- adjust_2050)
- tmp += 25;
- }
- break;
- case 0x2060:
- if (in_rssi > 127)
- tmp = in_rssi - 256;
- else
- tmp = in_rssi;
- break;
- default:
- tmp = in_rssi;
- tmp -= 11;
- tmp *= 103;
- tmp /= 64;
- if (adjust_2053)
- tmp -= 109;
- else
- tmp -= 83;
- }
-
- return (s8)tmp;
-}
-
-//TODO
-#if 0
-static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
- u8 in_rssi)
-{
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- s8 ret;
-
- if (phy->type == BCM43xx_PHYTYPE_A) {
- //TODO: Incomplete specs.
- ret = 0;
- } else
- ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
-
- return ret;
-}
-#endif
-
-int bcm43xx_rx(struct bcm43xx_private *bcm,
- struct sk_buff *skb,
- struct bcm43xx_rxhdr *rxhdr)
-{
- struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- struct bcm43xx_plcp_hdr4 *plcp;
- struct ieee80211_rx_stats stats;
- struct ieee80211_hdr_4addr *wlhdr;
- u16 frame_ctl;
- int is_packet_for_us = 0;
- int err = -EINVAL;
- const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
- const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
- const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
- const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
-
- if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
- plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
- /* Skip two unknown bytes and the PLCP header. */
- skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
- } else {
- plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
- /* Skip the PLCP header. */
- skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
- }
- /* The SKB contains the PAYLOAD (wireless header + data)
- * at this point. The FCS at the end is stripped.
- */
-
- memset(&stats, 0, sizeof(stats));
- stats.mac_time = le16_to_cpu(rxhdr->mactime);
- stats.rssi = rxhdr->rssi;
- stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
- !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
- !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
- stats.noise = bcm->stats.noise;
- if (is_ofdm)
- stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
- else
- stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
- stats.received_channel = radio->channel;
- stats.mask = IEEE80211_STATMASK_SIGNAL |
- IEEE80211_STATMASK_NOISE |
- IEEE80211_STATMASK_RATE |
- IEEE80211_STATMASK_RSSI;
- if (phy->type == BCM43xx_PHYTYPE_A)
- stats.freq = IEEE80211_52GHZ_BAND;
- else
- stats.freq = IEEE80211_24GHZ_BAND;
- stats.len = skb->len;
-
- bcm->stats.last_rx = jiffies;
- if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ieee80211_rx(bcm->ieee, skb, &stats);
- return (err == 0) ? -EINVAL : 0;
- }
-
- wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
-
- switch (bcm->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
- memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
- is_broadcast_ether_addr(wlhdr->addr1) ||
- is_multicast_ether_addr(wlhdr->addr1) ||
- bcm->net_dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- break;
- case IW_MODE_INFRA:
- default:
- /* When receiving multicast or broadcast packets, filter out
- the packets we send ourself; we shouldn't see those */
- if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
- memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
- (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
- (is_broadcast_ether_addr(wlhdr->addr1) ||
- is_multicast_ether_addr(wlhdr->addr1) ||
- bcm->net_dev->flags & IFF_PROMISC)))
- is_packet_for_us = 1;
- break;
- }
-
- frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
- switch (WLAN_FC_GET_TYPE(frame_ctl)) {
- case IEEE80211_FTYPE_MGMT:
- ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
- break;
- case IEEE80211_FTYPE_DATA:
- if (is_packet_for_us) {
- err = ieee80211_rx(bcm->ieee, skb, &stats);
- err = (err == 0) ? -EINVAL : 0;
- }
- break;
- case IEEE80211_FTYPE_CTL:
- break;
- default:
- assert(0);
- return -EINVAL;
- }
-
- return err;
-}