1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2cb3126e6SKarl Relton /* cfg80211 Interface for prism2_usb module */ 36eaf0788STair Rzayev #include "hfa384x.h" 46eaf0788STair Rzayev #include "prism2mgmt.h" 5cb3126e6SKarl Relton 6d34602deSJustin P. Mattock /* Prism2 channel/frequency/bitrate declarations */ 7cb3126e6SKarl Relton static const struct ieee80211_channel prism2_channels[] = { 8cb3126e6SKarl Relton { .center_freq = 2412 }, 9cb3126e6SKarl Relton { .center_freq = 2417 }, 10cb3126e6SKarl Relton { .center_freq = 2422 }, 11cb3126e6SKarl Relton { .center_freq = 2427 }, 12cb3126e6SKarl Relton { .center_freq = 2432 }, 13cb3126e6SKarl Relton { .center_freq = 2437 }, 14cb3126e6SKarl Relton { .center_freq = 2442 }, 15cb3126e6SKarl Relton { .center_freq = 2447 }, 16cb3126e6SKarl Relton { .center_freq = 2452 }, 17cb3126e6SKarl Relton { .center_freq = 2457 }, 18cb3126e6SKarl Relton { .center_freq = 2462 }, 19cb3126e6SKarl Relton { .center_freq = 2467 }, 20cb3126e6SKarl Relton { .center_freq = 2472 }, 21cb3126e6SKarl Relton { .center_freq = 2484 }, 22cb3126e6SKarl Relton }; 23cb3126e6SKarl Relton 24cb3126e6SKarl Relton static const struct ieee80211_rate prism2_rates[] = { 25cb3126e6SKarl Relton { .bitrate = 10 }, 26cb3126e6SKarl Relton { .bitrate = 20 }, 27cb3126e6SKarl Relton { .bitrate = 55 }, 28cb3126e6SKarl Relton { .bitrate = 110 } 29cb3126e6SKarl Relton }; 30cb3126e6SKarl Relton 31cb3126e6SKarl Relton #define PRISM2_NUM_CIPHER_SUITES 2 32cb3126e6SKarl Relton static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = { 33cb3126e6SKarl Relton WLAN_CIPHER_SUITE_WEP40, 34cb3126e6SKarl Relton WLAN_CIPHER_SUITE_WEP104 35cb3126e6SKarl Relton }; 36cb3126e6SKarl Relton 37cb3126e6SKarl Relton /* prism2 device private data */ 38cb3126e6SKarl Relton struct prism2_wiphy_private { 39c9573a8dSsayli karnik struct wlandevice *wlandev; 40cb3126e6SKarl Relton 41cb3126e6SKarl Relton struct ieee80211_supported_band band; 42cb3126e6SKarl Relton struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)]; 43cb3126e6SKarl Relton struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)]; 44cb3126e6SKarl Relton 45cb3126e6SKarl Relton struct cfg80211_scan_request *scan_request; 46cb3126e6SKarl Relton }; 47cb3126e6SKarl Relton 48cb3126e6SKarl Relton static const void * const prism2_wiphy_privid = &prism2_wiphy_privid; 49cb3126e6SKarl Relton 50cb3126e6SKarl Relton /* Helper Functions */ 51cb3126e6SKarl Relton static int prism2_result2err(int prism2_result) 52cb3126e6SKarl Relton { 53cb3126e6SKarl Relton int err = 0; 54cb3126e6SKarl Relton 55cb3126e6SKarl Relton switch (prism2_result) { 56cb3126e6SKarl Relton case P80211ENUM_resultcode_invalid_parameters: 57cb3126e6SKarl Relton err = -EINVAL; 58cb3126e6SKarl Relton break; 59cb3126e6SKarl Relton case P80211ENUM_resultcode_implementation_failure: 60cb3126e6SKarl Relton err = -EIO; 61cb3126e6SKarl Relton break; 62cb3126e6SKarl Relton case P80211ENUM_resultcode_not_supported: 63cb3126e6SKarl Relton err = -EOPNOTSUPP; 64cb3126e6SKarl Relton break; 65cb3126e6SKarl Relton default: 66cb3126e6SKarl Relton err = 0; 67cb3126e6SKarl Relton break; 68cb3126e6SKarl Relton } 69cb3126e6SKarl Relton 70cb3126e6SKarl Relton return err; 71cb3126e6SKarl Relton } 72cb3126e6SKarl Relton 73c9573a8dSsayli karnik static int prism2_domibset_uint32(struct wlandevice *wlandev, u32 did, u32 data) 74cb3126e6SKarl Relton { 75b6bb56e6SEdgardo Hames struct p80211msg_dot11req_mibset msg; 76b26b2325SSergio Paracuellos struct p80211item_uint32 *mibitem = 77b26b2325SSergio Paracuellos (struct p80211item_uint32 *)&msg.mibattribute.data; 78cb3126e6SKarl Relton 79e409d2bcSTim Collier msg.msgcode = DIDMSG_DOT11REQ_MIBSET; 80cb3126e6SKarl Relton mibitem->did = did; 81cb3126e6SKarl Relton mibitem->data = data; 82cb3126e6SKarl Relton 83cb3126e6SKarl Relton return p80211req_dorequest(wlandev, (u8 *)&msg); 84cb3126e6SKarl Relton } 85cb3126e6SKarl Relton 86c9573a8dSsayli karnik static int prism2_domibset_pstr32(struct wlandevice *wlandev, 87c1e5f471SJohannes Berg u32 did, u8 len, const u8 *data) 88cb3126e6SKarl Relton { 89b6bb56e6SEdgardo Hames struct p80211msg_dot11req_mibset msg; 906a50b5afSSergio Paracuellos struct p80211item_pstr32 *mibitem = 916a50b5afSSergio Paracuellos (struct p80211item_pstr32 *)&msg.mibattribute.data; 92cb3126e6SKarl Relton 93e409d2bcSTim Collier msg.msgcode = DIDMSG_DOT11REQ_MIBSET; 94cb3126e6SKarl Relton mibitem->did = did; 95cb3126e6SKarl Relton mibitem->data.len = len; 96cb3126e6SKarl Relton memcpy(mibitem->data.data, data, len); 97cb3126e6SKarl Relton 98cb3126e6SKarl Relton return p80211req_dorequest(wlandev, (u8 *)&msg); 99cb3126e6SKarl Relton } 100cb3126e6SKarl Relton 101cb3126e6SKarl Relton /* The interface functions, called by the cfg80211 layer */ 10255da06ebSTeodora Baluta static int prism2_change_virtual_intf(struct wiphy *wiphy, 103cb3126e6SKarl Relton struct net_device *dev, 104818a986eSJohannes Berg enum nl80211_iftype type, 105cb3126e6SKarl Relton struct vif_params *params) 106cb3126e6SKarl Relton { 107c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 108cb3126e6SKarl Relton u32 data; 109cb3126e6SKarl Relton int result; 110cb3126e6SKarl Relton int err = 0; 111cb3126e6SKarl Relton 112cb3126e6SKarl Relton switch (type) { 113cb3126e6SKarl Relton case NL80211_IFTYPE_ADHOC: 1148dd82ebeSEdgardo Hames if (wlandev->macmode == WLAN_MACMODE_IBSS_STA) 1158dd82ebeSEdgardo Hames goto exit; 116cb3126e6SKarl Relton wlandev->macmode = WLAN_MACMODE_IBSS_STA; 117cb3126e6SKarl Relton data = 0; 118cb3126e6SKarl Relton break; 119cb3126e6SKarl Relton case NL80211_IFTYPE_STATION: 1208dd82ebeSEdgardo Hames if (wlandev->macmode == WLAN_MACMODE_ESS_STA) 1218dd82ebeSEdgardo Hames goto exit; 122cb3126e6SKarl Relton wlandev->macmode = WLAN_MACMODE_ESS_STA; 123cb3126e6SKarl Relton data = 1; 124cb3126e6SKarl Relton break; 125cb3126e6SKarl Relton default: 126eed88971SAvinash Kumar netdev_warn(dev, "Operation mode: %d not support\n", type); 127cb3126e6SKarl Relton return -EOPNOTSUPP; 128cb3126e6SKarl Relton } 129cb3126e6SKarl Relton 130cb3126e6SKarl Relton /* Set Operation mode to the PORT TYPE RID */ 1318aac4d44SDevendra Naga result = prism2_domibset_uint32(wlandev, 1328aac4d44SDevendra Naga DIDmib_p2_p2Static_p2CnfPortType, 1338aac4d44SDevendra Naga data); 134cb3126e6SKarl Relton 135cb3126e6SKarl Relton if (result) 136cb3126e6SKarl Relton err = -EFAULT; 137cb3126e6SKarl Relton 138cb3126e6SKarl Relton dev->ieee80211_ptr->iftype = type; 139cb3126e6SKarl Relton 140cb3126e6SKarl Relton exit: 141cb3126e6SKarl Relton return err; 142cb3126e6SKarl Relton } 143cb3126e6SKarl Relton 14455da06ebSTeodora Baluta static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev, 14534a488c1SBen Hutchings u8 key_index, bool pairwise, const u8 *mac_addr, 1468dd82ebeSEdgardo Hames struct key_params *params) 1478dd82ebeSEdgardo Hames { 148c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 149cb3126e6SKarl Relton u32 did; 150cb3126e6SKarl Relton 1510ca6d8e7SClaudiu Beznea if (key_index >= NUM_WEPKEYS) 1520ca6d8e7SClaudiu Beznea return -EINVAL; 1530ca6d8e7SClaudiu Beznea 1546b142341SChris Opperman if (params->cipher != WLAN_CIPHER_SUITE_WEP40 && 1556b142341SChris Opperman params->cipher != WLAN_CIPHER_SUITE_WEP104) { 1566b142341SChris Opperman pr_debug("Unsupported cipher suite\n"); 1576b142341SChris Opperman return -EFAULT; 1586b142341SChris Opperman } 1596b142341SChris Opperman 1606b142341SChris Opperman if (prism2_domibset_uint32(wlandev, 161eeeeacd8STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, 1626b142341SChris Opperman key_index)) 1636b142341SChris Opperman return -EFAULT; 164cb3126e6SKarl Relton 165cb3126e6SKarl Relton /* send key to driver */ 166ce0f34e4STim Collier did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1); 167cb3126e6SKarl Relton 1686b142341SChris Opperman if (prism2_domibset_pstr32(wlandev, did, params->key_len, params->key)) 1696b142341SChris Opperman return -EFAULT; 1706b142341SChris Opperman return 0; 171cb3126e6SKarl Relton } 172cb3126e6SKarl Relton 17355da06ebSTeodora Baluta static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, 17455da06ebSTeodora Baluta u8 key_index, bool pairwise, 17555da06ebSTeodora Baluta const u8 *mac_addr, void *cookie, 1768dd82ebeSEdgardo Hames void (*callback)(void *cookie, struct key_params*)) 1778dd82ebeSEdgardo Hames { 178c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 179cb3126e6SKarl Relton struct key_params params; 180cb3126e6SKarl Relton int len; 181cb3126e6SKarl Relton 1828dd82ebeSEdgardo Hames if (key_index >= NUM_WEPKEYS) 1838dd82ebeSEdgardo Hames return -EINVAL; 184cb3126e6SKarl Relton 185cb3126e6SKarl Relton len = wlandev->wep_keylens[key_index]; 186cb3126e6SKarl Relton memset(¶ms, 0, sizeof(params)); 187cb3126e6SKarl Relton 1888dd82ebeSEdgardo Hames if (len == 13) 189cb3126e6SKarl Relton params.cipher = WLAN_CIPHER_SUITE_WEP104; 1908dd82ebeSEdgardo Hames else if (len == 5) 191cb3126e6SKarl Relton params.cipher = WLAN_CIPHER_SUITE_WEP104; 1928dd82ebeSEdgardo Hames else 1938dd82ebeSEdgardo Hames return -ENOENT; 194cb3126e6SKarl Relton params.key_len = len; 195cb3126e6SKarl Relton params.key = wlandev->wep_keys[key_index]; 196aff3ea4eSKarl Relton params.seq_len = 0; 197cb3126e6SKarl Relton 198cb3126e6SKarl Relton callback(cookie, ¶ms); 1998dd82ebeSEdgardo Hames 200cb3126e6SKarl Relton return 0; 201cb3126e6SKarl Relton } 202cb3126e6SKarl Relton 20355da06ebSTeodora Baluta static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, 20434a488c1SBen Hutchings u8 key_index, bool pairwise, const u8 *mac_addr) 2058dd82ebeSEdgardo Hames { 206c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 207cb3126e6SKarl Relton u32 did; 208cb3126e6SKarl Relton int err = 0; 209cb3126e6SKarl Relton int result = 0; 210cb3126e6SKarl Relton 211cb3126e6SKarl Relton /* There is no direct way in the hardware (AFAIK) of removing 21235028fe1SGavin O'Leary * a key, so we will cheat by setting the key to a bogus value 21335028fe1SGavin O'Leary */ 21435028fe1SGavin O'Leary 2150ca6d8e7SClaudiu Beznea if (key_index >= NUM_WEPKEYS) 2160ca6d8e7SClaudiu Beznea return -EINVAL; 2170ca6d8e7SClaudiu Beznea 218cb3126e6SKarl Relton /* send key to driver */ 219ce0f34e4STim Collier did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1); 220cb3126e6SKarl Relton result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000"); 221cb3126e6SKarl Relton 2228dd82ebeSEdgardo Hames if (result) 2238dd82ebeSEdgardo Hames err = -EFAULT; 224cb3126e6SKarl Relton 225cb3126e6SKarl Relton return err; 226cb3126e6SKarl Relton } 227cb3126e6SKarl Relton 22855da06ebSTeodora Baluta static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, 2299005fcd8SHarry Wei u8 key_index, bool unicast, bool multicast) 2308dd82ebeSEdgardo Hames { 231c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 232cb3126e6SKarl Relton 233cb3126e6SKarl Relton int err = 0; 234cb3126e6SKarl Relton int result = 0; 235cb3126e6SKarl Relton 236cb3126e6SKarl Relton result = prism2_domibset_uint32(wlandev, 237eeeeacd8STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, 238cb3126e6SKarl Relton key_index); 239cb3126e6SKarl Relton 2408dd82ebeSEdgardo Hames if (result) 2418dd82ebeSEdgardo Hames err = -EFAULT; 242cb3126e6SKarl Relton 243cb3126e6SKarl Relton return err; 244cb3126e6SKarl Relton } 245cb3126e6SKarl Relton 24655da06ebSTeodora Baluta static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, 2473b3a0162SJohannes Berg const u8 *mac, struct station_info *sinfo) 2488dd82ebeSEdgardo Hames { 249c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 250b6bb56e6SEdgardo Hames struct p80211msg_lnxreq_commsquality quality; 251cb3126e6SKarl Relton int result; 252cb3126e6SKarl Relton 253cb3126e6SKarl Relton memset(sinfo, 0, sizeof(*sinfo)); 254cb3126e6SKarl Relton 255e52f2149SSandhya Bankar if (!wlandev || (wlandev->msdstate != WLAN_MSD_RUNNING)) 256cb3126e6SKarl Relton return -EOPNOTSUPP; 257cb3126e6SKarl Relton 258cb3126e6SKarl Relton /* build request message */ 2593b6ee123STim Collier quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY; 260cb3126e6SKarl Relton quality.dbm.data = P80211ENUM_truth_true; 261cb3126e6SKarl Relton quality.dbm.status = P80211ENUM_msgitem_status_data_ok; 262cb3126e6SKarl Relton 263cb3126e6SKarl Relton /* send message to nsd */ 264e52f2149SSandhya Bankar if (!wlandev->mlmerequest) 265cb3126e6SKarl Relton return -EOPNOTSUPP; 266cb3126e6SKarl Relton 2673d049431SEdgardo Hames result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality); 268cb3126e6SKarl Relton 269cb3126e6SKarl Relton if (result == 0) { 270cb3126e6SKarl Relton sinfo->txrate.legacy = quality.txrate.data; 2715c6a5eb3SOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 272cb3126e6SKarl Relton sinfo->signal = quality.level.data; 2735c6a5eb3SOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); 274cb3126e6SKarl Relton } 275cb3126e6SKarl Relton 276cb3126e6SKarl Relton return result; 277cb3126e6SKarl Relton } 278cb3126e6SKarl Relton 279bb1da756SHimangi Saraogi static int prism2_scan(struct wiphy *wiphy, 280bb1da756SHimangi Saraogi struct cfg80211_scan_request *request) 281cb3126e6SKarl Relton { 2825d5d7c3bSEmil Goode struct net_device *dev; 283cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 284c9573a8dSsayli karnik struct wlandevice *wlandev; 285b6bb56e6SEdgardo Hames struct p80211msg_dot11req_scan msg1; 286b6bb56e6SEdgardo Hames struct p80211msg_dot11req_scan_results msg2; 28719f798adSKrzysztof Wilczynski struct cfg80211_bss *bss; 2881d76250bSAvraham Stern struct cfg80211_scan_info info = {}; 2891d76250bSAvraham Stern 290cb3126e6SKarl Relton int result; 291cb3126e6SKarl Relton int err = 0; 292cb3126e6SKarl Relton int numbss = 0; 293cb3126e6SKarl Relton int i = 0; 294cb3126e6SKarl Relton u8 ie_buf[46]; 295cb3126e6SKarl Relton int ie_len; 296cb3126e6SKarl Relton 297cb3126e6SKarl Relton if (!request) 298cb3126e6SKarl Relton return -EINVAL; 299cb3126e6SKarl Relton 3005d5d7c3bSEmil Goode dev = request->wdev->netdev; 3015d5d7c3bSEmil Goode wlandev = dev->ml_priv; 3025d5d7c3bSEmil Goode 303cb3126e6SKarl Relton if (priv->scan_request && priv->scan_request != request) 304cb3126e6SKarl Relton return -EBUSY; 305cb3126e6SKarl Relton 306cb3126e6SKarl Relton if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { 307eed88971SAvinash Kumar netdev_err(dev, "Can't scan in AP mode\n"); 308cb3126e6SKarl Relton return -EOPNOTSUPP; 309cb3126e6SKarl Relton } 310cb3126e6SKarl Relton 311cb3126e6SKarl Relton priv->scan_request = request; 312cb3126e6SKarl Relton 31389e13b45SSergio Paracuellos memset(&msg1, 0x00, sizeof(msg1)); 3141ffaa906STim Collier msg1.msgcode = DIDMSG_DOT11REQ_SCAN; 315cb3126e6SKarl Relton msg1.bsstype.data = P80211ENUM_bsstype_any; 316cb3126e6SKarl Relton 317625aeb3aSDan Carpenter memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data)); 318cb3126e6SKarl Relton msg1.bssid.data.len = 6; 319cb3126e6SKarl Relton 320cb3126e6SKarl Relton if (request->n_ssids > 0) { 321cb3126e6SKarl Relton msg1.scantype.data = P80211ENUM_scantype_active; 322cb3126e6SKarl Relton msg1.ssid.data.len = request->ssids->ssid_len; 3238aac4d44SDevendra Naga memcpy(msg1.ssid.data.data, 3248aac4d44SDevendra Naga request->ssids->ssid, request->ssids->ssid_len); 325cb3126e6SKarl Relton } else { 326cb3126e6SKarl Relton msg1.scantype.data = 0; 327cb3126e6SKarl Relton } 328cb3126e6SKarl Relton msg1.probedelay.data = 0; 329cb3126e6SKarl Relton 330cb3126e6SKarl Relton for (i = 0; 331cb3126e6SKarl Relton (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); 332cb3126e6SKarl Relton i++) 333cb3126e6SKarl Relton msg1.channellist.data.data[i] = 334bb1da756SHimangi Saraogi ieee80211_frequency_to_channel( 335bb1da756SHimangi Saraogi request->channels[i]->center_freq); 336cb3126e6SKarl Relton msg1.channellist.data.len = request->n_channels; 337cb3126e6SKarl Relton 338cb3126e6SKarl Relton msg1.maxchanneltime.data = 250; 339cb3126e6SKarl Relton msg1.minchanneltime.data = 200; 340cb3126e6SKarl Relton 341cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg1); 342cb3126e6SKarl Relton if (result) { 343cb3126e6SKarl Relton err = prism2_result2err(msg1.resultcode.data); 344cb3126e6SKarl Relton goto exit; 345cb3126e6SKarl Relton } 346cb3126e6SKarl Relton /* Now retrieve scan results */ 347cb3126e6SKarl Relton numbss = msg1.numbss.data; 348cb3126e6SKarl Relton 349cb3126e6SKarl Relton for (i = 0; i < numbss; i++) { 3504e5e9d7cSZhao, Gang int freq; 3514e5e9d7cSZhao, Gang 352cb3126e6SKarl Relton memset(&msg2, 0, sizeof(msg2)); 353e3186790STim Collier msg2.msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS; 354cb3126e6SKarl Relton msg2.bssindex.data = i; 355cb3126e6SKarl Relton 356cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg2); 357cb3126e6SKarl Relton if ((result != 0) || 358cb3126e6SKarl Relton (msg2.resultcode.data != P80211ENUM_resultcode_success)) { 359cb3126e6SKarl Relton break; 360cb3126e6SKarl Relton } 361cb3126e6SKarl Relton 362cb3126e6SKarl Relton ie_buf[0] = WLAN_EID_SSID; 363cb3126e6SKarl Relton ie_buf[1] = msg2.ssid.data.len; 364cb3126e6SKarl Relton ie_len = ie_buf[1] + 2; 365efffed8eSsayli karnik memcpy(&ie_buf[2], &msg2.ssid.data.data, msg2.ssid.data.len); 3664e5e9d7cSZhao, Gang freq = ieee80211_channel_to_frequency(msg2.dschannel.data, 36757fbcce3SJohannes Berg NL80211_BAND_2GHZ); 36819f798adSKrzysztof Wilczynski bss = cfg80211_inform_bss(wiphy, 3694e5e9d7cSZhao, Gang ieee80211_get_channel(wiphy, freq), 3705bc8c1f2SJohannes Berg CFG80211_BSS_FTYPE_UNKNOWN, 371efffed8eSsayli karnik (const u8 *)&msg2.bssid.data.data, 372cb3126e6SKarl Relton msg2.timestamp.data, msg2.capinfo.data, 373cb3126e6SKarl Relton msg2.beaconperiod.data, 374cb3126e6SKarl Relton ie_buf, 375cb3126e6SKarl Relton ie_len, 376cb3126e6SKarl Relton (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ 377cb3126e6SKarl Relton GFP_KERNEL 378cb3126e6SKarl Relton ); 37919f798adSKrzysztof Wilczynski 38019f798adSKrzysztof Wilczynski if (!bss) { 38119f798adSKrzysztof Wilczynski err = -ENOMEM; 38219f798adSKrzysztof Wilczynski goto exit; 38319f798adSKrzysztof Wilczynski } 38419f798adSKrzysztof Wilczynski 3855b112d3dSJohannes Berg cfg80211_put_bss(wiphy, bss); 386cb3126e6SKarl Relton } 387cb3126e6SKarl Relton 3888dd82ebeSEdgardo Hames if (result) 389cb3126e6SKarl Relton err = prism2_result2err(msg2.resultcode.data); 390cb3126e6SKarl Relton 391cb3126e6SKarl Relton exit: 3921d76250bSAvraham Stern info.aborted = !!(err); 3931d76250bSAvraham Stern cfg80211_scan_done(request, &info); 394cb3126e6SKarl Relton priv->scan_request = NULL; 395cb3126e6SKarl Relton return err; 396cb3126e6SKarl Relton } 397cb3126e6SKarl Relton 39855da06ebSTeodora Baluta static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) 3998dd82ebeSEdgardo Hames { 400cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 401c9573a8dSsayli karnik struct wlandevice *wlandev = priv->wlandev; 402cb3126e6SKarl Relton u32 data; 403cb3126e6SKarl Relton int result; 404cb3126e6SKarl Relton int err = 0; 405cb3126e6SKarl Relton 406cb3126e6SKarl Relton if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 407cb3126e6SKarl Relton if (wiphy->rts_threshold == -1) 408cb3126e6SKarl Relton data = 2347; 409cb3126e6SKarl Relton else 410cb3126e6SKarl Relton data = wiphy->rts_threshold; 411cb3126e6SKarl Relton 4128dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 413334e5e68STim Collier DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD, 414cb3126e6SKarl Relton data); 415cb3126e6SKarl Relton if (result) { 416cb3126e6SKarl Relton err = -EFAULT; 417cb3126e6SKarl Relton goto exit; 418cb3126e6SKarl Relton } 419cb3126e6SKarl Relton } 420cb3126e6SKarl Relton 421cb3126e6SKarl Relton if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { 422cb3126e6SKarl Relton if (wiphy->frag_threshold == -1) 423cb3126e6SKarl Relton data = 2346; 424cb3126e6SKarl Relton else 425cb3126e6SKarl Relton data = wiphy->frag_threshold; 426cb3126e6SKarl Relton 4278dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 42804bbfc2aSTim Collier DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD, 429cb3126e6SKarl Relton data); 430cb3126e6SKarl Relton if (result) { 431cb3126e6SKarl Relton err = -EFAULT; 432cb3126e6SKarl Relton goto exit; 433cb3126e6SKarl Relton } 434cb3126e6SKarl Relton } 435cb3126e6SKarl Relton 436cb3126e6SKarl Relton exit: 437cb3126e6SKarl Relton return err; 438cb3126e6SKarl Relton } 439cb3126e6SKarl Relton 44055da06ebSTeodora Baluta static int prism2_connect(struct wiphy *wiphy, struct net_device *dev, 4418dd82ebeSEdgardo Hames struct cfg80211_connect_params *sme) 4428dd82ebeSEdgardo Hames { 443c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 444cb3126e6SKarl Relton struct ieee80211_channel *channel = sme->channel; 445b6bb56e6SEdgardo Hames struct p80211msg_lnxreq_autojoin msg_join; 446cb3126e6SKarl Relton u32 did; 447cb3126e6SKarl Relton int length = sme->ssid_len; 448cb3126e6SKarl Relton int chan = -1; 449cb3126e6SKarl Relton int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || 450cb3126e6SKarl Relton (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104); 451cb3126e6SKarl Relton int result; 452cb3126e6SKarl Relton int err = 0; 453cb3126e6SKarl Relton 454cb3126e6SKarl Relton /* Set the channel */ 455cb3126e6SKarl Relton if (channel) { 456cb3126e6SKarl Relton chan = ieee80211_frequency_to_channel(channel->center_freq); 4578dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 458cb3126e6SKarl Relton DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, 459cb3126e6SKarl Relton chan); 4608dd82ebeSEdgardo Hames if (result) 4618dd82ebeSEdgardo Hames goto exit; 462cb3126e6SKarl Relton } 463cb3126e6SKarl Relton 464d34602deSJustin P. Mattock /* Set the authorization */ 465cb3126e6SKarl Relton if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) || 466cb3126e6SKarl Relton ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep)) 467cb3126e6SKarl Relton msg_join.authtype.data = P80211ENUM_authalg_opensystem; 468cb3126e6SKarl Relton else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) || 469cb3126e6SKarl Relton ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep)) 470cb3126e6SKarl Relton msg_join.authtype.data = P80211ENUM_authalg_sharedkey; 4718dd82ebeSEdgardo Hames else 472eed88971SAvinash Kumar netdev_warn(dev, 4738dd82ebeSEdgardo Hames "Unhandled authorisation type for connect (%d)\n", 4748dd82ebeSEdgardo Hames sme->auth_type); 475cb3126e6SKarl Relton 476cb3126e6SKarl Relton /* Set the encryption - we only support wep */ 477cb3126e6SKarl Relton if (is_wep) { 478cb3126e6SKarl Relton if (sme->key) { 4790ca6d8e7SClaudiu Beznea if (sme->key_idx >= NUM_WEPKEYS) { 4800ca6d8e7SClaudiu Beznea err = -EINVAL; 4810ca6d8e7SClaudiu Beznea goto exit; 4820ca6d8e7SClaudiu Beznea } 4830ca6d8e7SClaudiu Beznea 484cb3126e6SKarl Relton result = prism2_domibset_uint32(wlandev, 485eeeeacd8STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, 486cb3126e6SKarl Relton sme->key_idx); 4878dd82ebeSEdgardo Hames if (result) 4888dd82ebeSEdgardo Hames goto exit; 489cb3126e6SKarl Relton 490cb3126e6SKarl Relton /* send key to driver */ 491ce0f34e4STim Collier did = didmib_dot11smt_wepdefaultkeystable_key( 4920ca6d8e7SClaudiu Beznea sme->key_idx + 1); 4938aac4d44SDevendra Naga result = prism2_domibset_pstr32(wlandev, 4948aac4d44SDevendra Naga did, sme->key_len, 4958aac4d44SDevendra Naga (u8 *)sme->key); 4968dd82ebeSEdgardo Hames if (result) 4978dd82ebeSEdgardo Hames goto exit; 498cb3126e6SKarl Relton } 499cb3126e6SKarl Relton 500cb3126e6SKarl Relton /* Assume we should set privacy invoked and exclude unencrypted 50135028fe1SGavin O'Leary * We could possible use sme->privacy here, but the assumption 50235028fe1SGavin O'Leary * seems reasonable anyways 50335028fe1SGavin O'Leary */ 5048dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 505184fcaa1STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED, 506cb3126e6SKarl Relton P80211ENUM_truth_true); 5078dd82ebeSEdgardo Hames if (result) 5088dd82ebeSEdgardo Hames goto exit; 5098dd82ebeSEdgardo Hames 5108dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 5112ddc995dSTim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED, 512cb3126e6SKarl Relton P80211ENUM_truth_true); 5138dd82ebeSEdgardo Hames if (result) 5148dd82ebeSEdgardo Hames goto exit; 515cb3126e6SKarl Relton 516cb3126e6SKarl Relton } else { 5178dd82ebeSEdgardo Hames /* Assume we should unset privacy invoked 51835028fe1SGavin O'Leary * and exclude unencrypted 51935028fe1SGavin O'Leary */ 5208dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 521184fcaa1STim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED, 522cb3126e6SKarl Relton P80211ENUM_truth_false); 5238dd82ebeSEdgardo Hames if (result) 5248dd82ebeSEdgardo Hames goto exit; 5258dd82ebeSEdgardo Hames 5268dd82ebeSEdgardo Hames result = prism2_domibset_uint32(wlandev, 5272ddc995dSTim Collier DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED, 528cb3126e6SKarl Relton P80211ENUM_truth_false); 5298dd82ebeSEdgardo Hames if (result) 5308dd82ebeSEdgardo Hames goto exit; 531cb3126e6SKarl Relton } 532cb3126e6SKarl Relton 533cb3126e6SKarl Relton /* Now do the actual join. Note there is no way that I can 5344f9de774SGavin O'Leary * see to request a specific bssid 5354f9de774SGavin O'Leary */ 536b1f1118bSTim Collier msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN; 537cb3126e6SKarl Relton 538cb3126e6SKarl Relton memcpy(msg_join.ssid.data.data, sme->ssid, length); 539cb3126e6SKarl Relton msg_join.ssid.data.len = length; 540cb3126e6SKarl Relton 541cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg_join); 542cb3126e6SKarl Relton 543cb3126e6SKarl Relton exit: 5448dd82ebeSEdgardo Hames if (result) 5458dd82ebeSEdgardo Hames err = -EFAULT; 546cb3126e6SKarl Relton 547cb3126e6SKarl Relton return err; 548cb3126e6SKarl Relton } 549cb3126e6SKarl Relton 55055da06ebSTeodora Baluta static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, 5518dd82ebeSEdgardo Hames u16 reason_code) 5528dd82ebeSEdgardo Hames { 553c9573a8dSsayli karnik struct wlandevice *wlandev = dev->ml_priv; 554b6bb56e6SEdgardo Hames struct p80211msg_lnxreq_autojoin msg_join; 555cb3126e6SKarl Relton int result; 556cb3126e6SKarl Relton int err = 0; 557cb3126e6SKarl Relton 558cb3126e6SKarl Relton /* Do a join, with a bogus ssid. Thats the only way I can think of */ 559b1f1118bSTim Collier msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN; 560cb3126e6SKarl Relton 561cb3126e6SKarl Relton memcpy(msg_join.ssid.data.data, "---", 3); 562cb3126e6SKarl Relton msg_join.ssid.data.len = 3; 563cb3126e6SKarl Relton 564cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg_join); 565cb3126e6SKarl Relton 5668dd82ebeSEdgardo Hames if (result) 5678dd82ebeSEdgardo Hames err = -EFAULT; 568cb3126e6SKarl Relton 569cb3126e6SKarl Relton return err; 570cb3126e6SKarl Relton } 571cb3126e6SKarl Relton 57255da06ebSTeodora Baluta static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, 5738dd82ebeSEdgardo Hames struct cfg80211_ibss_params *params) 5748dd82ebeSEdgardo Hames { 575cb3126e6SKarl Relton return -EOPNOTSUPP; 576cb3126e6SKarl Relton } 577cb3126e6SKarl Relton 57855da06ebSTeodora Baluta static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) 5798dd82ebeSEdgardo Hames { 580cb3126e6SKarl Relton return -EOPNOTSUPP; 581cb3126e6SKarl Relton } 582cb3126e6SKarl Relton 58355da06ebSTeodora Baluta static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, 5845f3b361aSEmil Goode enum nl80211_tx_power_setting type, int mbm) 5858dd82ebeSEdgardo Hames { 586cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 587c9573a8dSsayli karnik struct wlandevice *wlandev = priv->wlandev; 588cb3126e6SKarl Relton u32 data; 589cb3126e6SKarl Relton int result; 590cb3126e6SKarl Relton int err = 0; 591cb3126e6SKarl Relton 5929015e499SChristoph Fritz if (type == NL80211_TX_POWER_AUTOMATIC) 593cb3126e6SKarl Relton data = 30; 594cb3126e6SKarl Relton else 5959015e499SChristoph Fritz data = MBM_TO_DBM(mbm); 596cb3126e6SKarl Relton 597cb3126e6SKarl Relton result = prism2_domibset_uint32(wlandev, 598cb3126e6SKarl Relton DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, 599cb3126e6SKarl Relton data); 600cb3126e6SKarl Relton 601cb3126e6SKarl Relton if (result) { 602cb3126e6SKarl Relton err = -EFAULT; 603cb3126e6SKarl Relton goto exit; 604cb3126e6SKarl Relton } 605cb3126e6SKarl Relton 606cb3126e6SKarl Relton exit: 607cb3126e6SKarl Relton return err; 608cb3126e6SKarl Relton } 609cb3126e6SKarl Relton 61055da06ebSTeodora Baluta static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, 6115f3b361aSEmil Goode int *dbm) 6128dd82ebeSEdgardo Hames { 613cb3126e6SKarl Relton struct prism2_wiphy_private *priv = wiphy_priv(wiphy); 614c9573a8dSsayli karnik struct wlandevice *wlandev = priv->wlandev; 615b6bb56e6SEdgardo Hames struct p80211msg_dot11req_mibget msg; 616b26b2325SSergio Paracuellos struct p80211item_uint32 *mibitem; 617cb3126e6SKarl Relton int result; 618cb3126e6SKarl Relton int err = 0; 619cb3126e6SKarl Relton 620b26b2325SSergio Paracuellos mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data; 62108ac8573STim Collier msg.msgcode = DIDMSG_DOT11REQ_MIBGET; 622cb3126e6SKarl Relton mibitem->did = 623cb3126e6SKarl Relton DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; 624cb3126e6SKarl Relton 625cb3126e6SKarl Relton result = p80211req_dorequest(wlandev, (u8 *)&msg); 626cb3126e6SKarl Relton 627cb3126e6SKarl Relton if (result) { 628cb3126e6SKarl Relton err = -EFAULT; 629cb3126e6SKarl Relton goto exit; 630cb3126e6SKarl Relton } 631cb3126e6SKarl Relton 632cb3126e6SKarl Relton *dbm = mibitem->data; 633cb3126e6SKarl Relton 634cb3126e6SKarl Relton exit: 635cb3126e6SKarl Relton return err; 636cb3126e6SKarl Relton } 637cb3126e6SKarl Relton 638cb3126e6SKarl Relton /* Interface callback functions, passing data back up to the cfg80211 layer */ 639c9573a8dSsayli karnik void prism2_connect_result(struct wlandevice *wlandev, u8 failed) 6408dd82ebeSEdgardo Hames { 6418aac4d44SDevendra Naga u16 status = failed ? 6428aac4d44SDevendra Naga WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS; 643cb3126e6SKarl Relton 644cb3126e6SKarl Relton cfg80211_connect_result(wlandev->netdev, wlandev->bssid, 6458dd82ebeSEdgardo Hames NULL, 0, NULL, 0, status, GFP_KERNEL); 646cb3126e6SKarl Relton } 647cb3126e6SKarl Relton 648c9573a8dSsayli karnik void prism2_disconnected(struct wlandevice *wlandev) 6498dd82ebeSEdgardo Hames { 650cb3126e6SKarl Relton cfg80211_disconnected(wlandev->netdev, 0, NULL, 65180279fb7SJohannes Berg 0, false, GFP_KERNEL); 652cb3126e6SKarl Relton } 653cb3126e6SKarl Relton 654c9573a8dSsayli karnik void prism2_roamed(struct wlandevice *wlandev) 6558dd82ebeSEdgardo Hames { 65629ce6ecbSAvraham Stern struct cfg80211_roam_info roam_info = { 65729ce6ecbSAvraham Stern .bssid = wlandev->bssid, 65829ce6ecbSAvraham Stern }; 65929ce6ecbSAvraham Stern 66029ce6ecbSAvraham Stern cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL); 661cb3126e6SKarl Relton } 662cb3126e6SKarl Relton 663cb3126e6SKarl Relton /* Structures for declaring wiphy interface */ 664cb3126e6SKarl Relton static const struct cfg80211_ops prism2_usb_cfg_ops = { 665cb3126e6SKarl Relton .change_virtual_intf = prism2_change_virtual_intf, 666cb3126e6SKarl Relton .add_key = prism2_add_key, 667cb3126e6SKarl Relton .get_key = prism2_get_key, 668cb3126e6SKarl Relton .del_key = prism2_del_key, 669cb3126e6SKarl Relton .set_default_key = prism2_set_default_key, 670cb3126e6SKarl Relton .get_station = prism2_get_station, 671cb3126e6SKarl Relton .scan = prism2_scan, 672cb3126e6SKarl Relton .set_wiphy_params = prism2_set_wiphy_params, 673cb3126e6SKarl Relton .connect = prism2_connect, 674cb3126e6SKarl Relton .disconnect = prism2_disconnect, 675cb3126e6SKarl Relton .join_ibss = prism2_join_ibss, 676cb3126e6SKarl Relton .leave_ibss = prism2_leave_ibss, 677cb3126e6SKarl Relton .set_tx_power = prism2_set_tx_power, 678cb3126e6SKarl Relton .get_tx_power = prism2_get_tx_power, 679cb3126e6SKarl Relton }; 680cb3126e6SKarl Relton 681cb3126e6SKarl Relton /* Functions to create/free wiphy interface */ 682c9573a8dSsayli karnik static struct wiphy *wlan_create_wiphy(struct device *dev, struct wlandevice *wlandev) 683cb3126e6SKarl Relton { 684cb3126e6SKarl Relton struct wiphy *wiphy; 685cb3126e6SKarl Relton struct prism2_wiphy_private *priv; 6868aac4d44SDevendra Naga 6878aac4d44SDevendra Naga wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv)); 688cb3126e6SKarl Relton if (!wiphy) 689cb3126e6SKarl Relton return NULL; 690cb3126e6SKarl Relton 691cb3126e6SKarl Relton priv = wiphy_priv(wiphy); 692cb3126e6SKarl Relton priv->wlandev = wlandev; 693cb3126e6SKarl Relton memcpy(priv->channels, prism2_channels, sizeof(prism2_channels)); 694cb3126e6SKarl Relton memcpy(priv->rates, prism2_rates, sizeof(prism2_rates)); 695cb3126e6SKarl Relton priv->band.channels = priv->channels; 696cb3126e6SKarl Relton priv->band.n_channels = ARRAY_SIZE(prism2_channels); 697cb3126e6SKarl Relton priv->band.bitrates = priv->rates; 698cb3126e6SKarl Relton priv->band.n_bitrates = ARRAY_SIZE(prism2_rates); 69957fbcce3SJohannes Berg priv->band.band = NL80211_BAND_2GHZ; 700aff3ea4eSKarl Relton priv->band.ht_cap.ht_supported = false; 70157fbcce3SJohannes Berg wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; 702cb3126e6SKarl Relton 703cb3126e6SKarl Relton set_wiphy_dev(wiphy, dev); 704cb3126e6SKarl Relton wiphy->privid = prism2_wiphy_privid; 705cb3126e6SKarl Relton wiphy->max_scan_ssids = 1; 7068dd82ebeSEdgardo Hames wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) 7078dd82ebeSEdgardo Hames | BIT(NL80211_IFTYPE_ADHOC); 708cb3126e6SKarl Relton wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 709cb3126e6SKarl Relton wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES; 710cb3126e6SKarl Relton wiphy->cipher_suites = prism2_cipher_suites; 711cb3126e6SKarl Relton 712f96b36c7SClaudiu Beznea if (wiphy_register(wiphy) < 0) { 713f96b36c7SClaudiu Beznea wiphy_free(wiphy); 714cb3126e6SKarl Relton return NULL; 715f96b36c7SClaudiu Beznea } 716cb3126e6SKarl Relton 717cb3126e6SKarl Relton return wiphy; 718cb3126e6SKarl Relton } 719cb3126e6SKarl Relton 72036d9c250STugce Sirin static void wlan_free_wiphy(struct wiphy *wiphy) 721cb3126e6SKarl Relton { 722cb3126e6SKarl Relton wiphy_unregister(wiphy); 723cb3126e6SKarl Relton wiphy_free(wiphy); 724cb3126e6SKarl Relton } 725