Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f398f02d authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

[PATCH] bcm43xx: Move TX/RX related functions to its own file. Add basic RTS/CTS code.

parent 1d1a73cc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+6 −17
Original line number Diff line number Diff line
@@ -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_ */
+1 −0
Original line number Diff line number Diff line
@@ -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)

+1 −0
Original line number Diff line number Diff line
@@ -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>
+1 −429
Original line number Diff line number Diff line
@@ -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 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
	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)
Loading