1/* Encapsulate basic setting changes and retrieval on Hermes hardware 2 * 3 * See copyright notice in main.c 4 */ 5#include <linux/kernel.h> 6#include <linux/device.h> 7#include <linux/if_arp.h> 8#include <linux/ieee80211.h> 9#include <linux/wireless.h> 10#include <net/cfg80211.h> 11#include "hermes.h" 12#include "hermes_rid.h" 13#include "orinoco.h" 14 15#include "hw.h" 16 17#define SYMBOL_MAX_VER_LEN (14) 18 19/* Symbol firmware has a bug allocating buffers larger than this */ 20#define TX_NICBUF_SIZE_BUG 1585 21 22/********************************************************************/ 23/* Data tables */ 24/********************************************************************/ 25 26/* This tables gives the actual meanings of the bitrate IDs returned 27 * by the firmware. */ 28static const struct { 29 int bitrate; /* in 100s of kilobits */ 30 int automatic; 31 u16 agere_txratectrl; 32 u16 intersil_txratectrl; 33} bitrate_table[] = { 34 {110, 1, 3, 15}, /* Entry 0 is the default */ 35 {10, 0, 1, 1}, 36 {10, 1, 1, 1}, 37 {20, 0, 2, 2}, 38 {20, 1, 6, 3}, 39 {55, 0, 4, 4}, 40 {55, 1, 7, 7}, 41 {110, 0, 5, 8}, 42}; 43#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) 44 45/* Firmware version encoding */ 46struct comp_id { 47 u16 id, variant, major, minor; 48} __packed; 49 50static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) 51{ 52 if (nic_id->id < 0x8000) 53 return FIRMWARE_TYPE_AGERE; 54 else if (nic_id->id == 0x8000 && nic_id->major == 0) 55 return FIRMWARE_TYPE_SYMBOL; 56 else 57 return FIRMWARE_TYPE_INTERSIL; 58} 59 60/* Set priv->firmware type, determine firmware properties 61 * This function can be called before we have registerred with netdev, 62 * so all errors go out with dev_* rather than printk 63 * 64 * If non-NULL stores a firmware description in fw_name. 65 * If non-NULL stores a HW version in hw_ver 66 * 67 * These are output via generic cfg80211 ethtool support. 68 */ 69int determine_fw_capabilities(struct orinoco_private *priv, 70 char *fw_name, size_t fw_name_len, 71 u32 *hw_ver) 72{ 73 struct device *dev = priv->dev; 74 hermes_t *hw = &priv->hw; 75 int err; 76 struct comp_id nic_id, sta_id; 77 unsigned int firmver; 78 char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); 79 80 /* Get the hardware version */ 81 err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); 82 if (err) { 83 dev_err(dev, "Cannot read hardware identity: error %d\n", 84 err); 85 return err; 86 } 87 88 le16_to_cpus(&nic_id.id); 89 le16_to_cpus(&nic_id.variant); 90 le16_to_cpus(&nic_id.major); 91 le16_to_cpus(&nic_id.minor); 92 dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", 93 nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); 94 95 if (hw_ver) 96 *hw_ver = (((nic_id.id & 0xff) << 24) | 97 ((nic_id.variant & 0xff) << 16) | 98 ((nic_id.major & 0xff) << 8) | 99 (nic_id.minor & 0xff)); 100 101 priv->firmware_type = determine_firmware_type(&nic_id); 102 103 /* Get the firmware version */ 104 err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); 105 if (err) { 106 dev_err(dev, "Cannot read station identity: error %d\n", 107 err); 108 return err; 109 } 110 111 le16_to_cpus(&sta_id.id); 112 le16_to_cpus(&sta_id.variant); 113 le16_to_cpus(&sta_id.major); 114 le16_to_cpus(&sta_id.minor); 115 dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n", 116 sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); 117 118 switch (sta_id.id) { 119 case 0x15: 120 dev_err(dev, "Primary firmware is active\n"); 121 return -ENODEV; 122 case 0x14b: 123 dev_err(dev, "Tertiary firmware is active\n"); 124 return -ENODEV; 125 case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ 126 case 0x21: /* Symbol Spectrum24 Trilogy */ 127 break; 128 default: 129 dev_notice(dev, "Unknown station ID, please report\n"); 130 break; 131 } 132 133 /* Default capabilities */ 134 priv->has_sensitivity = 1; 135 priv->has_mwo = 0; 136 priv->has_preamble = 0; 137 priv->has_port3 = 1; 138 priv->has_ibss = 1; 139 priv->has_wep = 0; 140 priv->has_big_wep = 0; 141 priv->has_alt_txcntl = 0; 142 priv->has_ext_scan = 0; 143 priv->has_wpa = 0; 144 priv->do_fw_download = 0; 145 146 /* Determine capabilities from the firmware version */ 147 switch (priv->firmware_type) { 148 case FIRMWARE_TYPE_AGERE: 149 /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, 150 ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ 151 if (fw_name) 152 snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d", 153 sta_id.major, sta_id.minor); 154 155 firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; 156 157 priv->has_ibss = (firmver >= 0x60006); 158 priv->has_wep = (firmver >= 0x40020); 159 priv->has_big_wep = 1; 160 priv->has_mwo = (firmver >= 0x60000); 161 priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ 162 priv->ibss_port = 1; 163 priv->has_hostscan = (firmver >= 0x8000a); 164 priv->do_fw_download = 1; 165 priv->broken_monitor = (firmver >= 0x80000); 166 priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ 167 priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ 168 priv->has_wpa = (firmver >= 0x9002a); 169 /* Tested with Agere firmware : 170 * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II 171 * Tested CableTron firmware : 4.32 => Anton */ 172 break; 173 case FIRMWARE_TYPE_SYMBOL: 174 /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ 175 /* Intel MAC : 00:02:B3:* */ 176 /* 3Com MAC : 00:50:DA:* */ 177 memset(tmp, 0, sizeof(tmp)); 178 /* Get the Symbol firmware version */ 179 err = hw->ops->read_ltv(hw, USER_BAP, 180 HERMES_RID_SECONDARYVERSION_SYMBOL, 181 SYMBOL_MAX_VER_LEN, NULL, &tmp); 182 if (err) { 183 dev_warn(dev, "Error %d reading Symbol firmware info. " 184 "Wildly guessing capabilities...\n", err); 185 firmver = 0; 186 tmp[0] = '\0'; 187 } else { 188 /* The firmware revision is a string, the format is 189 * something like : "V2.20-01". 190 * Quick and dirty parsing... - Jean II 191 */ 192 firmver = ((tmp[1] - '0') << 16) 193 | ((tmp[3] - '0') << 12) 194 | ((tmp[4] - '0') << 8) 195 | ((tmp[6] - '0') << 4) 196 | (tmp[7] - '0'); 197 198 tmp[SYMBOL_MAX_VER_LEN] = '\0'; 199 } 200 201 if (fw_name) 202 snprintf(fw_name, fw_name_len, "Symbol %s", tmp); 203 204 priv->has_ibss = (firmver >= 0x20000); 205 priv->has_wep = (firmver >= 0x15012); 206 priv->has_big_wep = (firmver >= 0x20000); 207 priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 208 (firmver >= 0x29000 && firmver < 0x30000) || 209 firmver >= 0x31000; 210 priv->has_preamble = (firmver >= 0x20000); 211 priv->ibss_port = 4; 212 213 /* Symbol firmware is found on various cards, but 214 * there has been no attempt to check firmware 215 * download on non-spectrum_cs based cards. 216 * 217 * Given that the Agere firmware download works 218 * differently, we should avoid doing a firmware 219 * download with the Symbol algorithm on non-spectrum 220 * cards. 221 * 222 * For now we can identify a spectrum_cs based card 223 * because it has a firmware reset function. 224 */ 225 priv->do_fw_download = (priv->stop_fw != NULL); 226 227 priv->broken_disableport = (firmver == 0x25013) || 228 (firmver >= 0x30000 && firmver <= 0x31000); 229 priv->has_hostscan = (firmver >= 0x31001) || 230 (firmver >= 0x29057 && firmver < 0x30000); 231 /* Tested with Intel firmware : 0x20015 => Jean II */ 232 /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ 233 break; 234 case FIRMWARE_TYPE_INTERSIL: 235 /* D-Link, Linksys, Adtron, ZoomAir, and many others... 236 * Samsung, Compaq 100/200 and Proxim are slightly 237 * different and less well tested */ 238 /* D-Link MAC : 00:40:05:* */ 239 /* Addtron MAC : 00:90:D1:* */ 240 if (fw_name) 241 snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d", 242 sta_id.major, sta_id.minor, sta_id.variant); 243 244 firmver = ((unsigned long)sta_id.major << 16) | 245 ((unsigned long)sta_id.minor << 8) | sta_id.variant; 246 247 priv->has_ibss = (firmver >= 0x000700); 248 priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); 249 priv->has_pm = (firmver >= 0x000700); 250 priv->has_hostscan = (firmver >= 0x010301); 251 252 if (firmver >= 0x000800) 253 priv->ibss_port = 0; 254 else { 255 dev_notice(dev, "Intersil firmware earlier than v0.8.x" 256 " - several features not supported\n"); 257 priv->ibss_port = 1; 258 } 259 break; 260 } 261 if (fw_name) 262 dev_info(dev, "Firmware determined as %s\n", fw_name); 263 264#ifndef CONFIG_HERMES_PRISM 265 if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { 266 dev_err(dev, "Support for Prism chipset is not enabled\n"); 267 return -ENODEV; 268 } 269#endif 270 271 return 0; 272} 273 274/* Read settings from EEPROM into our private structure. 275 * MAC address gets dropped into callers buffer 276 * Can be called before netdev registration. 277 */ 278int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) 279{ 280 struct device *dev = priv->dev; 281 struct hermes_idstring nickbuf; 282 hermes_t *hw = &priv->hw; 283 int len; 284 int err; 285 u16 reclen; 286 287 /* Get the MAC address */ 288 err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, 289 ETH_ALEN, NULL, dev_addr); 290 if (err) { 291 dev_warn(dev, "Failed to read MAC address!\n"); 292 goto out; 293 } 294 295 dev_dbg(dev, "MAC address %pM\n", dev_addr); 296 297 /* Get the station name */ 298 err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, 299 sizeof(nickbuf), &reclen, &nickbuf); 300 if (err) { 301 dev_err(dev, "failed to read station name\n"); 302 goto out; 303 } 304 if (nickbuf.len) 305 len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); 306 else 307 len = min(IW_ESSID_MAX_SIZE, 2 * reclen); 308 memcpy(priv->nick, &nickbuf.val, len); 309 priv->nick[len] = '\0'; 310 311 dev_dbg(dev, "Station name \"%s\"\n", priv->nick); 312 313 /* Get allowed channels */ 314 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, 315 &priv->channel_mask); 316 if (err) { 317 dev_err(dev, "Failed to read channel list!\n"); 318 goto out; 319 } 320 321 /* Get initial AP density */ 322 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, 323 &priv->ap_density); 324 if (err || priv->ap_density < 1 || priv->ap_density > 3) 325 priv->has_sensitivity = 0; 326 327 /* Get initial RTS threshold */ 328 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, 329 &priv->rts_thresh); 330 if (err) { 331 dev_err(dev, "Failed to read RTS threshold!\n"); 332 goto out; 333 } 334 335 /* Get initial fragmentation settings */ 336 if (priv->has_mwo) 337 err = hermes_read_wordrec(hw, USER_BAP, 338 HERMES_RID_CNFMWOROBUST_AGERE, 339 &priv->mwo_robust); 340 else 341 err = hermes_read_wordrec(hw, USER_BAP, 342 HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, 343 &priv->frag_thresh); 344 if (err) { 345 dev_err(dev, "Failed to read fragmentation settings!\n"); 346 goto out; 347 } 348 349 /* Power management setup */ 350 if (priv->has_pm) { 351 priv->pm_on = 0; 352 priv->pm_mcast = 1; 353 err = hermes_read_wordrec(hw, USER_BAP, 354 HERMES_RID_CNFMAXSLEEPDURATION, 355 &priv->pm_period); 356 if (err) { 357 dev_err(dev, "Failed to read power management " 358 "period!\n"); 359 goto out; 360 } 361 err = hermes_read_wordrec(hw, USER_BAP, 362 HERMES_RID_CNFPMHOLDOVERDURATION, 363 &priv->pm_timeout); 364 if (err) { 365 dev_err(dev, "Failed to read power management " 366 "timeout!\n"); 367 goto out; 368 } 369 } 370 371 /* Preamble setup */ 372 if (priv->has_preamble) { 373 err = hermes_read_wordrec(hw, USER_BAP, 374 HERMES_RID_CNFPREAMBLE_SYMBOL, 375 &priv->preamble); 376 if (err) { 377 dev_err(dev, "Failed to read preamble setup\n"); 378 goto out; 379 } 380 } 381 382 /* Retry settings */ 383 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, 384 &priv->short_retry_limit); 385 if (err) { 386 dev_err(dev, "Failed to read short retry limit\n"); 387 goto out; 388 } 389 390 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, 391 &priv->long_retry_limit); 392 if (err) { 393 dev_err(dev, "Failed to read long retry limit\n"); 394 goto out; 395 } 396 397 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, 398 &priv->retry_lifetime); 399 if (err) { 400 dev_err(dev, "Failed to read max retry lifetime\n"); 401 goto out; 402 } 403 404out: 405 return err; 406} 407 408/* Can be called before netdev registration */ 409int orinoco_hw_allocate_fid(struct orinoco_private *priv) 410{ 411 struct device *dev = priv->dev; 412 struct hermes *hw = &priv->hw; 413 int err; 414 415 err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); 416 if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { 417 priv->nicbuf_size = TX_NICBUF_SIZE_BUG; 418 err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid); 419 420 dev_warn(dev, "Firmware ALLOC bug detected " 421 "(old Symbol firmware?). Work around %s\n", 422 err ? "failed!" : "ok."); 423 } 424 425 return err; 426} 427 428int orinoco_get_bitratemode(int bitrate, int automatic) 429{ 430 int ratemode = -1; 431 int i; 432 433 if ((bitrate != 10) && (bitrate != 20) && 434 (bitrate != 55) && (bitrate != 110)) 435 return ratemode; 436 437 for (i = 0; i < BITRATE_TABLE_SIZE; i++) { 438 if ((bitrate_table[i].bitrate == bitrate) && 439 (bitrate_table[i].automatic == automatic)) { 440 ratemode = i; 441 break; 442 } 443 } 444 return ratemode; 445} 446 447void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) 448{ 449 BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); 450 451 *bitrate = bitrate_table[ratemode].bitrate * 100000; 452 *automatic = bitrate_table[ratemode].automatic; 453} 454 455int orinoco_hw_program_rids(struct orinoco_private *priv) 456{ 457 struct net_device *dev = priv->ndev; 458 struct wireless_dev *wdev = netdev_priv(dev); 459 hermes_t *hw = &priv->hw; 460 int err; 461 struct hermes_idstring idbuf; 462 463 /* Set the MAC address */ 464 err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, 465 HERMES_BYTES_TO_RECLEN(ETH_ALEN), 466 dev->dev_addr); 467 if (err) { 468 printk(KERN_ERR "%s: Error %d setting MAC address\n", 469 dev->name, err); 470 return err; 471 } 472 473 /* Set up the link mode */ 474 err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, 475 priv->port_type); 476 if (err) { 477 printk(KERN_ERR "%s: Error %d setting port type\n", 478 dev->name, err); 479 return err; 480 } 481 /* Set the channel/frequency */ 482 if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) { 483 err = hermes_write_wordrec(hw, USER_BAP, 484 HERMES_RID_CNFOWNCHANNEL, 485 priv->channel); 486 if (err) { 487 printk(KERN_ERR "%s: Error %d setting channel %d\n", 488 dev->name, err, priv->channel); 489 return err; 490 } 491 } 492 493 if (priv->has_ibss) { 494 u16 createibss; 495 496 if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { 497 printk(KERN_WARNING "%s: This firmware requires an " 498 "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); 499 /* With wvlan_cs, in this case, we would crash. 500 * hopefully, this driver will behave better... 501 * Jean II */ 502 createibss = 0; 503 } else { 504 createibss = priv->createibss; 505 } 506 507 err = hermes_write_wordrec(hw, USER_BAP, 508 HERMES_RID_CNFCREATEIBSS, 509 createibss); 510 if (err) { 511 printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", 512 dev->name, err); 513 return err; 514 } 515 } 516 517 /* Set the desired BSSID */ 518 err = __orinoco_hw_set_wap(priv); 519 if (err) { 520 printk(KERN_ERR "%s: Error %d setting AP address\n", 521 dev->name, err); 522 return err; 523 } 524 525 /* Set the desired ESSID */ 526 idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); 527 memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); 528 /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ 529 err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, 530 HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), 531 &idbuf); 532 if (err) { 533 printk(KERN_ERR "%s: Error %d setting OWNSSID\n", 534 dev->name, err); 535 return err; 536 } 537 err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, 538 HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), 539 &idbuf); 540 if (err) { 541 printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", 542 dev->name, err); 543 return err; 544 } 545 546 /* Set the station name */ 547 idbuf.len = cpu_to_le16(strlen(priv->nick)); 548 memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); 549 err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, 550 HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), 551 &idbuf); 552 if (err) { 553 printk(KERN_ERR "%s: Error %d setting nickname\n", 554 dev->name, err); 555 return err; 556 } 557 558 /* Set AP density */ 559 if (priv->has_sensitivity) { 560 err = hermes_write_wordrec(hw, USER_BAP, 561 HERMES_RID_CNFSYSTEMSCALE, 562 priv->ap_density); 563 if (err) { 564 printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " 565 "Disabling sensitivity control\n", 566 dev->name, err); 567 568 priv->has_sensitivity = 0; 569 } 570 } 571 572 /* Set RTS threshold */ 573 err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, 574 priv->rts_thresh); 575 if (err) { 576 printk(KERN_ERR "%s: Error %d setting RTS threshold\n", 577 dev->name, err); 578 return err; 579 } 580 581 /* Set fragmentation threshold or MWO robustness */ 582 if (priv->has_mwo) 583 err = hermes_write_wordrec(hw, USER_BAP, 584 HERMES_RID_CNFMWOROBUST_AGERE, 585 priv->mwo_robust); 586 else 587 err = hermes_write_wordrec(hw, USER_BAP, 588 HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, 589 priv->frag_thresh); 590 if (err) { 591 printk(KERN_ERR "%s: Error %d setting fragmentation\n", 592 dev->name, err); 593 return err; 594 } 595 596 /* Set bitrate */ 597 err = __orinoco_hw_set_bitrate(priv); 598 if (err) { 599 printk(KERN_ERR "%s: Error %d setting bitrate\n", 600 dev->name, err); 601 return err; 602 } 603 604 /* Set power management */ 605 if (priv->has_pm) { 606 err = hermes_write_wordrec(hw, USER_BAP, 607 HERMES_RID_CNFPMENABLED, 608 priv->pm_on); 609 if (err) { 610 printk(KERN_ERR "%s: Error %d setting up PM\n", 611 dev->name, err); 612 return err; 613 } 614 615 err = hermes_write_wordrec(hw, USER_BAP, 616 HERMES_RID_CNFMULTICASTRECEIVE, 617 priv->pm_mcast); 618 if (err) { 619 printk(KERN_ERR "%s: Error %d setting up PM\n", 620 dev->name, err); 621 return err; 622 } 623 err = hermes_write_wordrec(hw, USER_BAP, 624 HERMES_RID_CNFMAXSLEEPDURATION, 625 priv->pm_period); 626 if (err) { 627 printk(KERN_ERR "%s: Error %d setting up PM\n", 628 dev->name, err); 629 return err; 630 } 631 err = hermes_write_wordrec(hw, USER_BAP, 632 HERMES_RID_CNFPMHOLDOVERDURATION, 633 priv->pm_timeout); 634 if (err) { 635 printk(KERN_ERR "%s: Error %d setting up PM\n", 636 dev->name, err); 637 return err; 638 } 639 } 640 641 /* Set preamble - only for Symbol so far... */ 642 if (priv->has_preamble) { 643 err = hermes_write_wordrec(hw, USER_BAP, 644 HERMES_RID_CNFPREAMBLE_SYMBOL, 645 priv->preamble); 646 if (err) { 647 printk(KERN_ERR "%s: Error %d setting preamble\n", 648 dev->name, err); 649 return err; 650 } 651 } 652 653 /* Set up encryption */ 654 if (priv->has_wep || priv->has_wpa) { 655 err = __orinoco_hw_setup_enc(priv); 656 if (err) { 657 printk(KERN_ERR "%s: Error %d activating encryption\n", 658 dev->name, err); 659 return err; 660 } 661 } 662 663 if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { 664 /* Enable monitor mode */ 665 dev->type = ARPHRD_IEEE80211; 666 err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | 667 HERMES_TEST_MONITOR, 0, NULL); 668 } else { 669 /* Disable monitor mode */ 670 dev->type = ARPHRD_ETHER; 671 err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | 672 HERMES_TEST_STOP, 0, NULL); 673 } 674 if (err) 675 return err; 676 677 /* Reset promiscuity / multicast*/ 678 priv->promiscuous = 0; 679 priv->mc_count = 0; 680 681 /* Record mode change */ 682 wdev->iftype = priv->iw_mode; 683 684 return 0; 685} 686 687/* Get tsc from the firmware */ 688int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) 689{ 690 hermes_t *hw = &priv->hw; 691 int err = 0; 692 u8 tsc_arr[4][ORINOCO_SEQ_LEN]; 693 694 if ((key < 0) || (key >= 4)) 695 return -EINVAL; 696 697 err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, 698 sizeof(tsc_arr), NULL, &tsc_arr); 699 if (!err) 700 memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); 701 702 return err; 703} 704 705int __orinoco_hw_set_bitrate(struct orinoco_private *priv) 706{ 707 hermes_t *hw = &priv->hw; 708 int ratemode = priv->bitratemode; 709 int err = 0; 710 711 if (ratemode >= BITRATE_TABLE_SIZE) { 712 printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", 713 priv->ndev->name, ratemode); 714 return -EINVAL; 715 } 716 717 switch (priv->firmware_type) { 718 case FIRMWARE_TYPE_AGERE: 719 err = hermes_write_wordrec(hw, USER_BAP, 720 HERMES_RID_CNFTXRATECONTROL, 721 bitrate_table[ratemode].agere_txratectrl); 722 break; 723 case FIRMWARE_TYPE_INTERSIL: 724 case FIRMWARE_TYPE_SYMBOL: 725 err = hermes_write_wordrec(hw, USER_BAP, 726 HERMES_RID_CNFTXRATECONTROL, 727 bitrate_table[ratemode].intersil_txratectrl); 728 break; 729 default: 730 BUG(); 731 } 732 733 return err; 734} 735 736int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) 737{ 738 hermes_t *hw = &priv->hw; 739 int i; 740 int err = 0; 741 u16 val; 742 743 err = hermes_read_wordrec(hw, USER_BAP, 744 HERMES_RID_CURRENTTXRATE, &val); 745 if (err) 746 return err; 747 748 switch (priv->firmware_type) { 749 case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ 750 /* Note : in Lucent firmware, the return value of 751 * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, 752 * and therefore is totally different from the 753 * encoding of HERMES_RID_CNFTXRATECONTROL. 754 * Don't forget that 6Mb/s is really 5.5Mb/s */ 755 if (val == 6) 756 *bitrate = 5500000; 757 else 758 *bitrate = val * 1000000; 759 break; 760 case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ 761 case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ 762 for (i = 0; i < BITRATE_TABLE_SIZE; i++) 763 if (bitrate_table[i].intersil_txratectrl == val) 764 break; 765 766 if (i >= BITRATE_TABLE_SIZE) 767 printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", 768 priv->ndev->name, val); 769 770 *bitrate = bitrate_table[i].bitrate * 100000; 771 break; 772 default: 773 BUG(); 774 } 775 776 return err; 777} 778 779/* Set fixed AP address */ 780int __orinoco_hw_set_wap(struct orinoco_private *priv) 781{ 782 int roaming_flag; 783 int err = 0; 784 hermes_t *hw = &priv->hw; 785 786 switch (priv->firmware_type) { 787 case FIRMWARE_TYPE_AGERE: 788 /* not supported */ 789 break; 790 case FIRMWARE_TYPE_INTERSIL: 791 if (priv->bssid_fixed) 792 roaming_flag = 2; 793 else 794 roaming_flag = 1; 795 796 err = hermes_write_wordrec(hw, USER_BAP, 797 HERMES_RID_CNFROAMINGMODE, 798 roaming_flag); 799 break; 800 case FIRMWARE_TYPE_SYMBOL: 801 err = HERMES_WRITE_RECORD(hw, USER_BAP, 802 HERMES_RID_CNFMANDATORYBSSID_SYMBOL, 803 &priv->desired_bssid); 804 break; 805 } 806 return err; 807} 808 809/* Change the WEP keys and/or the current keys. Can be called 810 * either from __orinoco_hw_setup_enc() or directly from 811 * orinoco_ioctl_setiwencode(). In the later case the association 812 * with the AP is not broken (if the firmware can handle it), 813 * which is needed for 802.1x implementations. */ 814int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) 815{ 816 hermes_t *hw = &priv->hw; 817 int err = 0; 818 int i; 819 820 switch (priv->firmware_type) { 821 case FIRMWARE_TYPE_AGERE: 822 { 823 struct orinoco_key keys[ORINOCO_MAX_KEYS]; 824 825 memset(&keys, 0, sizeof(keys)); 826 for (i = 0; i < ORINOCO_MAX_KEYS; i++) { 827 int len = min(priv->keys[i].key_len, 828 ORINOCO_MAX_KEY_SIZE); 829 memcpy(&keys[i].data, priv->keys[i].key, len); 830 if (len > SMALL_KEY_SIZE) 831 keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); 832 else if (len > 0) 833 keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); 834 else 835 keys[i].len = cpu_to_le16(0); 836 } 837 838 err = HERMES_WRITE_RECORD(hw, USER_BAP, 839 HERMES_RID_CNFWEPKEYS_AGERE, 840 &keys); 841 if (err) 842 return err; 843 err = hermes_write_wordrec(hw, USER_BAP, 844 HERMES_RID_CNFTXKEY_AGERE, 845 priv->tx_key); 846 if (err) 847 return err; 848 break; 849 } 850 case FIRMWARE_TYPE_INTERSIL: 851 case FIRMWARE_TYPE_SYMBOL: 852 { 853 int keylen; 854 855 keylen = priv->keys[priv->tx_key].key_len; 856 857 if (keylen > LARGE_KEY_SIZE) { 858 printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", 859 priv->ndev->name, priv->tx_key, keylen); 860 return -E2BIG; 861 } else if (keylen > SMALL_KEY_SIZE) 862 keylen = LARGE_KEY_SIZE; 863 else if (keylen > 0) 864 keylen = SMALL_KEY_SIZE; 865 else 866 keylen = 0; 867 868 /* Write all 4 keys */ 869 for (i = 0; i < ORINOCO_MAX_KEYS; i++) { 870 u8 key[LARGE_KEY_SIZE] = { 0 }; 871 872 memcpy(key, priv->keys[i].key, 873 priv->keys[i].key_len); 874 875 err = hw->ops->write_ltv(hw, USER_BAP, 876 HERMES_RID_CNFDEFAULTKEY0 + i, 877 HERMES_BYTES_TO_RECLEN(keylen), 878 key); 879 if (err) 880 return err; 881 } 882 883 /* Write the index of the key used in transmission */ 884 err = hermes_write_wordrec(hw, USER_BAP, 885 HERMES_RID_CNFWEPDEFAULTKEYID, 886 priv->tx_key); 887 if (err) 888 return err; 889 } 890 break; 891 } 892 893 return 0; 894} 895 896int __orinoco_hw_setup_enc(struct orinoco_private *priv) 897{ 898 hermes_t *hw = &priv->hw; 899 int err = 0; 900 int master_wep_flag; 901 int auth_flag; 902 int enc_flag; 903 904 /* Setup WEP keys */ 905 if (priv->encode_alg == ORINOCO_ALG_WEP) 906 __orinoco_hw_setup_wepkeys(priv); 907 908 if (priv->wep_restrict) 909 auth_flag = HERMES_AUTH_SHARED_KEY; 910 else 911 auth_flag = HERMES_AUTH_OPEN; 912 913 if (priv->wpa_enabled) 914 enc_flag = 2; 915 else if (priv->encode_alg == ORINOCO_ALG_WEP) 916 enc_flag = 1; 917 else 918 enc_flag = 0; 919 920 switch (priv->firmware_type) { 921 case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ 922 if (priv->encode_alg == ORINOCO_ALG_WEP) { 923 /* Enable the shared-key authentication. */ 924 err = hermes_write_wordrec(hw, USER_BAP, 925 HERMES_RID_CNFAUTHENTICATION_AGERE, 926 auth_flag); 927 } 928 err = hermes_write_wordrec(hw, USER_BAP, 929 HERMES_RID_CNFWEPENABLED_AGERE, 930 enc_flag); 931 if (err) 932 return err; 933 934 if (priv->has_wpa) { 935 /* Set WPA key management */ 936 err = hermes_write_wordrec(hw, USER_BAP, 937 HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, 938 priv->key_mgmt); 939 if (err) 940 return err; 941 } 942 943 break; 944 945 case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ 946 case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ 947 if (priv->encode_alg == ORINOCO_ALG_WEP) { 948 if (priv->wep_restrict || 949 (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) 950 master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | 951 HERMES_WEP_EXCL_UNENCRYPTED; 952 else 953 master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; 954 955 err = hermes_write_wordrec(hw, USER_BAP, 956 HERMES_RID_CNFAUTHENTICATION, 957 auth_flag); 958 if (err) 959 return err; 960 } else 961 master_wep_flag = 0; 962 963 if (priv->iw_mode == NL80211_IFTYPE_MONITOR) 964 master_wep_flag |= HERMES_WEP_HOST_DECRYPT; 965 966 /* Master WEP setting : on/off */ 967 err = hermes_write_wordrec(hw, USER_BAP, 968 HERMES_RID_CNFWEPFLAGS_INTERSIL, 969 master_wep_flag); 970 if (err) 971 return err; 972 973 break; 974 } 975 976 return 0; 977} 978 979/* key must be 32 bytes, including the tx and rx MIC keys. 980 * rsc must be NULL or up to 8 bytes 981 * tsc must be NULL or up to 8 bytes 982 */ 983int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, 984 int set_tx, u8 *key, u8 *rsc, size_t rsc_len, 985 u8 *tsc, size_t tsc_len) 986{ 987 struct { 988 __le16 idx; 989 u8 rsc[ORINOCO_SEQ_LEN]; 990 u8 key[TKIP_KEYLEN]; 991 u8 tx_mic[MIC_KEYLEN]; 992 u8 rx_mic[MIC_KEYLEN]; 993 u8 tsc[ORINOCO_SEQ_LEN]; 994 } __packed buf; 995 hermes_t *hw = &priv->hw; 996 int ret; 997 int err; 998 int k; 999 u16 xmitting; 1000 1001 key_idx &= 0x3; 1002 1003 if (set_tx) 1004 key_idx |= 0x8000; 1005 1006 buf.idx = cpu_to_le16(key_idx); 1007 memcpy(buf.key, key, 1008 sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); 1009 1010 if (rsc_len > sizeof(buf.rsc)) 1011 rsc_len = sizeof(buf.rsc); 1012 1013 if (tsc_len > sizeof(buf.tsc)) 1014 tsc_len = sizeof(buf.tsc); 1015 1016 memset(buf.rsc, 0, sizeof(buf.rsc)); 1017 memset(buf.tsc, 0, sizeof(buf.tsc)); 1018 1019 if (rsc != NULL) 1020 memcpy(buf.rsc, rsc, rsc_len); 1021 1022 if (tsc != NULL) 1023 memcpy(buf.tsc, tsc, tsc_len); 1024 else 1025 buf.tsc[4] = 0x10; 1026 1027 /* Wait upto 100ms for tx queue to empty */ 1028 for (k = 100; k > 0; k--) { 1029 udelay(1000); 1030 ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, 1031 &xmitting); 1032 if (ret || !xmitting) 1033 break; 1034 } 1035 1036 if (k == 0) 1037 ret = -ETIMEDOUT; 1038 1039 err = HERMES_WRITE_RECORD(hw, USER_BAP, 1040 HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, 1041 &buf); 1042 1043 return ret ? ret : err; 1044} 1045 1046int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) 1047{ 1048 hermes_t *hw = &priv->hw; 1049 int err; 1050 1051 err = hermes_write_wordrec(hw, USER_BAP, 1052 HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, 1053 key_idx); 1054 if (err) 1055 printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", 1056 priv->ndev->name, err, key_idx); 1057 return err; 1058} 1059 1060int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, 1061 struct net_device *dev, 1062 int mc_count, int promisc) 1063{ 1064 hermes_t *hw = &priv->hw; 1065 int err = 0; 1066 1067 if (promisc != priv->promiscuous) { 1068 err = hermes_write_wordrec(hw, USER_BAP, 1069 HERMES_RID_CNFPROMISCUOUSMODE, 1070 promisc); 1071 if (err) { 1072 printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", 1073 priv->ndev->name, err); 1074 } else 1075 priv->promiscuous = promisc; 1076 } 1077 1078 /* If we're not in promiscuous mode, then we need to set the 1079 * group address if either we want to multicast, or if we were 1080 * multicasting and want to stop */ 1081 if (!promisc && (mc_count || priv->mc_count)) { 1082 struct netdev_hw_addr *ha; 1083 struct hermes_multicast mclist; 1084 int i = 0; 1085 1086 netdev_for_each_mc_addr(ha, dev) { 1087 if (i == mc_count) 1088 break; 1089 memcpy(mclist.addr[i++], ha->addr, ETH_ALEN); 1090 } 1091 1092 err = hw->ops->write_ltv(hw, USER_BAP, 1093 HERMES_RID_CNFGROUPADDRESSES, 1094 HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), 1095 &mclist); 1096 if (err) 1097 printk(KERN_ERR "%s: Error %d setting multicast list.\n", 1098 priv->ndev->name, err); 1099 else 1100 priv->mc_count = mc_count; 1101 } 1102 return err; 1103} 1104 1105/* Return : < 0 -> error code ; >= 0 -> length */ 1106int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, 1107 char buf[IW_ESSID_MAX_SIZE+1]) 1108{ 1109 hermes_t *hw = &priv->hw; 1110 int err = 0; 1111 struct hermes_idstring essidbuf; 1112 char *p = (char *)(&essidbuf.val); 1113 int len; 1114 unsigned long flags; 1115 1116 if (orinoco_lock(priv, &flags) != 0) 1117 return -EBUSY; 1118 1119 if (strlen(priv->desired_essid) > 0) { 1120 /* We read the desired SSID from the hardware rather 1121 than from priv->desired_essid, just in case the 1122 firmware is allowed to change it on us. I'm not 1123 sure about this */ 1124 /* My guess is that the OWNSSID should always be whatever 1125 * we set to the card, whereas CURRENT_SSID is the one that 1126 * may change... - Jean II */ 1127 u16 rid; 1128 1129 *active = 1; 1130 1131 rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : 1132 HERMES_RID_CNFDESIREDSSID; 1133 1134 err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), 1135 NULL, &essidbuf); 1136 if (err) 1137 goto fail_unlock; 1138 } else { 1139 *active = 0; 1140 1141 err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, 1142 sizeof(essidbuf), NULL, &essidbuf); 1143 if (err) 1144 goto fail_unlock; 1145 } 1146 1147 len = le16_to_cpu(essidbuf.len); 1148 BUG_ON(len > IW_ESSID_MAX_SIZE); 1149 1150 memset(buf, 0, IW_ESSID_MAX_SIZE); 1151 memcpy(buf, p, len); 1152 err = len; 1153 1154 fail_unlock: 1155 orinoco_unlock(priv, &flags); 1156 1157 return err; 1158} 1159 1160int orinoco_hw_get_freq(struct orinoco_private *priv) 1161{ 1162 hermes_t *hw = &priv->hw; 1163 int err = 0; 1164 u16 channel; 1165 int freq = 0; 1166 unsigned long flags; 1167 1168 if (orinoco_lock(priv, &flags) != 0) 1169 return -EBUSY; 1170 1171 err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, 1172 &channel); 1173 if (err) 1174 goto out; 1175 1176 /* Intersil firmware 1.3.5 returns 0 when the interface is down */ 1177 if (channel == 0) { 1178 err = -EBUSY; 1179 goto out; 1180 } 1181 1182 if ((channel < 1) || (channel > NUM_CHANNELS)) { 1183 printk(KERN_WARNING "%s: Channel out of range (%d)!\n", 1184 priv->ndev->name, channel); 1185 err = -EBUSY; 1186 goto out; 1187 1188 } 1189 freq = ieee80211_dsss_chan_to_freq(channel); 1190 1191 out: 1192 orinoco_unlock(priv, &flags); 1193 1194 if (err > 0) 1195 err = -EBUSY; 1196 return err ? err : freq; 1197} 1198 1199int orinoco_hw_get_bitratelist(struct orinoco_private *priv, 1200 int *numrates, s32 *rates, int max) 1201{ 1202 hermes_t *hw = &priv->hw; 1203 struct hermes_idstring list; 1204 unsigned char *p = (unsigned char *)&list.val; 1205 int err = 0; 1206 int num; 1207 int i; 1208 unsigned long flags; 1209 1210 if (orinoco_lock(priv, &flags) != 0) 1211 return -EBUSY; 1212 1213 err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, 1214 sizeof(list), NULL, &list); 1215 orinoco_unlock(priv, &flags); 1216 1217 if (err) 1218 return err; 1219 1220 num = le16_to_cpu(list.len); 1221 *numrates = num; 1222 num = min(num, max); 1223 1224 for (i = 0; i < num; i++) 1225 rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ 1226 1227 return 0; 1228} 1229 1230int orinoco_hw_trigger_scan(struct orinoco_private *priv, 1231 const struct cfg80211_ssid *ssid) 1232{ 1233 struct net_device *dev = priv->ndev; 1234 hermes_t *hw = &priv->hw; 1235 unsigned long flags; 1236 int err = 0; 1237 1238 if (orinoco_lock(priv, &flags) != 0) 1239 return -EBUSY; 1240 1241 /* Scanning with port 0 disabled would fail */ 1242 if (!netif_running(dev)) { 1243 err = -ENETDOWN; 1244 goto out; 1245 } 1246 1247 /* In monitor mode, the scan results are always empty. 1248 * Probe responses are passed to the driver as received 1249 * frames and could be processed in software. */ 1250 if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { 1251 err = -EOPNOTSUPP; 1252 goto out; 1253 } 1254 1255 if (priv->has_hostscan) { 1256 switch (priv->firmware_type) { 1257 case FIRMWARE_TYPE_SYMBOL: 1258 err = hermes_write_wordrec(hw, USER_BAP, 1259 HERMES_RID_CNFHOSTSCAN_SYMBOL, 1260 HERMES_HOSTSCAN_SYMBOL_ONCE | 1261 HERMES_HOSTSCAN_SYMBOL_BCAST); 1262 break; 1263 case FIRMWARE_TYPE_INTERSIL: { 1264 __le16 req[3]; 1265 1266 req[0] = cpu_to_le16(0x3fff); /* All channels */ 1267 req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ 1268 req[2] = 0; /* Any ESSID */ 1269 err = HERMES_WRITE_RECORD(hw, USER_BAP, 1270 HERMES_RID_CNFHOSTSCAN, &req); 1271 break; 1272 } 1273 case FIRMWARE_TYPE_AGERE: 1274 if (ssid->ssid_len > 0) { 1275 struct hermes_idstring idbuf; 1276 size_t len = ssid->ssid_len; 1277 1278 idbuf.len = cpu_to_le16(len); 1279 memcpy(idbuf.val, ssid->ssid, len); 1280 1281 err = hw->ops->write_ltv(hw, USER_BAP, 1282 HERMES_RID_CNFSCANSSID_AGERE, 1283 HERMES_BYTES_TO_RECLEN(len + 2), 1284 &idbuf); 1285 } else 1286 err = hermes_write_wordrec(hw, USER_BAP, 1287 HERMES_RID_CNFSCANSSID_AGERE, 1288 0); /* Any ESSID */ 1289 if (err) 1290 break; 1291 1292 if (priv->has_ext_scan) { 1293 err = hermes_write_wordrec(hw, USER_BAP, 1294 HERMES_RID_CNFSCANCHANNELS2GHZ, 1295 0x7FFF); 1296 if (err) 1297 goto out; 1298 1299 err = hermes_inquire(hw, 1300 HERMES_INQ_CHANNELINFO); 1301 } else 1302 err = hermes_inquire(hw, HERMES_INQ_SCAN); 1303 1304 break; 1305 } 1306 } else 1307 err = hermes_inquire(hw, HERMES_INQ_SCAN); 1308 1309 out: 1310 orinoco_unlock(priv, &flags); 1311 1312 return err; 1313} 1314 1315/* Disassociate from node with BSSID addr */ 1316int orinoco_hw_disassociate(struct orinoco_private *priv, 1317 u8 *addr, u16 reason_code) 1318{ 1319 hermes_t *hw = &priv->hw; 1320 int err; 1321 1322 struct { 1323 u8 addr[ETH_ALEN]; 1324 __le16 reason_code; 1325 } __packed buf; 1326 1327 /* Currently only supported by WPA enabled Agere fw */ 1328 if (!priv->has_wpa) 1329 return -EOPNOTSUPP; 1330 1331 memcpy(buf.addr, addr, ETH_ALEN); 1332 buf.reason_code = cpu_to_le16(reason_code); 1333 err = HERMES_WRITE_RECORD(hw, USER_BAP, 1334 HERMES_RID_CNFDISASSOCIATE, 1335 &buf); 1336 return err; 1337} 1338 1339int orinoco_hw_get_current_bssid(struct orinoco_private *priv, 1340 u8 *addr) 1341{ 1342 hermes_t *hw = &priv->hw; 1343 int err; 1344 1345 err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, 1346 ETH_ALEN, NULL, addr); 1347 1348 return err; 1349} 1350