diff options
Diffstat (limited to 'package/b43/src/xmit.c')
-rw-r--r-- | package/b43/src/xmit.c | 302 |
1 files changed, 191 insertions, 111 deletions
diff --git a/package/b43/src/xmit.c b/package/b43/src/xmit.c index 0bd6f8a348..4014b6c827 100644 --- a/package/b43/src/xmit.c +++ b/package/b43/src/xmit.c @@ -5,7 +5,7 @@ Transmission (TX/RX) related functions. Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (C) 2005 Stefano Brivio <st3@riseup.net> + Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -30,48 +30,50 @@ #include "xmit.h" #include "phy.h" #include "dma.h" -#include "pio.h" -/* Extract the bitrate out of a CCK PLCP header. */ -static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) + +/* Extract the bitrate index out of a CCK PLCP header. */ +static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) { switch (plcp->raw[0]) { case 0x0A: - return B43_CCK_RATE_1MB; + return 0; case 0x14: - return B43_CCK_RATE_2MB; + return 1; case 0x37: - return B43_CCK_RATE_5MB; + return 2; case 0x6E: - return B43_CCK_RATE_11MB; + return 3; } B43_WARN_ON(1); - return 0; + return -1; } -/* Extract the bitrate out of an OFDM PLCP header. */ -static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp) +/* Extract the bitrate index out of an OFDM PLCP header. */ +static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) { + int base = aphy ? 0 : 4; + switch (plcp->raw[0] & 0xF) { case 0xB: - return B43_OFDM_RATE_6MB; + return base + 0; case 0xF: - return B43_OFDM_RATE_9MB; + return base + 1; case 0xA: - return B43_OFDM_RATE_12MB; + return base + 2; case 0xE: - return B43_OFDM_RATE_18MB; + return base + 3; case 0x9: - return B43_OFDM_RATE_24MB; + return base + 4; case 0xD: - return B43_OFDM_RATE_36MB; + return base + 5; case 0x8: - return B43_OFDM_RATE_48MB; + return base + 6; case 0xC: - return B43_OFDM_RATE_54MB; + return base + 7; } B43_WARN_ON(1); - return 0; + return -1; } u8 b43_plcp_get_ratecode_cck(const u8 bitrate) @@ -177,18 +179,21 @@ static u8 b43_calc_fallback_rate(u8 bitrate) return 0; } -static void generate_txhdr_fw4(struct b43_wldev *dev, - struct b43_txhdr_fw4 *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, - u16 cookie) +/* Generate a TX data header. */ +int b43_generate_txhdr(struct b43_wldev *dev, + u8 *_txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) { + struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl = le16_to_cpu(wlhdr->frame_control); + struct ieee80211_rate *fbrate; u8 rate, rate_fb; int rate_ofdm, rate_fb_ofdm; unsigned int plcp_fragment_len; @@ -198,9 +203,11 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate; + WARN_ON(!txctl->tx_rate); + rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); if (rate_ofdm) @@ -219,11 +226,10 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_len, - fbrate_base100kbps); + fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -235,29 +241,44 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, B43_WARN_ON(key_idx >= dev->max_nr_keys); key = &(dev->key[key_idx]); - B43_WARN_ON(!key->keyconf); + + if (unlikely(!key->keyconf)) { + /* This key is invalid. This might only happen + * in a short timeframe after machine resume before + * we were able to reconfigure keys. + * Drop this packet completely. Do not transmit it + * unencrypted to avoid leaking information. */ + return -ENOKEY; + } /* Hardware appends ICV. */ plcp_fragment_len += txctl->icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); - mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) & - B43_TX4_MAC_KEYIDX; - mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) & - B43_TX4_MAC_KEYALG; + mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & + B43_TXH_MAC_KEYIDX; + mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & + B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); iv_len = min((size_t) txctl->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp), - plcp_fragment_len, rate); + if (b43_is_old_txhdr_format(dev)) { + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), + plcp_fragment_len, rate); + } else { + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp), + plcp_fragment_len, rate); + } b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), plcp_fragment_len, rate_fb); /* Extra Frame Types */ if (rate_fb_ofdm) - extra_ft |= B43_TX4_EFT_FBOFDM; + extra_ft |= B43_TXH_EFT_FB_OFDM; + else + extra_ft |= B43_TXH_EFT_FB_CCK; /* Set channel radio code. Note that the micrcode ORs 0x100 to * this value before comparing it to the value in SHM, if this @@ -267,18 +288,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) - phy_ctl |= B43_TX4_PHY_OFDM; - if (dev->short_preamble) - phy_ctl |= B43_TX4_PHY_SHORTPRMBL; - switch (txctl->antenna_sel_tx) { - case 0: - phy_ctl |= B43_TX4_PHY_ANTLAST; + phy_ctl |= B43_TXH_PHY_ENC_OFDM; + else + phy_ctl |= B43_TXH_PHY_ENC_CCK; + if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + phy_ctl |= B43_TXH_PHY_SHORTPRMBL; + + switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + case 0: /* Default */ + phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; - case 1: - phy_ctl |= B43_TX4_PHY_ANT0; + case 1: /* Antenna 0 */ + phy_ctl |= B43_TXH_PHY_ANT0; break; - case 2: - phy_ctl |= B43_TX4_PHY_ANT1; + case 2: /* Antenna 1 */ + phy_ctl |= B43_TXH_PHY_ANT1; + break; + case 3: /* Antenna 2 */ + phy_ctl |= B43_TXH_PHY_ANT2; + break; + case 4: /* Antenna 3 */ + phy_ctl |= B43_TXH_PHY_ANT3; break; default: B43_WARN_ON(1); @@ -286,14 +316,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, /* MAC control */ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) - mac_ctl |= B43_TX4_MAC_ACK; + mac_ctl |= B43_TXH_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) - mac_ctl |= B43_TX4_MAC_HWSEQ; + mac_ctl |= B43_TXH_MAC_HWSEQ; if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) - mac_ctl |= B43_TX4_MAC_STMSDU; + mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) - mac_ctl |= B43_TX4_MAC_5GHZ; + mac_ctl |= B43_TXH_MAC_5GHZ; + if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -302,66 +334,94 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; + struct b43_plcp_hdr6 *plcp; - rts_rate = txctl->rts_cts_rate; + WARN_ON(!txctl->rts_cts_rate); + rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id, + struct ieee80211_cts *cts; + + if (b43_is_old_txhdr_format(dev)) { + cts = (struct ieee80211_cts *) + (txhdr->old_format.rts_frame); + } else { + cts = (struct ieee80211_cts *) + (txhdr->new_format.rts_frame); + } + ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, fragment_data, fragment_len, - txctl, - (struct ieee80211_cts *)(txhdr-> - rts_frame)); - mac_ctl |= B43_TX4_MAC_SENDCTS; + txctl, cts); + mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { - ieee80211_rts_get(dev->wl->hw, dev->wl->if_id, - fragment_data, fragment_len, txctl, - (struct ieee80211_rts *)(txhdr-> - rts_frame)); - mac_ctl |= B43_TX4_MAC_SENDRTS; + struct ieee80211_rts *rts; + + if (b43_is_old_txhdr_format(dev)) { + rts = (struct ieee80211_rts *) + (txhdr->old_format.rts_frame); + } else { + rts = (struct ieee80211_rts *) + (txhdr->new_format.rts_frame); + } + ieee80211_rts_get(dev->wl->hw, txctl->vif, + fragment_data, fragment_len, + txctl, rts); + mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } len += FCS_LEN; - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> - rts_plcp), len, - rts_rate); - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> - rts_plcp_fb), + + /* Generate the PLCP headers for the RTS/CTS frame */ + if (b43_is_old_txhdr_format(dev)) + plcp = &txhdr->old_format.rts_plcp; + else + plcp = &txhdr->new_format.rts_plcp; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, + len, rts_rate); + plcp = &txhdr->rts_plcp_fb; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, len, rts_rate_fb); - hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + + if (b43_is_old_txhdr_format(dev)) { + hdr = (struct ieee80211_hdr *) + (&txhdr->old_format.rts_frame); + } else { + hdr = (struct ieee80211_hdr *) + (&txhdr->new_format.rts_frame); + } txhdr->rts_dur_fb = hdr->duration_id; + if (rts_rate_ofdm) { - extra_ft |= B43_TX4_EFT_RTSOFDM; + extra_ft |= B43_TXH_EFT_RTS_OFDM; txhdr->phy_rate_rts = b43_plcp_get_ratecode_ofdm(rts_rate); - } else + } else { + extra_ft |= B43_TXH_EFT_RTS_CCK; txhdr->phy_rate_rts = b43_plcp_get_ratecode_cck(rts_rate); + } if (rts_rate_fb_ofdm) - extra_ft |= B43_TX4_EFT_RTSFBOFDM; - mac_ctl |= B43_TX4_MAC_LONGFRAME; + extra_ft |= B43_TXH_EFT_RTSFB_OFDM; + else + extra_ft |= B43_TXH_EFT_RTSFB_CCK; } /* Magic cookie */ - txhdr->cookie = cpu_to_le16(cookie); + if (b43_is_old_txhdr_format(dev)) + txhdr->old_format.cookie = cpu_to_le16(cookie); + else + txhdr->new_format.cookie = cpu_to_le16(cookie); /* Apply the bitfields */ txhdr->mac_ctl = cpu_to_le32(mac_ctl); txhdr->phy_ctl = cpu_to_le16(phy_ctl); txhdr->extra_ft = extra_ft; -} -void b43_generate_txhdr(struct b43_wldev *dev, - u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie) -{ - generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, - fragment_data, fragment_len, txctl, cookie); + return 0; } static s8 b43_rssi_postprocess(struct b43_wldev *dev, @@ -384,7 +444,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, else tmp -= 3; } else { - if (dev->dev->bus->sprom.r1. + if (dev->dev->bus->sprom. boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; @@ -451,6 +511,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) u16 phystat0, phystat3, chanstat, mactime; u32 macstat; u16 chanid; + u16 phytype; u8 jssi; int padding; @@ -463,6 +524,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) macstat = le32_to_cpu(rxhdr->mac_status); mactime = le16_to_cpu(rxhdr->mac_time); chanstat = le16_to_cpu(rxhdr->channel); + phytype = chanstat & B43_RX_CHAN_PHYTYPE; if (macstat & B43_RX_MAC_FCSERR) dev->wl->ieee_stats.dot11FCSErrorCount++; @@ -488,7 +550,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } wlhdr = (struct ieee80211_hdr *)(skb->data); fctl = le16_to_cpu(wlhdr->frame_control); - skb_trim(skb, skb->len - FCS_LEN); if (macstat & B43_RX_MAC_DEC) { unsigned int keyidx; @@ -521,31 +582,59 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) /* the next line looks wrong, but is what mac80211 wants */ status.signal = (jssi * 100) / B43_RX_MAX_SSI; if (phystat0 & B43_RX_PHYST0_OFDM) - status.rate = b43_plcp_get_bitrate_ofdm(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, + phytype == B43_PHYTYPE_A); else - status.rate = b43_plcp_get_bitrate_cck(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); - status.mactime = mactime; + + /* + * If monitors are present get full 64-bit timestamp. This + * code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY + * received the first symbol. + */ + if (dev->wl->radiotap_enabled) { + u16 low_mactime_now; + + b43_tsf_read(dev, &status.mactime); + low_mactime_now = status.mactime; + status.mactime = status.mactime & ~0xFFFFULL; + status.mactime += mactime; + if (low_mactime_now <= mactime) + status.mactime -= 0x10000; + status.flag |= RX_FLAG_TSFT; + } chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; switch (chanstat & B43_RX_CHAN_PHYTYPE) { case B43_PHYTYPE_A: - status.phymode = MODE_IEEE80211A; - status.freq = chanid; - status.channel = b43_freq_to_channel_a(chanid); - break; - case B43_PHYTYPE_B: - status.phymode = MODE_IEEE80211B; - status.freq = chanid + 2400; - status.channel = b43_freq_to_channel_bg(chanid + 2400); + status.band = IEEE80211_BAND_5GHZ; + B43_WARN_ON(1); + /* FIXME: We don't really know which value the "chanid" contains. + * So the following assignment might be wrong. */ + status.freq = b43_channel_to_freq_5ghz(chanid); break; case B43_PHYTYPE_G: - status.phymode = MODE_IEEE80211G; + status.band = IEEE80211_BAND_2GHZ; + /* chanid is the radio channel cookie value as used + * to tune the radio. */ status.freq = chanid + 2400; - status.channel = b43_freq_to_channel_bg(chanid + 2400); + break; + case B43_PHYTYPE_N: + /* chanid is the SHM channel cookie. Which is the plain + * channel number in b43. */ + if (chanstat & B43_RX_CHAN_5GHZ) { + status.band = IEEE80211_BAND_5GHZ; + status.freq = b43_freq_to_channel_5ghz(chanid); + } else { + status.band = IEEE80211_BAND_2GHZ; + status.freq = b43_freq_to_channel_2ghz(chanid); + } break; default: B43_WARN_ON(1); + goto drop; } dev->stats.last_rx = jiffies; @@ -575,10 +664,7 @@ void b43_handle_txstatus(struct b43_wldev *dev, dev->wl->ieee_stats.dot11RTSSuccessCount++; } - if (b43_using_pio(dev)) - b43_pio_handle_txstatus(dev, status); - else - b43_dma_handle_txstatus(dev, status); + b43_dma_handle_txstatus(dev, status); } /* Handle TX status report as received through DMA/PIO queues */ @@ -607,19 +693,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev, /* Stop any TX operation on the device (suspend the hardware queues) */ void b43_tx_suspend(struct b43_wldev *dev) { - if (b43_using_pio(dev)) - b43_pio_freeze_txqueues(dev); - else - b43_dma_tx_suspend(dev); + b43_dma_tx_suspend(dev); } /* Resume any TX operation on the device (resume the hardware queues) */ void b43_tx_resume(struct b43_wldev *dev) { - if (b43_using_pio(dev)) - b43_pio_thaw_txqueues(dev); - else - b43_dma_tx_resume(dev); + b43_dma_tx_resume(dev); } #if 0 |