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