forked from Minki/linux
[PATCH] bcm43xx: Move TX/RX related functions to its own file. Add basic RTS/CTS code.
Signed-off-by: Michael Buesch <mbuesch@freenet.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
1d1a73ccdc
commit
f398f02d12
@ -8,4 +8,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \
|
||||
bcm43xx_radio.o bcm43xx_phy.o \
|
||||
bcm43xx_power.o bcm43xx_wx.o \
|
||||
bcm43xx_leds.o bcm43xx_ethtool.o \
|
||||
bcm43xx_xmit.o \
|
||||
$(bcm43xx-obj-y)
|
||||
|
@ -314,23 +314,6 @@
|
||||
/* Initial default iw_mode */
|
||||
#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA
|
||||
|
||||
/* Values/Masks for the device TX header */
|
||||
#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001
|
||||
#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008
|
||||
#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020
|
||||
#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100
|
||||
#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800
|
||||
|
||||
#define BCM43xx_TXHDRCTL_OFDM 0x0001
|
||||
#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010
|
||||
#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030
|
||||
#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8
|
||||
|
||||
#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0
|
||||
#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4
|
||||
#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003
|
||||
#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0
|
||||
|
||||
/* Bus type PCI. */
|
||||
#define BCM43xx_BUSTYPE_PCI 0
|
||||
/* Bus type Silicone Backplane Bus. */
|
||||
@ -952,4 +935,10 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu
|
||||
__value; \
|
||||
})
|
||||
|
||||
/** Helpers to print MAC addresses. */
|
||||
#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \
|
||||
((u8*)(x))[2], ((u8*)(x))[3], \
|
||||
((u8*)(x))[4], ((u8*)(x))[5]
|
||||
|
||||
#endif /* BCM43xx_H_ */
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "bcm43xx_debugfs.h"
|
||||
#include "bcm43xx_dma.h"
|
||||
#include "bcm43xx_pio.h"
|
||||
#include "bcm43xx_xmit.h"
|
||||
|
||||
#define REALLY_BIG_BUFFER_SIZE (1024*256)
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "bcm43xx_main.h"
|
||||
#include "bcm43xx_debugfs.h"
|
||||
#include "bcm43xx_power.h"
|
||||
#include "bcm43xx_xmit.h"
|
||||
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/pci.h>
|
||||
|
@ -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)
|
||||
|
@ -52,134 +52,12 @@ static inline void e_aton(char *str, char *dest)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define _bcm43xx_declare_plcp_hdr(size) \
|
||||
struct bcm43xx_plcp_hdr##size { \
|
||||
union { \
|
||||
__le32 data; \
|
||||
__u8 raw[size]; \
|
||||
} __attribute__((__packed__)); \
|
||||
} __attribute__((__packed__))
|
||||
|
||||
/* struct bcm43xx_plcp_hdr4 */
|
||||
_bcm43xx_declare_plcp_hdr(4);
|
||||
/* struct bcm430c_plcp_hdr6 */
|
||||
_bcm43xx_declare_plcp_hdr(6);
|
||||
|
||||
#undef _bcm43xx_declare_plcp_hdr
|
||||
|
||||
|
||||
#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
|
||||
#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
|
||||
/* Magic helper macro to pad structures. Ignore those above. It's magic. */
|
||||
#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
|
||||
|
||||
|
||||
/* Device specific TX header. To be prepended to TX frames. */
|
||||
struct bcm43xx_txhdr {
|
||||
union {
|
||||
struct {
|
||||
u16 flags;
|
||||
u16 wsec_rate;
|
||||
u16 frame_control;
|
||||
u16 unknown_zeroed_0;
|
||||
u16 control;
|
||||
unsigned char wep_iv[10];
|
||||
unsigned char unknown_wsec_tkip_data[3]; //FIXME
|
||||
PAD_BYTES(3);
|
||||
unsigned char mac1[6];
|
||||
u16 unknown_zeroed_1;
|
||||
struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
|
||||
u16 rts_cts_dur_fallback;
|
||||
struct bcm43xx_plcp_hdr4 fallback_plcp;
|
||||
u16 fallback_dur_id;
|
||||
PAD_BYTES(2);
|
||||
u16 cookie;
|
||||
u16 unknown_scb_stuff; //FIXME
|
||||
struct bcm43xx_plcp_hdr6 rts_cts_plcp;
|
||||
u16 rts_cts_frame_type;
|
||||
u16 rts_cts_dur;
|
||||
unsigned char rts_cts_mac1[6];
|
||||
unsigned char rts_cts_mac2[6];
|
||||
PAD_BYTES(2);
|
||||
struct bcm43xx_plcp_hdr6 plcp;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
unsigned char raw[82];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
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);
|
||||
|
||||
/* RX header as received from the hardware. */
|
||||
struct bcm43xx_rxhdr {
|
||||
/* Frame Length. Must be generated explicitely in PIO mode. */
|
||||
__le16 frame_length;
|
||||
PAD_BYTES(2);
|
||||
/* Flags field 1 */
|
||||
__le16 flags1;
|
||||
u8 rssi;
|
||||
u8 signal_quality;
|
||||
PAD_BYTES(2);
|
||||
/* Flags field 3 */
|
||||
__le16 flags3;
|
||||
/* Flags field 2 */
|
||||
__le16 flags2;
|
||||
/* Lower 16bits of the TSF at the time the frame started. */
|
||||
__le16 mactime;
|
||||
PAD_BYTES(14);
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0)
|
||||
/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */
|
||||
#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7)
|
||||
#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14)
|
||||
|
||||
#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0)
|
||||
#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2)
|
||||
/*FIXME: WEP related flags */
|
||||
|
||||
#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10)
|
||||
|
||||
/* Transmit Status as received from the hardware. */
|
||||
struct bcm43xx_hwxmitstatus {
|
||||
PAD_BYTES(4);
|
||||
__le16 cookie;
|
||||
u8 flags;
|
||||
u8 cnt1:4,
|
||||
cnt2:4;
|
||||
PAD_BYTES(2);
|
||||
__le16 seq;
|
||||
__le16 unknown; //FIXME
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Transmit Status in CPU byteorder. */
|
||||
struct bcm43xx_xmitstatus {
|
||||
u16 cookie;
|
||||
u8 flags;
|
||||
u8 cnt1:4,
|
||||
cnt2:4;
|
||||
u16 seq;
|
||||
u16 unknown; //FIXME
|
||||
};
|
||||
|
||||
#define BCM43xx_TXSTAT_FLAG_ACK 0x01
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
|
||||
#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
|
||||
|
||||
|
||||
/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
|
||||
static inline
|
||||
u8 bcm43xx_freq_to_channel_a(int freq)
|
||||
@ -259,10 +137,6 @@ int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
|
||||
void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
|
||||
void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
|
||||
|
||||
int bcm43xx_rx(struct bcm43xx_private *bcm,
|
||||
struct sk_buff *skb,
|
||||
struct bcm43xx_rxhdr *rxhdr);
|
||||
|
||||
void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
|
||||
int iw_mode);
|
||||
|
||||
@ -283,11 +157,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
|
||||
|
||||
void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
|
||||
|
||||
int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val);
|
||||
int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val);
|
||||
int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val);
|
||||
int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val);
|
||||
|
||||
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
|
||||
void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "bcm43xx.h"
|
||||
#include "bcm43xx_pio.h"
|
||||
#include "bcm43xx_main.h"
|
||||
#include "bcm43xx_xmit.h"
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
|
579
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
Normal file
579
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
Normal file
@ -0,0 +1,579 @@
|
||||
/*
|
||||
|
||||
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) {
|
||||
*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);
|
||||
}
|
||||
}
|
||||
|
||||
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 = bcm->current_core->phy;
|
||||
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;
|
||||
|
||||
/* Now construct the TX header. */
|
||||
memset(txhdr, 0, sizeof(*txhdr));
|
||||
|
||||
bitrate = bcm->softmac->txrates.default_rate;
|
||||
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 = bcm->current_core->radio;
|
||||
struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
|
||||
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;
|
||||
}
|
||||
|
||||
static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
|
||||
u8 in_rssi)
|
||||
{
|
||||
struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
|
||||
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;
|
||||
}
|
||||
|
||||
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 =
|
||||
if (is_ofdm)
|
||||
stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
|
||||
else
|
||||
stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
|
||||
//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) {
|
||||
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);
|
||||
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 = ieee80211_rx(bcm->ieee, skb, &stats);
|
||||
err = (err == 0) ? -EINVAL : 0;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_FTYPE_CTL:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* vim: set ts=8 sw=8 sts=8: */
|
156
drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
Normal file
156
drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef BCM43xx_XMIT_H_
|
||||
#define BCM43xx_XMIT_H_
|
||||
|
||||
#include "bcm43xx_main.h"
|
||||
|
||||
|
||||
#define _bcm43xx_declare_plcp_hdr(size) \
|
||||
struct bcm43xx_plcp_hdr##size { \
|
||||
union { \
|
||||
__le32 data; \
|
||||
__u8 raw[size]; \
|
||||
} __attribute__((__packed__)); \
|
||||
} __attribute__((__packed__))
|
||||
|
||||
/* struct bcm43xx_plcp_hdr4 */
|
||||
_bcm43xx_declare_plcp_hdr(4);
|
||||
/* struct bcm43xx_plcp_hdr6 */
|
||||
_bcm43xx_declare_plcp_hdr(6);
|
||||
|
||||
#undef _bcm43xx_declare_plcp_hdr
|
||||
|
||||
/* Device specific TX header. To be prepended to TX frames. */
|
||||
struct bcm43xx_txhdr {
|
||||
union {
|
||||
struct {
|
||||
__le16 flags;
|
||||
__le16 wsec_rate;
|
||||
__le16 frame_control;
|
||||
u16 unknown_zeroed_0;
|
||||
__le16 control;
|
||||
u8 wep_iv[10];
|
||||
u8 unknown_wsec_tkip_data[3]; //FIXME
|
||||
PAD_BYTES(3);
|
||||
u8 mac1[6];
|
||||
u16 unknown_zeroed_1;
|
||||
struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
|
||||
__le16 rts_cts_dur_fallback;
|
||||
struct bcm43xx_plcp_hdr4 fallback_plcp;
|
||||
__le16 fallback_dur_id;
|
||||
PAD_BYTES(2);
|
||||
__le16 cookie;
|
||||
__le16 unknown_scb_stuff; //FIXME
|
||||
struct bcm43xx_plcp_hdr6 rts_cts_plcp;
|
||||
__le16 rts_cts_frame_control;
|
||||
__le16 rts_cts_dur;
|
||||
u8 rts_cts_mac1[6];
|
||||
u8 rts_cts_mac2[6];
|
||||
PAD_BYTES(2);
|
||||
struct bcm43xx_plcp_hdr6 plcp;
|
||||
} __attribute__((__packed__));
|
||||
u8 raw[82];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Values/Masks for the device TX header */
|
||||
#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001
|
||||
#define BCM43xx_TXHDRFLAG_RTSCTS 0x0002
|
||||
#define BCM43xx_TXHDRFLAG_RTS 0x0004
|
||||
#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008
|
||||
#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020
|
||||
#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080
|
||||
#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100
|
||||
#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200
|
||||
#define BCM43xx_TXHDRFLAG_CTS 0x0400
|
||||
#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800
|
||||
|
||||
#define BCM43xx_TXHDRCTL_OFDM 0x0001
|
||||
#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010
|
||||
#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030
|
||||
#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8
|
||||
|
||||
#define BCM43xx_TXHDR_RATE_MASK 0x0F00
|
||||
#define BCM43xx_TXHDR_RATE_SHIFT 8
|
||||
#define BCM43xx_TXHDR_RTSRATE_MASK 0xF000
|
||||
#define BCM43xx_TXHDR_RTSRATE_SHIFT 12
|
||||
#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0
|
||||
#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4
|
||||
#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003
|
||||
#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0
|
||||
|
||||
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);
|
||||
|
||||
/* RX header as received from the hardware. */
|
||||
struct bcm43xx_rxhdr {
|
||||
/* Frame Length. Must be generated explicitely in PIO mode. */
|
||||
__le16 frame_length;
|
||||
PAD_BYTES(2);
|
||||
/* Flags field 1 */
|
||||
__le16 flags1;
|
||||
u8 rssi;
|
||||
u8 signal_quality;
|
||||
PAD_BYTES(2);
|
||||
/* Flags field 3 */
|
||||
__le16 flags3;
|
||||
/* Flags field 2 */
|
||||
__le16 flags2;
|
||||
/* Lower 16bits of the TSF at the time the frame started. */
|
||||
__le16 mactime;
|
||||
PAD_BYTES(14);
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0)
|
||||
/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */
|
||||
#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7)
|
||||
#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14)
|
||||
|
||||
#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0)
|
||||
#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2)
|
||||
/*FIXME: WEP related flags */
|
||||
|
||||
#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10)
|
||||
|
||||
/* Transmit Status as received from the hardware. */
|
||||
struct bcm43xx_hwxmitstatus {
|
||||
PAD_BYTES(4);
|
||||
__le16 cookie;
|
||||
u8 flags;
|
||||
u8 cnt1:4,
|
||||
cnt2:4;
|
||||
PAD_BYTES(2);
|
||||
__le16 seq;
|
||||
__le16 unknown; //FIXME
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Transmit Status in CPU byteorder. */
|
||||
struct bcm43xx_xmitstatus {
|
||||
u16 cookie;
|
||||
u8 flags;
|
||||
u8 cnt1:4,
|
||||
cnt2:4;
|
||||
u16 seq;
|
||||
u16 unknown; //FIXME
|
||||
};
|
||||
|
||||
#define BCM43xx_TXSTAT_FLAG_ACK 0x01
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
|
||||
#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
|
||||
//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
|
||||
|
||||
u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate);
|
||||
u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate);
|
||||
|
||||
int bcm43xx_rx(struct bcm43xx_private *bcm,
|
||||
struct sk_buff *skb,
|
||||
struct bcm43xx_rxhdr *rxhdr);
|
||||
|
||||
#endif /* BCM43xx_XMIT_H_ */
|
Loading…
Reference in New Issue
Block a user