1/* cfg80211 Interface for prism2_usb module */ 2#include "hfa384x.h" 3#include "prism2mgmt.h" 4 5/* Prism2 channel/frequency/bitrate declarations */ 6static const struct ieee80211_channel prism2_channels[] = { 7 { .center_freq = 2412 }, 8 { .center_freq = 2417 }, 9 { .center_freq = 2422 }, 10 { .center_freq = 2427 }, 11 { .center_freq = 2432 }, 12 { .center_freq = 2437 }, 13 { .center_freq = 2442 }, 14 { .center_freq = 2447 }, 15 { .center_freq = 2452 }, 16 { .center_freq = 2457 }, 17 { .center_freq = 2462 }, 18 { .center_freq = 2467 }, 19 { .center_freq = 2472 }, 20 { .center_freq = 2484 }, 21}; 22 23static const struct ieee80211_rate prism2_rates[] = { 24 { .bitrate = 10 }, 25 { .bitrate = 20 }, 26 { .bitrate = 55 }, 27 { .bitrate = 110 } 28}; 29 30#define PRISM2_NUM_CIPHER_SUITES 2 31static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = { 32 WLAN_CIPHER_SUITE_WEP40, 33 WLAN_CIPHER_SUITE_WEP104 34}; 35 36/* prism2 device private data */ 37struct prism2_wiphy_private { 38 wlandevice_t *wlandev; 39 40 struct ieee80211_supported_band band; 41 struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)]; 42 struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)]; 43 44 struct cfg80211_scan_request *scan_request; 45}; 46 47static const void * const prism2_wiphy_privid = &prism2_wiphy_privid; 48 49/* Helper Functions */ 50static int prism2_result2err(int prism2_result) 51{ 52 int err = 0; 53 54 switch (prism2_result) { 55 case P80211ENUM_resultcode_invalid_parameters: 56 err = -EINVAL; 57 break; 58 case P80211ENUM_resultcode_implementation_failure: 59 err = -EIO; 60 break; 61 case P80211ENUM_resultcode_not_supported: 62 err = -EOPNOTSUPP; 63 break; 64 default: 65 err = 0; 66 break; 67 } 68 69 return err; 70} 71 72static int prism2_domibset_uint32(wlandevice_t *wlandev, u32 did, u32 data) 73{ 74 struct p80211msg_dot11req_mibset msg; 75 p80211item_uint32_t *mibitem = 76 (p80211item_uint32_t *) &msg.mibattribute.data; 77 78 msg.msgcode = DIDmsg_dot11req_mibset; 79 mibitem->did = did; 80 mibitem->data = data; 81 82 return p80211req_dorequest(wlandev, (u8 *) &msg); 83} 84 85static int prism2_domibset_pstr32(wlandevice_t *wlandev, 86 u32 did, u8 len, const u8 *data) 87{ 88 struct p80211msg_dot11req_mibset msg; 89 p80211item_pstr32_t *mibitem = 90 (p80211item_pstr32_t *) &msg.mibattribute.data; 91 92 msg.msgcode = DIDmsg_dot11req_mibset; 93 mibitem->did = did; 94 mibitem->data.len = len; 95 memcpy(mibitem->data.data, data, len); 96 97 return p80211req_dorequest(wlandev, (u8 *) &msg); 98} 99 100/* The interface functions, called by the cfg80211 layer */ 101static int prism2_change_virtual_intf(struct wiphy *wiphy, 102 struct net_device *dev, 103 enum nl80211_iftype type, u32 *flags, 104 struct vif_params *params) 105{ 106 wlandevice_t *wlandev = dev->ml_priv; 107 u32 data; 108 int result; 109 int err = 0; 110 111 switch (type) { 112 case NL80211_IFTYPE_ADHOC: 113 if (wlandev->macmode == WLAN_MACMODE_IBSS_STA) 114 goto exit; 115 wlandev->macmode = WLAN_MACMODE_IBSS_STA; 116 data = 0; 117 break; 118 case NL80211_IFTYPE_STATION: 119 if (wlandev->macmode == WLAN_MACMODE_ESS_STA) 120 goto exit; 121 wlandev->macmode = WLAN_MACMODE_ESS_STA; 122 data = 1; 123 break; 124 default: 125 netdev_warn(dev, "Operation mode: %d not support\n", type); 126 return -EOPNOTSUPP; 127 } 128 129 /* Set Operation mode to the PORT TYPE RID */ 130 result = prism2_domibset_uint32(wlandev, 131 DIDmib_p2_p2Static_p2CnfPortType, 132 data); 133 134 if (result) 135 err = -EFAULT; 136 137 dev->ieee80211_ptr->iftype = type; 138 139exit: 140 return err; 141} 142 143static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev, 144 u8 key_index, bool pairwise, const u8 *mac_addr, 145 struct key_params *params) 146{ 147 wlandevice_t *wlandev = dev->ml_priv; 148 u32 did; 149 150 int err = 0; 151 int result = 0; 152 153 switch (params->cipher) { 154 case WLAN_CIPHER_SUITE_WEP40: 155 case WLAN_CIPHER_SUITE_WEP104: 156 result = prism2_domibset_uint32(wlandev, 157 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, 158 key_index); 159 if (result) 160 goto exit; 161 162 /* send key to driver */ 163 switch (key_index) { 164 case 0: 165 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; 166 break; 167 168 case 1: 169 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; 170 break; 171 172 case 2: 173 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; 174 break; 175 176 case 3: 177 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; 178 break; 179 180 default: 181 err = -EINVAL; 182 goto exit; 183 } 184 185 result = prism2_domibset_pstr32(wlandev, did, 186 params->key_len, params->key); 187 if (result) 188 goto exit; 189 break; 190 191 default: 192 pr_debug("Unsupported cipher suite\n"); 193 result = 1; 194 } 195 196exit: 197 if (result) 198 err = -EFAULT; 199 200 return err; 201} 202 203static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, 204 u8 key_index, bool pairwise, 205 const u8 *mac_addr, void *cookie, 206 void (*callback)(void *cookie, struct key_params*)) 207{ 208 wlandevice_t *wlandev = dev->ml_priv; 209 struct key_params params; 210 int len; 211 212 if (key_index >= NUM_WEPKEYS) 213 return -EINVAL; 214 215 len = wlandev->wep_keylens[key_index]; 216 memset(¶ms, 0, sizeof(params)); 217 218 if (len == 13) 219 params.cipher = WLAN_CIPHER_SUITE_WEP104; 220 else if (len == 5) 221 params.cipher = WLAN_CIPHER_SUITE_WEP104; 222 else 223 return -ENOENT; 224 params.key_len = len; 225 params.key = wlandev->wep_keys[key_index]; 226 params.seq_len = 0; 227 228 callback(cookie, ¶ms); 229 230 return 0; 231} 232 233static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, 234 u8 key_index, bool pairwise, const u8 *mac_addr) 235{ 236 wlandevice_t *wlandev = dev->ml_priv; 237 u32 did; 238 int err = 0; 239 int result = 0; 240 241 /* There is no direct way in the hardware (AFAIK) of removing 242 a key, so we will cheat by setting the key to a bogus value */ 243 /* send key to driver */ 244 switch (key_index) { 245 case 0: 246 did = 247 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; 248 break; 249 250 case 1: 251 did = 252 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; 253 break; 254 255 case 2: 256 did = 257 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; 258 break; 259 260 case 3: 261 did = 262 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; 263 break; 264 265 default: 266 err = -EINVAL; 267 goto exit; 268 } 269 270 result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000"); 271 272exit: 273 if (result) 274 err = -EFAULT; 275 276 return err; 277} 278 279static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, 280 u8 key_index, bool unicast, bool multicast) 281{ 282 wlandevice_t *wlandev = dev->ml_priv; 283 284 int err = 0; 285 int result = 0; 286 287 result = prism2_domibset_uint32(wlandev, 288 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, 289 key_index); 290 291 if (result) 292 err = -EFAULT; 293 294 return err; 295} 296 297static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, 298 const u8 *mac, struct station_info *sinfo) 299{ 300 wlandevice_t *wlandev = dev->ml_priv; 301 struct p80211msg_lnxreq_commsquality quality; 302 int result; 303 304 memset(sinfo, 0, sizeof(*sinfo)); 305 306 if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING)) 307 return -EOPNOTSUPP; 308 309 /* build request message */ 310 quality.msgcode = DIDmsg_lnxreq_commsquality; 311 quality.dbm.data = P80211ENUM_truth_true; 312 quality.dbm.status = P80211ENUM_msgitem_status_data_ok; 313 314 /* send message to nsd */ 315 if (wlandev->mlmerequest == NULL) 316 return -EOPNOTSUPP; 317 318 result = wlandev->mlmerequest(wlandev, (struct p80211msg *) &quality); 319 320 if (result == 0) { 321 sinfo->txrate.legacy = quality.txrate.data; 322 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); 323 sinfo->signal = quality.level.data; 324 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); 325 } 326 327 return result; 328} 329 330static int prism2_scan(struct wiphy *wiphy, 331 struct cfg80211_scan_request *request) 332{ 333 struct net_device *dev; 334 struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 335 wlandevice_t *wlandev; 336 struct p80211msg_dot11req_scan msg1; 337 struct p80211msg_dot11req_scan_results msg2; 338 struct cfg80211_bss *bss; 339 int result; 340 int err = 0; 341 int numbss = 0; 342 int i = 0; 343 u8 ie_buf[46]; 344 int ie_len; 345 346 if (!request) 347 return -EINVAL; 348 349 dev = request->wdev->netdev; 350 wlandev = dev->ml_priv; 351 352 if (priv->scan_request && priv->scan_request != request) 353 return -EBUSY; 354 355 if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { 356 netdev_err(dev, "Can't scan in AP mode\n"); 357 return -EOPNOTSUPP; 358 } 359 360 priv->scan_request = request; 361 362 memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan)); 363 msg1.msgcode = DIDmsg_dot11req_scan; 364 msg1.bsstype.data = P80211ENUM_bsstype_any; 365 366 memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data)); 367 msg1.bssid.data.len = 6; 368 369 if (request->n_ssids > 0) { 370 msg1.scantype.data = P80211ENUM_scantype_active; 371 msg1.ssid.data.len = request->ssids->ssid_len; 372 memcpy(msg1.ssid.data.data, 373 request->ssids->ssid, request->ssids->ssid_len); 374 } else { 375 msg1.scantype.data = 0; 376 } 377 msg1.probedelay.data = 0; 378 379 for (i = 0; 380 (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); 381 i++) 382 msg1.channellist.data.data[i] = 383 ieee80211_frequency_to_channel( 384 request->channels[i]->center_freq); 385 msg1.channellist.data.len = request->n_channels; 386 387 msg1.maxchanneltime.data = 250; 388 msg1.minchanneltime.data = 200; 389 390 result = p80211req_dorequest(wlandev, (u8 *) &msg1); 391 if (result) { 392 err = prism2_result2err(msg1.resultcode.data); 393 goto exit; 394 } 395 /* Now retrieve scan results */ 396 numbss = msg1.numbss.data; 397 398 for (i = 0; i < numbss; i++) { 399 int freq; 400 401 memset(&msg2, 0, sizeof(msg2)); 402 msg2.msgcode = DIDmsg_dot11req_scan_results; 403 msg2.bssindex.data = i; 404 405 result = p80211req_dorequest(wlandev, (u8 *) &msg2); 406 if ((result != 0) || 407 (msg2.resultcode.data != P80211ENUM_resultcode_success)) { 408 break; 409 } 410 411 ie_buf[0] = WLAN_EID_SSID; 412 ie_buf[1] = msg2.ssid.data.len; 413 ie_len = ie_buf[1] + 2; 414 memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); 415 freq = ieee80211_channel_to_frequency(msg2.dschannel.data, 416 IEEE80211_BAND_2GHZ); 417 bss = cfg80211_inform_bss(wiphy, 418 ieee80211_get_channel(wiphy, freq), 419 CFG80211_BSS_FTYPE_UNKNOWN, 420 (const u8 *) &(msg2.bssid.data.data), 421 msg2.timestamp.data, msg2.capinfo.data, 422 msg2.beaconperiod.data, 423 ie_buf, 424 ie_len, 425 (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ 426 GFP_KERNEL 427 ); 428 429 if (!bss) { 430 err = -ENOMEM; 431 goto exit; 432 } 433 434 cfg80211_put_bss(wiphy, bss); 435 } 436 437 if (result) 438 err = prism2_result2err(msg2.resultcode.data); 439 440exit: 441 cfg80211_scan_done(request, err ? 1 : 0); 442 priv->scan_request = NULL; 443 return err; 444} 445 446static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) 447{ 448 struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 449 wlandevice_t *wlandev = priv->wlandev; 450 u32 data; 451 int result; 452 int err = 0; 453 454 if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 455 if (wiphy->rts_threshold == -1) 456 data = 2347; 457 else 458 data = wiphy->rts_threshold; 459 460 result = prism2_domibset_uint32(wlandev, 461 DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, 462 data); 463 if (result) { 464 err = -EFAULT; 465 goto exit; 466 } 467 } 468 469 if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { 470 if (wiphy->frag_threshold == -1) 471 data = 2346; 472 else 473 data = wiphy->frag_threshold; 474 475 result = prism2_domibset_uint32(wlandev, 476 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, 477 data); 478 if (result) { 479 err = -EFAULT; 480 goto exit; 481 } 482 } 483 484exit: 485 return err; 486} 487 488static int prism2_connect(struct wiphy *wiphy, struct net_device *dev, 489 struct cfg80211_connect_params *sme) 490{ 491 wlandevice_t *wlandev = dev->ml_priv; 492 struct ieee80211_channel *channel = sme->channel; 493 struct p80211msg_lnxreq_autojoin msg_join; 494 u32 did; 495 int length = sme->ssid_len; 496 int chan = -1; 497 int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || 498 (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104); 499 int result; 500 int err = 0; 501 502 /* Set the channel */ 503 if (channel) { 504 chan = ieee80211_frequency_to_channel(channel->center_freq); 505 result = prism2_domibset_uint32(wlandev, 506 DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, 507 chan); 508 if (result) 509 goto exit; 510 } 511 512 /* Set the authorization */ 513 if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) || 514 ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep)) 515 msg_join.authtype.data = P80211ENUM_authalg_opensystem; 516 else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) || 517 ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep)) 518 msg_join.authtype.data = P80211ENUM_authalg_sharedkey; 519 else 520 netdev_warn(dev, 521 "Unhandled authorisation type for connect (%d)\n", 522 sme->auth_type); 523 524 /* Set the encryption - we only support wep */ 525 if (is_wep) { 526 if (sme->key) { 527 result = prism2_domibset_uint32(wlandev, 528 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, 529 sme->key_idx); 530 if (result) 531 goto exit; 532 533 /* send key to driver */ 534 switch (sme->key_idx) { 535 case 0: 536 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; 537 break; 538 539 case 1: 540 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; 541 break; 542 543 case 2: 544 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; 545 break; 546 547 case 3: 548 did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; 549 break; 550 551 default: 552 err = -EINVAL; 553 goto exit; 554 } 555 556 result = prism2_domibset_pstr32(wlandev, 557 did, sme->key_len, 558 (u8 *)sme->key); 559 if (result) 560 goto exit; 561 562 } 563 564 /* Assume we should set privacy invoked and exclude unencrypted 565 We could possibly use sme->privacy here, but the assumption 566 seems reasonable anyway */ 567 result = prism2_domibset_uint32(wlandev, 568 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, 569 P80211ENUM_truth_true); 570 if (result) 571 goto exit; 572 573 result = prism2_domibset_uint32(wlandev, 574 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, 575 P80211ENUM_truth_true); 576 if (result) 577 goto exit; 578 579 } else { 580 /* Assume we should unset privacy invoked 581 and exclude unencrypted */ 582 result = prism2_domibset_uint32(wlandev, 583 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, 584 P80211ENUM_truth_false); 585 if (result) 586 goto exit; 587 588 result = prism2_domibset_uint32(wlandev, 589 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, 590 P80211ENUM_truth_false); 591 if (result) 592 goto exit; 593 594 } 595 596 /* Now do the actual join. Note there is no way that I can 597 see to request a specific bssid */ 598 msg_join.msgcode = DIDmsg_lnxreq_autojoin; 599 600 memcpy(msg_join.ssid.data.data, sme->ssid, length); 601 msg_join.ssid.data.len = length; 602 603 result = p80211req_dorequest(wlandev, (u8 *) &msg_join); 604 605exit: 606 if (result) 607 err = -EFAULT; 608 609 return err; 610} 611 612static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, 613 u16 reason_code) 614{ 615 wlandevice_t *wlandev = dev->ml_priv; 616 struct p80211msg_lnxreq_autojoin msg_join; 617 int result; 618 int err = 0; 619 620 /* Do a join, with a bogus ssid. Thats the only way I can think of */ 621 msg_join.msgcode = DIDmsg_lnxreq_autojoin; 622 623 memcpy(msg_join.ssid.data.data, "---", 3); 624 msg_join.ssid.data.len = 3; 625 626 result = p80211req_dorequest(wlandev, (u8 *) &msg_join); 627 628 if (result) 629 err = -EFAULT; 630 631 return err; 632} 633 634static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, 635 struct cfg80211_ibss_params *params) 636{ 637 return -EOPNOTSUPP; 638} 639 640static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) 641{ 642 return -EOPNOTSUPP; 643} 644 645static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, 646 enum nl80211_tx_power_setting type, int mbm) 647{ 648 struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 649 wlandevice_t *wlandev = priv->wlandev; 650 u32 data; 651 int result; 652 int err = 0; 653 654 if (type == NL80211_TX_POWER_AUTOMATIC) 655 data = 30; 656 else 657 data = MBM_TO_DBM(mbm); 658 659 result = prism2_domibset_uint32(wlandev, 660 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, 661 data); 662 663 if (result) { 664 err = -EFAULT; 665 goto exit; 666 } 667 668exit: 669 return err; 670} 671 672static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, 673 int *dbm) 674{ 675 struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 676 wlandevice_t *wlandev = priv->wlandev; 677 struct p80211msg_dot11req_mibget msg; 678 p80211item_uint32_t *mibitem; 679 int result; 680 int err = 0; 681 682 mibitem = (p80211item_uint32_t *) &msg.mibattribute.data; 683 msg.msgcode = DIDmsg_dot11req_mibget; 684 mibitem->did = 685 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; 686 687 result = p80211req_dorequest(wlandev, (u8 *) &msg); 688 689 if (result) { 690 err = -EFAULT; 691 goto exit; 692 } 693 694 *dbm = mibitem->data; 695 696exit: 697 return err; 698} 699 700/* Interface callback functions, passing data back up to the cfg80211 layer */ 701void prism2_connect_result(wlandevice_t *wlandev, u8 failed) 702{ 703 u16 status = failed ? 704 WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS; 705 706 cfg80211_connect_result(wlandev->netdev, wlandev->bssid, 707 NULL, 0, NULL, 0, status, GFP_KERNEL); 708} 709 710void prism2_disconnected(wlandevice_t *wlandev) 711{ 712 cfg80211_disconnected(wlandev->netdev, 0, NULL, 713 0, false, GFP_KERNEL); 714} 715 716void prism2_roamed(wlandevice_t *wlandev) 717{ 718 cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid, 719 NULL, 0, NULL, 0, GFP_KERNEL); 720} 721 722/* Structures for declaring wiphy interface */ 723static const struct cfg80211_ops prism2_usb_cfg_ops = { 724 .change_virtual_intf = prism2_change_virtual_intf, 725 .add_key = prism2_add_key, 726 .get_key = prism2_get_key, 727 .del_key = prism2_del_key, 728 .set_default_key = prism2_set_default_key, 729 .get_station = prism2_get_station, 730 .scan = prism2_scan, 731 .set_wiphy_params = prism2_set_wiphy_params, 732 .connect = prism2_connect, 733 .disconnect = prism2_disconnect, 734 .join_ibss = prism2_join_ibss, 735 .leave_ibss = prism2_leave_ibss, 736 .set_tx_power = prism2_set_tx_power, 737 .get_tx_power = prism2_get_tx_power, 738}; 739 740/* Functions to create/free wiphy interface */ 741static struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev) 742{ 743 struct wiphy *wiphy; 744 struct prism2_wiphy_private *priv; 745 746 wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv)); 747 if (!wiphy) 748 return NULL; 749 750 priv = wiphy_priv(wiphy); 751 priv->wlandev = wlandev; 752 memcpy(priv->channels, prism2_channels, sizeof(prism2_channels)); 753 memcpy(priv->rates, prism2_rates, sizeof(prism2_rates)); 754 priv->band.channels = priv->channels; 755 priv->band.n_channels = ARRAY_SIZE(prism2_channels); 756 priv->band.bitrates = priv->rates; 757 priv->band.n_bitrates = ARRAY_SIZE(prism2_rates); 758 priv->band.band = IEEE80211_BAND_2GHZ; 759 priv->band.ht_cap.ht_supported = false; 760 wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; 761 762 set_wiphy_dev(wiphy, dev); 763 wiphy->privid = prism2_wiphy_privid; 764 wiphy->max_scan_ssids = 1; 765 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) 766 | BIT(NL80211_IFTYPE_ADHOC); 767 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 768 wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES; 769 wiphy->cipher_suites = prism2_cipher_suites; 770 771 if (wiphy_register(wiphy) < 0) 772 return NULL; 773 774 return wiphy; 775} 776 777static void wlan_free_wiphy(struct wiphy *wiphy) 778{ 779 wiphy_unregister(wiphy); 780 wiphy_free(wiphy); 781} 782