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