Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.35-rc2 1690 lines 40 kB view raw
1/* src/p80211/p80211wext.c 2* 3* Glue code to make linux-wlan-ng a happy wireless extension camper. 4* 5* original author: Reyk Floeter <reyk@synack.de> 6* Completely re-written by Solomon Peachy <solomon@linux-wlan.com> 7* 8* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. 9* -------------------------------------------------------------------- 10* 11* linux-wlan 12* 13* The contents of this file are subject to the Mozilla Public 14* License Version 1.1 (the "License"); you may not use this file 15* except in compliance with the License. You may obtain a copy of 16* the License at http://www.mozilla.org/MPL/ 17* 18* Software distributed under the License is distributed on an "AS 19* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 20* implied. See the License for the specific language governing 21* rights and limitations under the License. 22* 23* Alternatively, the contents of this file may be used under the 24* terms of the GNU Public License version 2 (the "GPL"), in which 25* case the provisions of the GPL are applicable instead of the 26* above. If you wish to allow the use of your version of this file 27* only under the terms of the GPL and not to allow others to use 28* your version of this file under the MPL, indicate your decision 29* by deleting the provisions above and replace them with the notice 30* and other provisions required by the GPL. If you do not delete 31* the provisions above, a recipient may use your version of this 32* file under either the MPL or the GPL. 33* 34* -------------------------------------------------------------------- 35*/ 36 37/*================================================================*/ 38/* System Includes */ 39 40#include <linux/kernel.h> 41#include <linux/sched.h> 42#include <linux/types.h> 43#include <linux/netdevice.h> 44#include <linux/etherdevice.h> 45#include <linux/wireless.h> 46#include <net/iw_handler.h> 47#include <linux/if_arp.h> 48#include <linux/bitops.h> 49#include <linux/uaccess.h> 50#include <asm/byteorder.h> 51#include <linux/if_ether.h> 52 53#include "p80211types.h" 54#include "p80211hdr.h" 55#include "p80211conv.h" 56#include "p80211mgmt.h" 57#include "p80211msg.h" 58#include "p80211metastruct.h" 59#include "p80211metadef.h" 60#include "p80211netdev.h" 61#include "p80211ioctl.h" 62#include "p80211req.h" 63 64static int p80211wext_giwrate(netdevice_t *dev, 65 struct iw_request_info *info, 66 struct iw_param *rrq, char *extra); 67static int p80211wext_giwessid(netdevice_t *dev, 68 struct iw_request_info *info, 69 struct iw_point *data, char *essid); 70 71static u8 p80211_mhz_to_channel(u16 mhz) 72{ 73 if (mhz >= 5000) 74 return (mhz - 5000) / 5; 75 76 if (mhz == 2484) 77 return 14; 78 79 if (mhz >= 2407) 80 return (mhz - 2407) / 5; 81 82 return 0; 83} 84 85static u16 p80211_channel_to_mhz(u8 ch, int dot11a) 86{ 87 88 if (ch == 0) 89 return 0; 90 if (ch > 200) 91 return 0; 92 93 /* 5G */ 94 if (dot11a) 95 return 5000 + (5 * ch); 96 97 /* 2.4G */ 98 if (ch == 14) 99 return 2484; 100 101 if ((ch < 14) && (ch > 0)) 102 return 2407 + (5 * ch); 103 104 return 0; 105} 106 107/* taken from orinoco.c ;-) */ 108static const long p80211wext_channel_freq[] = { 109 2412, 2417, 2422, 2427, 2432, 2437, 2442, 110 2447, 2452, 2457, 2462, 2467, 2472, 2484 111}; 112 113#define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq) 114 115/* steal a spare bit to store the shared/opensystems state. 116 should default to open if not set */ 117#define HOSTWEP_SHAREDKEY BIT(3) 118 119static int qual_as_percent(int snr) 120{ 121 if (snr <= 0) 122 return 0; 123 if (snr <= 40) 124 return snr * 5 / 2; 125 return 100; 126} 127 128static int p80211wext_setmib(wlandevice_t *wlandev, u32 did, u32 data) 129{ 130 p80211msg_dot11req_mibset_t msg; 131 p80211item_uint32_t *mibitem = 132 (p80211item_uint32_t *)&msg.mibattribute.data; 133 int result; 134 135 msg.msgcode = DIDmsg_dot11req_mibset; 136 memset(mibitem, 0, sizeof(*mibitem)); 137 mibitem->did = did; 138 mibitem->data = data; 139 result = p80211req_dorequest(wlandev, (u8 *) &msg); 140 141 return result; 142} 143 144/* 145 * get a 32 bit mib value 146 */ 147static int p80211wext_getmib(wlandevice_t *wlandev, u32 did, u32 *data) 148{ 149 p80211msg_dot11req_mibset_t msg; 150 p80211item_uint32_t *mibitem = 151 (p80211item_uint32_t *)&msg.mibattribute.data; 152 int result; 153 154 msg.msgcode = DIDmsg_dot11req_mibget; 155 memset(mibitem, 0, sizeof(*mibitem)); 156 mibitem->did = did; 157 result = p80211req_dorequest(wlandev, (u8 *) &msg); 158 if (!result) 159 *data = mibitem->data; 160 161 return result; 162} 163 164static int p80211wext_autojoin(wlandevice_t *wlandev) 165{ 166 p80211msg_lnxreq_autojoin_t msg; 167 struct iw_point data; 168 char ssid[IW_ESSID_MAX_SIZE]; 169 170 int result; 171 int err = 0; 172 173 /* Get ESSID */ 174 result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid); 175 176 if (result) { 177 err = -EFAULT; 178 goto exit; 179 } 180 181 if (wlandev->hostwep & HOSTWEP_SHAREDKEY) 182 msg.authtype.data = P80211ENUM_authalg_sharedkey; 183 else 184 msg.authtype.data = P80211ENUM_authalg_opensystem; 185 186 msg.msgcode = DIDmsg_lnxreq_autojoin; 187 188 /* Trim the last '\0' to fit the SSID format */ 189 190 if (data.length && ssid[data.length - 1] == '\0') 191 data.length = data.length - 1; 192 193 memcpy(msg.ssid.data.data, ssid, data.length); 194 msg.ssid.data.len = data.length; 195 196 result = p80211req_dorequest(wlandev, (u8 *) &msg); 197 198 if (result) { 199 err = -EFAULT; 200 goto exit; 201 } 202 203exit: 204 205 return err; 206 207} 208 209/* called by /proc/net/wireless */ 210struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev) 211{ 212 p80211msg_lnxreq_commsquality_t quality; 213 wlandevice_t *wlandev = dev->ml_priv; 214 struct iw_statistics *wstats = &wlandev->wstats; 215 int retval; 216 217 /* Check */ 218 if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING)) 219 return NULL; 220 221 /* XXX Only valid in station mode */ 222 wstats->status = 0; 223 224 /* build request message */ 225 quality.msgcode = DIDmsg_lnxreq_commsquality; 226 quality.dbm.data = P80211ENUM_truth_true; 227 quality.dbm.status = P80211ENUM_msgitem_status_data_ok; 228 229 /* send message to nsd */ 230 if (wlandev->mlmerequest == NULL) 231 return NULL; 232 233 retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) &quality); 234 235 wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */ 236 wstats->qual.level = quality.level.data; /* instant signal level */ 237 wstats->qual.noise = quality.noise.data; /* instant noise level */ 238 239 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 240 wstats->discard.code = wlandev->rx.decrypt_err; 241 wstats->discard.nwid = 0; 242 wstats->discard.misc = 0; 243 244 wstats->discard.fragment = 0; /* incomplete fragments */ 245 wstats->discard.retries = 0; /* tx retries. */ 246 wstats->miss.beacon = 0; 247 248 return wstats; 249} 250 251static int p80211wext_giwname(netdevice_t *dev, 252 struct iw_request_info *info, 253 char *name, char *extra) 254{ 255 struct iw_param rate; 256 int result; 257 int err = 0; 258 259 result = p80211wext_giwrate(dev, NULL, &rate, NULL); 260 261 if (result) { 262 err = -EFAULT; 263 goto exit; 264 } 265 266 switch (rate.value) { 267 case 1000000: 268 case 2000000: 269 strcpy(name, "IEEE 802.11-DS"); 270 break; 271 case 5500000: 272 case 11000000: 273 strcpy(name, "IEEE 802.11-b"); 274 break; 275 } 276exit: 277 return err; 278} 279 280static int p80211wext_giwfreq(netdevice_t *dev, 281 struct iw_request_info *info, 282 struct iw_freq *freq, char *extra) 283{ 284 wlandevice_t *wlandev = dev->ml_priv; 285 int result; 286 int err = 0; 287 unsigned int value; 288 289 result = p80211wext_getmib(wlandev, 290 DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, 291 &value); 292 if (result) { 293 err = -EFAULT; 294 goto exit; 295 } 296 297 if (value > NUM_CHANNELS) { 298 err = -EFAULT; 299 goto exit; 300 } 301 302 /* convert into frequency instead of a channel */ 303 freq->e = 1; 304 freq->m = p80211_channel_to_mhz(value, 0) * 100000; 305 306exit: 307 return err; 308} 309 310static int p80211wext_siwfreq(netdevice_t *dev, 311 struct iw_request_info *info, 312 struct iw_freq *freq, char *extra) 313{ 314 wlandevice_t *wlandev = dev->ml_priv; 315 int result; 316 int err = 0; 317 unsigned int value; 318 319 if (!wlan_wext_write) { 320 err = -EOPNOTSUPP; 321 goto exit; 322 } 323 324 if ((freq->e == 0) && (freq->m <= 1000)) 325 value = freq->m; 326 else 327 value = p80211_mhz_to_channel(freq->m); 328 329 result = p80211wext_setmib(wlandev, 330 DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, 331 value); 332 333 if (result) { 334 err = -EFAULT; 335 goto exit; 336 } 337 338exit: 339 return err; 340} 341 342static int p80211wext_giwmode(netdevice_t *dev, 343 struct iw_request_info *info, 344 __u32 *mode, char *extra) 345{ 346 wlandevice_t *wlandev = dev->ml_priv; 347 348 switch (wlandev->macmode) { 349 case WLAN_MACMODE_IBSS_STA: 350 *mode = IW_MODE_ADHOC; 351 break; 352 case WLAN_MACMODE_ESS_STA: 353 *mode = IW_MODE_INFRA; 354 break; 355 case WLAN_MACMODE_ESS_AP: 356 *mode = IW_MODE_MASTER; 357 break; 358 default: 359 /* Not set yet. */ 360 *mode = IW_MODE_AUTO; 361 } 362 363 return 0; 364} 365 366static int p80211wext_siwmode(netdevice_t *dev, 367 struct iw_request_info *info, 368 __u32 *mode, char *extra) 369{ 370 wlandevice_t *wlandev = dev->ml_priv; 371 int result; 372 int err = 0; 373 374 if (!wlan_wext_write) { 375 err = -EOPNOTSUPP; 376 goto exit; 377 } 378 379 if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && 380 *mode != IW_MODE_MASTER) { 381 err = (-EOPNOTSUPP); 382 goto exit; 383 } 384 385 /* Operation mode is the same with current mode */ 386 if (*mode == wlandev->macmode) 387 goto exit; 388 389 switch (*mode) { 390 case IW_MODE_ADHOC: 391 wlandev->macmode = WLAN_MACMODE_IBSS_STA; 392 break; 393 case IW_MODE_INFRA: 394 wlandev->macmode = WLAN_MACMODE_ESS_STA; 395 break; 396 case IW_MODE_MASTER: 397 wlandev->macmode = WLAN_MACMODE_ESS_AP; 398 break; 399 default: 400 /* Not set yet. */ 401 printk(KERN_INFO "Operation mode: %d not support\n", *mode); 402 return -EOPNOTSUPP; 403 } 404 405 /* Set Operation mode to the PORT TYPE RID */ 406 result = p80211wext_setmib(wlandev, 407 DIDmib_p2_p2Static_p2CnfPortType, 408 (*mode == IW_MODE_ADHOC) ? 0 : 1); 409 if (result) 410 err = -EFAULT; 411exit: 412 return err; 413} 414 415static int p80211wext_giwrange(netdevice_t *dev, 416 struct iw_request_info *info, 417 struct iw_point *data, char *extra) 418{ 419 struct iw_range *range = (struct iw_range *)extra; 420 int i, val; 421 422 /* for backward compatability set size and zero everything we don't understand */ 423 data->length = sizeof(*range); 424 memset(range, 0, sizeof(*range)); 425 426 range->txpower_capa = IW_TXPOW_DBM; 427 /* XXX what about min/max_pmp, min/max_pmt, etc. */ 428 429 range->we_version_compiled = WIRELESS_EXT; 430 range->we_version_source = 13; 431 432 range->retry_capa = IW_RETRY_LIMIT; 433 range->retry_flags = IW_RETRY_LIMIT; 434 range->min_retry = 0; 435 range->max_retry = 255; 436 437 range->event_capa[0] = (IW_EVENT_CAPA_K_0 | /* mode/freq/ssid */ 438 IW_EVENT_CAPA_MASK(SIOCGIWAP) | 439 IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); 440 range->event_capa[1] = IW_EVENT_CAPA_K_1; /* encode */ 441 range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) | 442 IW_EVENT_CAPA_MASK(IWEVCUSTOM)); 443 444 range->num_channels = NUM_CHANNELS; 445 446 /* XXX need to filter against the regulatory domain &| active set */ 447 val = 0; 448 for (i = 0; i < NUM_CHANNELS; i++) { 449 range->freq[val].i = i + 1; 450 range->freq[val].m = p80211wext_channel_freq[i] * 100000; 451 range->freq[val].e = 1; 452 val++; 453 } 454 455 range->num_frequency = val; 456 457 /* Max of /proc/net/wireless */ 458 range->max_qual.qual = 100; 459 range->max_qual.level = 0; 460 range->max_qual.noise = 0; 461 range->sensitivity = 3; 462 /* XXX these need to be nsd-specific! */ 463 464 range->min_rts = 0; 465 range->max_rts = 2347; 466 range->min_frag = 256; 467 range->max_frag = 2346; 468 469 range->max_encoding_tokens = NUM_WEPKEYS; 470 range->num_encoding_sizes = 2; 471 range->encoding_size[0] = 5; 472 range->encoding_size[1] = 13; 473 474 /* XXX what about num_bitrates/throughput? */ 475 range->num_bitrates = 0; 476 477 /* estimated max throughput */ 478 /* XXX need to cap it if we're running at ~2Mbps.. */ 479 range->throughput = 5500000; 480 481 return 0; 482} 483 484static int p80211wext_giwap(netdevice_t *dev, 485 struct iw_request_info *info, 486 struct sockaddr *ap_addr, char *extra) 487{ 488 489 wlandevice_t *wlandev = dev->ml_priv; 490 491 memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN); 492 ap_addr->sa_family = ARPHRD_ETHER; 493 494 return 0; 495} 496 497static int p80211wext_giwencode(netdevice_t *dev, 498 struct iw_request_info *info, 499 struct iw_point *erq, char *key) 500{ 501 wlandevice_t *wlandev = dev->ml_priv; 502 int err = 0; 503 int i; 504 505 i = (erq->flags & IW_ENCODE_INDEX) - 1; 506 erq->flags = 0; 507 508 if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) 509 erq->flags |= IW_ENCODE_ENABLED; 510 else 511 erq->flags |= IW_ENCODE_DISABLED; 512 513 if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) 514 erq->flags |= IW_ENCODE_RESTRICTED; 515 else 516 erq->flags |= IW_ENCODE_OPEN; 517 518 i = (erq->flags & IW_ENCODE_INDEX) - 1; 519 520 if (i == -1) 521 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; 522 523 if ((i < 0) || (i >= NUM_WEPKEYS)) { 524 err = -EINVAL; 525 goto exit; 526 } 527 528 erq->flags |= i + 1; 529 530 /* copy the key from the driver cache as the keys are read-only MIBs */ 531 erq->length = wlandev->wep_keylens[i]; 532 memcpy(key, wlandev->wep_keys[i], erq->length); 533 534exit: 535 return err; 536} 537 538static int p80211wext_siwencode(netdevice_t *dev, 539 struct iw_request_info *info, 540 struct iw_point *erq, char *key) 541{ 542 wlandevice_t *wlandev = dev->ml_priv; 543 p80211msg_dot11req_mibset_t msg; 544 p80211item_pstr32_t pstr; 545 546 int err = 0; 547 int result = 0; 548 int i; 549 550 if (!wlan_wext_write) { 551 err = (-EOPNOTSUPP); 552 goto exit; 553 } 554 555 /* Check the Key index first. */ 556 i = (erq->flags & IW_ENCODE_INDEX); 557 if (i) { 558 if ((i < 1) || (i > NUM_WEPKEYS)) { 559 err = -EINVAL; 560 goto exit; 561 } else { 562 i--; 563 } 564 /* Set current key number only if no keys are given */ 565 if (erq->flags & IW_ENCODE_NOKEY) { 566 result = 567 p80211wext_setmib(wlandev, 568 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, 569 i); 570 571 if (result) { 572 err = -EFAULT; 573 goto exit; 574 } 575 } 576 577 } else { 578 /* Use defaultkey if no Key Index */ 579 i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; 580 } 581 582 /* Check if there is no key information in the iwconfig request */ 583 if ((erq->flags & IW_ENCODE_NOKEY) == 0) { 584 585 /*------------------------------------------------------------ 586 * If there is WEP Key for setting, check the Key Information 587 * and then set it to the firmware. 588 -------------------------------------------------------------*/ 589 590 if (erq->length > 0) { 591 /* copy the key from the driver cache as the keys are read-only MIBs */ 592 wlandev->wep_keylens[i] = erq->length; 593 memcpy(wlandev->wep_keys[i], key, erq->length); 594 595 /* Prepare data struture for p80211req_dorequest. */ 596 memcpy(pstr.data.data, key, erq->length); 597 pstr.data.len = erq->length; 598 599 switch (i) { 600 case 0: 601 pstr.did = 602 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; 603 break; 604 605 case 1: 606 pstr.did = 607 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; 608 break; 609 610 case 2: 611 pstr.did = 612 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; 613 break; 614 615 case 3: 616 pstr.did = 617 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; 618 break; 619 620 default: 621 err = -EINVAL; 622 goto exit; 623 } 624 625 msg.msgcode = DIDmsg_dot11req_mibset; 626 memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr)); 627 result = p80211req_dorequest(wlandev, (u8 *) &msg); 628 629 if (result) { 630 err = -EFAULT; 631 goto exit; 632 } 633 } 634 635 } 636 637 /* Check the PrivacyInvoked flag */ 638 if (erq->flags & IW_ENCODE_DISABLED) { 639 result = 640 p80211wext_setmib(wlandev, 641 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, 642 P80211ENUM_truth_false); 643 } else { 644 result = 645 p80211wext_setmib(wlandev, 646 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, 647 P80211ENUM_truth_true); 648 } 649 650 if (result) { 651 err = -EFAULT; 652 goto exit; 653 } 654 655 /* The security mode may be open or restricted, and its meaning 656 depends on the card used. With most cards, in open mode no 657 authentication is used and the card may also accept non- 658 encrypted sessions, whereas in restricted mode only encrypted 659 sessions are accepted and the card will use authentication if 660 available. 661 */ 662 if (erq->flags & IW_ENCODE_RESTRICTED) { 663 result = 664 p80211wext_setmib(wlandev, 665 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, 666 P80211ENUM_truth_true); 667 } else if (erq->flags & IW_ENCODE_OPEN) { 668 result = 669 p80211wext_setmib(wlandev, 670 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, 671 P80211ENUM_truth_false); 672 } 673 674 if (result) { 675 err = -EFAULT; 676 goto exit; 677 } 678 679exit: 680 681 return err; 682} 683 684static int p80211wext_giwessid(netdevice_t *dev, 685 struct iw_request_info *info, 686 struct iw_point *data, char *essid) 687{ 688 wlandevice_t *wlandev = dev->ml_priv; 689 690 if (wlandev->ssid.len) { 691 data->length = wlandev->ssid.len; 692 data->flags = 1; 693 memcpy(essid, wlandev->ssid.data, data->length); 694 essid[data->length] = 0; 695 } else { 696 memset(essid, 0, sizeof(wlandev->ssid.data)); 697 data->length = 0; 698 data->flags = 0; 699 } 700 701 return 0; 702} 703 704static int p80211wext_siwessid(netdevice_t *dev, 705 struct iw_request_info *info, 706 struct iw_point *data, char *essid) 707{ 708 wlandevice_t *wlandev = dev->ml_priv; 709 p80211msg_lnxreq_autojoin_t msg; 710 711 int result; 712 int err = 0; 713 int length = data->length; 714 715 if (!wlan_wext_write) { 716 err = (-EOPNOTSUPP); 717 goto exit; 718 } 719 720 if (wlandev->hostwep & HOSTWEP_SHAREDKEY) 721 msg.authtype.data = P80211ENUM_authalg_sharedkey; 722 else 723 msg.authtype.data = P80211ENUM_authalg_opensystem; 724 725 msg.msgcode = DIDmsg_lnxreq_autojoin; 726 727 /* Trim the last '\0' to fit the SSID format */ 728 if (length && essid[length - 1] == '\0') 729 length--; 730 731 memcpy(msg.ssid.data.data, essid, length); 732 msg.ssid.data.len = length; 733 734 pr_debug("autojoin_ssid for %s \n", essid); 735 result = p80211req_dorequest(wlandev, (u8 *) &msg); 736 pr_debug("autojoin_ssid %d\n", result); 737 738 if (result) { 739 err = -EFAULT; 740 goto exit; 741 } 742 743exit: 744 return err; 745} 746 747static int p80211wext_siwcommit(netdevice_t *dev, 748 struct iw_request_info *info, 749 struct iw_point *data, char *essid) 750{ 751 wlandevice_t *wlandev = dev->ml_priv; 752 int err = 0; 753 754 if (!wlan_wext_write) { 755 err = (-EOPNOTSUPP); 756 goto exit; 757 } 758 759 /* Auto Join */ 760 err = p80211wext_autojoin(wlandev); 761 762exit: 763 return err; 764} 765 766static int p80211wext_giwrate(netdevice_t *dev, 767 struct iw_request_info *info, 768 struct iw_param *rrq, char *extra) 769{ 770 wlandevice_t *wlandev = dev->ml_priv; 771 int result; 772 int err = 0; 773 unsigned int value; 774 775 result = p80211wext_getmib(wlandev, DIDmib_p2_p2MAC_p2CurrentTxRate, &value); 776 if (result) { 777 err = -EFAULT; 778 goto exit; 779 } 780 781 rrq->fixed = 0; /* can it change? */ 782 rrq->disabled = 0; 783 rrq->value = 0; 784 785#define HFA384x_RATEBIT_1 ((u16)1) 786#define HFA384x_RATEBIT_2 ((u16)2) 787#define HFA384x_RATEBIT_5dot5 ((u16)4) 788#define HFA384x_RATEBIT_11 ((u16)8) 789 790 switch (value) { 791 case HFA384x_RATEBIT_1: 792 rrq->value = 1000000; 793 break; 794 case HFA384x_RATEBIT_2: 795 rrq->value = 2000000; 796 break; 797 case HFA384x_RATEBIT_5dot5: 798 rrq->value = 5500000; 799 break; 800 case HFA384x_RATEBIT_11: 801 rrq->value = 11000000; 802 break; 803 default: 804 err = -EINVAL; 805 } 806exit: 807 return err; 808} 809 810static int p80211wext_giwrts(netdevice_t *dev, 811 struct iw_request_info *info, 812 struct iw_param *rts, char *extra) 813{ 814 wlandevice_t *wlandev = dev->ml_priv; 815 int result; 816 int err = 0; 817 unsigned int value; 818 819 result = p80211wext_getmib(wlandev, 820 DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, 821 &value); 822 if (result) { 823 err = -EFAULT; 824 goto exit; 825 } 826 827 rts->value = value; 828 rts->disabled = (rts->value == 2347); 829 rts->fixed = 1; 830 831exit: 832 return err; 833} 834 835static int p80211wext_siwrts(netdevice_t *dev, 836 struct iw_request_info *info, 837 struct iw_param *rts, char *extra) 838{ 839 wlandevice_t *wlandev = dev->ml_priv; 840 int result; 841 int err = 0; 842 unsigned int value; 843 844 if (!wlan_wext_write) { 845 err = -EOPNOTSUPP; 846 goto exit; 847 } 848 849 if (rts->disabled) 850 value = 2347; 851 else 852 value = rts->value; 853 854 result = p80211wext_setmib(wlandev, 855 DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, 856 value); 857 if (result) { 858 err = -EFAULT; 859 goto exit; 860 } 861 862exit: 863 return err; 864} 865 866static int p80211wext_giwfrag(netdevice_t *dev, 867 struct iw_request_info *info, 868 struct iw_param *frag, char *extra) 869{ 870 wlandevice_t *wlandev = dev->ml_priv; 871 int result; 872 int err = 0; 873 unsigned int value; 874 875 result = p80211wext_getmib(wlandev, 876 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, 877 &value); 878 if (result) { 879 err = -EFAULT; 880 goto exit; 881 } 882 883 frag->value = value; 884 frag->disabled = (frag->value == 2346); 885 frag->fixed = 1; 886 887exit: 888 return err; 889} 890 891static int p80211wext_siwfrag(netdevice_t *dev, 892 struct iw_request_info *info, 893 struct iw_param *frag, char *extra) 894{ 895 wlandevice_t *wlandev = dev->ml_priv; 896 int result; 897 int err = 0; 898 int value; 899 900 if (!wlan_wext_write) { 901 err = (-EOPNOTSUPP); 902 goto exit; 903 } 904 905 if (frag->disabled) 906 value = 2346; 907 else 908 value = frag->value; 909 910 result = p80211wext_setmib(wlandev, 911 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, 912 value); 913 914 if (result) { 915 err = -EFAULT; 916 goto exit; 917 } 918 919exit: 920 return err; 921} 922 923#ifndef IW_RETRY_LONG 924#define IW_RETRY_LONG IW_RETRY_MAX 925#endif 926 927#ifndef IW_RETRY_SHORT 928#define IW_RETRY_SHORT IW_RETRY_MIN 929#endif 930 931static int p80211wext_giwretry(netdevice_t *dev, 932 struct iw_request_info *info, 933 struct iw_param *rrq, char *extra) 934{ 935 wlandevice_t *wlandev = dev->ml_priv; 936 int result; 937 int err = 0; 938 u16 shortretry, longretry, lifetime; 939 unsigned int value; 940 941 result = p80211wext_getmib(wlandev, 942 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit, 943 &value); 944 if (result) { 945 err = -EFAULT; 946 goto exit; 947 } 948 949 shortretry = value; 950 951 result = p80211wext_getmib(wlandev, 952 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit, 953 &value); 954 if (result) { 955 err = -EFAULT; 956 goto exit; 957 } 958 959 longretry = value; 960 961 result = p80211wext_getmib(wlandev, 962 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime, 963 &value); 964 if (result) { 965 err = -EFAULT; 966 goto exit; 967 } 968 969 lifetime = value; 970 971 rrq->disabled = 0; 972 973 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { 974 rrq->flags = IW_RETRY_LIFETIME; 975 rrq->value = lifetime * 1024; 976 } else { 977 if (rrq->flags & IW_RETRY_LONG) { 978 rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; 979 rrq->value = longretry; 980 } else { 981 rrq->flags = IW_RETRY_LIMIT; 982 rrq->value = shortretry; 983 if (shortretry != longretry) 984 rrq->flags |= IW_RETRY_SHORT; 985 } 986 } 987 988exit: 989 return err; 990 991} 992 993static int p80211wext_siwretry(netdevice_t *dev, 994 struct iw_request_info *info, 995 struct iw_param *rrq, char *extra) 996{ 997 wlandevice_t *wlandev = dev->ml_priv; 998 p80211item_uint32_t mibitem; 999 p80211msg_dot11req_mibset_t msg; 1000 int result; 1001 int err = 0; 1002 unsigned int value; 1003 1004 if (!wlan_wext_write) { 1005 err = (-EOPNOTSUPP); 1006 goto exit; 1007 } 1008 1009 if (rrq->disabled) { 1010 err = -EINVAL; 1011 goto exit; 1012 } 1013 1014 msg.msgcode = DIDmsg_dot11req_mibset; 1015 1016 if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { 1017 1018 value = rrq->value /= 1024; 1019 result = p80211wext_setmib(wlandev, 1020 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime, 1021 value); 1022 if (result) { 1023 err = -EFAULT; 1024 goto exit; 1025 } 1026 } else { 1027 if (rrq->flags & IW_RETRY_LONG) { 1028 result = p80211wext_setmib(wlandev, 1029 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit, 1030 rrq->value); 1031 1032 if (result) { 1033 err = -EFAULT; 1034 goto exit; 1035 } 1036 } 1037 1038 if (rrq->flags & IW_RETRY_SHORT) { 1039 result = p80211wext_setmib(wlandev, 1040 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit, 1041 rrq->value); 1042 1043 if (result) { 1044 err = -EFAULT; 1045 goto exit; 1046 } 1047 } 1048 } 1049 1050exit: 1051 return err; 1052 1053} 1054 1055static int p80211wext_siwtxpow(netdevice_t *dev, 1056 struct iw_request_info *info, 1057 struct iw_param *rrq, char *extra) 1058{ 1059 wlandevice_t *wlandev = dev->ml_priv; 1060 p80211item_uint32_t mibitem; 1061 p80211msg_dot11req_mibset_t msg; 1062 int result; 1063 int err = 0; 1064 unsigned int value; 1065 1066 if (!wlan_wext_write) { 1067 err = (-EOPNOTSUPP); 1068 goto exit; 1069 } 1070 1071 if (rrq->fixed == 0) 1072 value = 30; 1073 else 1074 value = rrq->value; 1075 result = p80211wext_setmib(wlandev, 1076 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, 1077 value); 1078 1079 if (result) { 1080 err = -EFAULT; 1081 goto exit; 1082 } 1083 1084exit: 1085 return err; 1086} 1087 1088static int p80211wext_giwtxpow(netdevice_t *dev, 1089 struct iw_request_info *info, 1090 struct iw_param *rrq, char *extra) 1091{ 1092 wlandevice_t *wlandev = dev->ml_priv; 1093 int result; 1094 int err = 0; 1095 unsigned int value; 1096 1097 result = p80211wext_getmib(wlandev, 1098 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, 1099 &value); 1100 1101 if (result) { 1102 err = -EFAULT; 1103 goto exit; 1104 } 1105 1106 /* XXX handle OFF by setting disabled = 1; */ 1107 1108 rrq->flags = 0; /* IW_TXPOW_DBM; */ 1109 rrq->disabled = 0; 1110 rrq->fixed = 0; 1111 rrq->value = value; 1112 1113exit: 1114 return err; 1115} 1116 1117static int p80211wext_siwspy(netdevice_t *dev, 1118 struct iw_request_info *info, 1119 struct iw_point *srq, char *extra) 1120{ 1121 wlandevice_t *wlandev = dev->ml_priv; 1122 struct sockaddr address[IW_MAX_SPY]; 1123 int number = srq->length; 1124 int i; 1125 1126 /* Copy the data from the input buffer */ 1127 memcpy(address, extra, sizeof(struct sockaddr) * number); 1128 1129 wlandev->spy_number = 0; 1130 1131 if (number > 0) { 1132 1133 /* extract the addresses */ 1134 for (i = 0; i < number; i++) { 1135 1136 memcpy(wlandev->spy_address[i], address[i].sa_data, 1137 ETH_ALEN); 1138 } 1139 1140 /* reset stats */ 1141 memset(wlandev->spy_stat, 0, 1142 sizeof(struct iw_quality) * IW_MAX_SPY); 1143 1144 /* set number of addresses */ 1145 wlandev->spy_number = number; 1146 } 1147 1148 return 0; 1149} 1150 1151/* jkriegl: from orinoco, modified */ 1152static int p80211wext_giwspy(netdevice_t *dev, 1153 struct iw_request_info *info, 1154 struct iw_point *srq, char *extra) 1155{ 1156 wlandevice_t *wlandev = dev->ml_priv; 1157 1158 struct sockaddr address[IW_MAX_SPY]; 1159 struct iw_quality spy_stat[IW_MAX_SPY]; 1160 int number; 1161 int i; 1162 1163 number = wlandev->spy_number; 1164 1165 if (number > 0) { 1166 1167 /* populate address and spy struct's */ 1168 for (i = 0; i < number; i++) { 1169 memcpy(address[i].sa_data, wlandev->spy_address[i], 1170 ETH_ALEN); 1171 address[i].sa_family = AF_UNIX; 1172 memcpy(&spy_stat[i], &wlandev->spy_stat[i], 1173 sizeof(struct iw_quality)); 1174 } 1175 1176 /* reset update flag */ 1177 for (i = 0; i < number; i++) 1178 wlandev->spy_stat[i].updated = 0; 1179 } 1180 1181 /* push stuff to user space */ 1182 srq->length = number; 1183 memcpy(extra, address, sizeof(struct sockaddr) * number); 1184 memcpy(extra + sizeof(struct sockaddr) * number, spy_stat, 1185 sizeof(struct iw_quality) * number); 1186 1187 return 0; 1188} 1189 1190static int prism2_result2err(int prism2_result) 1191{ 1192 int err = 0; 1193 1194 switch (prism2_result) { 1195 case P80211ENUM_resultcode_invalid_parameters: 1196 err = -EINVAL; 1197 break; 1198 case P80211ENUM_resultcode_implementation_failure: 1199 err = -EIO; 1200 break; 1201 case P80211ENUM_resultcode_not_supported: 1202 err = -EOPNOTSUPP; 1203 break; 1204 default: 1205 err = 0; 1206 break; 1207 } 1208 1209 return err; 1210} 1211 1212static int p80211wext_siwscan(netdevice_t *dev, 1213 struct iw_request_info *info, 1214 struct iw_point *srq, char *extra) 1215{ 1216 wlandevice_t *wlandev = dev->ml_priv; 1217 p80211msg_dot11req_scan_t msg; 1218 int result; 1219 int err = 0; 1220 int i = 0; 1221 1222 if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { 1223 printk(KERN_ERR "Can't scan in AP mode\n"); 1224 err = (-EOPNOTSUPP); 1225 goto exit; 1226 } 1227 1228 memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t)); 1229 msg.msgcode = DIDmsg_dot11req_scan; 1230 msg.bsstype.data = P80211ENUM_bsstype_any; 1231 1232 memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t)); 1233 msg.bssid.data.len = 6; 1234 1235 msg.scantype.data = P80211ENUM_scantype_active; 1236 msg.probedelay.data = 0; 1237 1238 for (i = 1; i <= 14; i++) 1239 msg.channellist.data.data[i - 1] = i; 1240 msg.channellist.data.len = 14; 1241 1242 msg.maxchanneltime.data = 250; 1243 msg.minchanneltime.data = 200; 1244 1245 result = p80211req_dorequest(wlandev, (u8 *) &msg); 1246 if (result) 1247 err = prism2_result2err(msg.resultcode.data); 1248 1249exit: 1250 return err; 1251} 1252 1253/* Helper to translate scan into Wireless Extensions scan results. 1254 * Inspired by the prism54 code, which was in turn inspired by the 1255 * airo driver code. 1256 */ 1257static char *wext_translate_bss(struct iw_request_info *info, char *current_ev, 1258 char *end_buf, 1259 p80211msg_dot11req_scan_results_t *bss) 1260{ 1261 struct iw_event iwe; /* Temporary buffer */ 1262 1263 /* The first entry must be the MAC address */ 1264 memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN); 1265 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 1266 iwe.cmd = SIOCGIWAP; 1267 current_ev = 1268 iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1269 IW_EV_ADDR_LEN); 1270 1271 /* The following entries will be displayed in the same order we give them */ 1272 1273 /* The ESSID. */ 1274 if (bss->ssid.data.len > 0) { 1275 char essid[IW_ESSID_MAX_SIZE + 1]; 1276 int size; 1277 1278 size = 1279 min_t(unsigned short, IW_ESSID_MAX_SIZE, 1280 bss->ssid.data.len); 1281 memset(&essid, 0, sizeof(essid)); 1282 memcpy(&essid, bss->ssid.data.data, size); 1283 pr_debug(" essid size = %d\n", size); 1284 iwe.u.data.length = size; 1285 iwe.u.data.flags = 1; 1286 iwe.cmd = SIOCGIWESSID; 1287 current_ev = 1288 iwe_stream_add_point(info, current_ev, end_buf, &iwe, 1289 &essid[0]); 1290 pr_debug(" essid size OK.\n"); 1291 } 1292 1293 switch (bss->bsstype.data) { 1294 case P80211ENUM_bsstype_infrastructure: 1295 iwe.u.mode = IW_MODE_MASTER; 1296 break; 1297 1298 case P80211ENUM_bsstype_independent: 1299 iwe.u.mode = IW_MODE_ADHOC; 1300 break; 1301 1302 default: 1303 iwe.u.mode = 0; 1304 break; 1305 } 1306 iwe.cmd = SIOCGIWMODE; 1307 if (iwe.u.mode) 1308 current_ev = 1309 iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1310 IW_EV_UINT_LEN); 1311 1312 /* Encryption capability */ 1313 if (bss->privacy.data == P80211ENUM_truth_true) 1314 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 1315 else 1316 iwe.u.data.flags = IW_ENCODE_DISABLED; 1317 iwe.u.data.length = 0; 1318 iwe.cmd = SIOCGIWENCODE; 1319 current_ev = 1320 iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL); 1321 1322 /* Add frequency. (short) bss->channel is the frequency in MHz */ 1323 iwe.u.freq.m = bss->dschannel.data; 1324 iwe.u.freq.e = 0; 1325 iwe.cmd = SIOCGIWFREQ; 1326 current_ev = 1327 iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1328 IW_EV_FREQ_LEN); 1329 1330 /* Add quality statistics */ 1331 iwe.u.qual.level = bss->signal.data; 1332 iwe.u.qual.noise = bss->noise.data; 1333 /* do a simple SNR for quality */ 1334 iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data); 1335 iwe.cmd = IWEVQUAL; 1336 current_ev = 1337 iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1338 IW_EV_QUAL_LEN); 1339 1340 return current_ev; 1341} 1342 1343static int p80211wext_giwscan(netdevice_t *dev, 1344 struct iw_request_info *info, 1345 struct iw_point *srq, char *extra) 1346{ 1347 wlandevice_t *wlandev = dev->ml_priv; 1348 p80211msg_dot11req_scan_results_t msg; 1349 int result = 0; 1350 int err = 0; 1351 int i = 0; 1352 int scan_good = 0; 1353 char *current_ev = extra; 1354 1355 /* Since wireless tools doesn't really have a way of passing how 1356 * many scan results results there were back here, keep grabbing them 1357 * until we fail. 1358 */ 1359 do { 1360 memset(&msg, 0, sizeof(msg)); 1361 msg.msgcode = DIDmsg_dot11req_scan_results; 1362 msg.bssindex.data = i; 1363 1364 result = p80211req_dorequest(wlandev, (u8 *) &msg); 1365 if ((result != 0) || 1366 (msg.resultcode.data != P80211ENUM_resultcode_success)) { 1367 break; 1368 } 1369 1370 current_ev = 1371 wext_translate_bss(info, current_ev, 1372 extra + IW_SCAN_MAX_DATA, &msg); 1373 scan_good = 1; 1374 i++; 1375 } while (i < IW_MAX_AP); 1376 1377 srq->length = (current_ev - extra); 1378 srq->flags = 0; /* todo */ 1379 1380 if (result && !scan_good) 1381 err = prism2_result2err(msg.resultcode.data); 1382 1383 return err; 1384} 1385 1386/* extra wireless extensions stuff to support NetworkManager (I hope) */ 1387 1388/* SIOCSIWENCODEEXT */ 1389static int p80211wext_set_encodeext(struct net_device *dev, 1390 struct iw_request_info *info, 1391 union iwreq_data *wrqu, char *extra) 1392{ 1393 wlandevice_t *wlandev = dev->ml_priv; 1394 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 1395 p80211msg_dot11req_mibset_t msg; 1396 p80211item_pstr32_t *pstr; 1397 1398 int result = 0; 1399 struct iw_point *encoding = &wrqu->encoding; 1400 int idx = encoding->flags & IW_ENCODE_INDEX; 1401 1402 pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n", 1403 ext->ext_flags, (int)ext->alg, (int)ext->key_len); 1404 1405 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { 1406 /* set default key ? I'm not sure if this the the correct thing to do here */ 1407 1408 if (idx) { 1409 if (idx < 1 || idx > NUM_WEPKEYS) 1410 return -EINVAL; 1411 else 1412 idx--; 1413 } 1414 pr_debug("setting default key (%d)\n", idx); 1415 result = 1416 p80211wext_setmib(wlandev, 1417 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, 1418 idx); 1419 if (result) 1420 return -EFAULT; 1421 } 1422 1423 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 1424 if (ext->alg != IW_ENCODE_ALG_WEP) { 1425 pr_debug("asked to set a non wep key :(\n"); 1426 return -EINVAL; 1427 } 1428 if (idx) { 1429 if (idx < 1 || idx > NUM_WEPKEYS) 1430 return -EINVAL; 1431 else 1432 idx--; 1433 } 1434 pr_debug("Set WEP key (%d)\n", idx); 1435 wlandev->wep_keylens[idx] = ext->key_len; 1436 memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len); 1437 1438 memset(&msg, 0, sizeof(msg)); 1439 pstr = (p80211item_pstr32_t *) &msg.mibattribute.data; 1440 memcpy(pstr->data.data, ext->key, ext->key_len); 1441 pstr->data.len = ext->key_len; 1442 switch (idx) { 1443 case 0: 1444 pstr->did = 1445 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; 1446 break; 1447 case 1: 1448 pstr->did = 1449 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; 1450 break; 1451 case 2: 1452 pstr->did = 1453 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; 1454 break; 1455 case 3: 1456 pstr->did = 1457 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; 1458 break; 1459 default: 1460 break; 1461 } 1462 msg.msgcode = DIDmsg_dot11req_mibset; 1463 result = p80211req_dorequest(wlandev, (u8 *) &msg); 1464 pr_debug("result (%d)\n", result); 1465 } 1466 return result; 1467} 1468 1469/* SIOCGIWENCODEEXT */ 1470static int p80211wext_get_encodeext(struct net_device *dev, 1471 struct iw_request_info *info, 1472 union iwreq_data *wrqu, char *extra) 1473{ 1474 wlandevice_t *wlandev = dev->ml_priv; 1475 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 1476 1477 struct iw_point *encoding = &wrqu->encoding; 1478 int result = 0; 1479 int max_len; 1480 int idx; 1481 1482 pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n", 1483 ext->ext_flags, (int)ext->alg, (int)ext->key_len); 1484 1485 max_len = encoding->length - sizeof(*ext); 1486 if (max_len <= 0) { 1487 pr_debug("get_encodeext max_len [%d] invalid\n", max_len); 1488 result = -EINVAL; 1489 goto exit; 1490 } 1491 idx = encoding->flags & IW_ENCODE_INDEX; 1492 1493 pr_debug("get_encode_ext index [%d]\n", idx); 1494 1495 if (idx) { 1496 if (idx < 1 || idx > NUM_WEPKEYS) { 1497 pr_debug("get_encode_ext invalid key index [%d]\n", 1498 idx); 1499 result = -EINVAL; 1500 goto exit; 1501 } 1502 idx--; 1503 } else { 1504 /* default key ? not sure what to do */ 1505 /* will just use key[0] for now ! FIX ME */ 1506 } 1507 1508 encoding->flags = idx + 1; 1509 memset(ext, 0, sizeof(*ext)); 1510 1511 ext->alg = IW_ENCODE_ALG_WEP; 1512 ext->key_len = wlandev->wep_keylens[idx]; 1513 memcpy(ext->key, wlandev->wep_keys[idx], ext->key_len); 1514 1515 encoding->flags |= IW_ENCODE_ENABLED; 1516exit: 1517 return result; 1518} 1519 1520/* SIOCSIWAUTH */ 1521static int p80211_wext_set_iwauth(struct net_device *dev, 1522 struct iw_request_info *info, 1523 union iwreq_data *wrqu, char *extra) 1524{ 1525 wlandevice_t *wlandev = dev->ml_priv; 1526 struct iw_param *param = &wrqu->param; 1527 int result = 0; 1528 1529 pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX); 1530 1531 switch (param->flags & IW_AUTH_INDEX) { 1532 case IW_AUTH_DROP_UNENCRYPTED: 1533 pr_debug("drop_unencrypted %d\n", param->value); 1534 if (param->value) 1535 result = 1536 p80211wext_setmib(wlandev, 1537 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, 1538 P80211ENUM_truth_true); 1539 else 1540 result = 1541 p80211wext_setmib(wlandev, 1542 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, 1543 P80211ENUM_truth_false); 1544 break; 1545 1546 case IW_AUTH_PRIVACY_INVOKED: 1547 pr_debug("privacy invoked %d\n", param->value); 1548 if (param->value) 1549 result = 1550 p80211wext_setmib(wlandev, 1551 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, 1552 P80211ENUM_truth_true); 1553 else 1554 result = 1555 p80211wext_setmib(wlandev, 1556 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, 1557 P80211ENUM_truth_false); 1558 1559 break; 1560 1561 case IW_AUTH_80211_AUTH_ALG: 1562 if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { 1563 pr_debug("set open_system\n"); 1564 wlandev->hostwep &= ~HOSTWEP_SHAREDKEY; 1565 } else if (param->value & IW_AUTH_ALG_SHARED_KEY) { 1566 pr_debug("set shared key\n"); 1567 wlandev->hostwep |= HOSTWEP_SHAREDKEY; 1568 } else { 1569 /* don't know what to do know */ 1570 pr_debug("unknown AUTH_ALG (%d)\n", param->value); 1571 result = -EINVAL; 1572 } 1573 break; 1574 1575 default: 1576 break; 1577 } 1578 1579 return result; 1580} 1581 1582/* SIOCSIWAUTH */ 1583static int p80211_wext_get_iwauth(struct net_device *dev, 1584 struct iw_request_info *info, 1585 union iwreq_data *wrqu, char *extra) 1586{ 1587 wlandevice_t *wlandev = dev->ml_priv; 1588 struct iw_param *param = &wrqu->param; 1589 int result = 0; 1590 1591 pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX); 1592 1593 switch (param->flags & IW_AUTH_INDEX) { 1594 case IW_AUTH_DROP_UNENCRYPTED: 1595 param->value = 1596 wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0; 1597 break; 1598 1599 case IW_AUTH_PRIVACY_INVOKED: 1600 param->value = 1601 wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0; 1602 break; 1603 1604 case IW_AUTH_80211_AUTH_ALG: 1605 param->value = 1606 wlandev->hostwep & HOSTWEP_SHAREDKEY ? 1607 IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; 1608 break; 1609 1610 default: 1611 break; 1612 } 1613 1614 return result; 1615} 1616 1617#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] 1618 1619static iw_handler p80211wext_handlers[] = { 1620 IW_IOCTL(SIOCSIWCOMMIT) = (iw_handler) p80211wext_siwcommit, 1621 IW_IOCTL(SIOCGIWNAME) = (iw_handler) p80211wext_giwname, 1622/* SIOCSIWNWID,SIOCGIWNWID */ 1623 IW_IOCTL(SIOCSIWFREQ) = (iw_handler) p80211wext_siwfreq, 1624 IW_IOCTL(SIOCGIWFREQ) = (iw_handler) p80211wext_giwfreq, 1625 IW_IOCTL(SIOCSIWMODE) = (iw_handler) p80211wext_siwmode, 1626 IW_IOCTL(SIOCGIWMODE) = (iw_handler) p80211wext_giwmode, 1627/* SIOCSIWSENS,SIOCGIWSENS,SIOCSIWRANGE */ 1628 IW_IOCTL(SIOCGIWRANGE) = (iw_handler) p80211wext_giwrange, 1629/* SIOCSIWPRIV,SIOCGIWPRIV,SIOCSIWSTATS,SIOCGIWSTATS */ 1630 IW_IOCTL(SIOCSIWSPY) = (iw_handler) p80211wext_siwspy, 1631 IW_IOCTL(SIOCGIWSPY) = (iw_handler) p80211wext_giwspy, 1632/* SIOCSIWAP */ 1633 IW_IOCTL(SIOCGIWAP) = (iw_handler) p80211wext_giwap, 1634/* SIOCGIWAPLIST */ 1635 IW_IOCTL(SIOCSIWSCAN) = (iw_handler) p80211wext_siwscan, 1636 IW_IOCTL(SIOCGIWSCAN) = (iw_handler) p80211wext_giwscan, 1637 IW_IOCTL(SIOCSIWESSID) = (iw_handler) p80211wext_siwessid, 1638 IW_IOCTL(SIOCGIWESSID) = (iw_handler) p80211wext_giwessid, 1639/* SIOCSIWNICKN */ 1640 IW_IOCTL(SIOCGIWNICKN) = (iw_handler) p80211wext_giwessid, 1641/* SIOCSIWRATE */ 1642 IW_IOCTL(SIOCGIWRATE) = (iw_handler) p80211wext_giwrate, 1643 IW_IOCTL(SIOCSIWRTS) = (iw_handler) p80211wext_siwrts, 1644 IW_IOCTL(SIOCGIWRTS) = (iw_handler) p80211wext_giwrts, 1645 IW_IOCTL(SIOCSIWFRAG) = (iw_handler) p80211wext_siwfrag, 1646 IW_IOCTL(SIOCGIWFRAG) = (iw_handler) p80211wext_giwfrag, 1647 IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) p80211wext_siwtxpow, 1648 IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) p80211wext_giwtxpow, 1649 IW_IOCTL(SIOCSIWRETRY) = (iw_handler) p80211wext_siwretry, 1650 IW_IOCTL(SIOCGIWRETRY) = (iw_handler) p80211wext_giwretry, 1651 IW_IOCTL(SIOCSIWENCODE) = (iw_handler) p80211wext_siwencode, 1652 IW_IOCTL(SIOCGIWENCODE) = (iw_handler) p80211wext_giwencode, 1653/* SIOCSIWPOWER,SIOCGIWPOWER */ 1654/* WPA operations */ 1655/* SIOCSIWGENIE,SIOCGIWGENIE generic IE */ 1656 IW_IOCTL(SIOCSIWAUTH) = (iw_handler) p80211_wext_set_iwauth, /*set authentication mode params */ 1657 IW_IOCTL(SIOCGIWAUTH) = (iw_handler) p80211_wext_get_iwauth, /*get authentication mode params */ 1658 IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) p80211wext_set_encodeext, /*set encoding token & mode */ 1659 IW_IOCTL(SIOCGIWENCODEEXT) = (iw_handler) p80211wext_get_encodeext, /*get encoding token & mode */ 1660/* SIOCSIWPMKSA PMKSA cache operation */ 1661}; 1662 1663struct iw_handler_def p80211wext_handler_def = { 1664 .num_standard = ARRAY_SIZE(p80211wext_handlers), 1665 .standard = p80211wext_handlers, 1666 .get_wireless_stats = p80211wext_get_wireless_stats 1667}; 1668 1669int p80211wext_event_associated(wlandevice_t *wlandev, int assoc) 1670{ 1671 union iwreq_data data; 1672 1673 /* Send the association state first */ 1674 data.ap_addr.sa_family = ARPHRD_ETHER; 1675 if (assoc) 1676 memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN); 1677 else 1678 memset(data.ap_addr.sa_data, 0, ETH_ALEN); 1679 1680 if (wlan_wext_write) 1681 wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL); 1682 1683 if (!assoc) 1684 goto done; 1685 1686 /* XXX send association data, like IEs, etc etc. */ 1687 1688done: 1689 return 0; 1690}