162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Copyright(c) 2004-2005 Intel Corporation. All rights reserved. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci Portions of this file are based on the WEP enablement code provided by the 762306a36Sopenharmony_ci Host AP project hostap-drivers v0.1.3 862306a36Sopenharmony_ci Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen 962306a36Sopenharmony_ci <j@w1.fi> 1062306a36Sopenharmony_ci Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci Contact Information: 1462306a36Sopenharmony_ci Intel Linux Wireless <ilw@linux.intel.com> 1562306a36Sopenharmony_ci Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci******************************************************************************/ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/hardirq.h> 2062306a36Sopenharmony_ci#include <linux/kmod.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/jiffies.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <net/lib80211.h> 2662306a36Sopenharmony_ci#include <linux/wireless.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "libipw.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const char *libipw_modes[] = { 3162306a36Sopenharmony_ci "?", "a", "b", "ab", "g", "ag", "bg", "abg" 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline unsigned int elapsed_jiffies_msecs(unsigned long start) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci unsigned long end = jiffies; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (end >= start) 3962306a36Sopenharmony_ci return jiffies_to_msecs(end - start); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define MAX_CUSTOM_LEN 64 4562306a36Sopenharmony_cistatic char *libipw_translate_scan(struct libipw_device *ieee, 4662306a36Sopenharmony_ci char *start, char *stop, 4762306a36Sopenharmony_ci struct libipw_network *network, 4862306a36Sopenharmony_ci struct iw_request_info *info) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci char custom[MAX_CUSTOM_LEN]; 5162306a36Sopenharmony_ci char *p; 5262306a36Sopenharmony_ci struct iw_event iwe; 5362306a36Sopenharmony_ci int i, j; 5462306a36Sopenharmony_ci char *current_val; /* For rates */ 5562306a36Sopenharmony_ci u8 rate; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* First entry *MUST* be the AP MAC address */ 5862306a36Sopenharmony_ci iwe.cmd = SIOCGIWAP; 5962306a36Sopenharmony_ci iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 6062306a36Sopenharmony_ci memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); 6162306a36Sopenharmony_ci start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Remaining entries will be displayed in the order we provide them */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Add the ESSID */ 6662306a36Sopenharmony_ci iwe.cmd = SIOCGIWESSID; 6762306a36Sopenharmony_ci iwe.u.data.flags = 1; 6862306a36Sopenharmony_ci iwe.u.data.length = min(network->ssid_len, (u8) 32); 6962306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, 7062306a36Sopenharmony_ci &iwe, network->ssid); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* Add the protocol name */ 7362306a36Sopenharmony_ci iwe.cmd = SIOCGIWNAME; 7462306a36Sopenharmony_ci snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", 7562306a36Sopenharmony_ci libipw_modes[network->mode]); 7662306a36Sopenharmony_ci start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Add mode */ 7962306a36Sopenharmony_ci iwe.cmd = SIOCGIWMODE; 8062306a36Sopenharmony_ci if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { 8162306a36Sopenharmony_ci if (network->capability & WLAN_CAPABILITY_ESS) 8262306a36Sopenharmony_ci iwe.u.mode = IW_MODE_MASTER; 8362306a36Sopenharmony_ci else 8462306a36Sopenharmony_ci iwe.u.mode = IW_MODE_ADHOC; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci start = iwe_stream_add_event(info, start, stop, 8762306a36Sopenharmony_ci &iwe, IW_EV_UINT_LEN); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Add channel and frequency */ 9162306a36Sopenharmony_ci /* Note : userspace automatically computes channel using iwrange */ 9262306a36Sopenharmony_ci iwe.cmd = SIOCGIWFREQ; 9362306a36Sopenharmony_ci iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel); 9462306a36Sopenharmony_ci iwe.u.freq.e = 6; 9562306a36Sopenharmony_ci iwe.u.freq.i = 0; 9662306a36Sopenharmony_ci start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Add encryption capability */ 9962306a36Sopenharmony_ci iwe.cmd = SIOCGIWENCODE; 10062306a36Sopenharmony_ci if (network->capability & WLAN_CAPABILITY_PRIVACY) 10162306a36Sopenharmony_ci iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci iwe.u.data.flags = IW_ENCODE_DISABLED; 10462306a36Sopenharmony_ci iwe.u.data.length = 0; 10562306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, 10662306a36Sopenharmony_ci &iwe, network->ssid); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Add basic and extended rates */ 10962306a36Sopenharmony_ci /* Rate : stuffing multiple values in a single event require a bit 11062306a36Sopenharmony_ci * more of magic - Jean II */ 11162306a36Sopenharmony_ci current_val = start + iwe_stream_lcp_len(info); 11262306a36Sopenharmony_ci iwe.cmd = SIOCGIWRATE; 11362306a36Sopenharmony_ci /* Those two flags are ignored... */ 11462306a36Sopenharmony_ci iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci for (i = 0, j = 0; i < network->rates_len;) { 11762306a36Sopenharmony_ci if (j < network->rates_ex_len && 11862306a36Sopenharmony_ci ((network->rates_ex[j] & 0x7F) < 11962306a36Sopenharmony_ci (network->rates[i] & 0x7F))) 12062306a36Sopenharmony_ci rate = network->rates_ex[j++] & 0x7F; 12162306a36Sopenharmony_ci else 12262306a36Sopenharmony_ci rate = network->rates[i++] & 0x7F; 12362306a36Sopenharmony_ci /* Bit rate given in 500 kb/s units (+ 0x80) */ 12462306a36Sopenharmony_ci iwe.u.bitrate.value = ((rate & 0x7f) * 500000); 12562306a36Sopenharmony_ci /* Add new value to event */ 12662306a36Sopenharmony_ci current_val = iwe_stream_add_value(info, start, current_val, 12762306a36Sopenharmony_ci stop, &iwe, IW_EV_PARAM_LEN); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci for (; j < network->rates_ex_len; j++) { 13062306a36Sopenharmony_ci rate = network->rates_ex[j] & 0x7F; 13162306a36Sopenharmony_ci /* Bit rate given in 500 kb/s units (+ 0x80) */ 13262306a36Sopenharmony_ci iwe.u.bitrate.value = ((rate & 0x7f) * 500000); 13362306a36Sopenharmony_ci /* Add new value to event */ 13462306a36Sopenharmony_ci current_val = iwe_stream_add_value(info, start, current_val, 13562306a36Sopenharmony_ci stop, &iwe, IW_EV_PARAM_LEN); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci /* Check if we added any rate */ 13862306a36Sopenharmony_ci if ((current_val - start) > iwe_stream_lcp_len(info)) 13962306a36Sopenharmony_ci start = current_val; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Add quality statistics */ 14262306a36Sopenharmony_ci iwe.cmd = IWEVQUAL; 14362306a36Sopenharmony_ci iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | 14462306a36Sopenharmony_ci IW_QUAL_NOISE_UPDATED; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) { 14762306a36Sopenharmony_ci iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | 14862306a36Sopenharmony_ci IW_QUAL_LEVEL_INVALID; 14962306a36Sopenharmony_ci iwe.u.qual.qual = 0; 15062306a36Sopenharmony_ci } else { 15162306a36Sopenharmony_ci if (ieee->perfect_rssi == ieee->worst_rssi) 15262306a36Sopenharmony_ci iwe.u.qual.qual = 100; 15362306a36Sopenharmony_ci else 15462306a36Sopenharmony_ci iwe.u.qual.qual = 15562306a36Sopenharmony_ci (100 * 15662306a36Sopenharmony_ci (ieee->perfect_rssi - ieee->worst_rssi) * 15762306a36Sopenharmony_ci (ieee->perfect_rssi - ieee->worst_rssi) - 15862306a36Sopenharmony_ci (ieee->perfect_rssi - network->stats.rssi) * 15962306a36Sopenharmony_ci (15 * (ieee->perfect_rssi - ieee->worst_rssi) + 16062306a36Sopenharmony_ci 62 * (ieee->perfect_rssi - 16162306a36Sopenharmony_ci network->stats.rssi))) / 16262306a36Sopenharmony_ci ((ieee->perfect_rssi - 16362306a36Sopenharmony_ci ieee->worst_rssi) * (ieee->perfect_rssi - 16462306a36Sopenharmony_ci ieee->worst_rssi)); 16562306a36Sopenharmony_ci if (iwe.u.qual.qual > 100) 16662306a36Sopenharmony_ci iwe.u.qual.qual = 100; 16762306a36Sopenharmony_ci else if (iwe.u.qual.qual < 1) 16862306a36Sopenharmony_ci iwe.u.qual.qual = 0; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) { 17262306a36Sopenharmony_ci iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; 17362306a36Sopenharmony_ci iwe.u.qual.noise = 0; 17462306a36Sopenharmony_ci } else { 17562306a36Sopenharmony_ci iwe.u.qual.noise = network->stats.noise; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) { 17962306a36Sopenharmony_ci iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; 18062306a36Sopenharmony_ci iwe.u.qual.level = 0; 18162306a36Sopenharmony_ci } else { 18262306a36Sopenharmony_ci iwe.u.qual.level = network->stats.signal; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci iwe.cmd = IWEVCUSTOM; 18862306a36Sopenharmony_ci p = custom; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci iwe.u.data.length = p - custom; 19162306a36Sopenharmony_ci if (iwe.u.data.length) 19262306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, &iwe, custom); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci memset(&iwe, 0, sizeof(iwe)); 19562306a36Sopenharmony_ci if (network->wpa_ie_len) { 19662306a36Sopenharmony_ci char buf[MAX_WPA_IE_LEN]; 19762306a36Sopenharmony_ci memcpy(buf, network->wpa_ie, network->wpa_ie_len); 19862306a36Sopenharmony_ci iwe.cmd = IWEVGENIE; 19962306a36Sopenharmony_ci iwe.u.data.length = network->wpa_ie_len; 20062306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, &iwe, buf); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci memset(&iwe, 0, sizeof(iwe)); 20462306a36Sopenharmony_ci if (network->rsn_ie_len) { 20562306a36Sopenharmony_ci char buf[MAX_WPA_IE_LEN]; 20662306a36Sopenharmony_ci memcpy(buf, network->rsn_ie, network->rsn_ie_len); 20762306a36Sopenharmony_ci iwe.cmd = IWEVGENIE; 20862306a36Sopenharmony_ci iwe.u.data.length = network->rsn_ie_len; 20962306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, &iwe, buf); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Add EXTRA: Age to display seconds since last beacon/probe response 21362306a36Sopenharmony_ci * for given network. */ 21462306a36Sopenharmony_ci iwe.cmd = IWEVCUSTOM; 21562306a36Sopenharmony_ci p = custom; 21662306a36Sopenharmony_ci p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), 21762306a36Sopenharmony_ci " Last beacon: %ums ago", 21862306a36Sopenharmony_ci elapsed_jiffies_msecs(network->last_scanned)); 21962306a36Sopenharmony_ci iwe.u.data.length = p - custom; 22062306a36Sopenharmony_ci if (iwe.u.data.length) 22162306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, &iwe, custom); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Add spectrum management information */ 22462306a36Sopenharmony_ci iwe.cmd = -1; 22562306a36Sopenharmony_ci p = custom; 22662306a36Sopenharmony_ci p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: "); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (libipw_get_channel_flags(ieee, network->channel) & 22962306a36Sopenharmony_ci LIBIPW_CH_INVALID) { 23062306a36Sopenharmony_ci iwe.cmd = IWEVCUSTOM; 23162306a36Sopenharmony_ci p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID "); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (libipw_get_channel_flags(ieee, network->channel) & 23562306a36Sopenharmony_ci LIBIPW_CH_RADAR_DETECT) { 23662306a36Sopenharmony_ci iwe.cmd = IWEVCUSTOM; 23762306a36Sopenharmony_ci p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS "); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (iwe.cmd == IWEVCUSTOM) { 24162306a36Sopenharmony_ci iwe.u.data.length = p - custom; 24262306a36Sopenharmony_ci start = iwe_stream_add_point(info, start, stop, &iwe, custom); 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return start; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci#define SCAN_ITEM_SIZE 128 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciint libipw_wx_get_scan(struct libipw_device *ieee, 25162306a36Sopenharmony_ci struct iw_request_info *info, 25262306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct libipw_network *network; 25562306a36Sopenharmony_ci unsigned long flags; 25662306a36Sopenharmony_ci int err = 0; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci char *ev = extra; 25962306a36Sopenharmony_ci char *stop = ev + wrqu->data.length; 26062306a36Sopenharmony_ci int i = 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Getting scan\n"); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci spin_lock_irqsave(&ieee->lock, flags); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci list_for_each_entry(network, &ieee->network_list, list) { 26762306a36Sopenharmony_ci i++; 26862306a36Sopenharmony_ci if (stop - ev < SCAN_ITEM_SIZE) { 26962306a36Sopenharmony_ci err = -E2BIG; 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (ieee->scan_age == 0 || 27462306a36Sopenharmony_ci time_after(network->last_scanned + ieee->scan_age, jiffies)) 27562306a36Sopenharmony_ci ev = libipw_translate_scan(ieee, ev, stop, network, 27662306a36Sopenharmony_ci info); 27762306a36Sopenharmony_ci else { 27862306a36Sopenharmony_ci LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n", 27962306a36Sopenharmony_ci network->ssid_len, network->ssid, 28062306a36Sopenharmony_ci network->bssid, 28162306a36Sopenharmony_ci elapsed_jiffies_msecs( 28262306a36Sopenharmony_ci network->last_scanned)); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci spin_unlock_irqrestore(&ieee->lock, flags); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci wrqu->data.length = ev - extra; 28962306a36Sopenharmony_ci wrqu->data.flags = 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return err; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciint libipw_wx_set_encode(struct libipw_device *ieee, 29762306a36Sopenharmony_ci struct iw_request_info *info, 29862306a36Sopenharmony_ci union iwreq_data *wrqu, char *keybuf) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct iw_point *erq = &(wrqu->encoding); 30162306a36Sopenharmony_ci struct net_device *dev = ieee->dev; 30262306a36Sopenharmony_ci struct libipw_security sec = { 30362306a36Sopenharmony_ci .flags = 0 30462306a36Sopenharmony_ci }; 30562306a36Sopenharmony_ci int i, key, key_provided, len; 30662306a36Sopenharmony_ci struct lib80211_crypt_data **crypt; 30762306a36Sopenharmony_ci int host_crypto = ieee->host_encrypt || ieee->host_decrypt; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci LIBIPW_DEBUG_WX("SET_ENCODE\n"); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci key = erq->flags & IW_ENCODE_INDEX; 31262306a36Sopenharmony_ci if (key) { 31362306a36Sopenharmony_ci if (key > WEP_KEYS) 31462306a36Sopenharmony_ci return -EINVAL; 31562306a36Sopenharmony_ci key--; 31662306a36Sopenharmony_ci key_provided = 1; 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci key_provided = 0; 31962306a36Sopenharmony_ci key = ieee->crypt_info.tx_keyidx; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? 32362306a36Sopenharmony_ci "provided" : "default"); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci crypt = &ieee->crypt_info.crypt[key]; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (erq->flags & IW_ENCODE_DISABLED) { 32862306a36Sopenharmony_ci if (key_provided && *crypt) { 32962306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n", 33062306a36Sopenharmony_ci key); 33162306a36Sopenharmony_ci lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); 33262306a36Sopenharmony_ci } else 33362306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Disabling encryption.\n"); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Check all the keys to see if any are still configured, 33662306a36Sopenharmony_ci * and if no key index was provided, de-init them all */ 33762306a36Sopenharmony_ci for (i = 0; i < WEP_KEYS; i++) { 33862306a36Sopenharmony_ci if (ieee->crypt_info.crypt[i] != NULL) { 33962306a36Sopenharmony_ci if (key_provided) 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci lib80211_crypt_delayed_deinit(&ieee->crypt_info, 34262306a36Sopenharmony_ci &ieee->crypt_info.crypt[i]); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (i == WEP_KEYS) { 34762306a36Sopenharmony_ci sec.enabled = 0; 34862306a36Sopenharmony_ci sec.encrypt = 0; 34962306a36Sopenharmony_ci sec.level = SEC_LEVEL_0; 35062306a36Sopenharmony_ci sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci goto done; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci sec.enabled = 1; 35762306a36Sopenharmony_ci sec.encrypt = 1; 35862306a36Sopenharmony_ci sec.flags |= SEC_ENABLED | SEC_ENCRYPT; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (*crypt != NULL && (*crypt)->ops != NULL && 36162306a36Sopenharmony_ci strcmp((*crypt)->ops->name, "WEP") != 0) { 36262306a36Sopenharmony_ci /* changing to use WEP; deinit previously used algorithm 36362306a36Sopenharmony_ci * on this key */ 36462306a36Sopenharmony_ci lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (*crypt == NULL && host_crypto) { 36862306a36Sopenharmony_ci struct lib80211_crypt_data *new_crypt; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* take WEP into use */ 37162306a36Sopenharmony_ci new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), 37262306a36Sopenharmony_ci GFP_KERNEL); 37362306a36Sopenharmony_ci if (new_crypt == NULL) 37462306a36Sopenharmony_ci return -ENOMEM; 37562306a36Sopenharmony_ci new_crypt->ops = lib80211_get_crypto_ops("WEP"); 37662306a36Sopenharmony_ci if (!new_crypt->ops) { 37762306a36Sopenharmony_ci request_module("lib80211_crypt_wep"); 37862306a36Sopenharmony_ci new_crypt->ops = lib80211_get_crypto_ops("WEP"); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 38262306a36Sopenharmony_ci new_crypt->priv = new_crypt->ops->init(key); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (!new_crypt->ops || !new_crypt->priv) { 38562306a36Sopenharmony_ci kfree(new_crypt); 38662306a36Sopenharmony_ci new_crypt = NULL; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci printk(KERN_WARNING "%s: could not initialize WEP: " 38962306a36Sopenharmony_ci "load module lib80211_crypt_wep\n", dev->name); 39062306a36Sopenharmony_ci return -EOPNOTSUPP; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci *crypt = new_crypt; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* If a new key was provided, set it up */ 39662306a36Sopenharmony_ci if (erq->length > 0) { 39762306a36Sopenharmony_ci len = erq->length <= 5 ? 5 : 13; 39862306a36Sopenharmony_ci memcpy(sec.keys[key], keybuf, erq->length); 39962306a36Sopenharmony_ci if (len > erq->length) 40062306a36Sopenharmony_ci memset(sec.keys[key] + erq->length, 0, 40162306a36Sopenharmony_ci len - erq->length); 40262306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n", 40362306a36Sopenharmony_ci key, len, sec.keys[key], 40462306a36Sopenharmony_ci erq->length, len); 40562306a36Sopenharmony_ci sec.key_sizes[key] = len; 40662306a36Sopenharmony_ci if (*crypt) 40762306a36Sopenharmony_ci (*crypt)->ops->set_key(sec.keys[key], len, NULL, 40862306a36Sopenharmony_ci (*crypt)->priv); 40962306a36Sopenharmony_ci sec.flags |= (1 << key); 41062306a36Sopenharmony_ci /* This ensures a key will be activated if no key is 41162306a36Sopenharmony_ci * explicitly set */ 41262306a36Sopenharmony_ci if (key == sec.active_key) 41362306a36Sopenharmony_ci sec.flags |= SEC_ACTIVE_KEY; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci if (host_crypto) { 41762306a36Sopenharmony_ci len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, 41862306a36Sopenharmony_ci NULL, (*crypt)->priv); 41962306a36Sopenharmony_ci if (len == 0) { 42062306a36Sopenharmony_ci /* Set a default key of all 0 */ 42162306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Setting key %d to all " 42262306a36Sopenharmony_ci "zero.\n", key); 42362306a36Sopenharmony_ci memset(sec.keys[key], 0, 13); 42462306a36Sopenharmony_ci (*crypt)->ops->set_key(sec.keys[key], 13, NULL, 42562306a36Sopenharmony_ci (*crypt)->priv); 42662306a36Sopenharmony_ci sec.key_sizes[key] = 13; 42762306a36Sopenharmony_ci sec.flags |= (1 << key); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci /* No key data - just set the default TX key index */ 43162306a36Sopenharmony_ci if (key_provided) { 43262306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Setting key %d to default Tx " 43362306a36Sopenharmony_ci "key.\n", key); 43462306a36Sopenharmony_ci ieee->crypt_info.tx_keyidx = key; 43562306a36Sopenharmony_ci sec.active_key = key; 43662306a36Sopenharmony_ci sec.flags |= SEC_ACTIVE_KEY; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) { 44062306a36Sopenharmony_ci ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); 44162306a36Sopenharmony_ci sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : 44262306a36Sopenharmony_ci WLAN_AUTH_SHARED_KEY; 44362306a36Sopenharmony_ci sec.flags |= SEC_AUTH_MODE; 44462306a36Sopenharmony_ci LIBIPW_DEBUG_WX("Auth: %s\n", 44562306a36Sopenharmony_ci sec.auth_mode == WLAN_AUTH_OPEN ? 44662306a36Sopenharmony_ci "OPEN" : "SHARED KEY"); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* For now we just support WEP, so only set that security level... 45062306a36Sopenharmony_ci * TODO: When WPA is added this is one place that needs to change */ 45162306a36Sopenharmony_ci sec.flags |= SEC_LEVEL; 45262306a36Sopenharmony_ci sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ 45362306a36Sopenharmony_ci sec.encode_alg[key] = SEC_ALG_WEP; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci done: 45662306a36Sopenharmony_ci if (ieee->set_security) 45762306a36Sopenharmony_ci ieee->set_security(dev, &sec); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ciint libipw_wx_get_encode(struct libipw_device *ieee, 46362306a36Sopenharmony_ci struct iw_request_info *info, 46462306a36Sopenharmony_ci union iwreq_data *wrqu, char *keybuf) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct iw_point *erq = &(wrqu->encoding); 46762306a36Sopenharmony_ci int len, key; 46862306a36Sopenharmony_ci struct libipw_security *sec = &ieee->sec; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci LIBIPW_DEBUG_WX("GET_ENCODE\n"); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci key = erq->flags & IW_ENCODE_INDEX; 47362306a36Sopenharmony_ci if (key) { 47462306a36Sopenharmony_ci if (key > WEP_KEYS) 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci key--; 47762306a36Sopenharmony_ci } else 47862306a36Sopenharmony_ci key = ieee->crypt_info.tx_keyidx; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci erq->flags = key + 1; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!sec->enabled) { 48362306a36Sopenharmony_ci erq->length = 0; 48462306a36Sopenharmony_ci erq->flags |= IW_ENCODE_DISABLED; 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci len = sec->key_sizes[key]; 48962306a36Sopenharmony_ci memcpy(keybuf, sec->keys[key], len); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci erq->length = len; 49262306a36Sopenharmony_ci erq->flags |= IW_ENCODE_ENABLED; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (ieee->open_wep) 49562306a36Sopenharmony_ci erq->flags |= IW_ENCODE_OPEN; 49662306a36Sopenharmony_ci else 49762306a36Sopenharmony_ci erq->flags |= IW_ENCODE_RESTRICTED; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciint libipw_wx_set_encodeext(struct libipw_device *ieee, 50362306a36Sopenharmony_ci struct iw_request_info *info, 50462306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct net_device *dev = ieee->dev; 50762306a36Sopenharmony_ci struct iw_point *encoding = &wrqu->encoding; 50862306a36Sopenharmony_ci struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 50962306a36Sopenharmony_ci int i, idx, ret = 0; 51062306a36Sopenharmony_ci int group_key = 0; 51162306a36Sopenharmony_ci const char *alg, *module; 51262306a36Sopenharmony_ci struct lib80211_crypto_ops *ops; 51362306a36Sopenharmony_ci struct lib80211_crypt_data **crypt; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci struct libipw_security sec = { 51662306a36Sopenharmony_ci .flags = 0, 51762306a36Sopenharmony_ci }; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci idx = encoding->flags & IW_ENCODE_INDEX; 52062306a36Sopenharmony_ci if (idx) { 52162306a36Sopenharmony_ci if (idx < 1 || idx > WEP_KEYS) 52262306a36Sopenharmony_ci return -EINVAL; 52362306a36Sopenharmony_ci idx--; 52462306a36Sopenharmony_ci } else 52562306a36Sopenharmony_ci idx = ieee->crypt_info.tx_keyidx; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { 52862306a36Sopenharmony_ci crypt = &ieee->crypt_info.crypt[idx]; 52962306a36Sopenharmony_ci group_key = 1; 53062306a36Sopenharmony_ci } else { 53162306a36Sopenharmony_ci /* some Cisco APs use idx>0 for unicast in dynamic WEP */ 53262306a36Sopenharmony_ci if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) 53362306a36Sopenharmony_ci return -EINVAL; 53462306a36Sopenharmony_ci if (ieee->iw_mode == IW_MODE_INFRA) 53562306a36Sopenharmony_ci crypt = &ieee->crypt_info.crypt[idx]; 53662306a36Sopenharmony_ci else 53762306a36Sopenharmony_ci return -EINVAL; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci sec.flags |= SEC_ENABLED | SEC_ENCRYPT; 54162306a36Sopenharmony_ci if ((encoding->flags & IW_ENCODE_DISABLED) || 54262306a36Sopenharmony_ci ext->alg == IW_ENCODE_ALG_NONE) { 54362306a36Sopenharmony_ci if (*crypt) 54462306a36Sopenharmony_ci lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci for (i = 0; i < WEP_KEYS; i++) 54762306a36Sopenharmony_ci if (ieee->crypt_info.crypt[i] != NULL) 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (i == WEP_KEYS) { 55162306a36Sopenharmony_ci sec.enabled = 0; 55262306a36Sopenharmony_ci sec.encrypt = 0; 55362306a36Sopenharmony_ci sec.level = SEC_LEVEL_0; 55462306a36Sopenharmony_ci sec.flags |= SEC_LEVEL; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci goto done; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci sec.enabled = 1; 56062306a36Sopenharmony_ci sec.encrypt = 1; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (group_key ? !ieee->host_mc_decrypt : 56362306a36Sopenharmony_ci !(ieee->host_encrypt || ieee->host_decrypt || 56462306a36Sopenharmony_ci ieee->host_encrypt_msdu)) 56562306a36Sopenharmony_ci goto skip_host_crypt; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci switch (ext->alg) { 56862306a36Sopenharmony_ci case IW_ENCODE_ALG_WEP: 56962306a36Sopenharmony_ci alg = "WEP"; 57062306a36Sopenharmony_ci module = "lib80211_crypt_wep"; 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci case IW_ENCODE_ALG_TKIP: 57362306a36Sopenharmony_ci alg = "TKIP"; 57462306a36Sopenharmony_ci module = "lib80211_crypt_tkip"; 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci case IW_ENCODE_ALG_CCMP: 57762306a36Sopenharmony_ci alg = "CCMP"; 57862306a36Sopenharmony_ci module = "lib80211_crypt_ccmp"; 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci default: 58162306a36Sopenharmony_ci LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", 58262306a36Sopenharmony_ci dev->name, ext->alg); 58362306a36Sopenharmony_ci ret = -EINVAL; 58462306a36Sopenharmony_ci goto done; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci ops = lib80211_get_crypto_ops(alg); 58862306a36Sopenharmony_ci if (ops == NULL) { 58962306a36Sopenharmony_ci request_module(module); 59062306a36Sopenharmony_ci ops = lib80211_get_crypto_ops(alg); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci if (ops == NULL) { 59362306a36Sopenharmony_ci LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", 59462306a36Sopenharmony_ci dev->name, ext->alg); 59562306a36Sopenharmony_ci ret = -EINVAL; 59662306a36Sopenharmony_ci goto done; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (*crypt == NULL || (*crypt)->ops != ops) { 60062306a36Sopenharmony_ci struct lib80211_crypt_data *new_crypt; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); 60562306a36Sopenharmony_ci if (new_crypt == NULL) { 60662306a36Sopenharmony_ci ret = -ENOMEM; 60762306a36Sopenharmony_ci goto done; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci new_crypt->ops = ops; 61062306a36Sopenharmony_ci if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 61162306a36Sopenharmony_ci new_crypt->priv = new_crypt->ops->init(idx); 61262306a36Sopenharmony_ci if (new_crypt->priv == NULL) { 61362306a36Sopenharmony_ci kfree(new_crypt); 61462306a36Sopenharmony_ci ret = -EINVAL; 61562306a36Sopenharmony_ci goto done; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci *crypt = new_crypt; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (ext->key_len > 0 && (*crypt)->ops->set_key && 62162306a36Sopenharmony_ci (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, 62262306a36Sopenharmony_ci (*crypt)->priv) < 0) { 62362306a36Sopenharmony_ci LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name); 62462306a36Sopenharmony_ci ret = -EINVAL; 62562306a36Sopenharmony_ci goto done; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci skip_host_crypt: 62962306a36Sopenharmony_ci if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 63062306a36Sopenharmony_ci ieee->crypt_info.tx_keyidx = idx; 63162306a36Sopenharmony_ci sec.active_key = idx; 63262306a36Sopenharmony_ci sec.flags |= SEC_ACTIVE_KEY; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (ext->alg != IW_ENCODE_ALG_NONE) { 63662306a36Sopenharmony_ci int key_len = clamp_val(ext->key_len, 0, SCM_KEY_LEN); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci memcpy(sec.keys[idx], ext->key, key_len); 63962306a36Sopenharmony_ci sec.key_sizes[idx] = key_len; 64062306a36Sopenharmony_ci sec.flags |= (1 << idx); 64162306a36Sopenharmony_ci if (ext->alg == IW_ENCODE_ALG_WEP) { 64262306a36Sopenharmony_ci sec.encode_alg[idx] = SEC_ALG_WEP; 64362306a36Sopenharmony_ci sec.flags |= SEC_LEVEL; 64462306a36Sopenharmony_ci sec.level = SEC_LEVEL_1; 64562306a36Sopenharmony_ci } else if (ext->alg == IW_ENCODE_ALG_TKIP) { 64662306a36Sopenharmony_ci sec.encode_alg[idx] = SEC_ALG_TKIP; 64762306a36Sopenharmony_ci sec.flags |= SEC_LEVEL; 64862306a36Sopenharmony_ci sec.level = SEC_LEVEL_2; 64962306a36Sopenharmony_ci } else if (ext->alg == IW_ENCODE_ALG_CCMP) { 65062306a36Sopenharmony_ci sec.encode_alg[idx] = SEC_ALG_CCMP; 65162306a36Sopenharmony_ci sec.flags |= SEC_LEVEL; 65262306a36Sopenharmony_ci sec.level = SEC_LEVEL_3; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci /* Don't set sec level for group keys. */ 65562306a36Sopenharmony_ci if (group_key) 65662306a36Sopenharmony_ci sec.flags &= ~SEC_LEVEL; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci done: 65962306a36Sopenharmony_ci if (ieee->set_security) 66062306a36Sopenharmony_ci ieee->set_security(dev, &sec); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci return ret; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ciint libipw_wx_get_encodeext(struct libipw_device *ieee, 66662306a36Sopenharmony_ci struct iw_request_info *info, 66762306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct iw_point *encoding = &wrqu->encoding; 67062306a36Sopenharmony_ci struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 67162306a36Sopenharmony_ci struct libipw_security *sec = &ieee->sec; 67262306a36Sopenharmony_ci int idx, max_key_len; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci max_key_len = encoding->length - sizeof(*ext); 67562306a36Sopenharmony_ci if (max_key_len < 0) 67662306a36Sopenharmony_ci return -EINVAL; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci idx = encoding->flags & IW_ENCODE_INDEX; 67962306a36Sopenharmony_ci if (idx) { 68062306a36Sopenharmony_ci if (idx < 1 || idx > WEP_KEYS) 68162306a36Sopenharmony_ci return -EINVAL; 68262306a36Sopenharmony_ci idx--; 68362306a36Sopenharmony_ci } else 68462306a36Sopenharmony_ci idx = ieee->crypt_info.tx_keyidx; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && 68762306a36Sopenharmony_ci ext->alg != IW_ENCODE_ALG_WEP) 68862306a36Sopenharmony_ci if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) 68962306a36Sopenharmony_ci return -EINVAL; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci encoding->flags = idx + 1; 69262306a36Sopenharmony_ci memset(ext, 0, sizeof(*ext)); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (!sec->enabled) { 69562306a36Sopenharmony_ci ext->alg = IW_ENCODE_ALG_NONE; 69662306a36Sopenharmony_ci ext->key_len = 0; 69762306a36Sopenharmony_ci encoding->flags |= IW_ENCODE_DISABLED; 69862306a36Sopenharmony_ci } else { 69962306a36Sopenharmony_ci if (sec->encode_alg[idx] == SEC_ALG_WEP) 70062306a36Sopenharmony_ci ext->alg = IW_ENCODE_ALG_WEP; 70162306a36Sopenharmony_ci else if (sec->encode_alg[idx] == SEC_ALG_TKIP) 70262306a36Sopenharmony_ci ext->alg = IW_ENCODE_ALG_TKIP; 70362306a36Sopenharmony_ci else if (sec->encode_alg[idx] == SEC_ALG_CCMP) 70462306a36Sopenharmony_ci ext->alg = IW_ENCODE_ALG_CCMP; 70562306a36Sopenharmony_ci else 70662306a36Sopenharmony_ci return -EINVAL; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci ext->key_len = sec->key_sizes[idx]; 70962306a36Sopenharmony_ci memcpy(ext->key, sec->keys[idx], ext->key_len); 71062306a36Sopenharmony_ci encoding->flags |= IW_ENCODE_ENABLED; 71162306a36Sopenharmony_ci if (ext->key_len && 71262306a36Sopenharmony_ci (ext->alg == IW_ENCODE_ALG_TKIP || 71362306a36Sopenharmony_ci ext->alg == IW_ENCODE_ALG_CCMP)) 71462306a36Sopenharmony_ci ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_wx_set_encodeext); 72262306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_wx_get_encodeext); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_wx_get_scan); 72562306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_wx_set_encode); 72662306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_wx_get_encode); 727