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