/*
Broadcom B43legacy wireless driver
Transmission (TX/RX) related functions.
Copyright (C) 2005 Martin Langer <[email protected]>
Copyright (C) 2005 Stefano Brivio <[email protected]>
Copyright (C) 2005, 2006 Michael Buesch <[email protected]>
Copyright (C) 2005 Danny van Dyk <[email protected]>
Copyright (C) 2005 Andreas Jaggi <[email protected]>
Copyright (C) 2007 Larry Finger <[email protected]>
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_idx_cck(struct b43legacy_plcp_hdr6 *plcp)
{
switch (plcp->raw[0]) {
case 0x0A:
return 0;
case 0x14:
return 1;
case 0x37:
return 2;
case 0x6E:
return 3;
}
B43legacy_BUG_ON(1);
return -1;
}
/* Extract the bitrate out of an OFDM PLCP header. */
static u8 b43legacy_plcp_get_bitrate_idx_ofdm(struct b43legacy_plcp_hdr6 *plcp,
bool aphy)
{
int base = aphy ? 0 : 4;
switch (plcp->raw[0] & 0xF) {
case 0xB:
return base + 0;
case 0xF:
return base + 1;
case 0xA:
return base + 2;
case 0xE:
return base + 3;
case 0x9:
return base + 4;
case 0xD:
return base + 5;
case 0x8:
return base + 6;
case 0xC:
return base + 7;
}
B43legacy_BUG_ON(1);
return -1;
}
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,
struct ieee80211_tx_info *info,
u16 cookie)
{
const struct ieee80211_hdr *wlhdr;
int use_encryption = !!info->control.hw_key;
u8 rate;
struct ieee80211_rate *rate_fb;
int rate_ofdm;
int rate_fb_ofdm;
unsigned int plcp_fragment_len;
u32 mac_ctl = 0;
u16 phy_ctl = 0;
struct ieee80211_rate *tx_rate;
struct ieee80211_tx_rate *rates;
wlhdr = (const struct ieee80211_hdr *)fragment_data;
memset(txhdr, 0, sizeof(*txhdr));
tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info);
rate = tx_rate->hw_value;
rate_ofdm = b43legacy_is_ofdm_rate(rate);
rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : tx_rate;
rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
txhdr->mac_frame_ctl = wlhdr->frame_control;
memcpy(txhdr->tx_receiver, wlhdr->addr1, ETH_ALEN);
/* Calculate duration for fallback rate */
if ((rate_fb->hw_value == 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 {
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
info->control.vif,
info->band,
fragment_len,
rate_fb);
}
plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) {
u8 key_idx = info->control.hw_key->hw_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 += info->control.hw_key->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_hdrlen(wlhdr->frame_control);
iv_len = min_t(size_t, info->control.hw_key->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(&txhdr->plcp_fb, plcp_fragment_len,
rate_fb->hw_value);
/* PHY TX Control word */
if (rate_ofdm)
phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM;
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
/* MAC control */
rates = info->control.rates;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43legacy_TX4_MAC_ACK;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43legacy_TX4_MAC_STMSDU;
if (rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
/* Overwrite rates[0].count to make the retry calculation
* in the tx status easier. need the actual retry
xmit.rar_pio
版权申诉
87 浏览量
2022-09-24
20:37:04
上传
评论
收藏 8KB RAR 举报
刘良运
- 粉丝: 67
- 资源: 1万+
最新资源
- Vue开发基于vue-cli搭建的仿TIM纯前端页面.zip
- BlankMap 2.xmind
- 2023-04-06-项目笔记 - 第一百三十九阶段 - 4.4.2.137全局变量的作用域-137 -2024.05.20
- 自动填满磁盘空间apk
- CH7219A-IMG.G000.07.02.21.IMG
- 多个单页PDF文件合并的Python脚本
- 本科毕业设计一套基于树莓派设计的空气检测系统python源码.zip
- ip.xdb 最新的,改进
- 海信电视刷机数据 LED32K370(0000)BOM1升级VIDAA2软件数据 务必确认机编一致 强制刷机 整机USB升级程序
- 拆分PDF文件的Python脚本
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈