3   Broadcom BCM43xx wireless driver
 
   5   Transmission (TX/RX) related functions.
 
   7   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
 
   8                      Stefano Brivio <st3@riseup.net>
 
   9                      Michael Buesch <mbuesch@freenet.de>
 
  10                      Danny van Dyk <kugelfang@gentoo.org>
 
  11                      Andreas Jaggi <andreas.jaggi@waterwave.ch>
 
  13   This program is free software; you can redistribute it and/or modify
 
  14   it under the terms of the GNU General Public License as published by
 
  15   the Free Software Foundation; either version 2 of the License, or
 
  16   (at your option) any later version.
 
  18   This program is distributed in the hope that it will be useful,
 
  19   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  21   GNU General Public License for more details.
 
  23   You should have received a copy of the GNU General Public License
 
  24   along with this program; see the file COPYING.  If not, write to
 
  25   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 
  26   Boston, MA 02110-1301, USA.
 
  30 #include "bcm43xx_xmit.h"
 
  32 #include <linux/etherdevice.h>
 
  35 /* Extract the bitrate out of a CCK PLCP header. */
 
  36 static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
 
  38         switch (plcp->raw[0]) {
 
  40                 return IEEE80211_CCK_RATE_1MB;
 
  42                 return IEEE80211_CCK_RATE_2MB;
 
  44                 return IEEE80211_CCK_RATE_5MB;
 
  46                 return IEEE80211_CCK_RATE_11MB;
 
  52 /* Extract the bitrate out of an OFDM PLCP header. */
 
  53 static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
 
  55         switch (plcp->raw[0] & 0xF) {
 
  57                 return IEEE80211_OFDM_RATE_6MB;
 
  59                 return IEEE80211_OFDM_RATE_9MB;
 
  61                 return IEEE80211_OFDM_RATE_12MB;
 
  63                 return IEEE80211_OFDM_RATE_18MB;
 
  65                 return IEEE80211_OFDM_RATE_24MB;
 
  67                 return IEEE80211_OFDM_RATE_36MB;
 
  69                 return IEEE80211_OFDM_RATE_48MB;
 
  71                 return IEEE80211_OFDM_RATE_54MB;
 
  77 u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
 
  80         case IEEE80211_CCK_RATE_1MB:
 
  82         case IEEE80211_CCK_RATE_2MB:
 
  84         case IEEE80211_CCK_RATE_5MB:
 
  86         case IEEE80211_CCK_RATE_11MB:
 
  93 u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
 
  96         case IEEE80211_OFDM_RATE_6MB:
 
  98         case IEEE80211_OFDM_RATE_9MB:
 
 100         case IEEE80211_OFDM_RATE_12MB:
 
 102         case IEEE80211_OFDM_RATE_18MB:
 
 104         case IEEE80211_OFDM_RATE_24MB:
 
 106         case IEEE80211_OFDM_RATE_36MB:
 
 108         case IEEE80211_OFDM_RATE_48MB:
 
 110         case IEEE80211_OFDM_RATE_54MB:
 
 117 static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
 
 118                                       const u16 octets, const u8 bitrate,
 
 119                                       const int ofdm_modulation)
 
 121         __le32 *data = &(plcp->data);
 
 122         __u8 *raw = plcp->raw;
 
 124         if (ofdm_modulation) {
 
 125                 u32 val = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
 
 126                 assert(!(octets & 0xF000));
 
 127                 val |= (octets << 5);
 
 128                 *data = cpu_to_le32(val);
 
 132                 plen = octets * 16 / bitrate;
 
 133                 if ((octets * 16 % bitrate) > 0) {
 
 135                         if ((bitrate == IEEE80211_CCK_RATE_11MB)
 
 136                             && ((octets * 8 % 11) < 4)) {
 
 142                 *data |= cpu_to_le32(plen << 16);
 
 143                 raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
 
 147 static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
 
 150         case IEEE80211_CCK_RATE_1MB:
 
 151                 return IEEE80211_CCK_RATE_1MB;
 
 152         case IEEE80211_CCK_RATE_2MB:
 
 153                 return IEEE80211_CCK_RATE_1MB;
 
 154         case IEEE80211_CCK_RATE_5MB:
 
 155                 return IEEE80211_CCK_RATE_2MB;
 
 156         case IEEE80211_CCK_RATE_11MB:
 
 157                 return IEEE80211_CCK_RATE_5MB;
 
 158         case IEEE80211_OFDM_RATE_6MB:
 
 159                 return IEEE80211_CCK_RATE_5MB;
 
 160         case IEEE80211_OFDM_RATE_9MB:
 
 161                 return IEEE80211_OFDM_RATE_6MB;
 
 162         case IEEE80211_OFDM_RATE_12MB:
 
 163                 return IEEE80211_OFDM_RATE_9MB;
 
 164         case IEEE80211_OFDM_RATE_18MB:
 
 165                 return IEEE80211_OFDM_RATE_12MB;
 
 166         case IEEE80211_OFDM_RATE_24MB:
 
 167                 return IEEE80211_OFDM_RATE_18MB;
 
 168         case IEEE80211_OFDM_RATE_36MB:
 
 169                 return IEEE80211_OFDM_RATE_24MB;
 
 170         case IEEE80211_OFDM_RATE_48MB:
 
 171                 return IEEE80211_OFDM_RATE_36MB;
 
 172         case IEEE80211_OFDM_RATE_54MB:
 
 173                 return IEEE80211_OFDM_RATE_48MB;
 
 180 __le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
 
 183         const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
 
 184         __le16 duration_id = wireless_header->duration_id;
 
 186         switch (WLAN_FC_GET_TYPE(frame_ctl)) {
 
 187         case IEEE80211_FTYPE_DATA:
 
 188         case IEEE80211_FTYPE_MGMT:
 
 189                 //TODO: Steal the code from ieee80211, once it is completed there.
 
 191         case IEEE80211_FTYPE_CTL:
 
 192                 /* Use the original duration/id. */
 
 202 u16 ceiling_div(u16 dividend, u16 divisor)
 
 204         return ((dividend + divisor - 1) / divisor);
 
 207 static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
 
 208                                  struct bcm43xx_txhdr *txhdr,
 
 211                                  const struct ieee80211_hdr_4addr *wlhdr)
 
 217         int fallback_ofdm_modulation;
 
 221 //FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
 
 222 //FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
 
 223         fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
 
 224         ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
 
 225         fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
 
 227         flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
 
 228         bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
 
 230                                   !ieee80211_is_cck_rate(bitrate));
 
 231         bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
 
 232                                   flen, fallback_bitrate,
 
 233                                   !ieee80211_is_cck_rate(fallback_bitrate));
 
 234         fctl = IEEE80211_FTYPE_CTL;
 
 235         fctl |= IEEE80211_STYPE_RTS;
 
 236         dur = le16_to_cpu(wlhdr->duration_id);
 
 237 /*FIXME: should we test for dur==0 here and let it unmodified in this case?
 
 238  *       The following assert checks for this case...
 
 241 /*FIXME: The duration calculation is not really correct.
 
 242  *       I am not 100% sure which bitrate to use. We use the RTS rate here,
 
 243  *       but this is likely to be wrong.
 
 245         if (phy->type == BCM43xx_PHYTYPE_A) {
 
 246                 /* Three times SIFS */
 
 248                 /* Add ACK duration. */
 
 249                 dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
 
 251                 /* Add CTS duration. */
 
 252                 dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
 
 255                 /* Three times SIFS */
 
 257                 /* Add ACK duration. */
 
 258                 dur += ceiling_div(8 * (14 /*bytes*/) * 10,
 
 260                 /* Add CTS duration. */
 
 261                 dur += ceiling_div(8 * (14 /*bytes*/) * 10,
 
 265         txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
 
 266         txhdr->rts_cts_dur = cpu_to_le16(dur);
 
 267 //printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
 
 268 //printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
 
 269         memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
 
 270 //      memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
 
 272         *flags |= BCM43xx_TXHDRFLAG_RTSCTS;
 
 273         *flags |= BCM43xx_TXHDRFLAG_RTS;
 
 275                 *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
 
 276         if (fallback_ofdm_modulation)
 
 277                 *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
 
 280 void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
 
 281                             struct bcm43xx_txhdr *txhdr,
 
 282                             const unsigned char *fragment_data,
 
 283                             const unsigned int fragment_len,
 
 284                             const int is_first_fragment,
 
 287         const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 288         const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
 
 289         const struct ieee80211_security *secinfo = &bcm->ieee->sec;
 
 293         int fallback_ofdm_modulation;
 
 294         u16 plcp_fragment_len = fragment_len;
 
 299         const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
 
 300         const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
 
 302         /* Now construct the TX header. */
 
 303         memset(txhdr, 0, sizeof(*txhdr));
 
 305         bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
 
 306                 is_multicast_ether_addr(wireless_header->addr1), is_mgt);
 
 307         ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
 
 308         fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
 
 309         fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
 
 311         /* Set Frame Control from 80211 header. */
 
 312         txhdr->frame_control = wireless_header->frame_ctl;
 
 313         /* Copy address1 from 80211 header. */
 
 314         memcpy(txhdr->mac1, wireless_header->addr1, 6);
 
 315         /* Set the fallback duration ID. */
 
 316         txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
 
 318         /* Set the cookie (used as driver internal ID for the frame) */
 
 319         txhdr->cookie = cpu_to_le16(cookie);
 
 321         /* Hardware appends FCS. */
 
 322         plcp_fragment_len += IEEE80211_FCS_LEN;
 
 324         /* Hardware encryption. */
 
 325         encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
 
 326         if (encrypt_frame && !bcm->ieee->host_encrypt) {
 
 327                 const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
 
 328                 memcpy(txhdr->wep_iv, hdr->payload, 4);
 
 329                 /* Hardware appends ICV. */
 
 330                 plcp_fragment_len += 4;
 
 332                 wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
 
 333                              & BCM43xx_TXHDR_WSEC_ALGO_MASK;
 
 334                 wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
 
 335                              & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
 
 338         /* Generate the PLCP header and the fallback PLCP header. */
 
 339         bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
 
 341                                   bitrate, ofdm_modulation);
 
 342         bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
 
 343                                   fallback_bitrate, fallback_ofdm_modulation);
 
 345         /* Set the CONTROL field */
 
 347                 control |= BCM43xx_TXHDRCTL_OFDM;
 
 348         if (bcm->short_preamble) //FIXME: could be the other way around, please test
 
 349                 control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
 
 350         control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
 
 351                    & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
 
 353         /* Set the FLAGS field */
 
 354         if (!is_multicast_ether_addr(wireless_header->addr1) &&
 
 355             !is_broadcast_ether_addr(wireless_header->addr1))
 
 356                 flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
 
 357         if (1 /* FIXME: PS poll?? */)
 
 358                 flags |= 0x10; // FIXME: unknown meaning.
 
 359         if (fallback_ofdm_modulation)
 
 360                 flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
 
 361         if (is_first_fragment)
 
 362                 flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
 
 364         /* Set WSEC/RATE field */
 
 365         wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
 
 366                      & BCM43xx_TXHDR_RATE_MASK;
 
 368         /* Generate the RTS/CTS packet, if required. */
 
 369         /* FIXME: We should first try with CTS-to-self,
 
 370          *        if we are on 80211g. If we get too many
 
 371          *        failures (hidden nodes), we should switch back to RTS/CTS.
 
 373         if (0/*FIXME txctl->use_rts_cts*/) {
 
 374                 bcm43xx_generate_rts(phy, txhdr, &flags,
 
 375                                      0/*FIXME txctl->rts_cts_rate*/,
 
 379         txhdr->flags = cpu_to_le16(flags);
 
 380         txhdr->control = cpu_to_le16(control);
 
 381         txhdr->wsec_rate = cpu_to_le16(wsec_rate);
 
 384 static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
 
 385                                    u8 in_rssi, int ofdm,
 
 386                                    int adjust_2053, int adjust_2050)
 
 388         struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 
 389         struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 392         switch (radio->version) {
 
 405                         if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
 
 408                                 tmp = radio->nrssi_lt[in_rssi];
 
 420                         if (phy->type == BCM43xx_PHYTYPE_G &&
 
 447 static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
 
 450         struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 453         if (phy->type == BCM43xx_PHYTYPE_A) {
 
 454                 //TODO: Incomplete specs.
 
 457                 ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
 
 463 int bcm43xx_rx(struct bcm43xx_private *bcm,
 
 465                struct bcm43xx_rxhdr *rxhdr)
 
 467         struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 
 468         struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 469         struct bcm43xx_plcp_hdr4 *plcp;
 
 470         struct ieee80211_rx_stats stats;
 
 471         struct ieee80211_hdr_4addr *wlhdr;
 
 473         int is_packet_for_us = 0;
 
 475         const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
 
 476         const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
 
 477         const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
 
 478         const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
 
 480         if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
 
 481                 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
 
 482                 /* Skip two unknown bytes and the PLCP header. */
 
 483                 skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
 
 485                 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
 
 486                 /* Skip the PLCP header. */
 
 487                 skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
 
 489         /* The SKB contains the PAYLOAD (wireless header + data)
 
 490          * at this point. The FCS at the end is stripped.
 
 493         memset(&stats, 0, sizeof(stats));
 
 494         stats.mac_time = le16_to_cpu(rxhdr->mactime);
 
 495         stats.rssi = rxhdr->rssi;
 
 496         stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
 
 497                                               !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
 
 498                                               !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
 
 499         stats.noise = bcm->stats.noise;
 
 501                 stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
 
 503                 stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
 
 504         stats.received_channel = radio->channel;
 
 505         stats.mask = IEEE80211_STATMASK_SIGNAL |
 
 506                      IEEE80211_STATMASK_NOISE |
 
 507                      IEEE80211_STATMASK_RATE |
 
 508                      IEEE80211_STATMASK_RSSI;
 
 509         if (phy->type == BCM43xx_PHYTYPE_A)
 
 510                 stats.freq = IEEE80211_52GHZ_BAND;
 
 512                 stats.freq = IEEE80211_24GHZ_BAND;
 
 513         stats.len = skb->len;
 
 515         bcm->stats.last_rx = jiffies;
 
 516         if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
 
 517                 err = ieee80211_rx(bcm->ieee, skb, &stats);
 
 518                 return (err == 0) ? -EINVAL : 0;
 
 521         wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
 
 523         switch (bcm->ieee->iw_mode) {
 
 525                 if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
 
 526                     memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
 
 527                     is_broadcast_ether_addr(wlhdr->addr1) ||
 
 528                     is_multicast_ether_addr(wlhdr->addr1) ||
 
 529                     bcm->net_dev->flags & IFF_PROMISC)
 
 530                         is_packet_for_us = 1;
 
 534                 /* When receiving multicast or broadcast packets, filter out
 
 535                    the packets we send ourself; we shouldn't see those */
 
 536                 if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
 
 537                     memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
 
 538                     (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
 
 539                      (is_broadcast_ether_addr(wlhdr->addr1) ||
 
 540                       is_multicast_ether_addr(wlhdr->addr1) ||
 
 541                       bcm->net_dev->flags & IFF_PROMISC)))
 
 542                         is_packet_for_us = 1;
 
 546         frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
 
 547         switch (WLAN_FC_GET_TYPE(frame_ctl)) {
 
 548         case IEEE80211_FTYPE_MGMT:
 
 549                 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
 
 551         case IEEE80211_FTYPE_DATA:
 
 552                 if (is_packet_for_us) {
 
 553                         err = ieee80211_rx(bcm->ieee, skb, &stats);
 
 554                         err = (err == 0) ? -EINVAL : 0;
 
 557         case IEEE80211_FTYPE_CTL: