📄 xmit.c
字号:
/* Broadcom B43legacy wireless driver 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, 2006 Michael Buesch <mb@bu3sch.de> Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net> 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 <net/dst.h>#include "xmit.h"#include "phy.h"#include "dma.h"#include "pio.h"/* Extract the bitrate out of a CCK PLCP header. */static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp){ switch (plcp->raw[0]) { case 0x0A: return B43legacy_CCK_RATE_1MB; case 0x14: return B43legacy_CCK_RATE_2MB; case 0x37: return B43legacy_CCK_RATE_5MB; case 0x6E: return B43legacy_CCK_RATE_11MB; } B43legacy_BUG_ON(1); return 0;}/* Extract the bitrate out of an OFDM PLCP header. */static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp){ switch (plcp->raw[0] & 0xF) { case 0xB: return B43legacy_OFDM_RATE_6MB; case 0xF: return B43legacy_OFDM_RATE_9MB; case 0xA: return B43legacy_OFDM_RATE_12MB; case 0xE: return B43legacy_OFDM_RATE_18MB; case 0x9: return B43legacy_OFDM_RATE_24MB; case 0xD: return B43legacy_OFDM_RATE_36MB; case 0x8: return B43legacy_OFDM_RATE_48MB; case 0xC: return B43legacy_OFDM_RATE_54MB; } B43legacy_BUG_ON(1); return 0;}u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate){ switch (bitrate) { case B43legacy_CCK_RATE_1MB: return 0x0A; case B43legacy_CCK_RATE_2MB: return 0x14; case B43legacy_CCK_RATE_5MB: return 0x37; case B43legacy_CCK_RATE_11MB: return 0x6E; } B43legacy_BUG_ON(1); return 0;}u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate){ switch (bitrate) { case B43legacy_OFDM_RATE_6MB: return 0xB; case B43legacy_OFDM_RATE_9MB: return 0xF; case B43legacy_OFDM_RATE_12MB: return 0xA; case B43legacy_OFDM_RATE_18MB: return 0xE; case B43legacy_OFDM_RATE_24MB: return 0x9; case B43legacy_OFDM_RATE_36MB: return 0xD; case B43legacy_OFDM_RATE_48MB: return 0x8; case B43legacy_OFDM_RATE_54MB: return 0xC; } B43legacy_BUG_ON(1); return 0;}void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp, const u16 octets, const u8 bitrate){ __le32 *data = &(plcp->data); __u8 *raw = plcp->raw; if (b43legacy_is_ofdm_rate(bitrate)) { u16 d; d = b43legacy_plcp_get_ratecode_ofdm(bitrate); B43legacy_WARN_ON(octets & 0xF000); d |= (octets << 5); *data = cpu_to_le32(d); } else { u32 plen; plen = octets * 16 / bitrate; if ((octets * 16 % bitrate) > 0) { plen++; if ((bitrate == B43legacy_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] = b43legacy_plcp_get_ratecode_cck(bitrate); }}static u8 b43legacy_calc_fallback_rate(u8 bitrate){ switch (bitrate) { case B43legacy_CCK_RATE_1MB: return B43legacy_CCK_RATE_1MB; case B43legacy_CCK_RATE_2MB: return B43legacy_CCK_RATE_1MB; case B43legacy_CCK_RATE_5MB: return B43legacy_CCK_RATE_2MB; case B43legacy_CCK_RATE_11MB: return B43legacy_CCK_RATE_5MB; case B43legacy_OFDM_RATE_6MB: return B43legacy_CCK_RATE_5MB; case B43legacy_OFDM_RATE_9MB: return B43legacy_OFDM_RATE_6MB; case B43legacy_OFDM_RATE_12MB: return B43legacy_OFDM_RATE_9MB; case B43legacy_OFDM_RATE_18MB: return B43legacy_OFDM_RATE_12MB; case B43legacy_OFDM_RATE_24MB: return B43legacy_OFDM_RATE_18MB; case B43legacy_OFDM_RATE_36MB: return B43legacy_OFDM_RATE_24MB; case B43legacy_OFDM_RATE_48MB: return B43legacy_OFDM_RATE_36MB; case B43legacy_OFDM_RATE_54MB: return B43legacy_OFDM_RATE_48MB; } B43legacy_BUG_ON(1); return 0;}static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, const struct ieee80211_tx_control *txctl, u16 cookie){ const struct ieee80211_hdr *wlhdr; int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl; u8 rate; u8 rate_fb; int rate_ofdm; int rate_fb_ofdm; unsigned int plcp_fragment_len; u32 mac_ctl = 0; u16 phy_ctl = 0; wlhdr = (const struct ieee80211_hdr *)fragment_data; fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); rate = txctl->tx_rate; rate_ofdm = b43legacy_is_ofdm_rate(rate); rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb); txhdr->mac_frame_ctl = wlhdr->frame_control; memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); /* Calculate duration for fallback rate */ if ((rate_fb == rate) || (wlhdr->duration_id & cpu_to_le16(0x8000)) || (wlhdr->duration_id == cpu_to_le16(0))) { /* If the fallback rate equals the normal rate or the * dur_id field contains an AID, CFP magic or 0, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->if_id, fragment_len, fbrate_base100kbps); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { u8 key_idx = (u16)(txctl->key_idx); struct b43legacy_key *key; int wlhdr_len; size_t iv_len; B43legacy_WARN_ON(key_idx >= dev->max_nr_keys); key = &(dev->key[key_idx]); if (key->enabled) { /* Hardware appends ICV. */ plcp_fragment_len += txctl->icv_len; key_idx = b43legacy_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & B43legacy_TX4_MAC_KEYIDX; mac_ctl |= (key->algorithm << B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_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); } else { /* 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; } } b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) (&txhdr->plcp), plcp_fragment_len, rate); b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) (&txhdr->plcp_fb), plcp_fragment_len, rate_fb); /* PHY TX Control word */ if (rate_ofdm) phy_ctl |= B43legacy_TX4_PHY_OFDM; if (dev->short_preamble) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (txctl->antenna_sel_tx) { case 0: phy_ctl |= B43legacy_TX4_PHY_ANTLAST; break; case 1: phy_ctl |= B43legacy_TX4_PHY_ANT0; break; case 2: phy_ctl |= B43legacy_TX4_PHY_ANT1; break; default: B43legacy_BUG_ON(1); } /* MAC control */ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) mac_ctl |= B43legacy_TX4_MAC_HWSEQ; if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; /* Generate the RTS or CTS-to-self frame */ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; int rts_rate_fb; int rts_rate_ofdm; int rts_rate_fb_ofdm; rts_rate = txctl->rts_cts_rate; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id, fragment_data, fragment_len, txctl, (struct ieee80211_cts *) (txhdr->rts_frame)); mac_ctl |= B43legacy_TX4_MAC_SENDCTS; len = sizeof(struct ieee80211_cts);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -