1/* 2 3 Broadcom BCM43xx wireless driver 4 5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 Stefano Brivio <st3@riseup.net> 7 Michael Buesch <mbuesch@freenet.de> 8 Danny van Dyk <kugelfang@gentoo.org> 9 Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 11 Some parts of the code in this file are derived from the ipw2200 12 driver Copyright(c) 2003 - 2004 Intel Corporation. 13 14 This program is free software; you can redistribute it and/or modify 15 it under the terms of the GNU General Public License as published by 16 the Free Software Foundation; either version 2 of the License, or 17 (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 GNU General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; see the file COPYING. If not, write to 26 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 Boston, MA 02110-1301, USA. 28 29*/ 30 31#include <linux/wireless.h> 32#include <net/iw_handler.h> 33#include <net/ieee80211softmac.h> 34#include <net/ieee80211softmac_wx.h> 35#include <linux/capability.h> 36#include <linux/delay.h> 37 38#include "bcm43xx.h" 39#include "bcm43xx_wx.h" 40#include "bcm43xx_main.h" 41#include "bcm43xx_radio.h" 42#include "bcm43xx_phy.h" 43 44 45/* The WIRELESS_EXT version, which is implemented by this driver. */ 46#define BCM43xx_WX_VERSION 18 47 48#define MAX_WX_STRING 80 49 50static int bcm43xx_wx_get_name(struct net_device *net_dev, 51 struct iw_request_info *info, 52 union iwreq_data *data, 53 char *extra) 54{ 55 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 56 int i; 57 struct bcm43xx_phyinfo *phy; 58 char suffix[7] = { 0 }; 59 int have_a = 0, have_b = 0, have_g = 0; 60 61 mutex_lock(&bcm->mutex); 62 for (i = 0; i < bcm->nr_80211_available; i++) { 63 phy = &(bcm->core_80211_ext[i].phy); 64 switch (phy->type) { 65 case BCM43xx_PHYTYPE_A: 66 have_a = 1; 67 break; 68 case BCM43xx_PHYTYPE_G: 69 have_g = 1; 70 case BCM43xx_PHYTYPE_B: 71 have_b = 1; 72 break; 73 default: 74 assert(0); 75 } 76 } 77 mutex_unlock(&bcm->mutex); 78 79 i = 0; 80 if (have_a) { 81 suffix[i++] = 'a'; 82 suffix[i++] = '/'; 83 } 84 if (have_b) { 85 suffix[i++] = 'b'; 86 suffix[i++] = '/'; 87 } 88 if (have_g) { 89 suffix[i++] = 'g'; 90 suffix[i++] = '/'; 91 } 92 if (i != 0) 93 suffix[i - 1] = '\0'; 94 95 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix); 96 97 return 0; 98} 99 100static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, 101 struct iw_request_info *info, 102 union iwreq_data *data, 103 char *extra) 104{ 105 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 106 unsigned long flags; 107 u8 channel; 108 s8 expon; 109 int freq; 110 int err = -EINVAL; 111 112 mutex_lock(&bcm->mutex); 113 spin_lock_irqsave(&bcm->irq_lock, flags); 114 115 if ((data->freq.e == 0) && 116 (data->freq.m >= 0) && (data->freq.m <= 1000)) { 117 channel = data->freq.m; 118 freq = bcm43xx_channel_to_freq(bcm, channel); 119 } else { 120 freq = data->freq.m; 121 expon = 6 - data->freq.e; 122 while (--expon >= 0) /* scale down the frequency to MHz */ 123 freq /= 10; 124 assert(freq > 1000); 125 channel = bcm43xx_freq_to_channel(bcm, freq); 126 } 127 if (!ieee80211_is_valid_channel(bcm->ieee, channel)) 128 goto out_unlock; 129 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { 130 //ieee80211softmac_disassoc(softmac, $REASON); 131 bcm43xx_mac_suspend(bcm); 132 err = bcm43xx_radio_selectchannel(bcm, channel, 0); 133 bcm43xx_mac_enable(bcm); 134 } else { 135 bcm43xx_current_radio(bcm)->initial_channel = channel; 136 err = 0; 137 } 138out_unlock: 139 spin_unlock_irqrestore(&bcm->irq_lock, flags); 140 mutex_unlock(&bcm->mutex); 141 142 return err; 143} 144 145static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, 146 struct iw_request_info *info, 147 union iwreq_data *data, 148 char *extra) 149{ 150 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 151 struct bcm43xx_radioinfo *radio; 152 int err = -ENODEV; 153 u16 channel; 154 155 mutex_lock(&bcm->mutex); 156 radio = bcm43xx_current_radio(bcm); 157 channel = radio->channel; 158 if (channel == 0xFF) { 159 channel = radio->initial_channel; 160 if (channel == 0xFF) 161 goto out_unlock; 162 } 163 assert(channel > 0 && channel <= 1000); 164 data->freq.e = 1; 165 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000; 166 data->freq.flags = 1; 167 168 err = 0; 169out_unlock: 170 mutex_unlock(&bcm->mutex); 171 172 return err; 173} 174 175static int bcm43xx_wx_set_mode(struct net_device *net_dev, 176 struct iw_request_info *info, 177 union iwreq_data *data, 178 char *extra) 179{ 180 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 181 unsigned long flags; 182 int mode; 183 184 mode = data->mode; 185 if (mode == IW_MODE_AUTO) 186 mode = BCM43xx_INITIAL_IWMODE; 187 188 mutex_lock(&bcm->mutex); 189 spin_lock_irqsave(&bcm->irq_lock, flags); 190 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { 191 if (bcm->ieee->iw_mode != mode) 192 bcm43xx_set_iwmode(bcm, mode); 193 } else 194 bcm->ieee->iw_mode = mode; 195 spin_unlock_irqrestore(&bcm->irq_lock, flags); 196 mutex_unlock(&bcm->mutex); 197 198 return 0; 199} 200 201static int bcm43xx_wx_get_mode(struct net_device *net_dev, 202 struct iw_request_info *info, 203 union iwreq_data *data, 204 char *extra) 205{ 206 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 207 208 mutex_lock(&bcm->mutex); 209 data->mode = bcm->ieee->iw_mode; 210 mutex_unlock(&bcm->mutex); 211 212 return 0; 213} 214 215static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, 216 struct iw_request_info *info, 217 union iwreq_data *data, 218 char *extra) 219{ 220 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 221 struct iw_range *range = (struct iw_range *)extra; 222 const struct ieee80211_geo *geo; 223 int i, j; 224 struct bcm43xx_phyinfo *phy; 225 226 data->data.length = sizeof(*range); 227 memset(range, 0, sizeof(*range)); 228 229 //TODO: What about 802.11b? 230 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */ 231 range->throughput = 27 * 1000 * 1000; 232 233 range->max_qual.qual = 100; 234 range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */ 235 range->max_qual.noise = 146; 236 range->max_qual.updated = IW_QUAL_ALL_UPDATED; 237 238 range->avg_qual.qual = 50; 239 range->avg_qual.level = 0; 240 range->avg_qual.noise = 0; 241 range->avg_qual.updated = IW_QUAL_ALL_UPDATED; 242 243 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; 244 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; 245 range->min_frag = MIN_FRAG_THRESHOLD; 246 range->max_frag = MAX_FRAG_THRESHOLD; 247 248 range->encoding_size[0] = 5; 249 range->encoding_size[1] = 13; 250 range->num_encoding_sizes = 2; 251 range->max_encoding_tokens = WEP_KEYS; 252 253 range->we_version_compiled = WIRELESS_EXT; 254 range->we_version_source = BCM43xx_WX_VERSION; 255 256 range->enc_capa = IW_ENC_CAPA_WPA | 257 IW_ENC_CAPA_WPA2 | 258 IW_ENC_CAPA_CIPHER_TKIP | 259 IW_ENC_CAPA_CIPHER_CCMP; 260 261 mutex_lock(&bcm->mutex); 262 phy = bcm43xx_current_phy(bcm); 263 264 range->num_bitrates = 0; 265 i = 0; 266 if (phy->type == BCM43xx_PHYTYPE_A || 267 phy->type == BCM43xx_PHYTYPE_G) { 268 range->num_bitrates = 8; 269 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000; 270 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000; 271 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000; 272 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000; 273 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000; 274 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000; 275 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000; 276 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000; 277 } 278 if (phy->type == BCM43xx_PHYTYPE_B || 279 phy->type == BCM43xx_PHYTYPE_G) { 280 range->num_bitrates += 4; 281 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000; 282 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000; 283 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000; 284 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000; 285 } 286 287 geo = ieee80211_get_geo(bcm->ieee); 288 range->num_channels = geo->a_channels + geo->bg_channels; 289 j = 0; 290 for (i = 0; i < geo->a_channels; i++) { 291 if (j == IW_MAX_FREQUENCIES) 292 break; 293 range->freq[j].i = j + 1; 294 range->freq[j].m = geo->a[i].freq * 100000; 295 range->freq[j].e = 1; 296 j++; 297 } 298 for (i = 0; i < geo->bg_channels; i++) { 299 if (j == IW_MAX_FREQUENCIES) 300 break; 301 range->freq[j].i = j + 1; 302 range->freq[j].m = geo->bg[i].freq * 100000; 303 range->freq[j].e = 1; 304 j++; 305 } 306 range->num_frequency = j; 307 308 mutex_unlock(&bcm->mutex); 309 310 return 0; 311} 312 313static int bcm43xx_wx_set_nick(struct net_device *net_dev, 314 struct iw_request_info *info, 315 union iwreq_data *data, 316 char *extra) 317{ 318 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 319 size_t len; 320 321 mutex_lock(&bcm->mutex); 322 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); 323 memcpy(bcm->nick, extra, len); 324 bcm->nick[len] = '\0'; 325 mutex_unlock(&bcm->mutex); 326 327 return 0; 328} 329 330static int bcm43xx_wx_get_nick(struct net_device *net_dev, 331 struct iw_request_info *info, 332 union iwreq_data *data, 333 char *extra) 334{ 335 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 336 size_t len; 337 338 mutex_lock(&bcm->mutex); 339 len = strlen(bcm->nick); 340 memcpy(extra, bcm->nick, len); 341 data->data.length = (__u16)len; 342 data->data.flags = 1; 343 mutex_unlock(&bcm->mutex); 344 345 return 0; 346} 347 348static int bcm43xx_wx_set_rts(struct net_device *net_dev, 349 struct iw_request_info *info, 350 union iwreq_data *data, 351 char *extra) 352{ 353 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 354 unsigned long flags; 355 int err = -EINVAL; 356 357 mutex_lock(&bcm->mutex); 358 spin_lock_irqsave(&bcm->irq_lock, flags); 359 if (data->rts.disabled) { 360 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; 361 err = 0; 362 } else { 363 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD && 364 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) { 365 bcm->rts_threshold = data->rts.value; 366 err = 0; 367 } 368 } 369 spin_unlock_irqrestore(&bcm->irq_lock, flags); 370 mutex_unlock(&bcm->mutex); 371 372 return err; 373} 374 375static int bcm43xx_wx_get_rts(struct net_device *net_dev, 376 struct iw_request_info *info, 377 union iwreq_data *data, 378 char *extra) 379{ 380 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 381 382 mutex_lock(&bcm->mutex); 383 data->rts.value = bcm->rts_threshold; 384 data->rts.fixed = 0; 385 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); 386 mutex_unlock(&bcm->mutex); 387 388 return 0; 389} 390 391static int bcm43xx_wx_set_frag(struct net_device *net_dev, 392 struct iw_request_info *info, 393 union iwreq_data *data, 394 char *extra) 395{ 396 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 397 unsigned long flags; 398 int err = -EINVAL; 399 400 mutex_lock(&bcm->mutex); 401 spin_lock_irqsave(&bcm->irq_lock, flags); 402 if (data->frag.disabled) { 403 bcm->ieee->fts = MAX_FRAG_THRESHOLD; 404 err = 0; 405 } else { 406 if (data->frag.value >= MIN_FRAG_THRESHOLD && 407 data->frag.value <= MAX_FRAG_THRESHOLD) { 408 bcm->ieee->fts = data->frag.value & ~0x1; 409 err = 0; 410 } 411 } 412 spin_unlock_irqrestore(&bcm->irq_lock, flags); 413 mutex_unlock(&bcm->mutex); 414 415 return err; 416} 417 418static int bcm43xx_wx_get_frag(struct net_device *net_dev, 419 struct iw_request_info *info, 420 union iwreq_data *data, 421 char *extra) 422{ 423 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 424 425 mutex_lock(&bcm->mutex); 426 data->frag.value = bcm->ieee->fts; 427 data->frag.fixed = 0; 428 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); 429 mutex_unlock(&bcm->mutex); 430 431 return 0; 432} 433 434static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, 435 struct iw_request_info *info, 436 union iwreq_data *data, 437 char *extra) 438{ 439 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 440 struct bcm43xx_radioinfo *radio; 441 struct bcm43xx_phyinfo *phy; 442 unsigned long flags; 443 int err = -ENODEV; 444 u16 maxpower; 445 446 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { 447 printk(PFX KERN_ERR "TX power not in dBm.\n"); 448 return -EOPNOTSUPP; 449 } 450 451 mutex_lock(&bcm->mutex); 452 spin_lock_irqsave(&bcm->irq_lock, flags); 453 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) 454 goto out_unlock; 455 radio = bcm43xx_current_radio(bcm); 456 phy = bcm43xx_current_phy(bcm); 457 if (data->txpower.disabled != (!(radio->enabled))) { 458 if (data->txpower.disabled) 459 bcm43xx_radio_turn_off(bcm); 460 else 461 bcm43xx_radio_turn_on(bcm); 462 } 463 if (data->txpower.value > 0) { 464 /* desired and maxpower dBm values are in Q5.2 */ 465 if (phy->type == BCM43xx_PHYTYPE_A) 466 maxpower = bcm->sprom.maxpower_aphy; 467 else 468 maxpower = bcm->sprom.maxpower_bgphy; 469 radio->txpower_desired = limit_value(data->txpower.value << 2, 470 0, maxpower); 471 bcm43xx_phy_xmitpower(bcm); 472 } 473 err = 0; 474 475out_unlock: 476 spin_unlock_irqrestore(&bcm->irq_lock, flags); 477 mutex_unlock(&bcm->mutex); 478 479 return err; 480} 481 482static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, 483 struct iw_request_info *info, 484 union iwreq_data *data, 485 char *extra) 486{ 487 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 488 struct bcm43xx_radioinfo *radio; 489 int err = -ENODEV; 490 491 mutex_lock(&bcm->mutex); 492 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) 493 goto out_unlock; 494 radio = bcm43xx_current_radio(bcm); 495 /* desired dBm value is in Q5.2 */ 496 data->txpower.value = radio->txpower_desired >> 2; 497 data->txpower.fixed = 1; 498 data->txpower.flags = IW_TXPOW_DBM; 499 data->txpower.disabled = !(radio->enabled); 500 501 err = 0; 502out_unlock: 503 mutex_unlock(&bcm->mutex); 504 505 return err; 506} 507 508static int bcm43xx_wx_set_encoding(struct net_device *net_dev, 509 struct iw_request_info *info, 510 union iwreq_data *data, 511 char *extra) 512{ 513 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 514 int err; 515 516 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); 517 518 return err; 519} 520 521static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, 522 struct iw_request_info *info, 523 union iwreq_data *data, 524 char *extra) 525{ 526 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 527 int err; 528 529 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); 530 531 return err; 532} 533 534static int bcm43xx_wx_get_encoding(struct net_device *net_dev, 535 struct iw_request_info *info, 536 union iwreq_data *data, 537 char *extra) 538{ 539 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 540 int err; 541 542 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); 543 544 return err; 545} 546 547static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, 548 struct iw_request_info *info, 549 union iwreq_data *data, 550 char *extra) 551{ 552 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 553 int err; 554 555 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); 556 557 return err; 558} 559 560static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, 561 struct iw_request_info *info, 562 union iwreq_data *data, 563 char *extra) 564{ 565 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 566 unsigned long flags; 567 int mode, err = 0; 568 569 mode = *((int *)extra); 570 switch (mode) { 571 case 0: 572 mode = BCM43xx_RADIO_INTERFMODE_NONE; 573 break; 574 case 1: 575 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; 576 break; 577 case 2: 578 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; 579 break; 580 case 3: 581 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; 582 break; 583 default: 584 printk(KERN_ERR PFX "set_interfmode allowed parameters are: " 585 "0 => None, 1 => Non-WLAN, 2 => WLAN, " 586 "3 => Auto-WLAN\n"); 587 return -EINVAL; 588 } 589 590 mutex_lock(&bcm->mutex); 591 spin_lock_irqsave(&bcm->irq_lock, flags); 592 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { 593 err = bcm43xx_radio_set_interference_mitigation(bcm, mode); 594 if (err) { 595 printk(KERN_ERR PFX "Interference Mitigation not " 596 "supported by device\n"); 597 } 598 } else { 599 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) { 600 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN " 601 "not supported while the interface is down.\n"); 602 err = -ENODEV; 603 } else 604 bcm43xx_current_radio(bcm)->interfmode = mode; 605 } 606 spin_unlock_irqrestore(&bcm->irq_lock, flags); 607 mutex_unlock(&bcm->mutex); 608 609 return err; 610} 611 612static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, 613 struct iw_request_info *info, 614 union iwreq_data *data, 615 char *extra) 616{ 617 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 618 int mode; 619 620 mutex_lock(&bcm->mutex); 621 mode = bcm43xx_current_radio(bcm)->interfmode; 622 mutex_unlock(&bcm->mutex); 623 624 switch (mode) { 625 case BCM43xx_RADIO_INTERFMODE_NONE: 626 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING); 627 break; 628 case BCM43xx_RADIO_INTERFMODE_NONWLAN: 629 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING); 630 break; 631 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: 632 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING); 633 break; 634 default: 635 assert(0); 636 } 637 data->data.length = strlen(extra) + 1; 638 639 return 0; 640} 641 642static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, 643 struct iw_request_info *info, 644 union iwreq_data *data, 645 char *extra) 646{ 647 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 648 unsigned long flags; 649 int on; 650 651 on = *((int *)extra); 652 mutex_lock(&bcm->mutex); 653 spin_lock_irqsave(&bcm->irq_lock, flags); 654 bcm->short_preamble = !!on; 655 spin_unlock_irqrestore(&bcm->irq_lock, flags); 656 mutex_unlock(&bcm->mutex); 657 658 return 0; 659} 660 661static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, 662 struct iw_request_info *info, 663 union iwreq_data *data, 664 char *extra) 665{ 666 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 667 int on; 668 669 mutex_lock(&bcm->mutex); 670 on = bcm->short_preamble; 671 mutex_unlock(&bcm->mutex); 672 673 if (on) 674 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); 675 else 676 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING); 677 data->data.length = strlen(extra) + 1; 678 679 return 0; 680} 681 682static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, 683 struct iw_request_info *info, 684 union iwreq_data *data, 685 char *extra) 686{ 687 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 688 unsigned long flags; 689 int on; 690 691 on = *((int *)extra); 692 693 mutex_lock(&bcm->mutex); 694 spin_lock_irqsave(&bcm->irq_lock, flags); 695 bcm->ieee->host_encrypt = !!on; 696 bcm->ieee->host_decrypt = !!on; 697 bcm->ieee->host_build_iv = !on; 698 bcm->ieee->host_strip_iv_icv = !on; 699 spin_unlock_irqrestore(&bcm->irq_lock, flags); 700 mutex_unlock(&bcm->mutex); 701 702 return 0; 703} 704 705static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, 706 struct iw_request_info *info, 707 union iwreq_data *data, 708 char *extra) 709{ 710 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 711 int on; 712 713 mutex_lock(&bcm->mutex); 714 on = bcm->ieee->host_encrypt; 715 mutex_unlock(&bcm->mutex); 716 717 if (on) 718 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); 719 else 720 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); 721 data->data.length = strlen(extra + 1); 722 723 return 0; 724} 725 726/* Enough buffer to hold a hexdump of the sprom data. */ 727#define SPROM_BUFFERSIZE 512 728 729static int sprom2hex(const u16 *sprom, char *dump) 730{ 731 int i, pos = 0; 732 733 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { 734 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1, 735 "%04X", swab16(sprom[i]) & 0xFFFF); 736 } 737 738 return pos + 1; 739} 740 741static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) 742{ 743 char tmp[5] = { 0 }; 744 int cnt = 0; 745 unsigned long parsed; 746 747 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) 748 return -EINVAL; 749 while (cnt < BCM43xx_SPROM_SIZE) { 750 memcpy(tmp, dump, 4); 751 dump += 4; 752 parsed = simple_strtoul(tmp, NULL, 16); 753 sprom[cnt++] = swab16((u16)parsed); 754 } 755 756 return 0; 757} 758 759static int bcm43xx_wx_sprom_read(struct net_device *net_dev, 760 struct iw_request_info *info, 761 union iwreq_data *data, 762 char *extra) 763{ 764 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 765 int err = -EPERM; 766 u16 *sprom; 767 unsigned long flags; 768 769 if (!capable(CAP_SYS_RAWIO)) 770 goto out; 771 772 err = -ENOMEM; 773 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), 774 GFP_KERNEL); 775 if (!sprom) 776 goto out; 777 778 mutex_lock(&bcm->mutex); 779 spin_lock_irqsave(&bcm->irq_lock, flags); 780 err = -ENODEV; 781 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) 782 err = bcm43xx_sprom_read(bcm, sprom); 783 spin_unlock_irqrestore(&bcm->irq_lock, flags); 784 mutex_unlock(&bcm->mutex); 785 if (!err) 786 data->data.length = sprom2hex(sprom, extra); 787 kfree(sprom); 788out: 789 return err; 790} 791 792static int bcm43xx_wx_sprom_write(struct net_device *net_dev, 793 struct iw_request_info *info, 794 union iwreq_data *data, 795 char *extra) 796{ 797 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 798 int err = -EPERM; 799 u16 *sprom; 800 unsigned long flags; 801 char *input; 802 unsigned int len; 803 804 if (!capable(CAP_SYS_RAWIO)) 805 goto out; 806 807 err = -ENOMEM; 808 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), 809 GFP_KERNEL); 810 if (!sprom) 811 goto out; 812 813 len = data->data.length; 814 extra[len - 1] = '\0'; 815 input = strchr(extra, ':'); 816 if (input) { 817 input++; 818 len -= input - extra; 819 } else 820 input = extra; 821 err = hex2sprom(sprom, input, len); 822 if (err) 823 goto out_kfree; 824 825 mutex_lock(&bcm->mutex); 826 spin_lock_irqsave(&bcm->irq_lock, flags); 827 spin_lock(&bcm->leds_lock); 828 err = -ENODEV; 829 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) 830 err = bcm43xx_sprom_write(bcm, sprom); 831 spin_unlock(&bcm->leds_lock); 832 spin_unlock_irqrestore(&bcm->irq_lock, flags); 833 mutex_unlock(&bcm->mutex); 834out_kfree: 835 kfree(sprom); 836out: 837 return err; 838} 839 840/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ 841 842static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev) 843{ 844 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 845 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); 846 struct iw_statistics *wstats; 847 struct ieee80211_network *network = NULL; 848 static int tmp_level = 0; 849 static int tmp_qual = 0; 850 unsigned long flags; 851 852 wstats = &bcm->stats.wstats; 853 if (!mac->associnfo.associated) { 854 wstats->miss.beacon = 0; 855 wstats->discard.retries = 0; 856 wstats->discard.nwid = 0; 857 wstats->discard.code = 0; 858 wstats->discard.fragment = 0; 859 wstats->discard.misc = 0; 860 wstats->qual.qual = 0; 861 wstats->qual.level = 0; 862 wstats->qual.noise = 0; 863 wstats->qual.updated = 7; 864 wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 865 return wstats; 866 } 867 /* fill in the real statistics when iface associated */ 868 spin_lock_irqsave(&mac->ieee->lock, flags); 869 list_for_each_entry(network, &mac->ieee->network_list, list) { 870 if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) { 871 if (!tmp_level) { /* get initial values */ 872 tmp_level = network->stats.signal; 873 tmp_qual = network->stats.rssi; 874 } else { /* smooth results */ 875 tmp_level = (15 * tmp_level + network->stats.signal)/16; 876 tmp_qual = (15 * tmp_qual + network->stats.rssi)/16; 877 } 878 break; 879 } 880 } 881 spin_unlock_irqrestore(&mac->ieee->lock, flags); 882 wstats->qual.level = tmp_level; 883 wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX; 884 wstats->qual.noise = bcm->stats.noise; 885 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 886 wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; 887 wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; 888 wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; 889 wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments; 890 wstats->discard.misc = 0; 891 wstats->miss.beacon = 0; 892 return wstats; 893} 894 895 896#ifdef WX 897# undef WX 898#endif 899#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] 900static const iw_handler bcm43xx_wx_handlers[] = { 901 /* Wireless Identification */ 902 WX(SIOCGIWNAME) = bcm43xx_wx_get_name, 903 /* Basic operations */ 904 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq, 905 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq, 906 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode, 907 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode, 908 /* Informative stuff */ 909 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams, 910 /* Access Point manipulation */ 911 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, 912 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, 913 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, 914 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, 915 /* 802.11 specific support */ 916 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, 917 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, 918 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick, 919 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick, 920 /* Other parameters */ 921 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, 922 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, 923 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts, 924 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts, 925 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag, 926 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag, 927 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower, 928 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower, 929//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry, 930//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry, 931 /* Encoding */ 932 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding, 933 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding, 934 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext, 935 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext, 936 /* Power saving */ 937//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power, 938//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power, 939 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, 940 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, 941 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, 942 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, 943}; 944#undef WX 945 946static const iw_handler bcm43xx_priv_wx_handlers[] = { 947 /* Set Interference Mitigation Mode. */ 948 bcm43xx_wx_set_interfmode, 949 /* Get Interference Mitigation Mode. */ 950 bcm43xx_wx_get_interfmode, 951 /* Enable/Disable Short Preamble mode. */ 952 bcm43xx_wx_set_shortpreamble, 953 /* Get Short Preamble mode. */ 954 bcm43xx_wx_get_shortpreamble, 955 /* Enable/Disable Software Encryption mode */ 956 bcm43xx_wx_set_swencryption, 957 /* Get Software Encryption mode */ 958 bcm43xx_wx_get_swencryption, 959 /* Write SRPROM data. */ 960 bcm43xx_wx_sprom_write, 961 /* Read SPROM data. */ 962 bcm43xx_wx_sprom_read, 963}; 964 965#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0) 966#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1) 967#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2) 968#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3) 969#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4) 970#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5) 971#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6) 972#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7) 973 974#define PRIV_WX_DUMMY(ioctl) \ 975 { \ 976 .cmd = (ioctl), \ 977 .name = "__unused" \ 978 } 979 980static const struct iw_priv_args bcm43xx_priv_wx_args[] = { 981 { 982 .cmd = PRIV_WX_SET_INTERFMODE, 983 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 984 .name = "set_interfmode", 985 }, 986 { 987 .cmd = PRIV_WX_GET_INTERFMODE, 988 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 989 .name = "get_interfmode", 990 }, 991 { 992 .cmd = PRIV_WX_SET_SHORTPREAMBLE, 993 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 994 .name = "set_shortpreamb", 995 }, 996 { 997 .cmd = PRIV_WX_GET_SHORTPREAMBLE, 998 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 999 .name = "get_shortpreamb", 1000 }, 1001 { 1002 .cmd = PRIV_WX_SET_SWENCRYPTION, 1003 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 1004 .name = "set_swencrypt", 1005 }, 1006 { 1007 .cmd = PRIV_WX_GET_SWENCRYPTION, 1008 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 1009 .name = "get_swencrypt", 1010 }, 1011 { 1012 .cmd = PRIV_WX_SPROM_WRITE, 1013 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE, 1014 .name = "write_sprom", 1015 }, 1016 { 1017 .cmd = PRIV_WX_SPROM_READ, 1018 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE, 1019 .name = "read_sprom", 1020 }, 1021}; 1022 1023const struct iw_handler_def bcm43xx_wx_handlers_def = { 1024 .standard = bcm43xx_wx_handlers, 1025 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers), 1026 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers), 1027 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), 1028 .private = bcm43xx_priv_wx_handlers, 1029 .private_args = bcm43xx_priv_wx_args, 1030 .get_wireless_stats = bcm43xx_get_wireless_stats, 1031}; 1032