1/* 2 * Copyright (C) 2002 Intersil Americas Inc. 3 * (C) 2003,2004 Aurelien Alleaume <slts@free.fr> 4 * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> 5 * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21#include <linux/capability.h> 22#include <linux/module.h> 23#include <linux/kernel.h> 24#include <linux/if_arp.h> 25#include <linux/slab.h> 26#include <linux/pci.h> 27#include <linux/etherdevice.h> 28 29#include <linux/uaccess.h> 30 31#include "prismcompat.h" 32#include "isl_ioctl.h" 33#include "islpci_mgt.h" 34#include "isl_oid.h" /* additional types and defs for isl38xx fw */ 35#include "oid_mgt.h" 36 37#include <net/iw_handler.h> /* New driver API */ 38 39#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ 40#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ 41/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */ 42#define KEY_SIZE_TKIP 32 /* TKIP keys */ 43 44static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, 45 u8 *wpa_ie, size_t wpa_ie_len); 46static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); 47static int prism54_set_wpa(struct net_device *, struct iw_request_info *, 48 __u32 *, char *); 49 50/* In 500 kbps */ 51static const unsigned char scan_rate_list[] = { 2, 4, 11, 22, 52 12, 18, 24, 36, 53 48, 72, 96, 108 }; 54 55/** 56 * prism54_mib_mode_helper - MIB change mode helper function 57 * @mib: the &struct islpci_mib object to modify 58 * @iw_mode: new mode (%IW_MODE_*) 59 * 60 * This is a helper function, hence it does not lock. Make sure 61 * caller deals with locking *if* necessary. This function sets the 62 * mode-dependent mib values and does the mapping of the Linux 63 * Wireless API modes to Device firmware modes. It also checks for 64 * correct valid Linux wireless modes. 65 */ 66static int 67prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) 68{ 69 u32 config = INL_CONFIG_MANUALRUN; 70 u32 mode, bsstype; 71 72 /* For now, just catch early the Repeater and Secondary modes here */ 73 if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { 74 printk(KERN_DEBUG 75 "%s(): Sorry, Repeater mode and Secondary mode " 76 "are not yet supported by this driver.\n", __func__); 77 return -EINVAL; 78 } 79 80 priv->iw_mode = iw_mode; 81 82 switch (iw_mode) { 83 case IW_MODE_AUTO: 84 mode = INL_MODE_CLIENT; 85 bsstype = DOT11_BSSTYPE_ANY; 86 break; 87 case IW_MODE_ADHOC: 88 mode = INL_MODE_CLIENT; 89 bsstype = DOT11_BSSTYPE_IBSS; 90 break; 91 case IW_MODE_INFRA: 92 mode = INL_MODE_CLIENT; 93 bsstype = DOT11_BSSTYPE_INFRA; 94 break; 95 case IW_MODE_MASTER: 96 mode = INL_MODE_AP; 97 bsstype = DOT11_BSSTYPE_INFRA; 98 break; 99 case IW_MODE_MONITOR: 100 mode = INL_MODE_PROMISCUOUS; 101 bsstype = DOT11_BSSTYPE_ANY; 102 config |= INL_CONFIG_RXANNEX; 103 break; 104 default: 105 return -EINVAL; 106 } 107 108 if (init_wds) 109 config |= INL_CONFIG_WDS; 110 mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); 111 mgt_set(priv, OID_INL_CONFIG, &config); 112 mgt_set(priv, OID_INL_MODE, &mode); 113 114 return 0; 115} 116 117/** 118 * prism54_mib_init - fill MIB cache with defaults 119 * 120 * this function initializes the struct given as @mib with defaults, 121 * of which many are retrieved from the global module parameter 122 * variables. 123 */ 124 125void 126prism54_mib_init(islpci_private *priv) 127{ 128 u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode; 129 struct obj_buffer psm_buffer = { 130 .size = PSM_BUFFER_SIZE, 131 .addr = priv->device_psm_buffer 132 }; 133 134 channel = CARD_DEFAULT_CHANNEL; 135 authen = CARD_DEFAULT_AUTHEN; 136 wep = CARD_DEFAULT_WEP; 137 filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */ 138 dot1x = CARD_DEFAULT_DOT1X; 139 mlme = CARD_DEFAULT_MLME_MODE; 140 conformance = CARD_DEFAULT_CONFORMANCE; 141 power = 127; 142 mode = CARD_DEFAULT_IW_MODE; 143 144 mgt_set(priv, DOT11_OID_CHANNEL, &channel); 145 mgt_set(priv, DOT11_OID_AUTHENABLE, &authen); 146 mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep); 147 mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); 148 mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter); 149 mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x); 150 mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme); 151 mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance); 152 mgt_set(priv, OID_INL_OUTPUTPOWER, &power); 153 154 /* This sets all of the mode-dependent values */ 155 prism54_mib_mode_helper(priv, mode); 156} 157 158/* this will be executed outside of atomic context thanks to 159 * schedule_work(), thus we can as well use sleeping semaphore 160 * locking */ 161void 162prism54_update_stats(struct work_struct *work) 163{ 164 islpci_private *priv = container_of(work, islpci_private, stats_work); 165 char *data; 166 struct obj_bss bss, *bss2; 167 union oid_res_t r; 168 169 mutex_lock(&priv->stats_lock); 170 171/* Noise floor. 172 * I'm not sure if the unit is dBm. 173 * Note : If we are not connected, this value seems to be irrelevant. */ 174 175 mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); 176 priv->local_iwstatistics.qual.noise = r.u; 177 178/* Get the rssi of the link. To do this we need to retrieve a bss. */ 179 180 /* First get the MAC address of the AP we are associated with. */ 181 mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); 182 data = r.ptr; 183 184 /* copy this MAC to the bss */ 185 memcpy(bss.address, data, ETH_ALEN); 186 kfree(data); 187 188 /* now ask for the corresponding bss */ 189 mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); 190 bss2 = r.ptr; 191 /* report the rssi and use it to calculate 192 * link quality through a signal-noise 193 * ratio */ 194 priv->local_iwstatistics.qual.level = bss2->rssi; 195 priv->local_iwstatistics.qual.qual = 196 bss2->rssi - priv->iwstatistics.qual.noise; 197 198 kfree(bss2); 199 200 /* report that the stats are new */ 201 priv->local_iwstatistics.qual.updated = 0x7; 202 203/* Rx : unable to decrypt the MPDU */ 204 mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); 205 priv->local_iwstatistics.discard.code = r.u; 206 207/* Tx : Max MAC retries num reached */ 208 mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); 209 priv->local_iwstatistics.discard.retries = r.u; 210 211 mutex_unlock(&priv->stats_lock); 212} 213 214struct iw_statistics * 215prism54_get_wireless_stats(struct net_device *ndev) 216{ 217 islpci_private *priv = netdev_priv(ndev); 218 219 /* If the stats are being updated return old data */ 220 if (mutex_trylock(&priv->stats_lock)) { 221 memcpy(&priv->iwstatistics, &priv->local_iwstatistics, 222 sizeof (struct iw_statistics)); 223 /* They won't be marked updated for the next time */ 224 priv->local_iwstatistics.qual.updated = 0; 225 mutex_unlock(&priv->stats_lock); 226 } else 227 priv->iwstatistics.qual.updated = 0; 228 229 /* Update our wireless stats, but do not schedule to often 230 * (max 1 HZ) */ 231 if ((priv->stats_timestamp == 0) || 232 time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { 233 schedule_work(&priv->stats_work); 234 priv->stats_timestamp = jiffies; 235 } 236 237 return &priv->iwstatistics; 238} 239 240static int 241prism54_commit(struct net_device *ndev, struct iw_request_info *info, 242 char *cwrq, char *extra) 243{ 244 islpci_private *priv = netdev_priv(ndev); 245 246 /* simply re-set the last set SSID, this should commit most stuff */ 247 248 /* Commit in Monitor mode is not necessary, also setting essid 249 * in Monitor mode does not make sense and isn't allowed for this 250 * device's firmware */ 251 if (priv->iw_mode != IW_MODE_MONITOR) 252 return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); 253 return 0; 254} 255 256static int 257prism54_get_name(struct net_device *ndev, struct iw_request_info *info, 258 char *cwrq, char *extra) 259{ 260 islpci_private *priv = netdev_priv(ndev); 261 char *capabilities; 262 union oid_res_t r; 263 int rvalue; 264 265 if (islpci_get_state(priv) < PRV_STATE_INIT) { 266 strncpy(cwrq, "NOT READY!", IFNAMSIZ); 267 return 0; 268 } 269 rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); 270 271 switch (r.u) { 272 case INL_PHYCAP_5000MHZ: 273 capabilities = "IEEE 802.11a/b/g"; 274 break; 275 case INL_PHYCAP_FAA: 276 capabilities = "IEEE 802.11b/g - FAA Support"; 277 break; 278 case INL_PHYCAP_2400MHZ: 279 default: 280 capabilities = "IEEE 802.11b/g"; /* Default */ 281 break; 282 } 283 strncpy(cwrq, capabilities, IFNAMSIZ); 284 return rvalue; 285} 286 287static int 288prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, 289 struct iw_freq *fwrq, char *extra) 290{ 291 islpci_private *priv = netdev_priv(ndev); 292 int rvalue; 293 u32 c; 294 295 if (fwrq->m < 1000) 296 /* we have a channel number */ 297 c = fwrq->m; 298 else 299 c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0; 300 301 rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL; 302 303 /* Call commit handler */ 304 return (rvalue ? rvalue : -EINPROGRESS); 305} 306 307static int 308prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, 309 struct iw_freq *fwrq, char *extra) 310{ 311 islpci_private *priv = netdev_priv(ndev); 312 union oid_res_t r; 313 int rvalue; 314 315 rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); 316 fwrq->i = r.u; 317 rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); 318 fwrq->m = r.u; 319 fwrq->e = 3; 320 321 return rvalue; 322} 323 324static int 325prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, 326 __u32 * uwrq, char *extra) 327{ 328 islpci_private *priv = netdev_priv(ndev); 329 u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; 330 331 /* Let's see if the user passed a valid Linux Wireless mode */ 332 if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { 333 printk(KERN_DEBUG 334 "%s: %s() You passed a non-valid init_mode.\n", 335 priv->ndev->name, __func__); 336 return -EINVAL; 337 } 338 339 down_write(&priv->mib_sem); 340 341 if (prism54_mib_mode_helper(priv, *uwrq)) { 342 up_write(&priv->mib_sem); 343 return -EOPNOTSUPP; 344 } 345 346 /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an 347 * extended one. 348 */ 349 if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) 350 mlmeautolevel = DOT11_MLME_INTERMEDIATE; 351 if (priv->wpa) 352 mlmeautolevel = DOT11_MLME_EXTENDED; 353 354 mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); 355 356 if (mgt_commit(priv)) { 357 up_write(&priv->mib_sem); 358 return -EIO; 359 } 360 priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) 361 ? priv->monitor_type : ARPHRD_ETHER; 362 up_write(&priv->mib_sem); 363 364 return 0; 365} 366 367/* Use mib cache */ 368static int 369prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, 370 __u32 * uwrq, char *extra) 371{ 372 islpci_private *priv = netdev_priv(ndev); 373 374 BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > 375 IW_MODE_MONITOR)); 376 *uwrq = priv->iw_mode; 377 378 return 0; 379} 380 381/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to 382 * emit data if (sensitivity > rssi - noise) (in dBm). 383 * prism54_set_sens does not seem to work. 384 */ 385 386static int 387prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, 388 struct iw_param *vwrq, char *extra) 389{ 390 islpci_private *priv = netdev_priv(ndev); 391 u32 sens; 392 393 /* by default the card sets this to 20. */ 394 sens = vwrq->disabled ? 20 : vwrq->value; 395 396 return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); 397} 398 399static int 400prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, 401 struct iw_param *vwrq, char *extra) 402{ 403 islpci_private *priv = netdev_priv(ndev); 404 union oid_res_t r; 405 int rvalue; 406 407 rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); 408 409 vwrq->value = r.u; 410 vwrq->disabled = (vwrq->value == 0); 411 vwrq->fixed = 1; 412 413 return rvalue; 414} 415 416static int 417prism54_get_range(struct net_device *ndev, struct iw_request_info *info, 418 struct iw_point *dwrq, char *extra) 419{ 420 struct iw_range *range = (struct iw_range *) extra; 421 islpci_private *priv = netdev_priv(ndev); 422 u8 *data; 423 int i, m, rvalue; 424 struct obj_frequencies *freq; 425 union oid_res_t r; 426 427 memset(range, 0, sizeof (struct iw_range)); 428 dwrq->length = sizeof (struct iw_range); 429 430 /* set the wireless extension version number */ 431 range->we_version_source = SUPPORTED_WIRELESS_EXT; 432 range->we_version_compiled = WIRELESS_EXT; 433 434 /* Now the encoding capabilities */ 435 range->num_encoding_sizes = 3; 436 /* 64(40) bits WEP */ 437 range->encoding_size[0] = 5; 438 /* 128(104) bits WEP */ 439 range->encoding_size[1] = 13; 440 /* 256 bits for WPA-PSK */ 441 range->encoding_size[2] = 32; 442 /* 4 keys are allowed */ 443 range->max_encoding_tokens = 4; 444 445 /* we don't know the quality range... */ 446 range->max_qual.level = 0; 447 range->max_qual.noise = 0; 448 range->max_qual.qual = 0; 449 /* these value describe an average quality. Needs more tweaking... */ 450 range->avg_qual.level = -80; /* -80 dBm */ 451 range->avg_qual.noise = 0; /* don't know what to put here */ 452 range->avg_qual.qual = 0; 453 454 range->sensitivity = 200; 455 456 /* retry limit capabilities */ 457 range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; 458 range->retry_flags = IW_RETRY_LIMIT; 459 range->r_time_flags = IW_RETRY_LIFETIME; 460 461 /* I don't know the range. Put stupid things here */ 462 range->min_retry = 1; 463 range->max_retry = 65535; 464 range->min_r_time = 1024; 465 range->max_r_time = 65535 * 1024; 466 467 /* txpower is supported in dBm's */ 468 range->txpower_capa = IW_TXPOW_DBM; 469 470 /* Event capability (kernel + driver) */ 471 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | 472 IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | 473 IW_EVENT_CAPA_MASK(SIOCGIWAP)); 474 range->event_capa[1] = IW_EVENT_CAPA_K_1; 475 range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); 476 477 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | 478 IW_ENC_CAPA_CIPHER_TKIP; 479 480 if (islpci_get_state(priv) < PRV_STATE_INIT) 481 return 0; 482 483 /* Request the device for the supported frequencies 484 * not really relevant since some devices will report the 5 GHz band 485 * frequencies even if they don't support them. 486 */ 487 rvalue = 488 mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); 489 freq = r.ptr; 490 491 range->num_channels = freq->nr; 492 range->num_frequency = freq->nr; 493 494 m = min(IW_MAX_FREQUENCIES, (int) freq->nr); 495 for (i = 0; i < m; i++) { 496 range->freq[i].m = freq->mhz[i]; 497 range->freq[i].e = 6; 498 range->freq[i].i = channel_of_freq(freq->mhz[i]); 499 } 500 kfree(freq); 501 502 rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); 503 data = r.ptr; 504 505 /* We got an array of char. It is NULL terminated. */ 506 i = 0; 507 while ((i < IW_MAX_BITRATES) && (*data != 0)) { 508 /* the result must be in bps. The card gives us 500Kbps */ 509 range->bitrate[i] = *data * 500000; 510 i++; 511 data++; 512 } 513 range->num_bitrates = i; 514 kfree(r.ptr); 515 516 return rvalue; 517} 518 519/* Set AP address*/ 520 521static int 522prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, 523 struct sockaddr *awrq, char *extra) 524{ 525 islpci_private *priv = netdev_priv(ndev); 526 char bssid[6]; 527 int rvalue; 528 529 if (awrq->sa_family != ARPHRD_ETHER) 530 return -EINVAL; 531 532 /* prepare the structure for the set object */ 533 memcpy(&bssid[0], awrq->sa_data, ETH_ALEN); 534 535 /* set the bssid -- does this make sense when in AP mode? */ 536 rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); 537 538 return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ 539} 540 541/* get AP address*/ 542 543static int 544prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, 545 struct sockaddr *awrq, char *extra) 546{ 547 islpci_private *priv = netdev_priv(ndev); 548 union oid_res_t r; 549 int rvalue; 550 551 rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); 552 memcpy(awrq->sa_data, r.ptr, ETH_ALEN); 553 awrq->sa_family = ARPHRD_ETHER; 554 kfree(r.ptr); 555 556 return rvalue; 557} 558 559static int 560prism54_set_scan(struct net_device *dev, struct iw_request_info *info, 561 struct iw_param *vwrq, char *extra) 562{ 563 /* hehe the device does this automagicaly */ 564 return 0; 565} 566 567/* a little helper that will translate our data into a card independent 568 * format that the Wireless Tools will understand. This was inspired by 569 * the "Aironet driver for 4500 and 4800 series cards" (GPL) 570 */ 571 572static char * 573prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info, 574 char *current_ev, char *end_buf, struct obj_bss *bss, 575 char noise) 576{ 577 struct iw_event iwe; /* Temporary buffer */ 578 short cap; 579 islpci_private *priv = netdev_priv(ndev); 580 u8 wpa_ie[MAX_WPA_IE_LEN]; 581 size_t wpa_ie_len; 582 583 /* The first entry must be the MAC address */ 584 memcpy(iwe.u.ap_addr.sa_data, bss->address, ETH_ALEN); 585 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 586 iwe.cmd = SIOCGIWAP; 587 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 588 &iwe, IW_EV_ADDR_LEN); 589 590 /* The following entries will be displayed in the same order we give them */ 591 592 /* The ESSID. */ 593 iwe.u.data.length = bss->ssid.length; 594 iwe.u.data.flags = 1; 595 iwe.cmd = SIOCGIWESSID; 596 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 597 &iwe, bss->ssid.octets); 598 599 /* Capabilities */ 600#define CAP_ESS 0x01 601#define CAP_IBSS 0x02 602#define CAP_CRYPT 0x10 603 604 /* Mode */ 605 cap = bss->capinfo; 606 iwe.u.mode = 0; 607 if (cap & CAP_ESS) 608 iwe.u.mode = IW_MODE_MASTER; 609 else if (cap & CAP_IBSS) 610 iwe.u.mode = IW_MODE_ADHOC; 611 iwe.cmd = SIOCGIWMODE; 612 if (iwe.u.mode) 613 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 614 &iwe, IW_EV_UINT_LEN); 615 616 /* Encryption capability */ 617 if (cap & CAP_CRYPT) 618 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 619 else 620 iwe.u.data.flags = IW_ENCODE_DISABLED; 621 iwe.u.data.length = 0; 622 iwe.cmd = SIOCGIWENCODE; 623 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 624 &iwe, NULL); 625 626 /* Add frequency. (short) bss->channel is the frequency in MHz */ 627 iwe.u.freq.m = bss->channel; 628 iwe.u.freq.e = 6; 629 iwe.cmd = SIOCGIWFREQ; 630 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 631 &iwe, IW_EV_FREQ_LEN); 632 633 /* Add quality statistics */ 634 iwe.u.qual.level = bss->rssi; 635 iwe.u.qual.noise = noise; 636 /* do a simple SNR for quality */ 637 iwe.u.qual.qual = bss->rssi - noise; 638 iwe.cmd = IWEVQUAL; 639 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 640 &iwe, IW_EV_QUAL_LEN); 641 642 /* Add WPA/RSN Information Element, if any */ 643 wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); 644 if (wpa_ie_len > 0) { 645 iwe.cmd = IWEVGENIE; 646 iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN); 647 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 648 &iwe, wpa_ie); 649 } 650 /* Do the bitrates */ 651 { 652 char *current_val = current_ev + iwe_stream_lcp_len(info); 653 int i; 654 int mask; 655 656 iwe.cmd = SIOCGIWRATE; 657 /* Those two flags are ignored... */ 658 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 659 660 /* Parse the bitmask */ 661 mask = 0x1; 662 for(i = 0; i < sizeof(scan_rate_list); i++) { 663 if(bss->rates & mask) { 664 iwe.u.bitrate.value = (scan_rate_list[i] * 500000); 665 current_val = iwe_stream_add_value( 666 info, current_ev, current_val, 667 end_buf, &iwe, IW_EV_PARAM_LEN); 668 } 669 mask <<= 1; 670 } 671 /* Check if we added any event */ 672 if ((current_val - current_ev) > iwe_stream_lcp_len(info)) 673 current_ev = current_val; 674 } 675 676 return current_ev; 677} 678 679static int 680prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, 681 struct iw_point *dwrq, char *extra) 682{ 683 islpci_private *priv = netdev_priv(ndev); 684 int i, rvalue; 685 struct obj_bsslist *bsslist; 686 u32 noise = 0; 687 char *current_ev = extra; 688 union oid_res_t r; 689 690 if (islpci_get_state(priv) < PRV_STATE_INIT) { 691 /* device is not ready, fail gently */ 692 dwrq->length = 0; 693 return 0; 694 } 695 696 /* first get the noise value. We will use it to report the link quality */ 697 rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); 698 noise = r.u; 699 700 /* Ask the device for a list of known bss. 701 * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64. 702 * The new API, using SIOCGIWSCAN, is only limited by the buffer size. 703 * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes. 704 * Starting with WE-17, the buffer can be as big as needed. 705 * But the device won't repport anything if you change the value 706 * of IWMAX_BSS=24. */ 707 708 rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); 709 bsslist = r.ptr; 710 711 /* ok now, scan the list and translate its info */ 712 for (i = 0; i < (int) bsslist->nr; i++) { 713 current_ev = prism54_translate_bss(ndev, info, current_ev, 714 extra + dwrq->length, 715 &(bsslist->bsslist[i]), 716 noise); 717 718 /* Check if there is space for one more entry */ 719 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { 720 /* Ask user space to try again with a bigger buffer */ 721 rvalue = -E2BIG; 722 break; 723 } 724 } 725 726 kfree(bsslist); 727 dwrq->length = (current_ev - extra); 728 dwrq->flags = 0; /* todo */ 729 730 return rvalue; 731} 732 733static int 734prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, 735 struct iw_point *dwrq, char *extra) 736{ 737 islpci_private *priv = netdev_priv(ndev); 738 struct obj_ssid essid; 739 740 memset(essid.octets, 0, 33); 741 742 /* Check if we were asked for `any' */ 743 if (dwrq->flags && dwrq->length) { 744 if (dwrq->length > 32) 745 return -E2BIG; 746 essid.length = dwrq->length; 747 memcpy(essid.octets, extra, dwrq->length); 748 } else 749 essid.length = 0; 750 751 if (priv->iw_mode != IW_MODE_MONITOR) 752 return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); 753 754 /* If in monitor mode, just save to mib */ 755 mgt_set(priv, DOT11_OID_SSID, &essid); 756 return 0; 757 758} 759 760static int 761prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, 762 struct iw_point *dwrq, char *extra) 763{ 764 islpci_private *priv = netdev_priv(ndev); 765 struct obj_ssid *essid; 766 union oid_res_t r; 767 int rvalue; 768 769 rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); 770 essid = r.ptr; 771 772 if (essid->length) { 773 dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ 774 /* if it is too big, trunk it */ 775 dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length); 776 } else { 777 dwrq->flags = 0; 778 dwrq->length = 0; 779 } 780 essid->octets[dwrq->length] = '\0'; 781 memcpy(extra, essid->octets, dwrq->length); 782 kfree(essid); 783 784 return rvalue; 785} 786 787/* Provides no functionality, just completes the ioctl. In essence this is a 788 * just a cosmetic ioctl. 789 */ 790static int 791prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, 792 struct iw_point *dwrq, char *extra) 793{ 794 islpci_private *priv = netdev_priv(ndev); 795 796 if (dwrq->length > IW_ESSID_MAX_SIZE) 797 return -E2BIG; 798 799 down_write(&priv->mib_sem); 800 memset(priv->nickname, 0, sizeof (priv->nickname)); 801 memcpy(priv->nickname, extra, dwrq->length); 802 up_write(&priv->mib_sem); 803 804 return 0; 805} 806 807static int 808prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, 809 struct iw_point *dwrq, char *extra) 810{ 811 islpci_private *priv = netdev_priv(ndev); 812 813 dwrq->length = 0; 814 815 down_read(&priv->mib_sem); 816 dwrq->length = strlen(priv->nickname); 817 memcpy(extra, priv->nickname, dwrq->length); 818 up_read(&priv->mib_sem); 819 820 return 0; 821} 822 823/* Set the allowed Bitrates */ 824 825static int 826prism54_set_rate(struct net_device *ndev, 827 struct iw_request_info *info, 828 struct iw_param *vwrq, char *extra) 829{ 830 831 islpci_private *priv = netdev_priv(ndev); 832 u32 rate, profile; 833 char *data; 834 int ret, i; 835 union oid_res_t r; 836 837 if (vwrq->value == -1) { 838 /* auto mode. No limit. */ 839 profile = 1; 840 return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); 841 } 842 843 ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); 844 if (ret) { 845 kfree(r.ptr); 846 return ret; 847 } 848 849 rate = (u32) (vwrq->value / 500000); 850 data = r.ptr; 851 i = 0; 852 853 while (data[i]) { 854 if (rate && (data[i] == rate)) { 855 break; 856 } 857 if (vwrq->value == i) { 858 break; 859 } 860 data[i] |= 0x80; 861 i++; 862 } 863 864 if (!data[i]) { 865 kfree(r.ptr); 866 return -EINVAL; 867 } 868 869 data[i] |= 0x80; 870 data[i + 1] = 0; 871 872 /* Now, check if we want a fixed or auto value */ 873 if (vwrq->fixed) { 874 data[0] = data[i]; 875 data[1] = 0; 876 } 877 878/* 879 i = 0; 880 printk("prism54 rate: "); 881 while(data[i]) { 882 printk("%u ", data[i]); 883 i++; 884 } 885 printk("0\n"); 886*/ 887 profile = -1; 888 ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); 889 ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); 890 ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); 891 892 kfree(r.ptr); 893 894 return ret; 895} 896 897/* Get the current bit rate */ 898static int 899prism54_get_rate(struct net_device *ndev, 900 struct iw_request_info *info, 901 struct iw_param *vwrq, char *extra) 902{ 903 islpci_private *priv = netdev_priv(ndev); 904 int rvalue; 905 char *data; 906 union oid_res_t r; 907 908 /* Get the current bit rate */ 909 if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) 910 return rvalue; 911 vwrq->value = r.u * 500000; 912 913 /* request the device for the enabled rates */ 914 rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r); 915 if (rvalue) { 916 kfree(r.ptr); 917 return rvalue; 918 } 919 data = r.ptr; 920 vwrq->fixed = (data[0] != 0) && (data[1] == 0); 921 kfree(r.ptr); 922 923 return 0; 924} 925 926static int 927prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, 928 struct iw_param *vwrq, char *extra) 929{ 930 islpci_private *priv = netdev_priv(ndev); 931 932 return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); 933} 934 935static int 936prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, 937 struct iw_param *vwrq, char *extra) 938{ 939 islpci_private *priv = netdev_priv(ndev); 940 union oid_res_t r; 941 int rvalue; 942 943 /* get the rts threshold */ 944 rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); 945 vwrq->value = r.u; 946 947 return rvalue; 948} 949 950static int 951prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, 952 struct iw_param *vwrq, char *extra) 953{ 954 islpci_private *priv = netdev_priv(ndev); 955 956 return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); 957} 958 959static int 960prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, 961 struct iw_param *vwrq, char *extra) 962{ 963 islpci_private *priv = netdev_priv(ndev); 964 union oid_res_t r; 965 int rvalue; 966 967 rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); 968 vwrq->value = r.u; 969 970 return rvalue; 971} 972 973/* Here we have (min,max) = max retries for (small frames, big frames). Where 974 * big frame <=> bigger than the rts threshold 975 * small frame <=> smaller than the rts threshold 976 * This is not really the behavior expected by the wireless tool but it seems 977 * to be a common behavior in other drivers. 978 */ 979 980static int 981prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, 982 struct iw_param *vwrq, char *extra) 983{ 984 islpci_private *priv = netdev_priv(ndev); 985 u32 slimit = 0, llimit = 0; /* short and long limit */ 986 u32 lifetime = 0; 987 int rvalue = 0; 988 989 if (vwrq->disabled) 990 /* we cannot disable this feature */ 991 return -EINVAL; 992 993 if (vwrq->flags & IW_RETRY_LIMIT) { 994 if (vwrq->flags & IW_RETRY_SHORT) 995 slimit = vwrq->value; 996 else if (vwrq->flags & IW_RETRY_LONG) 997 llimit = vwrq->value; 998 else { 999 /* we are asked to set both */ 1000 slimit = vwrq->value; 1001 llimit = vwrq->value; 1002 } 1003 } 1004 if (vwrq->flags & IW_RETRY_LIFETIME) 1005 /* Wireless tools use us unit while the device uses 1024 us unit */ 1006 lifetime = vwrq->value / 1024; 1007 1008 /* now set what is requested */ 1009 if (slimit) 1010 rvalue = 1011 mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); 1012 if (llimit) 1013 rvalue |= 1014 mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); 1015 if (lifetime) 1016 rvalue |= 1017 mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, 1018 &lifetime); 1019 return rvalue; 1020} 1021 1022static int 1023prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, 1024 struct iw_param *vwrq, char *extra) 1025{ 1026 islpci_private *priv = netdev_priv(ndev); 1027 union oid_res_t r; 1028 int rvalue = 0; 1029 vwrq->disabled = 0; /* It cannot be disabled */ 1030 1031 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { 1032 /* we are asked for the life time */ 1033 rvalue = 1034 mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); 1035 vwrq->value = r.u * 1024; 1036 vwrq->flags = IW_RETRY_LIFETIME; 1037 } else if ((vwrq->flags & IW_RETRY_LONG)) { 1038 /* we are asked for the long retry limit */ 1039 rvalue |= 1040 mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); 1041 vwrq->value = r.u; 1042 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; 1043 } else { 1044 /* default. get the short retry limit */ 1045 rvalue |= 1046 mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); 1047 vwrq->value = r.u; 1048 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; 1049 } 1050 1051 return rvalue; 1052} 1053 1054static int 1055prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, 1056 struct iw_point *dwrq, char *extra) 1057{ 1058 islpci_private *priv = netdev_priv(ndev); 1059 int rvalue = 0, force = 0; 1060 int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; 1061 union oid_res_t r; 1062 1063 /* with the new API, it's impossible to get a NULL pointer. 1064 * New version of iwconfig set the IW_ENCODE_NOKEY flag 1065 * when no key is given, but older versions don't. */ 1066 1067 if (dwrq->length > 0) { 1068 /* we have a key to set */ 1069 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 1070 int current_index; 1071 struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; 1072 1073 /* get the current key index */ 1074 rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 1075 current_index = r.u; 1076 /* Verify that the key is not marked as invalid */ 1077 if (!(dwrq->flags & IW_ENCODE_NOKEY)) { 1078 if (dwrq->length > KEY_SIZE_TKIP) { 1079 /* User-provided key data too big */ 1080 return -EINVAL; 1081 } 1082 if (dwrq->length > KEY_SIZE_WEP104) { 1083 /* WPA-PSK TKIP */ 1084 key.type = DOT11_PRIV_TKIP; 1085 key.length = KEY_SIZE_TKIP; 1086 } else if (dwrq->length > KEY_SIZE_WEP40) { 1087 /* WEP 104/128 */ 1088 key.length = KEY_SIZE_WEP104; 1089 } else { 1090 /* WEP 40/64 */ 1091 key.length = KEY_SIZE_WEP40; 1092 } 1093 memset(key.key, 0, sizeof (key.key)); 1094 memcpy(key.key, extra, dwrq->length); 1095 1096 if ((index < 0) || (index > 3)) 1097 /* no index provided use the current one */ 1098 index = current_index; 1099 1100 /* now send the key to the card */ 1101 rvalue |= 1102 mgt_set_request(priv, DOT11_OID_DEFKEYX, index, 1103 &key); 1104 } 1105 /* 1106 * If a valid key is set, encryption should be enabled 1107 * (user may turn it off later). 1108 * This is also how "iwconfig ethX key on" works 1109 */ 1110 if ((index == current_index) && (key.length > 0)) 1111 force = 1; 1112 } else { 1113 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 1114 if ((index >= 0) && (index <= 3)) { 1115 /* we want to set the key index */ 1116 rvalue |= 1117 mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, 1118 &index); 1119 } else { 1120 if (!(dwrq->flags & IW_ENCODE_MODE)) { 1121 /* we cannot do anything. Complain. */ 1122 return -EINVAL; 1123 } 1124 } 1125 } 1126 /* now read the flags */ 1127 if (dwrq->flags & IW_ENCODE_DISABLED) { 1128 /* Encoding disabled, 1129 * authen = DOT11_AUTH_OS; 1130 * invoke = 0; 1131 * exunencrypt = 0; */ 1132 } 1133 if (dwrq->flags & IW_ENCODE_OPEN) 1134 /* Encode but accept non-encoded packets. No auth */ 1135 invoke = 1; 1136 if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { 1137 /* Refuse non-encoded packets. Auth */ 1138 authen = DOT11_AUTH_BOTH; 1139 invoke = 1; 1140 exunencrypt = 1; 1141 } 1142 /* do the change if requested */ 1143 if ((dwrq->flags & IW_ENCODE_MODE) || force) { 1144 rvalue |= 1145 mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); 1146 rvalue |= 1147 mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); 1148 rvalue |= 1149 mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, 1150 &exunencrypt); 1151 } 1152 return rvalue; 1153} 1154 1155static int 1156prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, 1157 struct iw_point *dwrq, char *extra) 1158{ 1159 islpci_private *priv = netdev_priv(ndev); 1160 struct obj_key *key; 1161 u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 1162 u32 authen = 0, invoke = 0, exunencrypt = 0; 1163 int rvalue; 1164 union oid_res_t r; 1165 1166 /* first get the flags */ 1167 rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 1168 authen = r.u; 1169 rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 1170 invoke = r.u; 1171 rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 1172 exunencrypt = r.u; 1173 1174 if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) 1175 dwrq->flags = IW_ENCODE_RESTRICTED; 1176 else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { 1177 if (invoke) 1178 dwrq->flags = IW_ENCODE_OPEN; 1179 else 1180 dwrq->flags = IW_ENCODE_DISABLED; 1181 } else 1182 /* The card should not work in this state */ 1183 dwrq->flags = 0; 1184 1185 /* get the current device key index */ 1186 rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 1187 devindex = r.u; 1188 /* Now get the key, return it */ 1189 if (index == -1 || index > 3) 1190 /* no index provided, use the current one */ 1191 index = devindex; 1192 rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); 1193 key = r.ptr; 1194 dwrq->length = key->length; 1195 memcpy(extra, key->key, dwrq->length); 1196 kfree(key); 1197 /* return the used key index */ 1198 dwrq->flags |= devindex + 1; 1199 1200 return rvalue; 1201} 1202 1203static int 1204prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, 1205 struct iw_param *vwrq, char *extra) 1206{ 1207 islpci_private *priv = netdev_priv(ndev); 1208 union oid_res_t r; 1209 int rvalue; 1210 1211 rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); 1212 /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ 1213 vwrq->value = (s32) r.u / 4; 1214 vwrq->fixed = 1; 1215 /* radio is not turned of 1216 * btw: how is possible to turn off only the radio 1217 */ 1218 vwrq->disabled = 0; 1219 1220 return rvalue; 1221} 1222 1223static int 1224prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, 1225 struct iw_param *vwrq, char *extra) 1226{ 1227 islpci_private *priv = netdev_priv(ndev); 1228 s32 u = vwrq->value; 1229 1230 /* intersil firmware operates in 0.25 dBm (1/4) */ 1231 u *= 4; 1232 if (vwrq->disabled) { 1233 /* don't know how to disable radio */ 1234 printk(KERN_DEBUG 1235 "%s: %s() disabling radio is not yet supported.\n", 1236 priv->ndev->name, __func__); 1237 return -ENOTSUPP; 1238 } else if (vwrq->fixed) 1239 /* currently only fixed value is supported */ 1240 return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); 1241 else { 1242 printk(KERN_DEBUG 1243 "%s: %s() auto power will be implemented later.\n", 1244 priv->ndev->name, __func__); 1245 return -ENOTSUPP; 1246 } 1247} 1248 1249static int prism54_set_genie(struct net_device *ndev, 1250 struct iw_request_info *info, 1251 struct iw_point *data, char *extra) 1252{ 1253 islpci_private *priv = netdev_priv(ndev); 1254 int alen, ret = 0; 1255 struct obj_attachment *attach; 1256 1257 if (data->length > MAX_WPA_IE_LEN || 1258 (data->length && extra == NULL)) 1259 return -EINVAL; 1260 1261 memcpy(priv->wpa_ie, extra, data->length); 1262 priv->wpa_ie_len = data->length; 1263 1264 alen = sizeof(*attach) + priv->wpa_ie_len; 1265 attach = kzalloc(alen, GFP_KERNEL); 1266 if (attach == NULL) 1267 return -ENOMEM; 1268 1269#define WLAN_FC_TYPE_MGMT 0 1270#define WLAN_FC_STYPE_ASSOC_REQ 0 1271#define WLAN_FC_STYPE_REASSOC_REQ 2 1272 1273 /* Note: endianness is covered by mgt_set_varlen */ 1274 attach->type = (WLAN_FC_TYPE_MGMT << 2) | 1275 (WLAN_FC_STYPE_ASSOC_REQ << 4); 1276 attach->id = -1; 1277 attach->size = priv->wpa_ie_len; 1278 memcpy(attach->data, extra, priv->wpa_ie_len); 1279 1280 ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, 1281 priv->wpa_ie_len); 1282 if (ret == 0) { 1283 attach->type = (WLAN_FC_TYPE_MGMT << 2) | 1284 (WLAN_FC_STYPE_REASSOC_REQ << 4); 1285 1286 ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, 1287 priv->wpa_ie_len); 1288 if (ret == 0) 1289 printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", 1290 ndev->name); 1291 } 1292 1293 kfree(attach); 1294 return ret; 1295} 1296 1297 1298static int prism54_get_genie(struct net_device *ndev, 1299 struct iw_request_info *info, 1300 struct iw_point *data, char *extra) 1301{ 1302 islpci_private *priv = netdev_priv(ndev); 1303 int len = priv->wpa_ie_len; 1304 1305 if (len <= 0) { 1306 data->length = 0; 1307 return 0; 1308 } 1309 1310 if (data->length < len) 1311 return -E2BIG; 1312 1313 data->length = len; 1314 memcpy(extra, priv->wpa_ie, len); 1315 1316 return 0; 1317} 1318 1319static int prism54_set_auth(struct net_device *ndev, 1320 struct iw_request_info *info, 1321 union iwreq_data *wrqu, char *extra) 1322{ 1323 islpci_private *priv = netdev_priv(ndev); 1324 struct iw_param *param = &wrqu->param; 1325 u32 mlmelevel = 0, authen = 0, dot1x = 0; 1326 u32 exunencrypt = 0, privinvoked = 0, wpa = 0; 1327 u32 old_wpa; 1328 int ret = 0; 1329 union oid_res_t r; 1330 1331 if (islpci_get_state(priv) < PRV_STATE_INIT) 1332 return 0; 1333 1334 /* first get the flags */ 1335 down_write(&priv->mib_sem); 1336 wpa = old_wpa = priv->wpa; 1337 up_write(&priv->mib_sem); 1338 ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 1339 authen = r.u; 1340 ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 1341 privinvoked = r.u; 1342 ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 1343 exunencrypt = r.u; 1344 ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); 1345 dot1x = r.u; 1346 ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r); 1347 mlmelevel = r.u; 1348 1349 if (ret < 0) 1350 goto out; 1351 1352 switch (param->flags & IW_AUTH_INDEX) { 1353 case IW_AUTH_CIPHER_PAIRWISE: 1354 case IW_AUTH_CIPHER_GROUP: 1355 case IW_AUTH_KEY_MGMT: 1356 break; 1357 1358 case IW_AUTH_WPA_ENABLED: 1359 /* Do the same thing as IW_AUTH_WPA_VERSION */ 1360 if (param->value) { 1361 wpa = 1; 1362 privinvoked = 1; /* For privacy invoked */ 1363 exunencrypt = 1; /* Filter out all unencrypted frames */ 1364 dot1x = 0x01; /* To enable eap filter */ 1365 mlmelevel = DOT11_MLME_EXTENDED; 1366 authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ 1367 } else { 1368 wpa = 0; 1369 privinvoked = 0; 1370 exunencrypt = 0; /* Do not filter un-encrypted data */ 1371 dot1x = 0; 1372 mlmelevel = DOT11_MLME_AUTO; 1373 } 1374 break; 1375 1376 case IW_AUTH_WPA_VERSION: 1377 if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { 1378 wpa = 0; 1379 privinvoked = 0; 1380 exunencrypt = 0; /* Do not filter un-encrypted data */ 1381 dot1x = 0; 1382 mlmelevel = DOT11_MLME_AUTO; 1383 } else { 1384 if (param->value & IW_AUTH_WPA_VERSION_WPA) 1385 wpa = 1; 1386 else if (param->value & IW_AUTH_WPA_VERSION_WPA2) 1387 wpa = 2; 1388 privinvoked = 1; /* For privacy invoked */ 1389 exunencrypt = 1; /* Filter out all unencrypted frames */ 1390 dot1x = 0x01; /* To enable eap filter */ 1391 mlmelevel = DOT11_MLME_EXTENDED; 1392 authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ 1393 } 1394 break; 1395 1396 case IW_AUTH_RX_UNENCRYPTED_EAPOL: 1397 /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL; 1398 * turn off dot1x when allowing receipt of unencrypted EAPOL 1399 * frames, turn on dot1x when receipt should be disallowed 1400 */ 1401 dot1x = param->value ? 0 : 0x01; 1402 break; 1403 1404 case IW_AUTH_PRIVACY_INVOKED: 1405 privinvoked = param->value ? 1 : 0; 1406 break; 1407 1408 case IW_AUTH_DROP_UNENCRYPTED: 1409 exunencrypt = param->value ? 1 : 0; 1410 break; 1411 1412 case IW_AUTH_80211_AUTH_ALG: 1413 if (param->value & IW_AUTH_ALG_SHARED_KEY) { 1414 /* Only WEP uses _SK and _BOTH */ 1415 if (wpa > 0) { 1416 ret = -EINVAL; 1417 goto out; 1418 } 1419 authen = DOT11_AUTH_SK; 1420 } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { 1421 authen = DOT11_AUTH_OS; 1422 } else { 1423 ret = -EINVAL; 1424 goto out; 1425 } 1426 break; 1427 1428 default: 1429 return -EOPNOTSUPP; 1430 } 1431 1432 /* Set all the values */ 1433 down_write(&priv->mib_sem); 1434 priv->wpa = wpa; 1435 up_write(&priv->mib_sem); 1436 mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); 1437 mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked); 1438 mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt); 1439 mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); 1440 mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel); 1441 1442out: 1443 return ret; 1444} 1445 1446static int prism54_get_auth(struct net_device *ndev, 1447 struct iw_request_info *info, 1448 union iwreq_data *wrqu, char *extra) 1449{ 1450 islpci_private *priv = netdev_priv(ndev); 1451 struct iw_param *param = &wrqu->param; 1452 u32 wpa = 0; 1453 int ret = 0; 1454 union oid_res_t r; 1455 1456 if (islpci_get_state(priv) < PRV_STATE_INIT) 1457 return 0; 1458 1459 /* first get the flags */ 1460 down_write(&priv->mib_sem); 1461 wpa = priv->wpa; 1462 up_write(&priv->mib_sem); 1463 1464 switch (param->flags & IW_AUTH_INDEX) { 1465 case IW_AUTH_CIPHER_PAIRWISE: 1466 case IW_AUTH_CIPHER_GROUP: 1467 case IW_AUTH_KEY_MGMT: 1468 /* 1469 * wpa_supplicant will control these internally 1470 */ 1471 ret = -EOPNOTSUPP; 1472 break; 1473 1474 case IW_AUTH_WPA_VERSION: 1475 switch (wpa) { 1476 case 1: 1477 param->value = IW_AUTH_WPA_VERSION_WPA; 1478 break; 1479 case 2: 1480 param->value = IW_AUTH_WPA_VERSION_WPA2; 1481 break; 1482 case 0: 1483 default: 1484 param->value = IW_AUTH_WPA_VERSION_DISABLED; 1485 break; 1486 } 1487 break; 1488 1489 case IW_AUTH_DROP_UNENCRYPTED: 1490 ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 1491 if (ret >= 0) 1492 param->value = r.u > 0 ? 1 : 0; 1493 break; 1494 1495 case IW_AUTH_80211_AUTH_ALG: 1496 ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 1497 if (ret >= 0) { 1498 switch (r.u) { 1499 case DOT11_AUTH_OS: 1500 param->value = IW_AUTH_ALG_OPEN_SYSTEM; 1501 break; 1502 case DOT11_AUTH_BOTH: 1503 case DOT11_AUTH_SK: 1504 param->value = IW_AUTH_ALG_SHARED_KEY; 1505 break; 1506 case DOT11_AUTH_NONE: 1507 default: 1508 param->value = 0; 1509 break; 1510 } 1511 } 1512 break; 1513 1514 case IW_AUTH_WPA_ENABLED: 1515 param->value = wpa > 0 ? 1 : 0; 1516 break; 1517 1518 case IW_AUTH_RX_UNENCRYPTED_EAPOL: 1519 ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); 1520 if (ret >= 0) 1521 param->value = r.u > 0 ? 1 : 0; 1522 break; 1523 1524 case IW_AUTH_PRIVACY_INVOKED: 1525 ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 1526 if (ret >= 0) 1527 param->value = r.u > 0 ? 1 : 0; 1528 break; 1529 1530 default: 1531 return -EOPNOTSUPP; 1532 } 1533 return ret; 1534} 1535 1536static int prism54_set_encodeext(struct net_device *ndev, 1537 struct iw_request_info *info, 1538 union iwreq_data *wrqu, 1539 char *extra) 1540{ 1541 islpci_private *priv = netdev_priv(ndev); 1542 struct iw_point *encoding = &wrqu->encoding; 1543 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 1544 int idx, alg = ext->alg, set_key = 1; 1545 union oid_res_t r; 1546 int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; 1547 int ret = 0; 1548 1549 if (islpci_get_state(priv) < PRV_STATE_INIT) 1550 return 0; 1551 1552 /* Determine and validate the key index */ 1553 idx = (encoding->flags & IW_ENCODE_INDEX) - 1; 1554 if (idx) { 1555 if (idx < 0 || idx > 3) 1556 return -EINVAL; 1557 } else { 1558 ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 1559 if (ret < 0) 1560 goto out; 1561 idx = r.u; 1562 } 1563 1564 if (encoding->flags & IW_ENCODE_DISABLED) 1565 alg = IW_ENCODE_ALG_NONE; 1566 1567 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 1568 /* Only set transmit key index here, actual 1569 * key is set below if needed. 1570 */ 1571 ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx); 1572 set_key = ext->key_len > 0 ? 1 : 0; 1573 } 1574 1575 if (set_key) { 1576 struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; 1577 switch (alg) { 1578 case IW_ENCODE_ALG_NONE: 1579 break; 1580 case IW_ENCODE_ALG_WEP: 1581 if (ext->key_len > KEY_SIZE_WEP104) { 1582 ret = -EINVAL; 1583 goto out; 1584 } 1585 if (ext->key_len > KEY_SIZE_WEP40) 1586 key.length = KEY_SIZE_WEP104; 1587 else 1588 key.length = KEY_SIZE_WEP40; 1589 break; 1590 case IW_ENCODE_ALG_TKIP: 1591 if (ext->key_len > KEY_SIZE_TKIP) { 1592 ret = -EINVAL; 1593 goto out; 1594 } 1595 key.type = DOT11_PRIV_TKIP; 1596 key.length = KEY_SIZE_TKIP; 1597 break; 1598 default: 1599 return -EINVAL; 1600 } 1601 1602 if (key.length) { 1603 memset(key.key, 0, sizeof(key.key)); 1604 memcpy(key.key, ext->key, ext->key_len); 1605 ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx, 1606 &key); 1607 if (ret < 0) 1608 goto out; 1609 } 1610 } 1611 1612 /* Read the flags */ 1613 if (encoding->flags & IW_ENCODE_DISABLED) { 1614 /* Encoding disabled, 1615 * authen = DOT11_AUTH_OS; 1616 * invoke = 0; 1617 * exunencrypt = 0; */ 1618 } 1619 if (encoding->flags & IW_ENCODE_OPEN) { 1620 /* Encode but accept non-encoded packets. No auth */ 1621 invoke = 1; 1622 } 1623 if (encoding->flags & IW_ENCODE_RESTRICTED) { 1624 /* Refuse non-encoded packets. Auth */ 1625 authen = DOT11_AUTH_BOTH; 1626 invoke = 1; 1627 exunencrypt = 1; 1628 } 1629 1630 /* do the change if requested */ 1631 if (encoding->flags & IW_ENCODE_MODE) { 1632 ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, 1633 &authen); 1634 ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, 1635 &invoke); 1636 ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, 1637 &exunencrypt); 1638 } 1639 1640out: 1641 return ret; 1642} 1643 1644 1645static int prism54_get_encodeext(struct net_device *ndev, 1646 struct iw_request_info *info, 1647 union iwreq_data *wrqu, 1648 char *extra) 1649{ 1650 islpci_private *priv = netdev_priv(ndev); 1651 struct iw_point *encoding = &wrqu->encoding; 1652 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 1653 int idx, max_key_len; 1654 union oid_res_t r; 1655 int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; 1656 int ret = 0; 1657 1658 if (islpci_get_state(priv) < PRV_STATE_INIT) 1659 return 0; 1660 1661 /* first get the flags */ 1662 ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 1663 authen = r.u; 1664 ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 1665 invoke = r.u; 1666 ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 1667 exunencrypt = r.u; 1668 if (ret < 0) 1669 goto out; 1670 1671 max_key_len = encoding->length - sizeof(*ext); 1672 if (max_key_len < 0) 1673 return -EINVAL; 1674 1675 idx = (encoding->flags & IW_ENCODE_INDEX) - 1; 1676 if (idx) { 1677 if (idx < 0 || idx > 3) 1678 return -EINVAL; 1679 } else { 1680 ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 1681 if (ret < 0) 1682 goto out; 1683 idx = r.u; 1684 } 1685 1686 encoding->flags = idx + 1; 1687 memset(ext, 0, sizeof(*ext)); 1688 1689 switch (authen) { 1690 case DOT11_AUTH_BOTH: 1691 case DOT11_AUTH_SK: 1692 wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; 1693 fallthrough; 1694 case DOT11_AUTH_OS: 1695 default: 1696 wrqu->encoding.flags |= IW_ENCODE_OPEN; 1697 break; 1698 } 1699 1700 down_write(&priv->mib_sem); 1701 wpa = priv->wpa; 1702 up_write(&priv->mib_sem); 1703 1704 if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { 1705 /* No encryption */ 1706 ext->alg = IW_ENCODE_ALG_NONE; 1707 ext->key_len = 0; 1708 wrqu->encoding.flags |= IW_ENCODE_DISABLED; 1709 } else { 1710 struct obj_key *key; 1711 1712 ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r); 1713 if (ret < 0) 1714 goto out; 1715 key = r.ptr; 1716 if (max_key_len < key->length) { 1717 ret = -E2BIG; 1718 goto out; 1719 } 1720 memcpy(ext->key, key->key, key->length); 1721 ext->key_len = key->length; 1722 1723 switch (key->type) { 1724 case DOT11_PRIV_TKIP: 1725 ext->alg = IW_ENCODE_ALG_TKIP; 1726 break; 1727 default: 1728 case DOT11_PRIV_WEP: 1729 ext->alg = IW_ENCODE_ALG_WEP; 1730 break; 1731 } 1732 wrqu->encoding.flags |= IW_ENCODE_ENABLED; 1733 } 1734 1735out: 1736 return ret; 1737} 1738 1739 1740static int 1741prism54_reset(struct net_device *ndev, struct iw_request_info *info, 1742 __u32 * uwrq, char *extra) 1743{ 1744 islpci_reset(netdev_priv(ndev), 0); 1745 1746 return 0; 1747} 1748 1749static int 1750prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, 1751 struct iw_point *dwrq, char *extra) 1752{ 1753 union oid_res_t r; 1754 int rvalue; 1755 enum oid_num_t n = dwrq->flags; 1756 1757 rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r); 1758 dwrq->length = mgt_response_to_str(n, &r, extra); 1759 if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) 1760 kfree(r.ptr); 1761 return rvalue; 1762} 1763 1764static int 1765prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, 1766 __u32 * uwrq, char *extra) 1767{ 1768 u32 oid = uwrq[0], u = uwrq[1]; 1769 1770 return mgt_set_request(netdev_priv(ndev), oid, 0, &u); 1771} 1772 1773static int 1774prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, 1775 struct iw_point *dwrq, char *extra) 1776{ 1777 u32 oid = dwrq->flags; 1778 1779 return mgt_set_request(netdev_priv(ndev), oid, 0, extra); 1780} 1781 1782void 1783prism54_acl_init(struct islpci_acl *acl) 1784{ 1785 mutex_init(&acl->lock); 1786 INIT_LIST_HEAD(&acl->mac_list); 1787 acl->size = 0; 1788 acl->policy = MAC_POLICY_OPEN; 1789} 1790 1791static void 1792prism54_clear_mac(struct islpci_acl *acl) 1793{ 1794 struct list_head *ptr, *next; 1795 struct mac_entry *entry; 1796 1797 mutex_lock(&acl->lock); 1798 1799 if (acl->size == 0) { 1800 mutex_unlock(&acl->lock); 1801 return; 1802 } 1803 1804 for (ptr = acl->mac_list.next, next = ptr->next; 1805 ptr != &acl->mac_list; ptr = next, next = ptr->next) { 1806 entry = list_entry(ptr, struct mac_entry, _list); 1807 list_del(ptr); 1808 kfree(entry); 1809 } 1810 acl->size = 0; 1811 mutex_unlock(&acl->lock); 1812} 1813 1814void 1815prism54_acl_clean(struct islpci_acl *acl) 1816{ 1817 prism54_clear_mac(acl); 1818} 1819 1820static int 1821prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, 1822 struct sockaddr *awrq, char *extra) 1823{ 1824 islpci_private *priv = netdev_priv(ndev); 1825 struct islpci_acl *acl = &priv->acl; 1826 struct mac_entry *entry; 1827 struct sockaddr *addr = (struct sockaddr *) extra; 1828 1829 if (addr->sa_family != ARPHRD_ETHER) 1830 return -EOPNOTSUPP; 1831 1832 entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); 1833 if (entry == NULL) 1834 return -ENOMEM; 1835 1836 memcpy(entry->addr, addr->sa_data, ETH_ALEN); 1837 1838 if (mutex_lock_interruptible(&acl->lock)) { 1839 kfree(entry); 1840 return -ERESTARTSYS; 1841 } 1842 list_add_tail(&entry->_list, &acl->mac_list); 1843 acl->size++; 1844 mutex_unlock(&acl->lock); 1845 1846 return 0; 1847} 1848 1849static int 1850prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, 1851 struct sockaddr *awrq, char *extra) 1852{ 1853 islpci_private *priv = netdev_priv(ndev); 1854 struct islpci_acl *acl = &priv->acl; 1855 struct mac_entry *entry; 1856 struct sockaddr *addr = (struct sockaddr *) extra; 1857 1858 if (addr->sa_family != ARPHRD_ETHER) 1859 return -EOPNOTSUPP; 1860 1861 if (mutex_lock_interruptible(&acl->lock)) 1862 return -ERESTARTSYS; 1863 list_for_each_entry(entry, &acl->mac_list, _list) { 1864 if (ether_addr_equal(entry->addr, addr->sa_data)) { 1865 list_del(&entry->_list); 1866 acl->size--; 1867 kfree(entry); 1868 mutex_unlock(&acl->lock); 1869 return 0; 1870 } 1871 } 1872 mutex_unlock(&acl->lock); 1873 return -EINVAL; 1874} 1875 1876static int 1877prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, 1878 struct iw_point *dwrq, char *extra) 1879{ 1880 islpci_private *priv = netdev_priv(ndev); 1881 struct islpci_acl *acl = &priv->acl; 1882 struct mac_entry *entry; 1883 struct sockaddr *dst = (struct sockaddr *) extra; 1884 1885 dwrq->length = 0; 1886 1887 if (mutex_lock_interruptible(&acl->lock)) 1888 return -ERESTARTSYS; 1889 1890 list_for_each_entry(entry, &acl->mac_list, _list) { 1891 memcpy(dst->sa_data, entry->addr, ETH_ALEN); 1892 dst->sa_family = ARPHRD_ETHER; 1893 dwrq->length++; 1894 dst++; 1895 } 1896 mutex_unlock(&acl->lock); 1897 return 0; 1898} 1899 1900/* Setting policy also clears the MAC acl, even if we don't change the default 1901 * policy 1902 */ 1903 1904static int 1905prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, 1906 __u32 * uwrq, char *extra) 1907{ 1908 islpci_private *priv = netdev_priv(ndev); 1909 struct islpci_acl *acl = &priv->acl; 1910 u32 mlmeautolevel; 1911 1912 prism54_clear_mac(acl); 1913 1914 if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) 1915 return -EINVAL; 1916 1917 down_write(&priv->mib_sem); 1918 1919 acl->policy = *uwrq; 1920 1921 /* the ACL code needs an intermediate mlmeautolevel */ 1922 if ((priv->iw_mode == IW_MODE_MASTER) && 1923 (acl->policy != MAC_POLICY_OPEN)) 1924 mlmeautolevel = DOT11_MLME_INTERMEDIATE; 1925 else 1926 mlmeautolevel = CARD_DEFAULT_MLME_MODE; 1927 if (priv->wpa) 1928 mlmeautolevel = DOT11_MLME_EXTENDED; 1929 mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); 1930 /* restart the card with our new policy */ 1931 if (mgt_commit(priv)) { 1932 up_write(&priv->mib_sem); 1933 return -EIO; 1934 } 1935 up_write(&priv->mib_sem); 1936 1937 return 0; 1938} 1939 1940static int 1941prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, 1942 __u32 * uwrq, char *extra) 1943{ 1944 islpci_private *priv = netdev_priv(ndev); 1945 struct islpci_acl *acl = &priv->acl; 1946 1947 *uwrq = acl->policy; 1948 1949 return 0; 1950} 1951 1952/* Return 1 only if client should be accepted. */ 1953 1954static int 1955prism54_mac_accept(struct islpci_acl *acl, char *mac) 1956{ 1957 struct mac_entry *entry; 1958 int res = 0; 1959 1960 if (mutex_lock_interruptible(&acl->lock)) 1961 return -ERESTARTSYS; 1962 1963 if (acl->policy == MAC_POLICY_OPEN) { 1964 mutex_unlock(&acl->lock); 1965 return 1; 1966 } 1967 1968 list_for_each_entry(entry, &acl->mac_list, _list) { 1969 if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { 1970 res = 1; 1971 break; 1972 } 1973 } 1974 res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; 1975 mutex_unlock(&acl->lock); 1976 1977 return res; 1978} 1979 1980static int 1981prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, 1982 struct iw_point *dwrq, char *extra) 1983{ 1984 struct obj_mlme *mlme; 1985 int rvalue; 1986 1987 mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); 1988 if (mlme == NULL) 1989 return -ENOMEM; 1990 1991 /* Tell the card to kick every client */ 1992 mlme->id = 0; 1993 rvalue = 1994 mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); 1995 kfree(mlme); 1996 1997 return rvalue; 1998} 1999 2000static int 2001prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, 2002 struct sockaddr *awrq, char *extra) 2003{ 2004 struct obj_mlme *mlme; 2005 struct sockaddr *addr = (struct sockaddr *) extra; 2006 int rvalue; 2007 2008 if (addr->sa_family != ARPHRD_ETHER) 2009 return -EOPNOTSUPP; 2010 2011 mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); 2012 if (mlme == NULL) 2013 return -ENOMEM; 2014 2015 /* Tell the card to only kick the corresponding bastard */ 2016 memcpy(mlme->address, addr->sa_data, ETH_ALEN); 2017 mlme->id = -1; 2018 rvalue = 2019 mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); 2020 2021 kfree(mlme); 2022 2023 return rvalue; 2024} 2025 2026/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ 2027 2028static void 2029format_event(islpci_private *priv, char *dest, const char *str, 2030 const struct obj_mlme *mlme, u16 *length, int error) 2031{ 2032 int n = snprintf(dest, IW_CUSTOM_MAX, 2033 "%s %s %pM %s (%2.2X)", 2034 str, 2035 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), 2036 mlme->address, 2037 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") 2038 : ""), mlme->code); 2039 WARN_ON(n >= IW_CUSTOM_MAX); 2040 *length = n; 2041} 2042 2043static void 2044send_formatted_event(islpci_private *priv, const char *str, 2045 const struct obj_mlme *mlme, int error) 2046{ 2047 union iwreq_data wrqu; 2048 char *memptr; 2049 2050 memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); 2051 if (!memptr) 2052 return; 2053 wrqu.data.pointer = memptr; 2054 wrqu.data.length = 0; 2055 format_event(priv, memptr, str, mlme, &wrqu.data.length, 2056 error); 2057 wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); 2058 kfree(memptr); 2059} 2060 2061static void 2062send_simple_event(islpci_private *priv, const char *str) 2063{ 2064 union iwreq_data wrqu; 2065 char *memptr; 2066 int n = strlen(str); 2067 2068 memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); 2069 if (!memptr) 2070 return; 2071 BUG_ON(n >= IW_CUSTOM_MAX); 2072 wrqu.data.pointer = memptr; 2073 wrqu.data.length = n; 2074 strcpy(memptr, str); 2075 wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); 2076 kfree(memptr); 2077} 2078 2079static void 2080link_changed(struct net_device *ndev, u32 bitrate) 2081{ 2082 islpci_private *priv = netdev_priv(ndev); 2083 2084 if (bitrate) { 2085 netif_carrier_on(ndev); 2086 if (priv->iw_mode == IW_MODE_INFRA) { 2087 union iwreq_data uwrq; 2088 prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, 2089 NULL); 2090 wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); 2091 } else 2092 send_simple_event(netdev_priv(ndev), 2093 "Link established"); 2094 } else { 2095 netif_carrier_off(ndev); 2096 send_simple_event(netdev_priv(ndev), "Link lost"); 2097 } 2098} 2099 2100/* Beacon/ProbeResp payload header */ 2101struct ieee80211_beacon_phdr { 2102 u8 timestamp[8]; 2103 u16 beacon_int; 2104 u16 capab_info; 2105} __packed; 2106 2107#define WLAN_EID_GENERIC 0xdd 2108static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; 2109 2110static void 2111prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, 2112 u8 *wpa_ie, size_t wpa_ie_len) 2113{ 2114 struct list_head *ptr; 2115 struct islpci_bss_wpa_ie *bss = NULL; 2116 2117 if (wpa_ie_len > MAX_WPA_IE_LEN) 2118 wpa_ie_len = MAX_WPA_IE_LEN; 2119 2120 mutex_lock(&priv->wpa_lock); 2121 2122 /* try to use existing entry */ 2123 list_for_each(ptr, &priv->bss_wpa_list) { 2124 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); 2125 if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { 2126 list_move(&bss->list, &priv->bss_wpa_list); 2127 break; 2128 } 2129 bss = NULL; 2130 } 2131 2132 if (bss == NULL) { 2133 /* add a new BSS entry; if max number of entries is already 2134 * reached, replace the least recently updated */ 2135 if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { 2136 bss = list_entry(priv->bss_wpa_list.prev, 2137 struct islpci_bss_wpa_ie, list); 2138 list_del(&bss->list); 2139 } else { 2140 bss = kzalloc(sizeof (*bss), GFP_ATOMIC); 2141 if (bss != NULL) 2142 priv->num_bss_wpa++; 2143 } 2144 if (bss != NULL) { 2145 memcpy(bss->bssid, bssid, ETH_ALEN); 2146 list_add(&bss->list, &priv->bss_wpa_list); 2147 } 2148 } 2149 2150 if (bss != NULL) { 2151 memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); 2152 bss->wpa_ie_len = wpa_ie_len; 2153 bss->last_update = jiffies; 2154 } else { 2155 printk(KERN_DEBUG "Failed to add BSS WPA entry for " 2156 "%pM\n", bssid); 2157 } 2158 2159 /* expire old entries from WPA list */ 2160 while (priv->num_bss_wpa > 0) { 2161 bss = list_entry(priv->bss_wpa_list.prev, 2162 struct islpci_bss_wpa_ie, list); 2163 if (!time_after(jiffies, bss->last_update + 60 * HZ)) 2164 break; 2165 2166 list_del(&bss->list); 2167 priv->num_bss_wpa--; 2168 kfree(bss); 2169 } 2170 2171 mutex_unlock(&priv->wpa_lock); 2172} 2173 2174static size_t 2175prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) 2176{ 2177 struct list_head *ptr; 2178 struct islpci_bss_wpa_ie *bss = NULL; 2179 size_t len = 0; 2180 2181 mutex_lock(&priv->wpa_lock); 2182 2183 list_for_each(ptr, &priv->bss_wpa_list) { 2184 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); 2185 if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 2186 break; 2187 bss = NULL; 2188 } 2189 if (bss) { 2190 len = bss->wpa_ie_len; 2191 memcpy(wpa_ie, bss->wpa_ie, len); 2192 } 2193 mutex_unlock(&priv->wpa_lock); 2194 2195 return len; 2196} 2197 2198void 2199prism54_wpa_bss_ie_init(islpci_private *priv) 2200{ 2201 INIT_LIST_HEAD(&priv->bss_wpa_list); 2202 mutex_init(&priv->wpa_lock); 2203} 2204 2205void 2206prism54_wpa_bss_ie_clean(islpci_private *priv) 2207{ 2208 struct islpci_bss_wpa_ie *bss, *n; 2209 2210 list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) { 2211 kfree(bss); 2212 } 2213} 2214 2215static void 2216prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, 2217 u8 *payload, size_t len) 2218{ 2219 struct ieee80211_beacon_phdr *hdr; 2220 u8 *pos, *end; 2221 2222 if (!priv->wpa) 2223 return; 2224 2225 hdr = (struct ieee80211_beacon_phdr *) payload; 2226 pos = (u8 *) (hdr + 1); 2227 end = payload + len; 2228 while (pos < end) { 2229 if (pos + 2 + pos[1] > end) { 2230 printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " 2231 "for %pM\n", addr); 2232 return; 2233 } 2234 if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && 2235 memcmp(pos + 2, wpa_oid, 4) == 0) { 2236 prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2); 2237 return; 2238 } 2239 pos += 2 + pos[1]; 2240 } 2241} 2242 2243static void 2244handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) 2245{ 2246 if (((mlme->state == DOT11_STATE_AUTHING) || 2247 (mlme->state == DOT11_STATE_ASSOCING)) 2248 && mgt_mlme_answer(priv)) { 2249 /* Someone is requesting auth and we must respond. Just send back 2250 * the trap with error code set accordingly. 2251 */ 2252 mlme->code = prism54_mac_accept(&priv->acl, 2253 mlme->address) ? 0 : 1; 2254 mgt_set_request(priv, oid, 0, mlme); 2255 } 2256} 2257 2258static int 2259prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, 2260 char *data) 2261{ 2262 struct obj_mlme *mlme = (struct obj_mlme *) data; 2263 struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data; 2264 struct obj_mlmeex *confirm; 2265 u8 wpa_ie[MAX_WPA_IE_LEN]; 2266 int wpa_ie_len; 2267 size_t len = 0; /* u16, better? */ 2268 u8 *payload = NULL, *pos = NULL; 2269 int ret; 2270 2271 /* I think all trapable objects are listed here. 2272 * Some oids have a EX version. The difference is that they are emitted 2273 * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) 2274 * with more info. 2275 * The few events already defined by the wireless tools are not really 2276 * suited. We use the more flexible custom event facility. 2277 */ 2278 2279 if (oid >= DOT11_OID_BEACON) { 2280 len = mlmeex->size; 2281 payload = pos = mlmeex->data; 2282 } 2283 2284 /* I fear prism54_process_bss_data won't work with big endian data */ 2285 if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) 2286 prism54_process_bss_data(priv, oid, mlmeex->address, 2287 payload, len); 2288 2289 mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); 2290 2291 switch (oid) { 2292 2293 case GEN_OID_LINKSTATE: 2294 link_changed(priv->ndev, (u32) *data); 2295 break; 2296 2297 case DOT11_OID_MICFAILURE: 2298 send_simple_event(priv, "Mic failure"); 2299 break; 2300 2301 case DOT11_OID_DEAUTHENTICATE: 2302 send_formatted_event(priv, "DeAuthenticate request", mlme, 0); 2303 break; 2304 2305 case DOT11_OID_AUTHENTICATE: 2306 handle_request(priv, mlme, oid); 2307 send_formatted_event(priv, "Authenticate request", mlme, 1); 2308 break; 2309 2310 case DOT11_OID_DISASSOCIATE: 2311 send_formatted_event(priv, "Disassociate request", mlme, 0); 2312 break; 2313 2314 case DOT11_OID_ASSOCIATE: 2315 handle_request(priv, mlme, oid); 2316 send_formatted_event(priv, "Associate request", mlme, 1); 2317 break; 2318 2319 case DOT11_OID_REASSOCIATE: 2320 handle_request(priv, mlme, oid); 2321 send_formatted_event(priv, "ReAssociate request", mlme, 1); 2322 break; 2323 2324 case DOT11_OID_BEACON: 2325 send_formatted_event(priv, 2326 "Received a beacon from an unknown AP", 2327 mlme, 0); 2328 break; 2329 2330 case DOT11_OID_PROBE: 2331 /* we received a probe from a client. */ 2332 send_formatted_event(priv, "Received a probe from client", mlme, 2333 0); 2334 break; 2335 2336 /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this 2337 * is backward compatible layout-wise with "struct obj_mlme". 2338 */ 2339 2340 case DOT11_OID_DEAUTHENTICATEEX: 2341 send_formatted_event(priv, "DeAuthenticate request", mlme, 0); 2342 break; 2343 2344 case DOT11_OID_AUTHENTICATEEX: 2345 handle_request(priv, mlme, oid); 2346 send_formatted_event(priv, "Authenticate request (ex)", mlme, 1); 2347 2348 if (priv->iw_mode != IW_MODE_MASTER 2349 && mlmeex->state != DOT11_STATE_AUTHING) 2350 break; 2351 2352 confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC); 2353 2354 if (!confirm) 2355 break; 2356 2357 memcpy(&confirm->address, mlmeex->address, ETH_ALEN); 2358 printk(KERN_DEBUG "Authenticate from: address:\t%pM\n", 2359 mlmeex->address); 2360 confirm->id = -1; /* or mlmeex->id ? */ 2361 confirm->state = 0; /* not used */ 2362 confirm->code = 0; 2363 confirm->size = 6; 2364 confirm->data[0] = 0x00; 2365 confirm->data[1] = 0x00; 2366 confirm->data[2] = 0x02; 2367 confirm->data[3] = 0x00; 2368 confirm->data[4] = 0x00; 2369 confirm->data[5] = 0x00; 2370 2371 ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6); 2372 2373 kfree(confirm); 2374 if (ret) 2375 return ret; 2376 break; 2377 2378 case DOT11_OID_DISASSOCIATEEX: 2379 send_formatted_event(priv, "Disassociate request (ex)", mlme, 0); 2380 break; 2381 2382 case DOT11_OID_ASSOCIATEEX: 2383 handle_request(priv, mlme, oid); 2384 send_formatted_event(priv, "Associate request (ex)", mlme, 1); 2385 2386 if (priv->iw_mode != IW_MODE_MASTER 2387 && mlmeex->state != DOT11_STATE_ASSOCING) 2388 break; 2389 2390 confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); 2391 2392 if (!confirm) 2393 break; 2394 2395 memcpy(&confirm->address, mlmeex->address, ETH_ALEN); 2396 2397 confirm->id = ((struct obj_mlmeex *)mlme)->id; 2398 confirm->state = 0; /* not used */ 2399 confirm->code = 0; 2400 2401 wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); 2402 2403 if (!wpa_ie_len) { 2404 printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", 2405 mlmeex->address); 2406 kfree(confirm); 2407 break; 2408 } 2409 2410 confirm->size = wpa_ie_len; 2411 memcpy(&confirm->data, wpa_ie, wpa_ie_len); 2412 2413 mgt_set_varlen(priv, oid, confirm, wpa_ie_len); 2414 2415 kfree(confirm); 2416 2417 break; 2418 2419 case DOT11_OID_REASSOCIATEEX: 2420 handle_request(priv, mlme, oid); 2421 send_formatted_event(priv, "Reassociate request (ex)", mlme, 1); 2422 2423 if (priv->iw_mode != IW_MODE_MASTER 2424 && mlmeex->state != DOT11_STATE_ASSOCING) 2425 break; 2426 2427 confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); 2428 2429 if (!confirm) 2430 break; 2431 2432 memcpy(&confirm->address, mlmeex->address, ETH_ALEN); 2433 2434 confirm->id = mlmeex->id; 2435 confirm->state = 0; /* not used */ 2436 confirm->code = 0; 2437 2438 wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); 2439 2440 if (!wpa_ie_len) { 2441 printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", 2442 mlmeex->address); 2443 kfree(confirm); 2444 break; 2445 } 2446 2447 confirm->size = wpa_ie_len; 2448 memcpy(&confirm->data, wpa_ie, wpa_ie_len); 2449 2450 mgt_set_varlen(priv, oid, confirm, wpa_ie_len); 2451 2452 kfree(confirm); 2453 2454 break; 2455 2456 default: 2457 return -EINVAL; 2458 } 2459 2460 return 0; 2461} 2462 2463/* 2464 * Process a device trap. This is called via schedule_work(), outside of 2465 * interrupt context, no locks held. 2466 */ 2467void 2468prism54_process_trap(struct work_struct *work) 2469{ 2470 struct islpci_mgmtframe *frame = 2471 container_of(work, struct islpci_mgmtframe, ws); 2472 struct net_device *ndev = frame->ndev; 2473 enum oid_num_t n = mgt_oidtonum(frame->header->oid); 2474 2475 if (n != OID_NUM_LAST) 2476 prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); 2477 islpci_mgt_release(frame); 2478} 2479 2480int 2481prism54_set_mac_address(struct net_device *ndev, void *addr) 2482{ 2483 islpci_private *priv = netdev_priv(ndev); 2484 int ret; 2485 2486 if (ndev->addr_len != 6) 2487 return -EINVAL; 2488 ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, 2489 &((struct sockaddr *) addr)->sa_data); 2490 if (!ret) 2491 memcpy(priv->ndev->dev_addr, 2492 &((struct sockaddr *) addr)->sa_data, ETH_ALEN); 2493 2494 return ret; 2495} 2496 2497#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 2498 2499static int 2500prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, 2501 __u32 * uwrq, char *extra) 2502{ 2503 islpci_private *priv = netdev_priv(ndev); 2504 u32 mlme, authen, dot1x, filter, wep; 2505 2506 if (islpci_get_state(priv) < PRV_STATE_INIT) 2507 return 0; 2508 2509 wep = 1; /* For privacy invoked */ 2510 filter = 1; /* Filter out all unencrypted frames */ 2511 dot1x = 0x01; /* To enable eap filter */ 2512 mlme = DOT11_MLME_EXTENDED; 2513 authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ 2514 2515 down_write(&priv->mib_sem); 2516 priv->wpa = *uwrq; 2517 2518 switch (priv->wpa) { 2519 default: 2520 case 0: /* Clears/disables WPA and friends */ 2521 wep = 0; 2522 filter = 0; /* Do not filter un-encrypted data */ 2523 dot1x = 0; 2524 mlme = DOT11_MLME_AUTO; 2525 printk("%s: Disabling WPA\n", ndev->name); 2526 break; 2527 case 2: 2528 case 1: /* WPA */ 2529 printk("%s: Enabling WPA\n", ndev->name); 2530 break; 2531 } 2532 up_write(&priv->mib_sem); 2533 2534 mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); 2535 mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); 2536 mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); 2537 mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); 2538 mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); 2539 2540 return 0; 2541} 2542 2543static int 2544prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, 2545 __u32 * uwrq, char *extra) 2546{ 2547 islpci_private *priv = netdev_priv(ndev); 2548 *uwrq = priv->wpa; 2549 return 0; 2550} 2551 2552static int 2553prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, 2554 __u32 * uwrq, char *extra) 2555{ 2556 islpci_private *priv = netdev_priv(ndev); 2557 priv->monitor_type = 2558 (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); 2559 if (priv->iw_mode == IW_MODE_MONITOR) 2560 priv->ndev->type = priv->monitor_type; 2561 2562 return 0; 2563} 2564 2565static int 2566prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, 2567 __u32 * uwrq, char *extra) 2568{ 2569 islpci_private *priv = netdev_priv(ndev); 2570 *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); 2571 return 0; 2572} 2573 2574static int 2575prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, 2576 __u32 * uwrq, char *extra) 2577{ 2578 islpci_private *priv = netdev_priv(ndev); 2579 2580 priv->priv_oid = *uwrq; 2581 printk("%s: oid 0x%08X\n", ndev->name, *uwrq); 2582 2583 return 0; 2584} 2585 2586static int 2587prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, 2588 struct iw_point *data, char *extra) 2589{ 2590 islpci_private *priv = netdev_priv(ndev); 2591 struct islpci_mgmtframe *response; 2592 int ret = -EIO; 2593 2594 printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); 2595 data->length = 0; 2596 2597 if (islpci_get_state(priv) >= PRV_STATE_INIT) { 2598 ret = 2599 islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, 2600 priv->priv_oid, extra, 256, 2601 &response); 2602 printk("%s: ret: %i\n", ndev->name, ret); 2603 if (ret || !response 2604 || response->header->operation == PIMFOR_OP_ERROR) { 2605 if (response) { 2606 islpci_mgt_release(response); 2607 } 2608 printk("%s: EIO\n", ndev->name); 2609 ret = -EIO; 2610 } 2611 if (!ret) { 2612 data->length = response->header->length; 2613 memcpy(extra, response->data, data->length); 2614 islpci_mgt_release(response); 2615 printk("%s: len: %i\n", ndev->name, data->length); 2616 } 2617 } 2618 2619 return ret; 2620} 2621 2622static int 2623prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, 2624 struct iw_point *data, char *extra) 2625{ 2626 islpci_private *priv = netdev_priv(ndev); 2627 struct islpci_mgmtframe *response; 2628 int ret = 0, response_op = PIMFOR_OP_ERROR; 2629 2630 printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, 2631 data->length); 2632 2633 if (islpci_get_state(priv) >= PRV_STATE_INIT) { 2634 ret = 2635 islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, 2636 priv->priv_oid, extra, data->length, 2637 &response); 2638 printk("%s: ret: %i\n", ndev->name, ret); 2639 if (ret || !response 2640 || response->header->operation == PIMFOR_OP_ERROR) { 2641 if (response) { 2642 islpci_mgt_release(response); 2643 } 2644 printk("%s: EIO\n", ndev->name); 2645 ret = -EIO; 2646 } 2647 if (!ret) { 2648 response_op = response->header->operation; 2649 printk("%s: response_op: %i\n", ndev->name, 2650 response_op); 2651 islpci_mgt_release(response); 2652 } 2653 } 2654 2655 return (ret ? ret : -EINPROGRESS); 2656} 2657 2658static int 2659prism54_set_spy(struct net_device *ndev, 2660 struct iw_request_info *info, 2661 union iwreq_data *uwrq, char *extra) 2662{ 2663 islpci_private *priv = netdev_priv(ndev); 2664 u32 u; 2665 enum oid_num_t oid = OID_INL_CONFIG; 2666 2667 down_write(&priv->mib_sem); 2668 mgt_get(priv, OID_INL_CONFIG, &u); 2669 2670 if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) 2671 /* disable spy */ 2672 u &= ~INL_CONFIG_RXANNEX; 2673 else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) 2674 /* enable spy */ 2675 u |= INL_CONFIG_RXANNEX; 2676 2677 mgt_set(priv, OID_INL_CONFIG, &u); 2678 mgt_commit_list(priv, &oid, 1); 2679 up_write(&priv->mib_sem); 2680 2681 return iw_handler_set_spy(ndev, info, uwrq, extra); 2682} 2683 2684static const iw_handler prism54_handler[] = { 2685 (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ 2686 (iw_handler) prism54_get_name, /* SIOCGIWNAME */ 2687 (iw_handler) NULL, /* SIOCSIWNWID */ 2688 (iw_handler) NULL, /* SIOCGIWNWID */ 2689 (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ 2690 (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ 2691 (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ 2692 (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ 2693 (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ 2694 (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ 2695 (iw_handler) NULL, /* SIOCSIWRANGE */ 2696 (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ 2697 (iw_handler) NULL, /* SIOCSIWPRIV */ 2698 (iw_handler) NULL, /* SIOCGIWPRIV */ 2699 (iw_handler) NULL, /* SIOCSIWSTATS */ 2700 (iw_handler) NULL, /* SIOCGIWSTATS */ 2701 prism54_set_spy, /* SIOCSIWSPY */ 2702 iw_handler_get_spy, /* SIOCGIWSPY */ 2703 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ 2704 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ 2705 (iw_handler) prism54_set_wap, /* SIOCSIWAP */ 2706 (iw_handler) prism54_get_wap, /* SIOCGIWAP */ 2707 (iw_handler) NULL, /* -- hole -- */ 2708 (iw_handler) NULL, /* SIOCGIWAPLIST deprecated */ 2709 (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ 2710 (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ 2711 (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ 2712 (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ 2713 (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ 2714 (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ 2715 (iw_handler) NULL, /* -- hole -- */ 2716 (iw_handler) NULL, /* -- hole -- */ 2717 (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ 2718 (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ 2719 (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ 2720 (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ 2721 (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ 2722 (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ 2723 (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ 2724 (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ 2725 (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ 2726 (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ 2727 (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ 2728 (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ 2729 (iw_handler) NULL, /* SIOCSIWPOWER */ 2730 (iw_handler) NULL, /* SIOCGIWPOWER */ 2731 NULL, /* -- hole -- */ 2732 NULL, /* -- hole -- */ 2733 (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */ 2734 (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */ 2735 (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */ 2736 (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */ 2737 (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */ 2738 (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */ 2739 NULL, /* SIOCSIWPMKSA */ 2740}; 2741 2742/* The low order bit identify a SET (0) or a GET (1) ioctl. */ 2743 2744#define PRISM54_RESET SIOCIWFIRSTPRIV 2745#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1 2746#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2 2747#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3 2748#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4 2749 2750#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6 2751 2752#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8 2753 2754#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10 2755 2756#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11 2757#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 2758 2759#define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14 2760#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15 2761#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16 2762 2763#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 2764#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18 2765#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20 2766#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22 2767 2768#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23 2769#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24 2770 2771#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } 2772#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } 2773#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } 2774#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x } 2775 2776#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x) 2777#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x) 2778#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x) 2779 2780/* Note : limited to 128 private ioctls (wireless tools 26) */ 2781 2782static const struct iw_priv_args prism54_private_args[] = { 2783/*{ cmd, set_args, get_args, name } */ 2784 {PRISM54_RESET, 0, 0, "reset"}, 2785 {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 2786 "get_prismhdr"}, 2787 {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 2788 "set_prismhdr"}, 2789 {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 2790 "getPolicy"}, 2791 {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 2792 "setPolicy"}, 2793 {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, 2794 {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, 2795 "addMac"}, 2796 {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, 2797 "delMac"}, 2798 {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, 2799 "kickMac"}, 2800 {PRISM54_KICK_ALL, 0, 0, "kickAll"}, 2801 {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 2802 "get_wpa"}, 2803 {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 2804 "set_wpa"}, 2805 {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 2806 "dbg_oid"}, 2807 {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"}, 2808 {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"}, 2809 /* --- sub-ioctls handlers --- */ 2810 {PRISM54_GET_OID, 2811 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""}, 2812 {PRISM54_SET_OID_U32, 2813 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, 2814 {PRISM54_SET_OID_STR, 2815 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, 2816 {PRISM54_SET_OID_ADDR, 2817 IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, 2818 /* --- sub-ioctls definitions --- */ 2819 IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"), 2820 IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"), 2821 IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"), 2822 IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"), 2823 IWPRIV_U32(DOT11_OID_STATE, "state"), 2824 IWPRIV_U32(DOT11_OID_AID, "aid"), 2825 2826 IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"), 2827 2828 IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"), 2829 IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"), 2830 IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"), 2831 2832 IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"), 2833 IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"), 2834 IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"), 2835 2836 IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"), 2837 2838 IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"), 2839 IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"), 2840 IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"), 2841 IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"), 2842 IWPRIV_U32(DOT11_OID_PSM, "psm"), 2843 2844 IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"), 2845 IWPRIV_U32(DOT11_OID_CLIENTS, "clients"), 2846 IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"), 2847 IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"), 2848 IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"), 2849 IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"), 2850 IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"), 2851 IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"), 2852 IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"), 2853 IWPRIV_GET(DOT11_OID_RATES, "rates"), 2854 IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"), 2855 IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"), 2856 IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"), 2857 2858 IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"), 2859 IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"), 2860 IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"), 2861 IWPRIV_U32(DOT11_OID_PROFILES, "profile"), 2862 IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"), 2863 IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"), 2864 2865 IWPRIV_GET(DOT11_OID_BSSS, "bsss"), 2866 IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"), 2867 IWPRIV_U32(OID_INL_MODE, "mode"), 2868 IWPRIV_U32(OID_INL_CONFIG, "config"), 2869 IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"), 2870 IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"), 2871 IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"), 2872}; 2873 2874static const iw_handler prism54_private_handler[] = { 2875 (iw_handler) prism54_reset, 2876 (iw_handler) prism54_get_policy, 2877 (iw_handler) prism54_set_policy, 2878 (iw_handler) prism54_get_mac, 2879 (iw_handler) prism54_add_mac, 2880 (iw_handler) NULL, 2881 (iw_handler) prism54_del_mac, 2882 (iw_handler) NULL, 2883 (iw_handler) prism54_kick_mac, 2884 (iw_handler) NULL, 2885 (iw_handler) prism54_kick_all, 2886 (iw_handler) prism54_get_wpa, 2887 (iw_handler) prism54_set_wpa, 2888 (iw_handler) NULL, 2889 (iw_handler) prism54_debug_oid, 2890 (iw_handler) prism54_debug_get_oid, 2891 (iw_handler) prism54_debug_set_oid, 2892 (iw_handler) prism54_get_oid, 2893 (iw_handler) prism54_set_u32, 2894 (iw_handler) NULL, 2895 (iw_handler) prism54_set_raw, 2896 (iw_handler) NULL, 2897 (iw_handler) prism54_set_raw, 2898 (iw_handler) prism54_get_prismhdr, 2899 (iw_handler) prism54_set_prismhdr, 2900}; 2901 2902const struct iw_handler_def prism54_handler_def = { 2903 .num_standard = ARRAY_SIZE(prism54_handler), 2904 .num_private = ARRAY_SIZE(prism54_private_handler), 2905 .num_private_args = ARRAY_SIZE(prism54_private_args), 2906 .standard = (iw_handler *) prism54_handler, 2907 .private = (iw_handler *) prism54_private_handler, 2908 .private_args = (struct iw_priv_args *) prism54_private_args, 2909 .get_wireless_stats = prism54_get_wireless_stats, 2910}; 2911