diff options
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_main.c')
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 430 |
1 files changed, 1 insertions, 429 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 899c06fe0bf..f1ac9940f14 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -50,6 +50,7 @@ #include "bcm43xx_power.h" #include "bcm43xx_wx.h" #include "bcm43xx_ethtool.h" +#include "bcm43xx_xmit.h" MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); @@ -342,234 +343,6 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); } -static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, - const int ofdm_modulation) -{ - u8 rate; - - if (ofdm_modulation) { - switch (plcp->raw[0] & 0xF) { - case 0xB: - rate = IEEE80211_OFDM_RATE_6MB; - break; - case 0xF: - rate = IEEE80211_OFDM_RATE_9MB; - break; - case 0xA: - rate = IEEE80211_OFDM_RATE_12MB; - break; - case 0xE: - rate = IEEE80211_OFDM_RATE_18MB; - break; - case 0x9: - rate = IEEE80211_OFDM_RATE_24MB; - break; - case 0xD: - rate = IEEE80211_OFDM_RATE_36MB; - break; - case 0x8: - rate = IEEE80211_OFDM_RATE_48MB; - break; - case 0xC: - rate = IEEE80211_OFDM_RATE_54MB; - break; - default: - rate = 0; - assert(0); - } - } else { - switch (plcp->raw[0]) { - case 0x0A: - rate = IEEE80211_CCK_RATE_1MB; - break; - case 0x14: - rate = IEEE80211_CCK_RATE_2MB; - break; - case 0x37: - rate = IEEE80211_CCK_RATE_5MB; - break; - case 0x6E: - rate = IEEE80211_CCK_RATE_11MB; - break; - default: - rate = 0; - assert(0); - } - } - - return rate; -} - -static 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; -} - -static 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, - u16 octets, const u8 bitrate, - const int ofdm_modulation) -{ - __le32 *data = &(plcp->data); - __u8 *raw = plcp->raw; - - /* Account for hardware-appended FCS. */ - octets += IEEE80211_FCS_LEN; - - if (ofdm_modulation) { - *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); - assert(!(octets & 0xF000)); - *data |= (octets << 5); - *data = cpu_to_le32(*data); - } 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); - } - -//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); -} - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie) -{ - const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; - const struct ieee80211_security *secinfo = &bcm->ieee->sec; - u8 bitrate; - int ofdm_modulation; - u8 fallback_bitrate; - int fallback_ofdm_modulation; - u16 tmp; - u16 encrypt_frame; - - /* Now construct the TX header. */ - memset(txhdr, 0, sizeof(*txhdr)); - - //TODO: Some RTS/CTS stuff has to be done. - //TODO: Encryption stuff. - //TODO: others? - - bitrate = bcm->softmac->txrates.default_rate; - ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); - fallback_bitrate = bcm->softmac->txrates.default_fallback; - 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. */ - //FIXME: We use the original durid for now. - txhdr->fallback_dur_id = wireless_header->duration_id; - - /* Set the cookie (used as driver internal ID for the frame) */ - txhdr->cookie = cpu_to_le16(cookie); - - 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; - if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) { - dprintkl(KERN_ERR PFX "invalid packet with PROTECTED" - "flag set discarded"); - return; - } - memcpy(txhdr->wep_iv, hdr->payload, 4); - /* Hardware appends ICV. */ - fragment_len += 4; - } - - /* Generate the PLCP header and the fallback PLCP header. */ - bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), - fragment_len, - bitrate, ofdm_modulation); - bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len, - fallback_bitrate, fallback_ofdm_modulation); - - /* Set the CONTROL field */ - tmp = 0; - if (ofdm_modulation) - tmp |= BCM43xx_TXHDRCTL_OFDM; - if (bcm->short_preamble) //FIXME: could be the other way around, please test - tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; - tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) - & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; - txhdr->control = cpu_to_le16(tmp); - - /* Set the FLAGS field */ - tmp = 0; - if (!is_multicast_ether_addr(wireless_header->addr1) && - !is_broadcast_ether_addr(wireless_header->addr1)) - tmp |= BCM43xx_TXHDRFLAG_EXPECTACK; - if (1 /* FIXME: PS poll?? */) - tmp |= 0x10; // FIXME: unknown meaning. - if (fallback_ofdm_modulation) - tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; - if (is_first_fragment) - tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; - txhdr->flags = cpu_to_le16(tmp); - - /* Set WSEC/RATE field */ - if (encrypt_frame && !bcm->ieee->host_encrypt) { - tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) - & BCM43xx_TXHDR_WSEC_ALGO_MASK; - tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) - & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; - txhdr->wsec_rate = cpu_to_le16(tmp); - } - -//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header"); -} - static void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, u16 offset, @@ -3773,207 +3546,6 @@ err_pci_disable: goto out; } -static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi, int ofdm, - int adjust_2053, int adjust_2050) -{ - s32 tmp; - - switch (bcm->current_core->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 = bcm->current_core->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 (bcm->current_core->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; -} - -static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi) -{ - s8 ret; - - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - //TODO: Incomplete specs. - ret = 0; - } else - ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); - - return ret; -} - -static inline -int bcm43xx_rx_packet(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct ieee80211_rx_stats *stats) -{ - int err; - - err = ieee80211_rx(bcm->ieee, skb, stats); - if (unlikely(err == 0)) - return -EINVAL; - return 0; -} - -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr) -{ - 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 = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, - !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), - !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); - stats.signal = rxhdr->signal_quality; //FIXME -//TODO stats.noise = - stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm); -//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); - stats.received_channel = bcm->current_core->radio->channel; -//TODO stats.control = - stats.mask = IEEE80211_STATMASK_SIGNAL | -//TODO IEEE80211_STATMASK_NOISE | - IEEE80211_STATMASK_RATE | - IEEE80211_STATMASK_RSSI; - if (bcm->current_core->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) - return bcm43xx_rx_packet(bcm, skb, &stats); - - 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); - if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { - frame_ctl &= ~IEEE80211_FCTL_PROTECTED; - wlhdr->frame_ctl = cpu_to_le16(frame_ctl); - /* trim IV and ICV */ - /* FIXME: this must be done only for WEP encrypted packets */ - if (skb->len < 32) { - dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " - "set and length < 32)\n"); - return -EINVAL; - } else { - memmove(skb->data + 4, skb->data, 24); - skb_pull(skb, 4); - skb_trim(skb, skb->len - 4); - stats.len -= 8; - } - wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); - } - - 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 = bcm43xx_rx_packet(bcm, skb, &stats); - break; - case IEEE80211_FTYPE_CTL: - break; - default: - assert(0); - return -EINVAL; - } - - return err; -} - /* Do the Hardware IO operations to send the txb */ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb) |