1/* 2 3 Broadcom BCM43xx wireless driver 4 5 Transmission (TX/RX) related functions. 6 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> 12 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. 17 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. 22 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. 27 28*/ 29 30#include "bcm43xx_xmit.h" 31 32#include <linux/etherdevice.h> 33 34 35/* Extract the bitrate out of a CCK PLCP header. */ 36static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp) 37{ 38 switch (plcp->raw[0]) { 39 case 0x0A: 40 return IEEE80211_CCK_RATE_1MB; 41 case 0x14: 42 return IEEE80211_CCK_RATE_2MB; 43 case 0x37: 44 return IEEE80211_CCK_RATE_5MB; 45 case 0x6E: 46 return IEEE80211_CCK_RATE_11MB; 47 } 48 assert(0); 49 return 0; 50} 51 52/* Extract the bitrate out of an OFDM PLCP header. */ 53static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp) 54{ 55 switch (plcp->raw[0] & 0xF) { 56 case 0xB: 57 return IEEE80211_OFDM_RATE_6MB; 58 case 0xF: 59 return IEEE80211_OFDM_RATE_9MB; 60 case 0xA: 61 return IEEE80211_OFDM_RATE_12MB; 62 case 0xE: 63 return IEEE80211_OFDM_RATE_18MB; 64 case 0x9: 65 return IEEE80211_OFDM_RATE_24MB; 66 case 0xD: 67 return IEEE80211_OFDM_RATE_36MB; 68 case 0x8: 69 return IEEE80211_OFDM_RATE_48MB; 70 case 0xC: 71 return IEEE80211_OFDM_RATE_54MB; 72 } 73 assert(0); 74 return 0; 75} 76 77u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) 78{ 79 switch (bitrate) { 80 case IEEE80211_CCK_RATE_1MB: 81 return 0x0A; 82 case IEEE80211_CCK_RATE_2MB: 83 return 0x14; 84 case IEEE80211_CCK_RATE_5MB: 85 return 0x37; 86 case IEEE80211_CCK_RATE_11MB: 87 return 0x6E; 88 } 89 assert(0); 90 return 0; 91} 92 93u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) 94{ 95 switch (bitrate) { 96 case IEEE80211_OFDM_RATE_6MB: 97 return 0xB; 98 case IEEE80211_OFDM_RATE_9MB: 99 return 0xF; 100 case IEEE80211_OFDM_RATE_12MB: 101 return 0xA; 102 case IEEE80211_OFDM_RATE_18MB: 103 return 0xE; 104 case IEEE80211_OFDM_RATE_24MB: 105 return 0x9; 106 case IEEE80211_OFDM_RATE_36MB: 107 return 0xD; 108 case IEEE80211_OFDM_RATE_48MB: 109 return 0x8; 110 case IEEE80211_OFDM_RATE_54MB: 111 return 0xC; 112 } 113 assert(0); 114 return 0; 115} 116 117static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, 118 const u16 octets, const u8 bitrate, 119 const int ofdm_modulation) 120{ 121 __le32 *data = &(plcp->data); 122 __u8 *raw = plcp->raw; 123 124 if (ofdm_modulation) { 125 *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); 126 assert(!(octets & 0xF000)); 127 *data |= (octets << 5); 128 *data = cpu_to_le32(*data); 129 } else { 130 u32 plen; 131 132 plen = octets * 16 / bitrate; 133 if ((octets * 16 % bitrate) > 0) { 134 plen++; 135 if ((bitrate == IEEE80211_CCK_RATE_11MB) 136 && ((octets * 8 % 11) < 4)) { 137 raw[1] = 0x84; 138 } else 139 raw[1] = 0x04; 140 } else 141 raw[1] = 0x04; 142 *data |= cpu_to_le32(plen << 16); 143 raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); 144 } 145} 146 147static u8 bcm43xx_calc_fallback_rate(u8 bitrate) 148{ 149 switch (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; 174 } 175 assert(0); 176 return 0; 177} 178 179static 180__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header, 181 u8 bitrate) 182{ 183 const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl); 184 __le16 duration_id = wireless_header->duration_id; 185 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. 190 break; 191 case IEEE80211_FTYPE_CTL: 192 /* Use the original duration/id. */ 193 break; 194 default: 195 assert(0); 196 } 197 198 return duration_id; 199} 200 201static inline 202u16 ceiling_div(u16 dividend, u16 divisor) 203{ 204 return ((dividend + divisor - 1) / divisor); 205} 206 207static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, 208 struct bcm43xx_txhdr *txhdr, 209 u16 *flags, 210 u8 bitrate, 211 const struct ieee80211_hdr_4addr *wlhdr) 212{ 213 u16 fctl; 214 u16 dur; 215 u8 fallback_bitrate; 216 int ofdm_modulation; 217 int fallback_ofdm_modulation; 218// u8 *sa, *da; 219 u16 flen; 220 221 fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); 222 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); 223 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); 224 225 flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN, 226 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp), 227 flen, bitrate, 228 !ieee80211_is_cck_rate(bitrate)); 229 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp), 230 flen, fallback_bitrate, 231 !ieee80211_is_cck_rate(fallback_bitrate)); 232 fctl = IEEE80211_FTYPE_CTL; 233 fctl |= IEEE80211_STYPE_RTS; 234 dur = le16_to_cpu(wlhdr->duration_id); 235assert(dur); 236 if (phy->type == BCM43xx_PHYTYPE_A) { 237 /* Three times SIFS */ 238 dur += 16 * 3; 239 /* Add ACK duration. */ 240 dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, 241 bitrate * 4); 242 /* Add CTS duration. */ 243 dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, 244 bitrate * 4); 245 } else { 246 /* Three times SIFS */ 247 dur += 10 * 3; 248 /* Add ACK duration. */ 249 dur += ceiling_div(8 * (14 /*bytes*/) * 10, 250 bitrate); 251 /* Add CTS duration. */ 252 dur += ceiling_div(8 * (14 /*bytes*/) * 10, 253 bitrate); 254 } 255 256 txhdr->rts_cts_frame_control = cpu_to_le16(fctl); 257 txhdr->rts_cts_dur = cpu_to_le16(dur); 258//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); 259//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); 260 memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN); 261// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); 262 263 *flags |= BCM43xx_TXHDRFLAG_RTSCTS; 264 *flags |= BCM43xx_TXHDRFLAG_RTS; 265 if (ofdm_modulation) 266 *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM; 267 if (fallback_ofdm_modulation) 268 *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM; 269} 270 271void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, 272 struct bcm43xx_txhdr *txhdr, 273 const unsigned char *fragment_data, 274 const unsigned int fragment_len, 275 const int is_first_fragment, 276 const u16 cookie) 277{ 278 const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 279 const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; 280 const struct ieee80211_security *secinfo = &bcm->ieee->sec; 281 u8 bitrate; 282 u8 fallback_bitrate; 283 int ofdm_modulation; 284 int fallback_ofdm_modulation; 285 u16 plcp_fragment_len = fragment_len; 286 u16 flags = 0; 287 u16 control = 0; 288 u16 wsec_rate = 0; 289 u16 encrypt_frame; 290 const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl)); 291 const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT); 292 293 /* Now construct the TX header. */ 294 memset(txhdr, 0, sizeof(*txhdr)); 295 296 bitrate = ieee80211softmac_suggest_txrate(bcm->softmac, 297 is_multicast_ether_addr(wireless_header->addr1), is_mgt); 298 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); 299 fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); 300 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); 301 302 /* Set Frame Control from 80211 header. */ 303 txhdr->frame_control = wireless_header->frame_ctl; 304 /* Copy address1 from 80211 header. */ 305 memcpy(txhdr->mac1, wireless_header->addr1, 6); 306 /* Set the fallback duration ID. */ 307 txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header, 308 fallback_bitrate); 309 /* Set the cookie (used as driver internal ID for the frame) */ 310 txhdr->cookie = cpu_to_le16(cookie); 311 312 /* Hardware appends FCS. */ 313 plcp_fragment_len += IEEE80211_FCS_LEN; 314 315 /* Hardware encryption. */ 316 encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; 317 if (encrypt_frame && !bcm->ieee->host_encrypt) { 318 const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; 319 memcpy(txhdr->wep_iv, hdr->payload, 4); 320 /* Hardware appends ICV. */ 321 plcp_fragment_len += 4; 322 323 wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) 324 & BCM43xx_TXHDR_WSEC_ALGO_MASK; 325 wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) 326 & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; 327 } 328 329 /* Generate the PLCP header and the fallback PLCP header. */ 330 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), 331 plcp_fragment_len, 332 bitrate, ofdm_modulation); 333 bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len, 334 fallback_bitrate, fallback_ofdm_modulation); 335 336 /* Set the CONTROL field */ 337 if (ofdm_modulation) 338 control |= BCM43xx_TXHDRCTL_OFDM; 339 if (bcm->short_preamble) 340 control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; 341 control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) 342 & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; 343 344 /* Set the FLAGS field */ 345 if (!is_multicast_ether_addr(wireless_header->addr1) && 346 !is_broadcast_ether_addr(wireless_header->addr1)) 347 flags |= BCM43xx_TXHDRFLAG_EXPECTACK; 348 if (1) 349 flags |= 0x10; 350 if (fallback_ofdm_modulation) 351 flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; 352 if (is_first_fragment) 353 flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; 354 355 /* Set WSEC/RATE field */ 356 wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT) 357 & BCM43xx_TXHDR_RATE_MASK; 358 359 /* Generate the RTS/CTS packet, if required. */ 360 if (0) { 361 bcm43xx_generate_rts(phy, txhdr, &flags, 362 0, 363 wireless_header); 364 } 365 366 txhdr->flags = cpu_to_le16(flags); 367 txhdr->control = cpu_to_le16(control); 368 txhdr->wsec_rate = cpu_to_le16(wsec_rate); 369} 370 371static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, 372 u8 in_rssi, int ofdm, 373 int adjust_2053, int adjust_2050) 374{ 375 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 376 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 377 s32 tmp; 378 379 switch (radio->version) { 380 case 0x2050: 381 if (ofdm) { 382 tmp = in_rssi; 383 if (tmp > 127) 384 tmp -= 256; 385 tmp *= 73; 386 tmp /= 64; 387 if (adjust_2050) 388 tmp += 25; 389 else 390 tmp -= 3; 391 } else { 392 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { 393 if (in_rssi > 63) 394 in_rssi = 63; 395 tmp = radio->nrssi_lt[in_rssi]; 396 tmp = 31 - tmp; 397 tmp *= -131; 398 tmp /= 128; 399 tmp -= 57; 400 } else { 401 tmp = in_rssi; 402 tmp = 31 - tmp; 403 tmp *= -149; 404 tmp /= 128; 405 tmp -= 68; 406 } 407 if (phy->type == BCM43xx_PHYTYPE_G && 408 adjust_2050) 409 tmp += 25; 410 } 411 break; 412 case 0x2060: 413 if (in_rssi > 127) 414 tmp = in_rssi - 256; 415 else 416 tmp = in_rssi; 417 break; 418 default: 419 tmp = in_rssi; 420 tmp -= 11; 421 tmp *= 103; 422 tmp /= 64; 423 if (adjust_2053) 424 tmp -= 109; 425 else 426 tmp -= 83; 427 } 428 429 return (s8)tmp; 430} 431 432//TODO 433 434int bcm43xx_rx(struct bcm43xx_private *bcm, 435 struct sk_buff *skb, 436 struct bcm43xx_rxhdr *rxhdr) 437{ 438 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 439 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 440 struct bcm43xx_plcp_hdr4 *plcp; 441 struct ieee80211_rx_stats stats; 442 struct ieee80211_hdr_4addr *wlhdr; 443 u16 frame_ctl; 444 int is_packet_for_us = 0; 445 int err = -EINVAL; 446 const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); 447 const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); 448 const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); 449 const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); 450 451 if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { 452 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); 453 /* Skip two unknown bytes and the PLCP header. */ 454 skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); 455 } else { 456 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); 457 /* Skip the PLCP header. */ 458 skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); 459 } 460 /* The SKB contains the PAYLOAD (wireless header + data) 461 * at this point. The FCS at the end is stripped. 462 */ 463 464 memset(&stats, 0, sizeof(stats)); 465 stats.mac_time = le16_to_cpu(rxhdr->mactime); 466 stats.rssi = rxhdr->rssi; 467 stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, 468 !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), 469 !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); 470 stats.noise = bcm->stats.noise; 471 if (is_ofdm) 472 stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); 473 else 474 stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); 475 stats.received_channel = radio->channel; 476 stats.mask = IEEE80211_STATMASK_SIGNAL | 477 IEEE80211_STATMASK_NOISE | 478 IEEE80211_STATMASK_RATE | 479 IEEE80211_STATMASK_RSSI; 480 if (phy->type == BCM43xx_PHYTYPE_A) 481 stats.freq = IEEE80211_52GHZ_BAND; 482 else 483 stats.freq = IEEE80211_24GHZ_BAND; 484 stats.len = skb->len; 485 486 bcm->stats.last_rx = jiffies; 487 if (bcm->ieee->iw_mode == IW_MODE_MONITOR) { 488 err = ieee80211_rx(bcm->ieee, skb, &stats); 489 return (err == 0) ? -EINVAL : 0; 490 } 491 492 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); 493 494 switch (bcm->ieee->iw_mode) { 495 case IW_MODE_ADHOC: 496 if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || 497 memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || 498 is_broadcast_ether_addr(wlhdr->addr1) || 499 is_multicast_ether_addr(wlhdr->addr1) || 500 bcm->net_dev->flags & IFF_PROMISC) 501 is_packet_for_us = 1; 502 break; 503 case IW_MODE_INFRA: 504 default: 505 /* When receiving multicast or broadcast packets, filter out 506 the packets we send ourself; we shouldn't see those */ 507 if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || 508 memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || 509 (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && 510 (is_broadcast_ether_addr(wlhdr->addr1) || 511 is_multicast_ether_addr(wlhdr->addr1) || 512 bcm->net_dev->flags & IFF_PROMISC))) 513 is_packet_for_us = 1; 514 break; 515 } 516 517 frame_ctl = le16_to_cpu(wlhdr->frame_ctl); 518 switch (WLAN_FC_GET_TYPE(frame_ctl)) { 519 case IEEE80211_FTYPE_MGMT: 520 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); 521 break; 522 case IEEE80211_FTYPE_DATA: 523 if (is_packet_for_us) { 524 err = ieee80211_rx(bcm->ieee, skb, &stats); 525 err = (err == 0) ? -EINVAL : 0; 526 } 527 break; 528 case IEEE80211_FTYPE_CTL: 529 break; 530 default: 531 assert(0); 532 return -EINVAL; 533 } 534 535 return err; 536} 537