📄 bcm43xx_xmit.c
字号:
/* 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 inlineu16 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -