18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2002 Intersil Americas Inc. 38c2ecf20Sopenharmony_ci * (C) 2003,2004 Aurelien Alleaume <slts@free.fr> 48c2ecf20Sopenharmony_ci * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> 58c2ecf20Sopenharmony_ci * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 88c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 98c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 128c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148c2ecf20Sopenharmony_ci * GNU General Public License for more details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 178c2ecf20Sopenharmony_ci * along with this program; if not, see <http://www.gnu.org/licenses/>. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/capability.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/pci.h> 278c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "prismcompat.h" 328c2ecf20Sopenharmony_ci#include "isl_ioctl.h" 338c2ecf20Sopenharmony_ci#include "islpci_mgt.h" 348c2ecf20Sopenharmony_ci#include "isl_oid.h" /* additional types and defs for isl38xx fw */ 358c2ecf20Sopenharmony_ci#include "oid_mgt.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <net/iw_handler.h> /* New driver API */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ 408c2ecf20Sopenharmony_ci#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ 418c2ecf20Sopenharmony_ci/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */ 428c2ecf20Sopenharmony_ci#define KEY_SIZE_TKIP 32 /* TKIP keys */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, 458c2ecf20Sopenharmony_ci u8 *wpa_ie, size_t wpa_ie_len); 468c2ecf20Sopenharmony_cistatic size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); 478c2ecf20Sopenharmony_cistatic int prism54_set_wpa(struct net_device *, struct iw_request_info *, 488c2ecf20Sopenharmony_ci __u32 *, char *); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* In 500 kbps */ 518c2ecf20Sopenharmony_cistatic const unsigned char scan_rate_list[] = { 2, 4, 11, 22, 528c2ecf20Sopenharmony_ci 12, 18, 24, 36, 538c2ecf20Sopenharmony_ci 48, 72, 96, 108 }; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * prism54_mib_mode_helper - MIB change mode helper function 578c2ecf20Sopenharmony_ci * @mib: the &struct islpci_mib object to modify 588c2ecf20Sopenharmony_ci * @iw_mode: new mode (%IW_MODE_*) 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * This is a helper function, hence it does not lock. Make sure 618c2ecf20Sopenharmony_ci * caller deals with locking *if* necessary. This function sets the 628c2ecf20Sopenharmony_ci * mode-dependent mib values and does the mapping of the Linux 638c2ecf20Sopenharmony_ci * Wireless API modes to Device firmware modes. It also checks for 648c2ecf20Sopenharmony_ci * correct valid Linux wireless modes. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic int 678c2ecf20Sopenharmony_ciprism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci u32 config = INL_CONFIG_MANUALRUN; 708c2ecf20Sopenharmony_ci u32 mode, bsstype; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* For now, just catch early the Repeater and Secondary modes here */ 738c2ecf20Sopenharmony_ci if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { 748c2ecf20Sopenharmony_ci printk(KERN_DEBUG 758c2ecf20Sopenharmony_ci "%s(): Sorry, Repeater mode and Secondary mode " 768c2ecf20Sopenharmony_ci "are not yet supported by this driver.\n", __func__); 778c2ecf20Sopenharmony_ci return -EINVAL; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci priv->iw_mode = iw_mode; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci switch (iw_mode) { 838c2ecf20Sopenharmony_ci case IW_MODE_AUTO: 848c2ecf20Sopenharmony_ci mode = INL_MODE_CLIENT; 858c2ecf20Sopenharmony_ci bsstype = DOT11_BSSTYPE_ANY; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci case IW_MODE_ADHOC: 888c2ecf20Sopenharmony_ci mode = INL_MODE_CLIENT; 898c2ecf20Sopenharmony_ci bsstype = DOT11_BSSTYPE_IBSS; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case IW_MODE_INFRA: 928c2ecf20Sopenharmony_ci mode = INL_MODE_CLIENT; 938c2ecf20Sopenharmony_ci bsstype = DOT11_BSSTYPE_INFRA; 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci case IW_MODE_MASTER: 968c2ecf20Sopenharmony_ci mode = INL_MODE_AP; 978c2ecf20Sopenharmony_ci bsstype = DOT11_BSSTYPE_INFRA; 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci case IW_MODE_MONITOR: 1008c2ecf20Sopenharmony_ci mode = INL_MODE_PROMISCUOUS; 1018c2ecf20Sopenharmony_ci bsstype = DOT11_BSSTYPE_ANY; 1028c2ecf20Sopenharmony_ci config |= INL_CONFIG_RXANNEX; 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci default: 1058c2ecf20Sopenharmony_ci return -EINVAL; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (init_wds) 1098c2ecf20Sopenharmony_ci config |= INL_CONFIG_WDS; 1108c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); 1118c2ecf20Sopenharmony_ci mgt_set(priv, OID_INL_CONFIG, &config); 1128c2ecf20Sopenharmony_ci mgt_set(priv, OID_INL_MODE, &mode); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/** 1188c2ecf20Sopenharmony_ci * prism54_mib_init - fill MIB cache with defaults 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * this function initializes the struct given as @mib with defaults, 1218c2ecf20Sopenharmony_ci * of which many are retrieved from the global module parameter 1228c2ecf20Sopenharmony_ci * variables. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_civoid 1268c2ecf20Sopenharmony_ciprism54_mib_init(islpci_private *priv) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode; 1298c2ecf20Sopenharmony_ci struct obj_buffer psm_buffer = { 1308c2ecf20Sopenharmony_ci .size = PSM_BUFFER_SIZE, 1318c2ecf20Sopenharmony_ci .addr = priv->device_psm_buffer 1328c2ecf20Sopenharmony_ci }; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci channel = CARD_DEFAULT_CHANNEL; 1358c2ecf20Sopenharmony_ci authen = CARD_DEFAULT_AUTHEN; 1368c2ecf20Sopenharmony_ci wep = CARD_DEFAULT_WEP; 1378c2ecf20Sopenharmony_ci filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */ 1388c2ecf20Sopenharmony_ci dot1x = CARD_DEFAULT_DOT1X; 1398c2ecf20Sopenharmony_ci mlme = CARD_DEFAULT_MLME_MODE; 1408c2ecf20Sopenharmony_ci conformance = CARD_DEFAULT_CONFORMANCE; 1418c2ecf20Sopenharmony_ci power = 127; 1428c2ecf20Sopenharmony_ci mode = CARD_DEFAULT_IW_MODE; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_CHANNEL, &channel); 1458c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_AUTHENABLE, &authen); 1468c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep); 1478c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); 1488c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter); 1498c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x); 1508c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme); 1518c2ecf20Sopenharmony_ci mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance); 1528c2ecf20Sopenharmony_ci mgt_set(priv, OID_INL_OUTPUTPOWER, &power); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* This sets all of the mode-dependent values */ 1558c2ecf20Sopenharmony_ci prism54_mib_mode_helper(priv, mode); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* this will be executed outside of atomic context thanks to 1598c2ecf20Sopenharmony_ci * schedule_work(), thus we can as well use sleeping semaphore 1608c2ecf20Sopenharmony_ci * locking */ 1618c2ecf20Sopenharmony_civoid 1628c2ecf20Sopenharmony_ciprism54_update_stats(struct work_struct *work) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci islpci_private *priv = container_of(work, islpci_private, stats_work); 1658c2ecf20Sopenharmony_ci char *data; 1668c2ecf20Sopenharmony_ci struct obj_bss bss, *bss2; 1678c2ecf20Sopenharmony_ci union oid_res_t r; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci mutex_lock(&priv->stats_lock); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* Noise floor. 1728c2ecf20Sopenharmony_ci * I'm not sure if the unit is dBm. 1738c2ecf20Sopenharmony_ci * Note : If we are not connected, this value seems to be irrelevant. */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); 1768c2ecf20Sopenharmony_ci priv->local_iwstatistics.qual.noise = r.u; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* Get the rssi of the link. To do this we need to retrieve a bss. */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* First get the MAC address of the AP we are associated with. */ 1818c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); 1828c2ecf20Sopenharmony_ci data = r.ptr; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* copy this MAC to the bss */ 1858c2ecf20Sopenharmony_ci memcpy(bss.address, data, ETH_ALEN); 1868c2ecf20Sopenharmony_ci kfree(data); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* now ask for the corresponding bss */ 1898c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); 1908c2ecf20Sopenharmony_ci bss2 = r.ptr; 1918c2ecf20Sopenharmony_ci /* report the rssi and use it to calculate 1928c2ecf20Sopenharmony_ci * link quality through a signal-noise 1938c2ecf20Sopenharmony_ci * ratio */ 1948c2ecf20Sopenharmony_ci priv->local_iwstatistics.qual.level = bss2->rssi; 1958c2ecf20Sopenharmony_ci priv->local_iwstatistics.qual.qual = 1968c2ecf20Sopenharmony_ci bss2->rssi - priv->iwstatistics.qual.noise; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci kfree(bss2); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* report that the stats are new */ 2018c2ecf20Sopenharmony_ci priv->local_iwstatistics.qual.updated = 0x7; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/* Rx : unable to decrypt the MPDU */ 2048c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); 2058c2ecf20Sopenharmony_ci priv->local_iwstatistics.discard.code = r.u; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* Tx : Max MAC retries num reached */ 2088c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); 2098c2ecf20Sopenharmony_ci priv->local_iwstatistics.discard.retries = r.u; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci mutex_unlock(&priv->stats_lock); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistruct iw_statistics * 2158c2ecf20Sopenharmony_ciprism54_get_wireless_stats(struct net_device *ndev) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* If the stats are being updated return old data */ 2208c2ecf20Sopenharmony_ci if (mutex_trylock(&priv->stats_lock)) { 2218c2ecf20Sopenharmony_ci memcpy(&priv->iwstatistics, &priv->local_iwstatistics, 2228c2ecf20Sopenharmony_ci sizeof (struct iw_statistics)); 2238c2ecf20Sopenharmony_ci /* They won't be marked updated for the next time */ 2248c2ecf20Sopenharmony_ci priv->local_iwstatistics.qual.updated = 0; 2258c2ecf20Sopenharmony_ci mutex_unlock(&priv->stats_lock); 2268c2ecf20Sopenharmony_ci } else 2278c2ecf20Sopenharmony_ci priv->iwstatistics.qual.updated = 0; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Update our wireless stats, but do not schedule to often 2308c2ecf20Sopenharmony_ci * (max 1 HZ) */ 2318c2ecf20Sopenharmony_ci if ((priv->stats_timestamp == 0) || 2328c2ecf20Sopenharmony_ci time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { 2338c2ecf20Sopenharmony_ci schedule_work(&priv->stats_work); 2348c2ecf20Sopenharmony_ci priv->stats_timestamp = jiffies; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return &priv->iwstatistics; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int 2418c2ecf20Sopenharmony_ciprism54_commit(struct net_device *ndev, struct iw_request_info *info, 2428c2ecf20Sopenharmony_ci char *cwrq, char *extra) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* simply re-set the last set SSID, this should commit most stuff */ 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Commit in Monitor mode is not necessary, also setting essid 2498c2ecf20Sopenharmony_ci * in Monitor mode does not make sense and isn't allowed for this 2508c2ecf20Sopenharmony_ci * device's firmware */ 2518c2ecf20Sopenharmony_ci if (priv->iw_mode != IW_MODE_MONITOR) 2528c2ecf20Sopenharmony_ci return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int 2578c2ecf20Sopenharmony_ciprism54_get_name(struct net_device *ndev, struct iw_request_info *info, 2588c2ecf20Sopenharmony_ci char *cwrq, char *extra) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 2618c2ecf20Sopenharmony_ci char *capabilities; 2628c2ecf20Sopenharmony_ci union oid_res_t r; 2638c2ecf20Sopenharmony_ci int rvalue; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) { 2668c2ecf20Sopenharmony_ci strncpy(cwrq, "NOT READY!", IFNAMSIZ); 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci switch (r.u) { 2728c2ecf20Sopenharmony_ci case INL_PHYCAP_5000MHZ: 2738c2ecf20Sopenharmony_ci capabilities = "IEEE 802.11a/b/g"; 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case INL_PHYCAP_FAA: 2768c2ecf20Sopenharmony_ci capabilities = "IEEE 802.11b/g - FAA Support"; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case INL_PHYCAP_2400MHZ: 2798c2ecf20Sopenharmony_ci default: 2808c2ecf20Sopenharmony_ci capabilities = "IEEE 802.11b/g"; /* Default */ 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci strncpy(cwrq, capabilities, IFNAMSIZ); 2848c2ecf20Sopenharmony_ci return rvalue; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int 2888c2ecf20Sopenharmony_ciprism54_set_freq(struct net_device *ndev, struct iw_request_info *info, 2898c2ecf20Sopenharmony_ci struct iw_freq *fwrq, char *extra) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 2928c2ecf20Sopenharmony_ci int rvalue; 2938c2ecf20Sopenharmony_ci u32 c; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (fwrq->m < 1000) 2968c2ecf20Sopenharmony_ci /* we have a channel number */ 2978c2ecf20Sopenharmony_ci c = fwrq->m; 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Call commit handler */ 3048c2ecf20Sopenharmony_ci return (rvalue ? rvalue : -EINPROGRESS); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int 3088c2ecf20Sopenharmony_ciprism54_get_freq(struct net_device *ndev, struct iw_request_info *info, 3098c2ecf20Sopenharmony_ci struct iw_freq *fwrq, char *extra) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 3128c2ecf20Sopenharmony_ci union oid_res_t r; 3138c2ecf20Sopenharmony_ci int rvalue; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); 3168c2ecf20Sopenharmony_ci fwrq->i = r.u; 3178c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); 3188c2ecf20Sopenharmony_ci fwrq->m = r.u; 3198c2ecf20Sopenharmony_ci fwrq->e = 3; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return rvalue; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int 3258c2ecf20Sopenharmony_ciprism54_set_mode(struct net_device *ndev, struct iw_request_info *info, 3268c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 3298c2ecf20Sopenharmony_ci u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Let's see if the user passed a valid Linux Wireless mode */ 3328c2ecf20Sopenharmony_ci if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { 3338c2ecf20Sopenharmony_ci printk(KERN_DEBUG 3348c2ecf20Sopenharmony_ci "%s: %s() You passed a non-valid init_mode.\n", 3358c2ecf20Sopenharmony_ci priv->ndev->name, __func__); 3368c2ecf20Sopenharmony_ci return -EINVAL; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (prism54_mib_mode_helper(priv, *uwrq)) { 3428c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 3438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an 3478c2ecf20Sopenharmony_ci * extended one. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) 3508c2ecf20Sopenharmony_ci mlmeautolevel = DOT11_MLME_INTERMEDIATE; 3518c2ecf20Sopenharmony_ci if (priv->wpa) 3528c2ecf20Sopenharmony_ci mlmeautolevel = DOT11_MLME_EXTENDED; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (mgt_commit(priv)) { 3578c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 3588c2ecf20Sopenharmony_ci return -EIO; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) 3618c2ecf20Sopenharmony_ci ? priv->monitor_type : ARPHRD_ETHER; 3628c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/* Use mib cache */ 3688c2ecf20Sopenharmony_cistatic int 3698c2ecf20Sopenharmony_ciprism54_get_mode(struct net_device *ndev, struct iw_request_info *info, 3708c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > 3758c2ecf20Sopenharmony_ci IW_MODE_MONITOR)); 3768c2ecf20Sopenharmony_ci *uwrq = priv->iw_mode; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to 3828c2ecf20Sopenharmony_ci * emit data if (sensitivity > rssi - noise) (in dBm). 3838c2ecf20Sopenharmony_ci * prism54_set_sens does not seem to work. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int 3878c2ecf20Sopenharmony_ciprism54_set_sens(struct net_device *ndev, struct iw_request_info *info, 3888c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 3918c2ecf20Sopenharmony_ci u32 sens; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* by default the card sets this to 20. */ 3948c2ecf20Sopenharmony_ci sens = vwrq->disabled ? 20 : vwrq->value; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int 4008c2ecf20Sopenharmony_ciprism54_get_sens(struct net_device *ndev, struct iw_request_info *info, 4018c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 4048c2ecf20Sopenharmony_ci union oid_res_t r; 4058c2ecf20Sopenharmony_ci int rvalue; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci vwrq->value = r.u; 4108c2ecf20Sopenharmony_ci vwrq->disabled = (vwrq->value == 0); 4118c2ecf20Sopenharmony_ci vwrq->fixed = 1; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return rvalue; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int 4178c2ecf20Sopenharmony_ciprism54_get_range(struct net_device *ndev, struct iw_request_info *info, 4188c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct iw_range *range = (struct iw_range *) extra; 4218c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 4228c2ecf20Sopenharmony_ci u8 *data; 4238c2ecf20Sopenharmony_ci int i, m, rvalue; 4248c2ecf20Sopenharmony_ci struct obj_frequencies *freq; 4258c2ecf20Sopenharmony_ci union oid_res_t r; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci memset(range, 0, sizeof (struct iw_range)); 4288c2ecf20Sopenharmony_ci dwrq->length = sizeof (struct iw_range); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* set the wireless extension version number */ 4318c2ecf20Sopenharmony_ci range->we_version_source = SUPPORTED_WIRELESS_EXT; 4328c2ecf20Sopenharmony_ci range->we_version_compiled = WIRELESS_EXT; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Now the encoding capabilities */ 4358c2ecf20Sopenharmony_ci range->num_encoding_sizes = 3; 4368c2ecf20Sopenharmony_ci /* 64(40) bits WEP */ 4378c2ecf20Sopenharmony_ci range->encoding_size[0] = 5; 4388c2ecf20Sopenharmony_ci /* 128(104) bits WEP */ 4398c2ecf20Sopenharmony_ci range->encoding_size[1] = 13; 4408c2ecf20Sopenharmony_ci /* 256 bits for WPA-PSK */ 4418c2ecf20Sopenharmony_ci range->encoding_size[2] = 32; 4428c2ecf20Sopenharmony_ci /* 4 keys are allowed */ 4438c2ecf20Sopenharmony_ci range->max_encoding_tokens = 4; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* we don't know the quality range... */ 4468c2ecf20Sopenharmony_ci range->max_qual.level = 0; 4478c2ecf20Sopenharmony_ci range->max_qual.noise = 0; 4488c2ecf20Sopenharmony_ci range->max_qual.qual = 0; 4498c2ecf20Sopenharmony_ci /* these value describe an average quality. Needs more tweaking... */ 4508c2ecf20Sopenharmony_ci range->avg_qual.level = -80; /* -80 dBm */ 4518c2ecf20Sopenharmony_ci range->avg_qual.noise = 0; /* don't know what to put here */ 4528c2ecf20Sopenharmony_ci range->avg_qual.qual = 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci range->sensitivity = 200; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* retry limit capabilities */ 4578c2ecf20Sopenharmony_ci range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; 4588c2ecf20Sopenharmony_ci range->retry_flags = IW_RETRY_LIMIT; 4598c2ecf20Sopenharmony_ci range->r_time_flags = IW_RETRY_LIFETIME; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* I don't know the range. Put stupid things here */ 4628c2ecf20Sopenharmony_ci range->min_retry = 1; 4638c2ecf20Sopenharmony_ci range->max_retry = 65535; 4648c2ecf20Sopenharmony_ci range->min_r_time = 1024; 4658c2ecf20Sopenharmony_ci range->max_r_time = 65535 * 1024; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* txpower is supported in dBm's */ 4688c2ecf20Sopenharmony_ci range->txpower_capa = IW_TXPOW_DBM; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* Event capability (kernel + driver) */ 4718c2ecf20Sopenharmony_ci range->event_capa[0] = (IW_EVENT_CAPA_K_0 | 4728c2ecf20Sopenharmony_ci IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | 4738c2ecf20Sopenharmony_ci IW_EVENT_CAPA_MASK(SIOCGIWAP)); 4748c2ecf20Sopenharmony_ci range->event_capa[1] = IW_EVENT_CAPA_K_1; 4758c2ecf20Sopenharmony_ci range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | 4788c2ecf20Sopenharmony_ci IW_ENC_CAPA_CIPHER_TKIP; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) 4818c2ecf20Sopenharmony_ci return 0; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Request the device for the supported frequencies 4848c2ecf20Sopenharmony_ci * not really relevant since some devices will report the 5 GHz band 4858c2ecf20Sopenharmony_ci * frequencies even if they don't support them. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci rvalue = 4888c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); 4898c2ecf20Sopenharmony_ci freq = r.ptr; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci range->num_channels = freq->nr; 4928c2ecf20Sopenharmony_ci range->num_frequency = freq->nr; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci m = min(IW_MAX_FREQUENCIES, (int) freq->nr); 4958c2ecf20Sopenharmony_ci for (i = 0; i < m; i++) { 4968c2ecf20Sopenharmony_ci range->freq[i].m = freq->mhz[i]; 4978c2ecf20Sopenharmony_ci range->freq[i].e = 6; 4988c2ecf20Sopenharmony_ci range->freq[i].i = channel_of_freq(freq->mhz[i]); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci kfree(freq); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); 5038c2ecf20Sopenharmony_ci data = r.ptr; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* We got an array of char. It is NULL terminated. */ 5068c2ecf20Sopenharmony_ci i = 0; 5078c2ecf20Sopenharmony_ci while ((i < IW_MAX_BITRATES) && (*data != 0)) { 5088c2ecf20Sopenharmony_ci /* the result must be in bps. The card gives us 500Kbps */ 5098c2ecf20Sopenharmony_ci range->bitrate[i] = *data * 500000; 5108c2ecf20Sopenharmony_ci i++; 5118c2ecf20Sopenharmony_ci data++; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci range->num_bitrates = i; 5148c2ecf20Sopenharmony_ci kfree(r.ptr); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return rvalue; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/* Set AP address*/ 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int 5228c2ecf20Sopenharmony_ciprism54_set_wap(struct net_device *ndev, struct iw_request_info *info, 5238c2ecf20Sopenharmony_ci struct sockaddr *awrq, char *extra) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 5268c2ecf20Sopenharmony_ci char bssid[6]; 5278c2ecf20Sopenharmony_ci int rvalue; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (awrq->sa_family != ARPHRD_ETHER) 5308c2ecf20Sopenharmony_ci return -EINVAL; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* prepare the structure for the set object */ 5338c2ecf20Sopenharmony_ci memcpy(&bssid[0], awrq->sa_data, ETH_ALEN); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* set the bssid -- does this make sense when in AP mode? */ 5368c2ecf20Sopenharmony_ci rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* get AP address*/ 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int 5448c2ecf20Sopenharmony_ciprism54_get_wap(struct net_device *ndev, struct iw_request_info *info, 5458c2ecf20Sopenharmony_ci struct sockaddr *awrq, char *extra) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 5488c2ecf20Sopenharmony_ci union oid_res_t r; 5498c2ecf20Sopenharmony_ci int rvalue; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); 5528c2ecf20Sopenharmony_ci memcpy(awrq->sa_data, r.ptr, ETH_ALEN); 5538c2ecf20Sopenharmony_ci awrq->sa_family = ARPHRD_ETHER; 5548c2ecf20Sopenharmony_ci kfree(r.ptr); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return rvalue; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int 5608c2ecf20Sopenharmony_ciprism54_set_scan(struct net_device *dev, struct iw_request_info *info, 5618c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci /* hehe the device does this automagicaly */ 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci/* a little helper that will translate our data into a card independent 5688c2ecf20Sopenharmony_ci * format that the Wireless Tools will understand. This was inspired by 5698c2ecf20Sopenharmony_ci * the "Aironet driver for 4500 and 4800 series cards" (GPL) 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic char * 5738c2ecf20Sopenharmony_ciprism54_translate_bss(struct net_device *ndev, struct iw_request_info *info, 5748c2ecf20Sopenharmony_ci char *current_ev, char *end_buf, struct obj_bss *bss, 5758c2ecf20Sopenharmony_ci char noise) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct iw_event iwe; /* Temporary buffer */ 5788c2ecf20Sopenharmony_ci short cap; 5798c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 5808c2ecf20Sopenharmony_ci u8 wpa_ie[MAX_WPA_IE_LEN]; 5818c2ecf20Sopenharmony_ci size_t wpa_ie_len; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* The first entry must be the MAC address */ 5848c2ecf20Sopenharmony_ci memcpy(iwe.u.ap_addr.sa_data, bss->address, ETH_ALEN); 5858c2ecf20Sopenharmony_ci iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 5868c2ecf20Sopenharmony_ci iwe.cmd = SIOCGIWAP; 5878c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_event(info, current_ev, end_buf, 5888c2ecf20Sopenharmony_ci &iwe, IW_EV_ADDR_LEN); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* The following entries will be displayed in the same order we give them */ 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* The ESSID. */ 5938c2ecf20Sopenharmony_ci iwe.u.data.length = bss->ssid.length; 5948c2ecf20Sopenharmony_ci iwe.u.data.flags = 1; 5958c2ecf20Sopenharmony_ci iwe.cmd = SIOCGIWESSID; 5968c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_point(info, current_ev, end_buf, 5978c2ecf20Sopenharmony_ci &iwe, bss->ssid.octets); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* Capabilities */ 6008c2ecf20Sopenharmony_ci#define CAP_ESS 0x01 6018c2ecf20Sopenharmony_ci#define CAP_IBSS 0x02 6028c2ecf20Sopenharmony_ci#define CAP_CRYPT 0x10 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Mode */ 6058c2ecf20Sopenharmony_ci cap = bss->capinfo; 6068c2ecf20Sopenharmony_ci iwe.u.mode = 0; 6078c2ecf20Sopenharmony_ci if (cap & CAP_ESS) 6088c2ecf20Sopenharmony_ci iwe.u.mode = IW_MODE_MASTER; 6098c2ecf20Sopenharmony_ci else if (cap & CAP_IBSS) 6108c2ecf20Sopenharmony_ci iwe.u.mode = IW_MODE_ADHOC; 6118c2ecf20Sopenharmony_ci iwe.cmd = SIOCGIWMODE; 6128c2ecf20Sopenharmony_ci if (iwe.u.mode) 6138c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_event(info, current_ev, end_buf, 6148c2ecf20Sopenharmony_ci &iwe, IW_EV_UINT_LEN); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Encryption capability */ 6178c2ecf20Sopenharmony_ci if (cap & CAP_CRYPT) 6188c2ecf20Sopenharmony_ci iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 6198c2ecf20Sopenharmony_ci else 6208c2ecf20Sopenharmony_ci iwe.u.data.flags = IW_ENCODE_DISABLED; 6218c2ecf20Sopenharmony_ci iwe.u.data.length = 0; 6228c2ecf20Sopenharmony_ci iwe.cmd = SIOCGIWENCODE; 6238c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_point(info, current_ev, end_buf, 6248c2ecf20Sopenharmony_ci &iwe, NULL); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Add frequency. (short) bss->channel is the frequency in MHz */ 6278c2ecf20Sopenharmony_ci iwe.u.freq.m = bss->channel; 6288c2ecf20Sopenharmony_ci iwe.u.freq.e = 6; 6298c2ecf20Sopenharmony_ci iwe.cmd = SIOCGIWFREQ; 6308c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_event(info, current_ev, end_buf, 6318c2ecf20Sopenharmony_ci &iwe, IW_EV_FREQ_LEN); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Add quality statistics */ 6348c2ecf20Sopenharmony_ci iwe.u.qual.level = bss->rssi; 6358c2ecf20Sopenharmony_ci iwe.u.qual.noise = noise; 6368c2ecf20Sopenharmony_ci /* do a simple SNR for quality */ 6378c2ecf20Sopenharmony_ci iwe.u.qual.qual = bss->rssi - noise; 6388c2ecf20Sopenharmony_ci iwe.cmd = IWEVQUAL; 6398c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_event(info, current_ev, end_buf, 6408c2ecf20Sopenharmony_ci &iwe, IW_EV_QUAL_LEN); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* Add WPA/RSN Information Element, if any */ 6438c2ecf20Sopenharmony_ci wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); 6448c2ecf20Sopenharmony_ci if (wpa_ie_len > 0) { 6458c2ecf20Sopenharmony_ci iwe.cmd = IWEVGENIE; 6468c2ecf20Sopenharmony_ci iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN); 6478c2ecf20Sopenharmony_ci current_ev = iwe_stream_add_point(info, current_ev, end_buf, 6488c2ecf20Sopenharmony_ci &iwe, wpa_ie); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci /* Do the bitrates */ 6518c2ecf20Sopenharmony_ci { 6528c2ecf20Sopenharmony_ci char *current_val = current_ev + iwe_stream_lcp_len(info); 6538c2ecf20Sopenharmony_ci int i; 6548c2ecf20Sopenharmony_ci int mask; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci iwe.cmd = SIOCGIWRATE; 6578c2ecf20Sopenharmony_ci /* Those two flags are ignored... */ 6588c2ecf20Sopenharmony_ci iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Parse the bitmask */ 6618c2ecf20Sopenharmony_ci mask = 0x1; 6628c2ecf20Sopenharmony_ci for(i = 0; i < sizeof(scan_rate_list); i++) { 6638c2ecf20Sopenharmony_ci if(bss->rates & mask) { 6648c2ecf20Sopenharmony_ci iwe.u.bitrate.value = (scan_rate_list[i] * 500000); 6658c2ecf20Sopenharmony_ci current_val = iwe_stream_add_value( 6668c2ecf20Sopenharmony_ci info, current_ev, current_val, 6678c2ecf20Sopenharmony_ci end_buf, &iwe, IW_EV_PARAM_LEN); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci mask <<= 1; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci /* Check if we added any event */ 6728c2ecf20Sopenharmony_ci if ((current_val - current_ev) > iwe_stream_lcp_len(info)) 6738c2ecf20Sopenharmony_ci current_ev = current_val; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return current_ev; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic int 6808c2ecf20Sopenharmony_ciprism54_get_scan(struct net_device *ndev, struct iw_request_info *info, 6818c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 6848c2ecf20Sopenharmony_ci int i, rvalue; 6858c2ecf20Sopenharmony_ci struct obj_bsslist *bsslist; 6868c2ecf20Sopenharmony_ci u32 noise = 0; 6878c2ecf20Sopenharmony_ci char *current_ev = extra; 6888c2ecf20Sopenharmony_ci union oid_res_t r; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) { 6918c2ecf20Sopenharmony_ci /* device is not ready, fail gently */ 6928c2ecf20Sopenharmony_ci dwrq->length = 0; 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* first get the noise value. We will use it to report the link quality */ 6978c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); 6988c2ecf20Sopenharmony_ci noise = r.u; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Ask the device for a list of known bss. 7018c2ecf20Sopenharmony_ci * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64. 7028c2ecf20Sopenharmony_ci * The new API, using SIOCGIWSCAN, is only limited by the buffer size. 7038c2ecf20Sopenharmony_ci * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes. 7048c2ecf20Sopenharmony_ci * Starting with WE-17, the buffer can be as big as needed. 7058c2ecf20Sopenharmony_ci * But the device won't repport anything if you change the value 7068c2ecf20Sopenharmony_ci * of IWMAX_BSS=24. */ 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); 7098c2ecf20Sopenharmony_ci bsslist = r.ptr; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* ok now, scan the list and translate its info */ 7128c2ecf20Sopenharmony_ci for (i = 0; i < (int) bsslist->nr; i++) { 7138c2ecf20Sopenharmony_ci current_ev = prism54_translate_bss(ndev, info, current_ev, 7148c2ecf20Sopenharmony_ci extra + dwrq->length, 7158c2ecf20Sopenharmony_ci &(bsslist->bsslist[i]), 7168c2ecf20Sopenharmony_ci noise); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Check if there is space for one more entry */ 7198c2ecf20Sopenharmony_ci if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { 7208c2ecf20Sopenharmony_ci /* Ask user space to try again with a bigger buffer */ 7218c2ecf20Sopenharmony_ci rvalue = -E2BIG; 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci kfree(bsslist); 7278c2ecf20Sopenharmony_ci dwrq->length = (current_ev - extra); 7288c2ecf20Sopenharmony_ci dwrq->flags = 0; /* todo */ 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return rvalue; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int 7348c2ecf20Sopenharmony_ciprism54_set_essid(struct net_device *ndev, struct iw_request_info *info, 7358c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 7388c2ecf20Sopenharmony_ci struct obj_ssid essid; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci memset(essid.octets, 0, 33); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Check if we were asked for `any' */ 7438c2ecf20Sopenharmony_ci if (dwrq->flags && dwrq->length) { 7448c2ecf20Sopenharmony_ci if (dwrq->length > 32) 7458c2ecf20Sopenharmony_ci return -E2BIG; 7468c2ecf20Sopenharmony_ci essid.length = dwrq->length; 7478c2ecf20Sopenharmony_ci memcpy(essid.octets, extra, dwrq->length); 7488c2ecf20Sopenharmony_ci } else 7498c2ecf20Sopenharmony_ci essid.length = 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (priv->iw_mode != IW_MODE_MONITOR) 7528c2ecf20Sopenharmony_ci return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* If in monitor mode, just save to mib */ 7558c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_SSID, &essid); 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int 7618c2ecf20Sopenharmony_ciprism54_get_essid(struct net_device *ndev, struct iw_request_info *info, 7628c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 7658c2ecf20Sopenharmony_ci struct obj_ssid *essid; 7668c2ecf20Sopenharmony_ci union oid_res_t r; 7678c2ecf20Sopenharmony_ci int rvalue; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); 7708c2ecf20Sopenharmony_ci essid = r.ptr; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (essid->length) { 7738c2ecf20Sopenharmony_ci dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ 7748c2ecf20Sopenharmony_ci /* if it is too big, trunk it */ 7758c2ecf20Sopenharmony_ci dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length); 7768c2ecf20Sopenharmony_ci } else { 7778c2ecf20Sopenharmony_ci dwrq->flags = 0; 7788c2ecf20Sopenharmony_ci dwrq->length = 0; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci essid->octets[dwrq->length] = '\0'; 7818c2ecf20Sopenharmony_ci memcpy(extra, essid->octets, dwrq->length); 7828c2ecf20Sopenharmony_ci kfree(essid); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci return rvalue; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci/* Provides no functionality, just completes the ioctl. In essence this is a 7888c2ecf20Sopenharmony_ci * just a cosmetic ioctl. 7898c2ecf20Sopenharmony_ci */ 7908c2ecf20Sopenharmony_cistatic int 7918c2ecf20Sopenharmony_ciprism54_set_nick(struct net_device *ndev, struct iw_request_info *info, 7928c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (dwrq->length > IW_ESSID_MAX_SIZE) 7978c2ecf20Sopenharmony_ci return -E2BIG; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 8008c2ecf20Sopenharmony_ci memset(priv->nickname, 0, sizeof (priv->nickname)); 8018c2ecf20Sopenharmony_ci memcpy(priv->nickname, extra, dwrq->length); 8028c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int 8088c2ecf20Sopenharmony_ciprism54_get_nick(struct net_device *ndev, struct iw_request_info *info, 8098c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci dwrq->length = 0; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci down_read(&priv->mib_sem); 8168c2ecf20Sopenharmony_ci dwrq->length = strlen(priv->nickname); 8178c2ecf20Sopenharmony_ci memcpy(extra, priv->nickname, dwrq->length); 8188c2ecf20Sopenharmony_ci up_read(&priv->mib_sem); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return 0; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci/* Set the allowed Bitrates */ 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic int 8268c2ecf20Sopenharmony_ciprism54_set_rate(struct net_device *ndev, 8278c2ecf20Sopenharmony_ci struct iw_request_info *info, 8288c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 8328c2ecf20Sopenharmony_ci u32 rate, profile; 8338c2ecf20Sopenharmony_ci char *data; 8348c2ecf20Sopenharmony_ci int ret, i; 8358c2ecf20Sopenharmony_ci union oid_res_t r; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (vwrq->value == -1) { 8388c2ecf20Sopenharmony_ci /* auto mode. No limit. */ 8398c2ecf20Sopenharmony_ci profile = 1; 8408c2ecf20Sopenharmony_ci return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); 8448c2ecf20Sopenharmony_ci if (ret) { 8458c2ecf20Sopenharmony_ci kfree(r.ptr); 8468c2ecf20Sopenharmony_ci return ret; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci rate = (u32) (vwrq->value / 500000); 8508c2ecf20Sopenharmony_ci data = r.ptr; 8518c2ecf20Sopenharmony_ci i = 0; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci while (data[i]) { 8548c2ecf20Sopenharmony_ci if (rate && (data[i] == rate)) { 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci if (vwrq->value == i) { 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci data[i] |= 0x80; 8618c2ecf20Sopenharmony_ci i++; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (!data[i]) { 8658c2ecf20Sopenharmony_ci kfree(r.ptr); 8668c2ecf20Sopenharmony_ci return -EINVAL; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci data[i] |= 0x80; 8708c2ecf20Sopenharmony_ci data[i + 1] = 0; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* Now, check if we want a fixed or auto value */ 8738c2ecf20Sopenharmony_ci if (vwrq->fixed) { 8748c2ecf20Sopenharmony_ci data[0] = data[i]; 8758c2ecf20Sopenharmony_ci data[1] = 0; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci/* 8798c2ecf20Sopenharmony_ci i = 0; 8808c2ecf20Sopenharmony_ci printk("prism54 rate: "); 8818c2ecf20Sopenharmony_ci while(data[i]) { 8828c2ecf20Sopenharmony_ci printk("%u ", data[i]); 8838c2ecf20Sopenharmony_ci i++; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci printk("0\n"); 8868c2ecf20Sopenharmony_ci*/ 8878c2ecf20Sopenharmony_ci profile = -1; 8888c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); 8898c2ecf20Sopenharmony_ci ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); 8908c2ecf20Sopenharmony_ci ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci kfree(r.ptr); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci/* Get the current bit rate */ 8988c2ecf20Sopenharmony_cistatic int 8998c2ecf20Sopenharmony_ciprism54_get_rate(struct net_device *ndev, 9008c2ecf20Sopenharmony_ci struct iw_request_info *info, 9018c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 9048c2ecf20Sopenharmony_ci int rvalue; 9058c2ecf20Sopenharmony_ci char *data; 9068c2ecf20Sopenharmony_ci union oid_res_t r; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Get the current bit rate */ 9098c2ecf20Sopenharmony_ci if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) 9108c2ecf20Sopenharmony_ci return rvalue; 9118c2ecf20Sopenharmony_ci vwrq->value = r.u * 500000; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* request the device for the enabled rates */ 9148c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r); 9158c2ecf20Sopenharmony_ci if (rvalue) { 9168c2ecf20Sopenharmony_ci kfree(r.ptr); 9178c2ecf20Sopenharmony_ci return rvalue; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci data = r.ptr; 9208c2ecf20Sopenharmony_ci vwrq->fixed = (data[0] != 0) && (data[1] == 0); 9218c2ecf20Sopenharmony_ci kfree(r.ptr); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic int 9278c2ecf20Sopenharmony_ciprism54_set_rts(struct net_device *ndev, struct iw_request_info *info, 9288c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int 9368c2ecf20Sopenharmony_ciprism54_get_rts(struct net_device *ndev, struct iw_request_info *info, 9378c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 9408c2ecf20Sopenharmony_ci union oid_res_t r; 9418c2ecf20Sopenharmony_ci int rvalue; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* get the rts threshold */ 9448c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); 9458c2ecf20Sopenharmony_ci vwrq->value = r.u; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return rvalue; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int 9518c2ecf20Sopenharmony_ciprism54_set_frag(struct net_device *ndev, struct iw_request_info *info, 9528c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic int 9608c2ecf20Sopenharmony_ciprism54_get_frag(struct net_device *ndev, struct iw_request_info *info, 9618c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 9648c2ecf20Sopenharmony_ci union oid_res_t r; 9658c2ecf20Sopenharmony_ci int rvalue; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); 9688c2ecf20Sopenharmony_ci vwrq->value = r.u; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci return rvalue; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci/* Here we have (min,max) = max retries for (small frames, big frames). Where 9748c2ecf20Sopenharmony_ci * big frame <=> bigger than the rts threshold 9758c2ecf20Sopenharmony_ci * small frame <=> smaller than the rts threshold 9768c2ecf20Sopenharmony_ci * This is not really the behavior expected by the wireless tool but it seems 9778c2ecf20Sopenharmony_ci * to be a common behavior in other drivers. 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic int 9818c2ecf20Sopenharmony_ciprism54_set_retry(struct net_device *ndev, struct iw_request_info *info, 9828c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 9858c2ecf20Sopenharmony_ci u32 slimit = 0, llimit = 0; /* short and long limit */ 9868c2ecf20Sopenharmony_ci u32 lifetime = 0; 9878c2ecf20Sopenharmony_ci int rvalue = 0; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (vwrq->disabled) 9908c2ecf20Sopenharmony_ci /* we cannot disable this feature */ 9918c2ecf20Sopenharmony_ci return -EINVAL; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (vwrq->flags & IW_RETRY_LIMIT) { 9948c2ecf20Sopenharmony_ci if (vwrq->flags & IW_RETRY_SHORT) 9958c2ecf20Sopenharmony_ci slimit = vwrq->value; 9968c2ecf20Sopenharmony_ci else if (vwrq->flags & IW_RETRY_LONG) 9978c2ecf20Sopenharmony_ci llimit = vwrq->value; 9988c2ecf20Sopenharmony_ci else { 9998c2ecf20Sopenharmony_ci /* we are asked to set both */ 10008c2ecf20Sopenharmony_ci slimit = vwrq->value; 10018c2ecf20Sopenharmony_ci llimit = vwrq->value; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci if (vwrq->flags & IW_RETRY_LIFETIME) 10058c2ecf20Sopenharmony_ci /* Wireless tools use us unit while the device uses 1024 us unit */ 10068c2ecf20Sopenharmony_ci lifetime = vwrq->value / 1024; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* now set what is requested */ 10098c2ecf20Sopenharmony_ci if (slimit) 10108c2ecf20Sopenharmony_ci rvalue = 10118c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); 10128c2ecf20Sopenharmony_ci if (llimit) 10138c2ecf20Sopenharmony_ci rvalue |= 10148c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); 10158c2ecf20Sopenharmony_ci if (lifetime) 10168c2ecf20Sopenharmony_ci rvalue |= 10178c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, 10188c2ecf20Sopenharmony_ci &lifetime); 10198c2ecf20Sopenharmony_ci return rvalue; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int 10238c2ecf20Sopenharmony_ciprism54_get_retry(struct net_device *ndev, struct iw_request_info *info, 10248c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 10278c2ecf20Sopenharmony_ci union oid_res_t r; 10288c2ecf20Sopenharmony_ci int rvalue = 0; 10298c2ecf20Sopenharmony_ci vwrq->disabled = 0; /* It cannot be disabled */ 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { 10328c2ecf20Sopenharmony_ci /* we are asked for the life time */ 10338c2ecf20Sopenharmony_ci rvalue = 10348c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); 10358c2ecf20Sopenharmony_ci vwrq->value = r.u * 1024; 10368c2ecf20Sopenharmony_ci vwrq->flags = IW_RETRY_LIFETIME; 10378c2ecf20Sopenharmony_ci } else if ((vwrq->flags & IW_RETRY_LONG)) { 10388c2ecf20Sopenharmony_ci /* we are asked for the long retry limit */ 10398c2ecf20Sopenharmony_ci rvalue |= 10408c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); 10418c2ecf20Sopenharmony_ci vwrq->value = r.u; 10428c2ecf20Sopenharmony_ci vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; 10438c2ecf20Sopenharmony_ci } else { 10448c2ecf20Sopenharmony_ci /* default. get the short retry limit */ 10458c2ecf20Sopenharmony_ci rvalue |= 10468c2ecf20Sopenharmony_ci mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); 10478c2ecf20Sopenharmony_ci vwrq->value = r.u; 10488c2ecf20Sopenharmony_ci vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci return rvalue; 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic int 10558c2ecf20Sopenharmony_ciprism54_set_encode(struct net_device *ndev, struct iw_request_info *info, 10568c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 10598c2ecf20Sopenharmony_ci int rvalue = 0, force = 0; 10608c2ecf20Sopenharmony_ci int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; 10618c2ecf20Sopenharmony_ci union oid_res_t r; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* with the new API, it's impossible to get a NULL pointer. 10648c2ecf20Sopenharmony_ci * New version of iwconfig set the IW_ENCODE_NOKEY flag 10658c2ecf20Sopenharmony_ci * when no key is given, but older versions don't. */ 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (dwrq->length > 0) { 10688c2ecf20Sopenharmony_ci /* we have a key to set */ 10698c2ecf20Sopenharmony_ci int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 10708c2ecf20Sopenharmony_ci int current_index; 10718c2ecf20Sopenharmony_ci struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* get the current key index */ 10748c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 10758c2ecf20Sopenharmony_ci current_index = r.u; 10768c2ecf20Sopenharmony_ci /* Verify that the key is not marked as invalid */ 10778c2ecf20Sopenharmony_ci if (!(dwrq->flags & IW_ENCODE_NOKEY)) { 10788c2ecf20Sopenharmony_ci if (dwrq->length > KEY_SIZE_TKIP) { 10798c2ecf20Sopenharmony_ci /* User-provided key data too big */ 10808c2ecf20Sopenharmony_ci return -EINVAL; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci if (dwrq->length > KEY_SIZE_WEP104) { 10838c2ecf20Sopenharmony_ci /* WPA-PSK TKIP */ 10848c2ecf20Sopenharmony_ci key.type = DOT11_PRIV_TKIP; 10858c2ecf20Sopenharmony_ci key.length = KEY_SIZE_TKIP; 10868c2ecf20Sopenharmony_ci } else if (dwrq->length > KEY_SIZE_WEP40) { 10878c2ecf20Sopenharmony_ci /* WEP 104/128 */ 10888c2ecf20Sopenharmony_ci key.length = KEY_SIZE_WEP104; 10898c2ecf20Sopenharmony_ci } else { 10908c2ecf20Sopenharmony_ci /* WEP 40/64 */ 10918c2ecf20Sopenharmony_ci key.length = KEY_SIZE_WEP40; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci memset(key.key, 0, sizeof (key.key)); 10948c2ecf20Sopenharmony_ci memcpy(key.key, extra, dwrq->length); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if ((index < 0) || (index > 3)) 10978c2ecf20Sopenharmony_ci /* no index provided use the current one */ 10988c2ecf20Sopenharmony_ci index = current_index; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* now send the key to the card */ 11018c2ecf20Sopenharmony_ci rvalue |= 11028c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_DEFKEYX, index, 11038c2ecf20Sopenharmony_ci &key); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci /* 11068c2ecf20Sopenharmony_ci * If a valid key is set, encryption should be enabled 11078c2ecf20Sopenharmony_ci * (user may turn it off later). 11088c2ecf20Sopenharmony_ci * This is also how "iwconfig ethX key on" works 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci if ((index == current_index) && (key.length > 0)) 11118c2ecf20Sopenharmony_ci force = 1; 11128c2ecf20Sopenharmony_ci } else { 11138c2ecf20Sopenharmony_ci int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 11148c2ecf20Sopenharmony_ci if ((index >= 0) && (index <= 3)) { 11158c2ecf20Sopenharmony_ci /* we want to set the key index */ 11168c2ecf20Sopenharmony_ci rvalue |= 11178c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, 11188c2ecf20Sopenharmony_ci &index); 11198c2ecf20Sopenharmony_ci } else { 11208c2ecf20Sopenharmony_ci if (!(dwrq->flags & IW_ENCODE_MODE)) { 11218c2ecf20Sopenharmony_ci /* we cannot do anything. Complain. */ 11228c2ecf20Sopenharmony_ci return -EINVAL; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci /* now read the flags */ 11278c2ecf20Sopenharmony_ci if (dwrq->flags & IW_ENCODE_DISABLED) { 11288c2ecf20Sopenharmony_ci /* Encoding disabled, 11298c2ecf20Sopenharmony_ci * authen = DOT11_AUTH_OS; 11308c2ecf20Sopenharmony_ci * invoke = 0; 11318c2ecf20Sopenharmony_ci * exunencrypt = 0; */ 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci if (dwrq->flags & IW_ENCODE_OPEN) 11348c2ecf20Sopenharmony_ci /* Encode but accept non-encoded packets. No auth */ 11358c2ecf20Sopenharmony_ci invoke = 1; 11368c2ecf20Sopenharmony_ci if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { 11378c2ecf20Sopenharmony_ci /* Refuse non-encoded packets. Auth */ 11388c2ecf20Sopenharmony_ci authen = DOT11_AUTH_BOTH; 11398c2ecf20Sopenharmony_ci invoke = 1; 11408c2ecf20Sopenharmony_ci exunencrypt = 1; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci /* do the change if requested */ 11438c2ecf20Sopenharmony_ci if ((dwrq->flags & IW_ENCODE_MODE) || force) { 11448c2ecf20Sopenharmony_ci rvalue |= 11458c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); 11468c2ecf20Sopenharmony_ci rvalue |= 11478c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); 11488c2ecf20Sopenharmony_ci rvalue |= 11498c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, 11508c2ecf20Sopenharmony_ci &exunencrypt); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci return rvalue; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic int 11568c2ecf20Sopenharmony_ciprism54_get_encode(struct net_device *ndev, struct iw_request_info *info, 11578c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 11608c2ecf20Sopenharmony_ci struct obj_key *key; 11618c2ecf20Sopenharmony_ci u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 11628c2ecf20Sopenharmony_ci u32 authen = 0, invoke = 0, exunencrypt = 0; 11638c2ecf20Sopenharmony_ci int rvalue; 11648c2ecf20Sopenharmony_ci union oid_res_t r; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* first get the flags */ 11678c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 11688c2ecf20Sopenharmony_ci authen = r.u; 11698c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 11708c2ecf20Sopenharmony_ci invoke = r.u; 11718c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 11728c2ecf20Sopenharmony_ci exunencrypt = r.u; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) 11758c2ecf20Sopenharmony_ci dwrq->flags = IW_ENCODE_RESTRICTED; 11768c2ecf20Sopenharmony_ci else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { 11778c2ecf20Sopenharmony_ci if (invoke) 11788c2ecf20Sopenharmony_ci dwrq->flags = IW_ENCODE_OPEN; 11798c2ecf20Sopenharmony_ci else 11808c2ecf20Sopenharmony_ci dwrq->flags = IW_ENCODE_DISABLED; 11818c2ecf20Sopenharmony_ci } else 11828c2ecf20Sopenharmony_ci /* The card should not work in this state */ 11838c2ecf20Sopenharmony_ci dwrq->flags = 0; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* get the current device key index */ 11868c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 11878c2ecf20Sopenharmony_ci devindex = r.u; 11888c2ecf20Sopenharmony_ci /* Now get the key, return it */ 11898c2ecf20Sopenharmony_ci if (index == -1 || index > 3) 11908c2ecf20Sopenharmony_ci /* no index provided, use the current one */ 11918c2ecf20Sopenharmony_ci index = devindex; 11928c2ecf20Sopenharmony_ci rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); 11938c2ecf20Sopenharmony_ci key = r.ptr; 11948c2ecf20Sopenharmony_ci dwrq->length = key->length; 11958c2ecf20Sopenharmony_ci memcpy(extra, key->key, dwrq->length); 11968c2ecf20Sopenharmony_ci kfree(key); 11978c2ecf20Sopenharmony_ci /* return the used key index */ 11988c2ecf20Sopenharmony_ci dwrq->flags |= devindex + 1; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci return rvalue; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic int 12048c2ecf20Sopenharmony_ciprism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, 12058c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 12088c2ecf20Sopenharmony_ci union oid_res_t r; 12098c2ecf20Sopenharmony_ci int rvalue; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); 12128c2ecf20Sopenharmony_ci /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ 12138c2ecf20Sopenharmony_ci vwrq->value = (s32) r.u / 4; 12148c2ecf20Sopenharmony_ci vwrq->fixed = 1; 12158c2ecf20Sopenharmony_ci /* radio is not turned of 12168c2ecf20Sopenharmony_ci * btw: how is possible to turn off only the radio 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_ci vwrq->disabled = 0; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci return rvalue; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic int 12248c2ecf20Sopenharmony_ciprism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, 12258c2ecf20Sopenharmony_ci struct iw_param *vwrq, char *extra) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 12288c2ecf20Sopenharmony_ci s32 u = vwrq->value; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* intersil firmware operates in 0.25 dBm (1/4) */ 12318c2ecf20Sopenharmony_ci u *= 4; 12328c2ecf20Sopenharmony_ci if (vwrq->disabled) { 12338c2ecf20Sopenharmony_ci /* don't know how to disable radio */ 12348c2ecf20Sopenharmony_ci printk(KERN_DEBUG 12358c2ecf20Sopenharmony_ci "%s: %s() disabling radio is not yet supported.\n", 12368c2ecf20Sopenharmony_ci priv->ndev->name, __func__); 12378c2ecf20Sopenharmony_ci return -ENOTSUPP; 12388c2ecf20Sopenharmony_ci } else if (vwrq->fixed) 12398c2ecf20Sopenharmony_ci /* currently only fixed value is supported */ 12408c2ecf20Sopenharmony_ci return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); 12418c2ecf20Sopenharmony_ci else { 12428c2ecf20Sopenharmony_ci printk(KERN_DEBUG 12438c2ecf20Sopenharmony_ci "%s: %s() auto power will be implemented later.\n", 12448c2ecf20Sopenharmony_ci priv->ndev->name, __func__); 12458c2ecf20Sopenharmony_ci return -ENOTSUPP; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic int prism54_set_genie(struct net_device *ndev, 12508c2ecf20Sopenharmony_ci struct iw_request_info *info, 12518c2ecf20Sopenharmony_ci struct iw_point *data, char *extra) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 12548c2ecf20Sopenharmony_ci int alen, ret = 0; 12558c2ecf20Sopenharmony_ci struct obj_attachment *attach; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (data->length > MAX_WPA_IE_LEN || 12588c2ecf20Sopenharmony_ci (data->length && extra == NULL)) 12598c2ecf20Sopenharmony_ci return -EINVAL; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci memcpy(priv->wpa_ie, extra, data->length); 12628c2ecf20Sopenharmony_ci priv->wpa_ie_len = data->length; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci alen = sizeof(*attach) + priv->wpa_ie_len; 12658c2ecf20Sopenharmony_ci attach = kzalloc(alen, GFP_KERNEL); 12668c2ecf20Sopenharmony_ci if (attach == NULL) 12678c2ecf20Sopenharmony_ci return -ENOMEM; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci#define WLAN_FC_TYPE_MGMT 0 12708c2ecf20Sopenharmony_ci#define WLAN_FC_STYPE_ASSOC_REQ 0 12718c2ecf20Sopenharmony_ci#define WLAN_FC_STYPE_REASSOC_REQ 2 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* Note: endianness is covered by mgt_set_varlen */ 12748c2ecf20Sopenharmony_ci attach->type = (WLAN_FC_TYPE_MGMT << 2) | 12758c2ecf20Sopenharmony_ci (WLAN_FC_STYPE_ASSOC_REQ << 4); 12768c2ecf20Sopenharmony_ci attach->id = -1; 12778c2ecf20Sopenharmony_ci attach->size = priv->wpa_ie_len; 12788c2ecf20Sopenharmony_ci memcpy(attach->data, extra, priv->wpa_ie_len); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, 12818c2ecf20Sopenharmony_ci priv->wpa_ie_len); 12828c2ecf20Sopenharmony_ci if (ret == 0) { 12838c2ecf20Sopenharmony_ci attach->type = (WLAN_FC_TYPE_MGMT << 2) | 12848c2ecf20Sopenharmony_ci (WLAN_FC_STYPE_REASSOC_REQ << 4); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, 12878c2ecf20Sopenharmony_ci priv->wpa_ie_len); 12888c2ecf20Sopenharmony_ci if (ret == 0) 12898c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", 12908c2ecf20Sopenharmony_ci ndev->name); 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci kfree(attach); 12948c2ecf20Sopenharmony_ci return ret; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic int prism54_get_genie(struct net_device *ndev, 12998c2ecf20Sopenharmony_ci struct iw_request_info *info, 13008c2ecf20Sopenharmony_ci struct iw_point *data, char *extra) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 13038c2ecf20Sopenharmony_ci int len = priv->wpa_ie_len; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (len <= 0) { 13068c2ecf20Sopenharmony_ci data->length = 0; 13078c2ecf20Sopenharmony_ci return 0; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (data->length < len) 13118c2ecf20Sopenharmony_ci return -E2BIG; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci data->length = len; 13148c2ecf20Sopenharmony_ci memcpy(extra, priv->wpa_ie, len); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci return 0; 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic int prism54_set_auth(struct net_device *ndev, 13208c2ecf20Sopenharmony_ci struct iw_request_info *info, 13218c2ecf20Sopenharmony_ci union iwreq_data *wrqu, char *extra) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 13248c2ecf20Sopenharmony_ci struct iw_param *param = &wrqu->param; 13258c2ecf20Sopenharmony_ci u32 mlmelevel = 0, authen = 0, dot1x = 0; 13268c2ecf20Sopenharmony_ci u32 exunencrypt = 0, privinvoked = 0, wpa = 0; 13278c2ecf20Sopenharmony_ci u32 old_wpa; 13288c2ecf20Sopenharmony_ci int ret = 0; 13298c2ecf20Sopenharmony_ci union oid_res_t r; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) 13328c2ecf20Sopenharmony_ci return 0; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* first get the flags */ 13358c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 13368c2ecf20Sopenharmony_ci wpa = old_wpa = priv->wpa; 13378c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 13388c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 13398c2ecf20Sopenharmony_ci authen = r.u; 13408c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 13418c2ecf20Sopenharmony_ci privinvoked = r.u; 13428c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 13438c2ecf20Sopenharmony_ci exunencrypt = r.u; 13448c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); 13458c2ecf20Sopenharmony_ci dot1x = r.u; 13468c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r); 13478c2ecf20Sopenharmony_ci mlmelevel = r.u; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (ret < 0) 13508c2ecf20Sopenharmony_ci goto out; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci switch (param->flags & IW_AUTH_INDEX) { 13538c2ecf20Sopenharmony_ci case IW_AUTH_CIPHER_PAIRWISE: 13548c2ecf20Sopenharmony_ci case IW_AUTH_CIPHER_GROUP: 13558c2ecf20Sopenharmony_ci case IW_AUTH_KEY_MGMT: 13568c2ecf20Sopenharmony_ci break; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci case IW_AUTH_WPA_ENABLED: 13598c2ecf20Sopenharmony_ci /* Do the same thing as IW_AUTH_WPA_VERSION */ 13608c2ecf20Sopenharmony_ci if (param->value) { 13618c2ecf20Sopenharmony_ci wpa = 1; 13628c2ecf20Sopenharmony_ci privinvoked = 1; /* For privacy invoked */ 13638c2ecf20Sopenharmony_ci exunencrypt = 1; /* Filter out all unencrypted frames */ 13648c2ecf20Sopenharmony_ci dot1x = 0x01; /* To enable eap filter */ 13658c2ecf20Sopenharmony_ci mlmelevel = DOT11_MLME_EXTENDED; 13668c2ecf20Sopenharmony_ci authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ 13678c2ecf20Sopenharmony_ci } else { 13688c2ecf20Sopenharmony_ci wpa = 0; 13698c2ecf20Sopenharmony_ci privinvoked = 0; 13708c2ecf20Sopenharmony_ci exunencrypt = 0; /* Do not filter un-encrypted data */ 13718c2ecf20Sopenharmony_ci dot1x = 0; 13728c2ecf20Sopenharmony_ci mlmelevel = DOT11_MLME_AUTO; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci break; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci case IW_AUTH_WPA_VERSION: 13778c2ecf20Sopenharmony_ci if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { 13788c2ecf20Sopenharmony_ci wpa = 0; 13798c2ecf20Sopenharmony_ci privinvoked = 0; 13808c2ecf20Sopenharmony_ci exunencrypt = 0; /* Do not filter un-encrypted data */ 13818c2ecf20Sopenharmony_ci dot1x = 0; 13828c2ecf20Sopenharmony_ci mlmelevel = DOT11_MLME_AUTO; 13838c2ecf20Sopenharmony_ci } else { 13848c2ecf20Sopenharmony_ci if (param->value & IW_AUTH_WPA_VERSION_WPA) 13858c2ecf20Sopenharmony_ci wpa = 1; 13868c2ecf20Sopenharmony_ci else if (param->value & IW_AUTH_WPA_VERSION_WPA2) 13878c2ecf20Sopenharmony_ci wpa = 2; 13888c2ecf20Sopenharmony_ci privinvoked = 1; /* For privacy invoked */ 13898c2ecf20Sopenharmony_ci exunencrypt = 1; /* Filter out all unencrypted frames */ 13908c2ecf20Sopenharmony_ci dot1x = 0x01; /* To enable eap filter */ 13918c2ecf20Sopenharmony_ci mlmelevel = DOT11_MLME_EXTENDED; 13928c2ecf20Sopenharmony_ci authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci break; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci case IW_AUTH_RX_UNENCRYPTED_EAPOL: 13978c2ecf20Sopenharmony_ci /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL; 13988c2ecf20Sopenharmony_ci * turn off dot1x when allowing receipt of unencrypted EAPOL 13998c2ecf20Sopenharmony_ci * frames, turn on dot1x when receipt should be disallowed 14008c2ecf20Sopenharmony_ci */ 14018c2ecf20Sopenharmony_ci dot1x = param->value ? 0 : 0x01; 14028c2ecf20Sopenharmony_ci break; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci case IW_AUTH_PRIVACY_INVOKED: 14058c2ecf20Sopenharmony_ci privinvoked = param->value ? 1 : 0; 14068c2ecf20Sopenharmony_ci break; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci case IW_AUTH_DROP_UNENCRYPTED: 14098c2ecf20Sopenharmony_ci exunencrypt = param->value ? 1 : 0; 14108c2ecf20Sopenharmony_ci break; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci case IW_AUTH_80211_AUTH_ALG: 14138c2ecf20Sopenharmony_ci if (param->value & IW_AUTH_ALG_SHARED_KEY) { 14148c2ecf20Sopenharmony_ci /* Only WEP uses _SK and _BOTH */ 14158c2ecf20Sopenharmony_ci if (wpa > 0) { 14168c2ecf20Sopenharmony_ci ret = -EINVAL; 14178c2ecf20Sopenharmony_ci goto out; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci authen = DOT11_AUTH_SK; 14208c2ecf20Sopenharmony_ci } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { 14218c2ecf20Sopenharmony_ci authen = DOT11_AUTH_OS; 14228c2ecf20Sopenharmony_ci } else { 14238c2ecf20Sopenharmony_ci ret = -EINVAL; 14248c2ecf20Sopenharmony_ci goto out; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci default: 14298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci /* Set all the values */ 14338c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 14348c2ecf20Sopenharmony_ci priv->wpa = wpa; 14358c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 14368c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); 14378c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked); 14388c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt); 14398c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); 14408c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ciout: 14438c2ecf20Sopenharmony_ci return ret; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic int prism54_get_auth(struct net_device *ndev, 14478c2ecf20Sopenharmony_ci struct iw_request_info *info, 14488c2ecf20Sopenharmony_ci union iwreq_data *wrqu, char *extra) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 14518c2ecf20Sopenharmony_ci struct iw_param *param = &wrqu->param; 14528c2ecf20Sopenharmony_ci u32 wpa = 0; 14538c2ecf20Sopenharmony_ci int ret = 0; 14548c2ecf20Sopenharmony_ci union oid_res_t r; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) 14578c2ecf20Sopenharmony_ci return 0; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* first get the flags */ 14608c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 14618c2ecf20Sopenharmony_ci wpa = priv->wpa; 14628c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci switch (param->flags & IW_AUTH_INDEX) { 14658c2ecf20Sopenharmony_ci case IW_AUTH_CIPHER_PAIRWISE: 14668c2ecf20Sopenharmony_ci case IW_AUTH_CIPHER_GROUP: 14678c2ecf20Sopenharmony_ci case IW_AUTH_KEY_MGMT: 14688c2ecf20Sopenharmony_ci /* 14698c2ecf20Sopenharmony_ci * wpa_supplicant will control these internally 14708c2ecf20Sopenharmony_ci */ 14718c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 14728c2ecf20Sopenharmony_ci break; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci case IW_AUTH_WPA_VERSION: 14758c2ecf20Sopenharmony_ci switch (wpa) { 14768c2ecf20Sopenharmony_ci case 1: 14778c2ecf20Sopenharmony_ci param->value = IW_AUTH_WPA_VERSION_WPA; 14788c2ecf20Sopenharmony_ci break; 14798c2ecf20Sopenharmony_ci case 2: 14808c2ecf20Sopenharmony_ci param->value = IW_AUTH_WPA_VERSION_WPA2; 14818c2ecf20Sopenharmony_ci break; 14828c2ecf20Sopenharmony_ci case 0: 14838c2ecf20Sopenharmony_ci default: 14848c2ecf20Sopenharmony_ci param->value = IW_AUTH_WPA_VERSION_DISABLED; 14858c2ecf20Sopenharmony_ci break; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci break; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci case IW_AUTH_DROP_UNENCRYPTED: 14908c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 14918c2ecf20Sopenharmony_ci if (ret >= 0) 14928c2ecf20Sopenharmony_ci param->value = r.u > 0 ? 1 : 0; 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci case IW_AUTH_80211_AUTH_ALG: 14968c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 14978c2ecf20Sopenharmony_ci if (ret >= 0) { 14988c2ecf20Sopenharmony_ci switch (r.u) { 14998c2ecf20Sopenharmony_ci case DOT11_AUTH_OS: 15008c2ecf20Sopenharmony_ci param->value = IW_AUTH_ALG_OPEN_SYSTEM; 15018c2ecf20Sopenharmony_ci break; 15028c2ecf20Sopenharmony_ci case DOT11_AUTH_BOTH: 15038c2ecf20Sopenharmony_ci case DOT11_AUTH_SK: 15048c2ecf20Sopenharmony_ci param->value = IW_AUTH_ALG_SHARED_KEY; 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci case DOT11_AUTH_NONE: 15078c2ecf20Sopenharmony_ci default: 15088c2ecf20Sopenharmony_ci param->value = 0; 15098c2ecf20Sopenharmony_ci break; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci case IW_AUTH_WPA_ENABLED: 15158c2ecf20Sopenharmony_ci param->value = wpa > 0 ? 1 : 0; 15168c2ecf20Sopenharmony_ci break; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci case IW_AUTH_RX_UNENCRYPTED_EAPOL: 15198c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); 15208c2ecf20Sopenharmony_ci if (ret >= 0) 15218c2ecf20Sopenharmony_ci param->value = r.u > 0 ? 1 : 0; 15228c2ecf20Sopenharmony_ci break; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci case IW_AUTH_PRIVACY_INVOKED: 15258c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 15268c2ecf20Sopenharmony_ci if (ret >= 0) 15278c2ecf20Sopenharmony_ci param->value = r.u > 0 ? 1 : 0; 15288c2ecf20Sopenharmony_ci break; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci default: 15318c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci return ret; 15348c2ecf20Sopenharmony_ci} 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_cistatic int prism54_set_encodeext(struct net_device *ndev, 15378c2ecf20Sopenharmony_ci struct iw_request_info *info, 15388c2ecf20Sopenharmony_ci union iwreq_data *wrqu, 15398c2ecf20Sopenharmony_ci char *extra) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 15428c2ecf20Sopenharmony_ci struct iw_point *encoding = &wrqu->encoding; 15438c2ecf20Sopenharmony_ci struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 15448c2ecf20Sopenharmony_ci int idx, alg = ext->alg, set_key = 1; 15458c2ecf20Sopenharmony_ci union oid_res_t r; 15468c2ecf20Sopenharmony_ci int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; 15478c2ecf20Sopenharmony_ci int ret = 0; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) 15508c2ecf20Sopenharmony_ci return 0; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci /* Determine and validate the key index */ 15538c2ecf20Sopenharmony_ci idx = (encoding->flags & IW_ENCODE_INDEX) - 1; 15548c2ecf20Sopenharmony_ci if (idx) { 15558c2ecf20Sopenharmony_ci if (idx < 0 || idx > 3) 15568c2ecf20Sopenharmony_ci return -EINVAL; 15578c2ecf20Sopenharmony_ci } else { 15588c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 15598c2ecf20Sopenharmony_ci if (ret < 0) 15608c2ecf20Sopenharmony_ci goto out; 15618c2ecf20Sopenharmony_ci idx = r.u; 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (encoding->flags & IW_ENCODE_DISABLED) 15658c2ecf20Sopenharmony_ci alg = IW_ENCODE_ALG_NONE; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 15688c2ecf20Sopenharmony_ci /* Only set transmit key index here, actual 15698c2ecf20Sopenharmony_ci * key is set below if needed. 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx); 15728c2ecf20Sopenharmony_ci set_key = ext->key_len > 0 ? 1 : 0; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (set_key) { 15768c2ecf20Sopenharmony_ci struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; 15778c2ecf20Sopenharmony_ci switch (alg) { 15788c2ecf20Sopenharmony_ci case IW_ENCODE_ALG_NONE: 15798c2ecf20Sopenharmony_ci break; 15808c2ecf20Sopenharmony_ci case IW_ENCODE_ALG_WEP: 15818c2ecf20Sopenharmony_ci if (ext->key_len > KEY_SIZE_WEP104) { 15828c2ecf20Sopenharmony_ci ret = -EINVAL; 15838c2ecf20Sopenharmony_ci goto out; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci if (ext->key_len > KEY_SIZE_WEP40) 15868c2ecf20Sopenharmony_ci key.length = KEY_SIZE_WEP104; 15878c2ecf20Sopenharmony_ci else 15888c2ecf20Sopenharmony_ci key.length = KEY_SIZE_WEP40; 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci case IW_ENCODE_ALG_TKIP: 15918c2ecf20Sopenharmony_ci if (ext->key_len > KEY_SIZE_TKIP) { 15928c2ecf20Sopenharmony_ci ret = -EINVAL; 15938c2ecf20Sopenharmony_ci goto out; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci key.type = DOT11_PRIV_TKIP; 15968c2ecf20Sopenharmony_ci key.length = KEY_SIZE_TKIP; 15978c2ecf20Sopenharmony_ci break; 15988c2ecf20Sopenharmony_ci default: 15998c2ecf20Sopenharmony_ci return -EINVAL; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if (key.length) { 16038c2ecf20Sopenharmony_ci memset(key.key, 0, sizeof(key.key)); 16048c2ecf20Sopenharmony_ci memcpy(key.key, ext->key, ext->key_len); 16058c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx, 16068c2ecf20Sopenharmony_ci &key); 16078c2ecf20Sopenharmony_ci if (ret < 0) 16088c2ecf20Sopenharmony_ci goto out; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* Read the flags */ 16138c2ecf20Sopenharmony_ci if (encoding->flags & IW_ENCODE_DISABLED) { 16148c2ecf20Sopenharmony_ci /* Encoding disabled, 16158c2ecf20Sopenharmony_ci * authen = DOT11_AUTH_OS; 16168c2ecf20Sopenharmony_ci * invoke = 0; 16178c2ecf20Sopenharmony_ci * exunencrypt = 0; */ 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci if (encoding->flags & IW_ENCODE_OPEN) { 16208c2ecf20Sopenharmony_ci /* Encode but accept non-encoded packets. No auth */ 16218c2ecf20Sopenharmony_ci invoke = 1; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci if (encoding->flags & IW_ENCODE_RESTRICTED) { 16248c2ecf20Sopenharmony_ci /* Refuse non-encoded packets. Auth */ 16258c2ecf20Sopenharmony_ci authen = DOT11_AUTH_BOTH; 16268c2ecf20Sopenharmony_ci invoke = 1; 16278c2ecf20Sopenharmony_ci exunencrypt = 1; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* do the change if requested */ 16318c2ecf20Sopenharmony_ci if (encoding->flags & IW_ENCODE_MODE) { 16328c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, 16338c2ecf20Sopenharmony_ci &authen); 16348c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, 16358c2ecf20Sopenharmony_ci &invoke); 16368c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, 16378c2ecf20Sopenharmony_ci &exunencrypt); 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ciout: 16418c2ecf20Sopenharmony_ci return ret; 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_cistatic int prism54_get_encodeext(struct net_device *ndev, 16468c2ecf20Sopenharmony_ci struct iw_request_info *info, 16478c2ecf20Sopenharmony_ci union iwreq_data *wrqu, 16488c2ecf20Sopenharmony_ci char *extra) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 16518c2ecf20Sopenharmony_ci struct iw_point *encoding = &wrqu->encoding; 16528c2ecf20Sopenharmony_ci struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 16538c2ecf20Sopenharmony_ci int idx, max_key_len; 16548c2ecf20Sopenharmony_ci union oid_res_t r; 16558c2ecf20Sopenharmony_ci int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; 16568c2ecf20Sopenharmony_ci int ret = 0; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) 16598c2ecf20Sopenharmony_ci return 0; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci /* first get the flags */ 16628c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); 16638c2ecf20Sopenharmony_ci authen = r.u; 16648c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); 16658c2ecf20Sopenharmony_ci invoke = r.u; 16668c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); 16678c2ecf20Sopenharmony_ci exunencrypt = r.u; 16688c2ecf20Sopenharmony_ci if (ret < 0) 16698c2ecf20Sopenharmony_ci goto out; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci max_key_len = encoding->length - sizeof(*ext); 16728c2ecf20Sopenharmony_ci if (max_key_len < 0) 16738c2ecf20Sopenharmony_ci return -EINVAL; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci idx = (encoding->flags & IW_ENCODE_INDEX) - 1; 16768c2ecf20Sopenharmony_ci if (idx) { 16778c2ecf20Sopenharmony_ci if (idx < 0 || idx > 3) 16788c2ecf20Sopenharmony_ci return -EINVAL; 16798c2ecf20Sopenharmony_ci } else { 16808c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); 16818c2ecf20Sopenharmony_ci if (ret < 0) 16828c2ecf20Sopenharmony_ci goto out; 16838c2ecf20Sopenharmony_ci idx = r.u; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci encoding->flags = idx + 1; 16878c2ecf20Sopenharmony_ci memset(ext, 0, sizeof(*ext)); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci switch (authen) { 16908c2ecf20Sopenharmony_ci case DOT11_AUTH_BOTH: 16918c2ecf20Sopenharmony_ci case DOT11_AUTH_SK: 16928c2ecf20Sopenharmony_ci wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; 16938c2ecf20Sopenharmony_ci fallthrough; 16948c2ecf20Sopenharmony_ci case DOT11_AUTH_OS: 16958c2ecf20Sopenharmony_ci default: 16968c2ecf20Sopenharmony_ci wrqu->encoding.flags |= IW_ENCODE_OPEN; 16978c2ecf20Sopenharmony_ci break; 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 17018c2ecf20Sopenharmony_ci wpa = priv->wpa; 17028c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { 17058c2ecf20Sopenharmony_ci /* No encryption */ 17068c2ecf20Sopenharmony_ci ext->alg = IW_ENCODE_ALG_NONE; 17078c2ecf20Sopenharmony_ci ext->key_len = 0; 17088c2ecf20Sopenharmony_ci wrqu->encoding.flags |= IW_ENCODE_DISABLED; 17098c2ecf20Sopenharmony_ci } else { 17108c2ecf20Sopenharmony_ci struct obj_key *key; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r); 17138c2ecf20Sopenharmony_ci if (ret < 0) 17148c2ecf20Sopenharmony_ci goto out; 17158c2ecf20Sopenharmony_ci key = r.ptr; 17168c2ecf20Sopenharmony_ci if (max_key_len < key->length) { 17178c2ecf20Sopenharmony_ci ret = -E2BIG; 17188c2ecf20Sopenharmony_ci goto out; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci memcpy(ext->key, key->key, key->length); 17218c2ecf20Sopenharmony_ci ext->key_len = key->length; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci switch (key->type) { 17248c2ecf20Sopenharmony_ci case DOT11_PRIV_TKIP: 17258c2ecf20Sopenharmony_ci ext->alg = IW_ENCODE_ALG_TKIP; 17268c2ecf20Sopenharmony_ci break; 17278c2ecf20Sopenharmony_ci default: 17288c2ecf20Sopenharmony_ci case DOT11_PRIV_WEP: 17298c2ecf20Sopenharmony_ci ext->alg = IW_ENCODE_ALG_WEP; 17308c2ecf20Sopenharmony_ci break; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci wrqu->encoding.flags |= IW_ENCODE_ENABLED; 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ciout: 17368c2ecf20Sopenharmony_ci return ret; 17378c2ecf20Sopenharmony_ci} 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cistatic int 17418c2ecf20Sopenharmony_ciprism54_reset(struct net_device *ndev, struct iw_request_info *info, 17428c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci islpci_reset(netdev_priv(ndev), 0); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci return 0; 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic int 17508c2ecf20Sopenharmony_ciprism54_get_oid(struct net_device *ndev, struct iw_request_info *info, 17518c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci union oid_res_t r; 17548c2ecf20Sopenharmony_ci int rvalue; 17558c2ecf20Sopenharmony_ci enum oid_num_t n = dwrq->flags; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r); 17588c2ecf20Sopenharmony_ci dwrq->length = mgt_response_to_str(n, &r, extra); 17598c2ecf20Sopenharmony_ci if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) 17608c2ecf20Sopenharmony_ci kfree(r.ptr); 17618c2ecf20Sopenharmony_ci return rvalue; 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistatic int 17658c2ecf20Sopenharmony_ciprism54_set_u32(struct net_device *ndev, struct iw_request_info *info, 17668c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci u32 oid = uwrq[0], u = uwrq[1]; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci return mgt_set_request(netdev_priv(ndev), oid, 0, &u); 17718c2ecf20Sopenharmony_ci} 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_cistatic int 17748c2ecf20Sopenharmony_ciprism54_set_raw(struct net_device *ndev, struct iw_request_info *info, 17758c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci u32 oid = dwrq->flags; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci return mgt_set_request(netdev_priv(ndev), oid, 0, extra); 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_civoid 17838c2ecf20Sopenharmony_ciprism54_acl_init(struct islpci_acl *acl) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci mutex_init(&acl->lock); 17868c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&acl->mac_list); 17878c2ecf20Sopenharmony_ci acl->size = 0; 17888c2ecf20Sopenharmony_ci acl->policy = MAC_POLICY_OPEN; 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_cistatic void 17928c2ecf20Sopenharmony_ciprism54_clear_mac(struct islpci_acl *acl) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci struct list_head *ptr, *next; 17958c2ecf20Sopenharmony_ci struct mac_entry *entry; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci mutex_lock(&acl->lock); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci if (acl->size == 0) { 18008c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 18018c2ecf20Sopenharmony_ci return; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci for (ptr = acl->mac_list.next, next = ptr->next; 18058c2ecf20Sopenharmony_ci ptr != &acl->mac_list; ptr = next, next = ptr->next) { 18068c2ecf20Sopenharmony_ci entry = list_entry(ptr, struct mac_entry, _list); 18078c2ecf20Sopenharmony_ci list_del(ptr); 18088c2ecf20Sopenharmony_ci kfree(entry); 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci acl->size = 0; 18118c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_civoid 18158c2ecf20Sopenharmony_ciprism54_acl_clean(struct islpci_acl *acl) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci prism54_clear_mac(acl); 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_cistatic int 18218c2ecf20Sopenharmony_ciprism54_add_mac(struct net_device *ndev, struct iw_request_info *info, 18228c2ecf20Sopenharmony_ci struct sockaddr *awrq, char *extra) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 18258c2ecf20Sopenharmony_ci struct islpci_acl *acl = &priv->acl; 18268c2ecf20Sopenharmony_ci struct mac_entry *entry; 18278c2ecf20Sopenharmony_ci struct sockaddr *addr = (struct sockaddr *) extra; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (addr->sa_family != ARPHRD_ETHER) 18308c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); 18338c2ecf20Sopenharmony_ci if (entry == NULL) 18348c2ecf20Sopenharmony_ci return -ENOMEM; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci memcpy(entry->addr, addr->sa_data, ETH_ALEN); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&acl->lock)) { 18398c2ecf20Sopenharmony_ci kfree(entry); 18408c2ecf20Sopenharmony_ci return -ERESTARTSYS; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci list_add_tail(&entry->_list, &acl->mac_list); 18438c2ecf20Sopenharmony_ci acl->size++; 18448c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci return 0; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic int 18508c2ecf20Sopenharmony_ciprism54_del_mac(struct net_device *ndev, struct iw_request_info *info, 18518c2ecf20Sopenharmony_ci struct sockaddr *awrq, char *extra) 18528c2ecf20Sopenharmony_ci{ 18538c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 18548c2ecf20Sopenharmony_ci struct islpci_acl *acl = &priv->acl; 18558c2ecf20Sopenharmony_ci struct mac_entry *entry; 18568c2ecf20Sopenharmony_ci struct sockaddr *addr = (struct sockaddr *) extra; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci if (addr->sa_family != ARPHRD_ETHER) 18598c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&acl->lock)) 18628c2ecf20Sopenharmony_ci return -ERESTARTSYS; 18638c2ecf20Sopenharmony_ci list_for_each_entry(entry, &acl->mac_list, _list) { 18648c2ecf20Sopenharmony_ci if (ether_addr_equal(entry->addr, addr->sa_data)) { 18658c2ecf20Sopenharmony_ci list_del(&entry->_list); 18668c2ecf20Sopenharmony_ci acl->size--; 18678c2ecf20Sopenharmony_ci kfree(entry); 18688c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 18698c2ecf20Sopenharmony_ci return 0; 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 18738c2ecf20Sopenharmony_ci return -EINVAL; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cistatic int 18778c2ecf20Sopenharmony_ciprism54_get_mac(struct net_device *ndev, struct iw_request_info *info, 18788c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 18818c2ecf20Sopenharmony_ci struct islpci_acl *acl = &priv->acl; 18828c2ecf20Sopenharmony_ci struct mac_entry *entry; 18838c2ecf20Sopenharmony_ci struct sockaddr *dst = (struct sockaddr *) extra; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci dwrq->length = 0; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&acl->lock)) 18888c2ecf20Sopenharmony_ci return -ERESTARTSYS; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci list_for_each_entry(entry, &acl->mac_list, _list) { 18918c2ecf20Sopenharmony_ci memcpy(dst->sa_data, entry->addr, ETH_ALEN); 18928c2ecf20Sopenharmony_ci dst->sa_family = ARPHRD_ETHER; 18938c2ecf20Sopenharmony_ci dwrq->length++; 18948c2ecf20Sopenharmony_ci dst++; 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci/* Setting policy also clears the MAC acl, even if we don't change the default 19018c2ecf20Sopenharmony_ci * policy 19028c2ecf20Sopenharmony_ci */ 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_cistatic int 19058c2ecf20Sopenharmony_ciprism54_set_policy(struct net_device *ndev, struct iw_request_info *info, 19068c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 19098c2ecf20Sopenharmony_ci struct islpci_acl *acl = &priv->acl; 19108c2ecf20Sopenharmony_ci u32 mlmeautolevel; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci prism54_clear_mac(acl); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) 19158c2ecf20Sopenharmony_ci return -EINVAL; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci acl->policy = *uwrq; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci /* the ACL code needs an intermediate mlmeautolevel */ 19228c2ecf20Sopenharmony_ci if ((priv->iw_mode == IW_MODE_MASTER) && 19238c2ecf20Sopenharmony_ci (acl->policy != MAC_POLICY_OPEN)) 19248c2ecf20Sopenharmony_ci mlmeautolevel = DOT11_MLME_INTERMEDIATE; 19258c2ecf20Sopenharmony_ci else 19268c2ecf20Sopenharmony_ci mlmeautolevel = CARD_DEFAULT_MLME_MODE; 19278c2ecf20Sopenharmony_ci if (priv->wpa) 19288c2ecf20Sopenharmony_ci mlmeautolevel = DOT11_MLME_EXTENDED; 19298c2ecf20Sopenharmony_ci mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); 19308c2ecf20Sopenharmony_ci /* restart the card with our new policy */ 19318c2ecf20Sopenharmony_ci if (mgt_commit(priv)) { 19328c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 19338c2ecf20Sopenharmony_ci return -EIO; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci return 0; 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_cistatic int 19418c2ecf20Sopenharmony_ciprism54_get_policy(struct net_device *ndev, struct iw_request_info *info, 19428c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 19458c2ecf20Sopenharmony_ci struct islpci_acl *acl = &priv->acl; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci *uwrq = acl->policy; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci return 0; 19508c2ecf20Sopenharmony_ci} 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci/* Return 1 only if client should be accepted. */ 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_cistatic int 19558c2ecf20Sopenharmony_ciprism54_mac_accept(struct islpci_acl *acl, char *mac) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct mac_entry *entry; 19588c2ecf20Sopenharmony_ci int res = 0; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&acl->lock)) 19618c2ecf20Sopenharmony_ci return -ERESTARTSYS; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (acl->policy == MAC_POLICY_OPEN) { 19648c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 19658c2ecf20Sopenharmony_ci return 1; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci list_for_each_entry(entry, &acl->mac_list, _list) { 19698c2ecf20Sopenharmony_ci if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { 19708c2ecf20Sopenharmony_ci res = 1; 19718c2ecf20Sopenharmony_ci break; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci } 19748c2ecf20Sopenharmony_ci res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; 19758c2ecf20Sopenharmony_ci mutex_unlock(&acl->lock); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci return res; 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic int 19818c2ecf20Sopenharmony_ciprism54_kick_all(struct net_device *ndev, struct iw_request_info *info, 19828c2ecf20Sopenharmony_ci struct iw_point *dwrq, char *extra) 19838c2ecf20Sopenharmony_ci{ 19848c2ecf20Sopenharmony_ci struct obj_mlme *mlme; 19858c2ecf20Sopenharmony_ci int rvalue; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); 19888c2ecf20Sopenharmony_ci if (mlme == NULL) 19898c2ecf20Sopenharmony_ci return -ENOMEM; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci /* Tell the card to kick every client */ 19928c2ecf20Sopenharmony_ci mlme->id = 0; 19938c2ecf20Sopenharmony_ci rvalue = 19948c2ecf20Sopenharmony_ci mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); 19958c2ecf20Sopenharmony_ci kfree(mlme); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci return rvalue; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic int 20018c2ecf20Sopenharmony_ciprism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, 20028c2ecf20Sopenharmony_ci struct sockaddr *awrq, char *extra) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci struct obj_mlme *mlme; 20058c2ecf20Sopenharmony_ci struct sockaddr *addr = (struct sockaddr *) extra; 20068c2ecf20Sopenharmony_ci int rvalue; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if (addr->sa_family != ARPHRD_ETHER) 20098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); 20128c2ecf20Sopenharmony_ci if (mlme == NULL) 20138c2ecf20Sopenharmony_ci return -ENOMEM; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* Tell the card to only kick the corresponding bastard */ 20168c2ecf20Sopenharmony_ci memcpy(mlme->address, addr->sa_data, ETH_ALEN); 20178c2ecf20Sopenharmony_ci mlme->id = -1; 20188c2ecf20Sopenharmony_ci rvalue = 20198c2ecf20Sopenharmony_ci mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci kfree(mlme); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci return rvalue; 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_cistatic void 20298c2ecf20Sopenharmony_ciformat_event(islpci_private *priv, char *dest, const char *str, 20308c2ecf20Sopenharmony_ci const struct obj_mlme *mlme, u16 *length, int error) 20318c2ecf20Sopenharmony_ci{ 20328c2ecf20Sopenharmony_ci int n = snprintf(dest, IW_CUSTOM_MAX, 20338c2ecf20Sopenharmony_ci "%s %s %pM %s (%2.2X)", 20348c2ecf20Sopenharmony_ci str, 20358c2ecf20Sopenharmony_ci ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), 20368c2ecf20Sopenharmony_ci mlme->address, 20378c2ecf20Sopenharmony_ci (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") 20388c2ecf20Sopenharmony_ci : ""), mlme->code); 20398c2ecf20Sopenharmony_ci WARN_ON(n >= IW_CUSTOM_MAX); 20408c2ecf20Sopenharmony_ci *length = n; 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_cistatic void 20448c2ecf20Sopenharmony_cisend_formatted_event(islpci_private *priv, const char *str, 20458c2ecf20Sopenharmony_ci const struct obj_mlme *mlme, int error) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci union iwreq_data wrqu; 20488c2ecf20Sopenharmony_ci char *memptr; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); 20518c2ecf20Sopenharmony_ci if (!memptr) 20528c2ecf20Sopenharmony_ci return; 20538c2ecf20Sopenharmony_ci wrqu.data.pointer = memptr; 20548c2ecf20Sopenharmony_ci wrqu.data.length = 0; 20558c2ecf20Sopenharmony_ci format_event(priv, memptr, str, mlme, &wrqu.data.length, 20568c2ecf20Sopenharmony_ci error); 20578c2ecf20Sopenharmony_ci wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); 20588c2ecf20Sopenharmony_ci kfree(memptr); 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_cistatic void 20628c2ecf20Sopenharmony_cisend_simple_event(islpci_private *priv, const char *str) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci union iwreq_data wrqu; 20658c2ecf20Sopenharmony_ci char *memptr; 20668c2ecf20Sopenharmony_ci int n = strlen(str); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); 20698c2ecf20Sopenharmony_ci if (!memptr) 20708c2ecf20Sopenharmony_ci return; 20718c2ecf20Sopenharmony_ci BUG_ON(n >= IW_CUSTOM_MAX); 20728c2ecf20Sopenharmony_ci wrqu.data.pointer = memptr; 20738c2ecf20Sopenharmony_ci wrqu.data.length = n; 20748c2ecf20Sopenharmony_ci strcpy(memptr, str); 20758c2ecf20Sopenharmony_ci wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); 20768c2ecf20Sopenharmony_ci kfree(memptr); 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistatic void 20808c2ecf20Sopenharmony_cilink_changed(struct net_device *ndev, u32 bitrate) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (bitrate) { 20858c2ecf20Sopenharmony_ci netif_carrier_on(ndev); 20868c2ecf20Sopenharmony_ci if (priv->iw_mode == IW_MODE_INFRA) { 20878c2ecf20Sopenharmony_ci union iwreq_data uwrq; 20888c2ecf20Sopenharmony_ci prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, 20898c2ecf20Sopenharmony_ci NULL); 20908c2ecf20Sopenharmony_ci wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); 20918c2ecf20Sopenharmony_ci } else 20928c2ecf20Sopenharmony_ci send_simple_event(netdev_priv(ndev), 20938c2ecf20Sopenharmony_ci "Link established"); 20948c2ecf20Sopenharmony_ci } else { 20958c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 20968c2ecf20Sopenharmony_ci send_simple_event(netdev_priv(ndev), "Link lost"); 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci/* Beacon/ProbeResp payload header */ 21018c2ecf20Sopenharmony_cistruct ieee80211_beacon_phdr { 21028c2ecf20Sopenharmony_ci u8 timestamp[8]; 21038c2ecf20Sopenharmony_ci u16 beacon_int; 21048c2ecf20Sopenharmony_ci u16 capab_info; 21058c2ecf20Sopenharmony_ci} __packed; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci#define WLAN_EID_GENERIC 0xdd 21088c2ecf20Sopenharmony_cistatic u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_cistatic void 21118c2ecf20Sopenharmony_ciprism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, 21128c2ecf20Sopenharmony_ci u8 *wpa_ie, size_t wpa_ie_len) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci struct list_head *ptr; 21158c2ecf20Sopenharmony_ci struct islpci_bss_wpa_ie *bss = NULL; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci if (wpa_ie_len > MAX_WPA_IE_LEN) 21188c2ecf20Sopenharmony_ci wpa_ie_len = MAX_WPA_IE_LEN; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci mutex_lock(&priv->wpa_lock); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci /* try to use existing entry */ 21238c2ecf20Sopenharmony_ci list_for_each(ptr, &priv->bss_wpa_list) { 21248c2ecf20Sopenharmony_ci bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); 21258c2ecf20Sopenharmony_ci if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { 21268c2ecf20Sopenharmony_ci list_move(&bss->list, &priv->bss_wpa_list); 21278c2ecf20Sopenharmony_ci break; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci bss = NULL; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (bss == NULL) { 21338c2ecf20Sopenharmony_ci /* add a new BSS entry; if max number of entries is already 21348c2ecf20Sopenharmony_ci * reached, replace the least recently updated */ 21358c2ecf20Sopenharmony_ci if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { 21368c2ecf20Sopenharmony_ci bss = list_entry(priv->bss_wpa_list.prev, 21378c2ecf20Sopenharmony_ci struct islpci_bss_wpa_ie, list); 21388c2ecf20Sopenharmony_ci list_del(&bss->list); 21398c2ecf20Sopenharmony_ci } else { 21408c2ecf20Sopenharmony_ci bss = kzalloc(sizeof (*bss), GFP_ATOMIC); 21418c2ecf20Sopenharmony_ci if (bss != NULL) 21428c2ecf20Sopenharmony_ci priv->num_bss_wpa++; 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci if (bss != NULL) { 21458c2ecf20Sopenharmony_ci memcpy(bss->bssid, bssid, ETH_ALEN); 21468c2ecf20Sopenharmony_ci list_add(&bss->list, &priv->bss_wpa_list); 21478c2ecf20Sopenharmony_ci } 21488c2ecf20Sopenharmony_ci } 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci if (bss != NULL) { 21518c2ecf20Sopenharmony_ci memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); 21528c2ecf20Sopenharmony_ci bss->wpa_ie_len = wpa_ie_len; 21538c2ecf20Sopenharmony_ci bss->last_update = jiffies; 21548c2ecf20Sopenharmony_ci } else { 21558c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Failed to add BSS WPA entry for " 21568c2ecf20Sopenharmony_ci "%pM\n", bssid); 21578c2ecf20Sopenharmony_ci } 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci /* expire old entries from WPA list */ 21608c2ecf20Sopenharmony_ci while (priv->num_bss_wpa > 0) { 21618c2ecf20Sopenharmony_ci bss = list_entry(priv->bss_wpa_list.prev, 21628c2ecf20Sopenharmony_ci struct islpci_bss_wpa_ie, list); 21638c2ecf20Sopenharmony_ci if (!time_after(jiffies, bss->last_update + 60 * HZ)) 21648c2ecf20Sopenharmony_ci break; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci list_del(&bss->list); 21678c2ecf20Sopenharmony_ci priv->num_bss_wpa--; 21688c2ecf20Sopenharmony_ci kfree(bss); 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci mutex_unlock(&priv->wpa_lock); 21728c2ecf20Sopenharmony_ci} 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_cistatic size_t 21758c2ecf20Sopenharmony_ciprism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci struct list_head *ptr; 21788c2ecf20Sopenharmony_ci struct islpci_bss_wpa_ie *bss = NULL; 21798c2ecf20Sopenharmony_ci size_t len = 0; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci mutex_lock(&priv->wpa_lock); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci list_for_each(ptr, &priv->bss_wpa_list) { 21848c2ecf20Sopenharmony_ci bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); 21858c2ecf20Sopenharmony_ci if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 21868c2ecf20Sopenharmony_ci break; 21878c2ecf20Sopenharmony_ci bss = NULL; 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci if (bss) { 21908c2ecf20Sopenharmony_ci len = bss->wpa_ie_len; 21918c2ecf20Sopenharmony_ci memcpy(wpa_ie, bss->wpa_ie, len); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci mutex_unlock(&priv->wpa_lock); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci return len; 21968c2ecf20Sopenharmony_ci} 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_civoid 21998c2ecf20Sopenharmony_ciprism54_wpa_bss_ie_init(islpci_private *priv) 22008c2ecf20Sopenharmony_ci{ 22018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->bss_wpa_list); 22028c2ecf20Sopenharmony_ci mutex_init(&priv->wpa_lock); 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_civoid 22068c2ecf20Sopenharmony_ciprism54_wpa_bss_ie_clean(islpci_private *priv) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci struct islpci_bss_wpa_ie *bss, *n; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) { 22118c2ecf20Sopenharmony_ci kfree(bss); 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci} 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_cistatic void 22168c2ecf20Sopenharmony_ciprism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, 22178c2ecf20Sopenharmony_ci u8 *payload, size_t len) 22188c2ecf20Sopenharmony_ci{ 22198c2ecf20Sopenharmony_ci struct ieee80211_beacon_phdr *hdr; 22208c2ecf20Sopenharmony_ci u8 *pos, *end; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (!priv->wpa) 22238c2ecf20Sopenharmony_ci return; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci hdr = (struct ieee80211_beacon_phdr *) payload; 22268c2ecf20Sopenharmony_ci pos = (u8 *) (hdr + 1); 22278c2ecf20Sopenharmony_ci end = payload + len; 22288c2ecf20Sopenharmony_ci while (pos < end) { 22298c2ecf20Sopenharmony_ci if (pos + 2 + pos[1] > end) { 22308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " 22318c2ecf20Sopenharmony_ci "for %pM\n", addr); 22328c2ecf20Sopenharmony_ci return; 22338c2ecf20Sopenharmony_ci } 22348c2ecf20Sopenharmony_ci if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && 22358c2ecf20Sopenharmony_ci memcmp(pos + 2, wpa_oid, 4) == 0) { 22368c2ecf20Sopenharmony_ci prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2); 22378c2ecf20Sopenharmony_ci return; 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci pos += 2 + pos[1]; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_cistatic void 22448c2ecf20Sopenharmony_cihandle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) 22458c2ecf20Sopenharmony_ci{ 22468c2ecf20Sopenharmony_ci if (((mlme->state == DOT11_STATE_AUTHING) || 22478c2ecf20Sopenharmony_ci (mlme->state == DOT11_STATE_ASSOCING)) 22488c2ecf20Sopenharmony_ci && mgt_mlme_answer(priv)) { 22498c2ecf20Sopenharmony_ci /* Someone is requesting auth and we must respond. Just send back 22508c2ecf20Sopenharmony_ci * the trap with error code set accordingly. 22518c2ecf20Sopenharmony_ci */ 22528c2ecf20Sopenharmony_ci mlme->code = prism54_mac_accept(&priv->acl, 22538c2ecf20Sopenharmony_ci mlme->address) ? 0 : 1; 22548c2ecf20Sopenharmony_ci mgt_set_request(priv, oid, 0, mlme); 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci} 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistatic int 22598c2ecf20Sopenharmony_ciprism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, 22608c2ecf20Sopenharmony_ci char *data) 22618c2ecf20Sopenharmony_ci{ 22628c2ecf20Sopenharmony_ci struct obj_mlme *mlme = (struct obj_mlme *) data; 22638c2ecf20Sopenharmony_ci struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data; 22648c2ecf20Sopenharmony_ci struct obj_mlmeex *confirm; 22658c2ecf20Sopenharmony_ci u8 wpa_ie[MAX_WPA_IE_LEN]; 22668c2ecf20Sopenharmony_ci int wpa_ie_len; 22678c2ecf20Sopenharmony_ci size_t len = 0; /* u16, better? */ 22688c2ecf20Sopenharmony_ci u8 *payload = NULL, *pos = NULL; 22698c2ecf20Sopenharmony_ci int ret; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci /* I think all trapable objects are listed here. 22728c2ecf20Sopenharmony_ci * Some oids have a EX version. The difference is that they are emitted 22738c2ecf20Sopenharmony_ci * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) 22748c2ecf20Sopenharmony_ci * with more info. 22758c2ecf20Sopenharmony_ci * The few events already defined by the wireless tools are not really 22768c2ecf20Sopenharmony_ci * suited. We use the more flexible custom event facility. 22778c2ecf20Sopenharmony_ci */ 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci if (oid >= DOT11_OID_BEACON) { 22808c2ecf20Sopenharmony_ci len = mlmeex->size; 22818c2ecf20Sopenharmony_ci payload = pos = mlmeex->data; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci /* I fear prism54_process_bss_data won't work with big endian data */ 22858c2ecf20Sopenharmony_ci if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) 22868c2ecf20Sopenharmony_ci prism54_process_bss_data(priv, oid, mlmeex->address, 22878c2ecf20Sopenharmony_ci payload, len); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci switch (oid) { 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci case GEN_OID_LINKSTATE: 22948c2ecf20Sopenharmony_ci link_changed(priv->ndev, (u32) *data); 22958c2ecf20Sopenharmony_ci break; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci case DOT11_OID_MICFAILURE: 22988c2ecf20Sopenharmony_ci send_simple_event(priv, "Mic failure"); 22998c2ecf20Sopenharmony_ci break; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci case DOT11_OID_DEAUTHENTICATE: 23028c2ecf20Sopenharmony_ci send_formatted_event(priv, "DeAuthenticate request", mlme, 0); 23038c2ecf20Sopenharmony_ci break; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci case DOT11_OID_AUTHENTICATE: 23068c2ecf20Sopenharmony_ci handle_request(priv, mlme, oid); 23078c2ecf20Sopenharmony_ci send_formatted_event(priv, "Authenticate request", mlme, 1); 23088c2ecf20Sopenharmony_ci break; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci case DOT11_OID_DISASSOCIATE: 23118c2ecf20Sopenharmony_ci send_formatted_event(priv, "Disassociate request", mlme, 0); 23128c2ecf20Sopenharmony_ci break; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci case DOT11_OID_ASSOCIATE: 23158c2ecf20Sopenharmony_ci handle_request(priv, mlme, oid); 23168c2ecf20Sopenharmony_ci send_formatted_event(priv, "Associate request", mlme, 1); 23178c2ecf20Sopenharmony_ci break; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci case DOT11_OID_REASSOCIATE: 23208c2ecf20Sopenharmony_ci handle_request(priv, mlme, oid); 23218c2ecf20Sopenharmony_ci send_formatted_event(priv, "ReAssociate request", mlme, 1); 23228c2ecf20Sopenharmony_ci break; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci case DOT11_OID_BEACON: 23258c2ecf20Sopenharmony_ci send_formatted_event(priv, 23268c2ecf20Sopenharmony_ci "Received a beacon from an unknown AP", 23278c2ecf20Sopenharmony_ci mlme, 0); 23288c2ecf20Sopenharmony_ci break; 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci case DOT11_OID_PROBE: 23318c2ecf20Sopenharmony_ci /* we received a probe from a client. */ 23328c2ecf20Sopenharmony_ci send_formatted_event(priv, "Received a probe from client", mlme, 23338c2ecf20Sopenharmony_ci 0); 23348c2ecf20Sopenharmony_ci break; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this 23378c2ecf20Sopenharmony_ci * is backward compatible layout-wise with "struct obj_mlme". 23388c2ecf20Sopenharmony_ci */ 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci case DOT11_OID_DEAUTHENTICATEEX: 23418c2ecf20Sopenharmony_ci send_formatted_event(priv, "DeAuthenticate request", mlme, 0); 23428c2ecf20Sopenharmony_ci break; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci case DOT11_OID_AUTHENTICATEEX: 23458c2ecf20Sopenharmony_ci handle_request(priv, mlme, oid); 23468c2ecf20Sopenharmony_ci send_formatted_event(priv, "Authenticate request (ex)", mlme, 1); 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci if (priv->iw_mode != IW_MODE_MASTER 23498c2ecf20Sopenharmony_ci && mlmeex->state != DOT11_STATE_AUTHING) 23508c2ecf20Sopenharmony_ci break; 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC); 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci if (!confirm) 23558c2ecf20Sopenharmony_ci break; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci memcpy(&confirm->address, mlmeex->address, ETH_ALEN); 23588c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Authenticate from: address:\t%pM\n", 23598c2ecf20Sopenharmony_ci mlmeex->address); 23608c2ecf20Sopenharmony_ci confirm->id = -1; /* or mlmeex->id ? */ 23618c2ecf20Sopenharmony_ci confirm->state = 0; /* not used */ 23628c2ecf20Sopenharmony_ci confirm->code = 0; 23638c2ecf20Sopenharmony_ci confirm->size = 6; 23648c2ecf20Sopenharmony_ci confirm->data[0] = 0x00; 23658c2ecf20Sopenharmony_ci confirm->data[1] = 0x00; 23668c2ecf20Sopenharmony_ci confirm->data[2] = 0x02; 23678c2ecf20Sopenharmony_ci confirm->data[3] = 0x00; 23688c2ecf20Sopenharmony_ci confirm->data[4] = 0x00; 23698c2ecf20Sopenharmony_ci confirm->data[5] = 0x00; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci kfree(confirm); 23748c2ecf20Sopenharmony_ci if (ret) 23758c2ecf20Sopenharmony_ci return ret; 23768c2ecf20Sopenharmony_ci break; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci case DOT11_OID_DISASSOCIATEEX: 23798c2ecf20Sopenharmony_ci send_formatted_event(priv, "Disassociate request (ex)", mlme, 0); 23808c2ecf20Sopenharmony_ci break; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci case DOT11_OID_ASSOCIATEEX: 23838c2ecf20Sopenharmony_ci handle_request(priv, mlme, oid); 23848c2ecf20Sopenharmony_ci send_formatted_event(priv, "Associate request (ex)", mlme, 1); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci if (priv->iw_mode != IW_MODE_MASTER 23878c2ecf20Sopenharmony_ci && mlmeex->state != DOT11_STATE_ASSOCING) 23888c2ecf20Sopenharmony_ci break; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci if (!confirm) 23938c2ecf20Sopenharmony_ci break; 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci memcpy(&confirm->address, mlmeex->address, ETH_ALEN); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci confirm->id = ((struct obj_mlmeex *)mlme)->id; 23988c2ecf20Sopenharmony_ci confirm->state = 0; /* not used */ 23998c2ecf20Sopenharmony_ci confirm->code = 0; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci if (!wpa_ie_len) { 24048c2ecf20Sopenharmony_ci printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", 24058c2ecf20Sopenharmony_ci mlmeex->address); 24068c2ecf20Sopenharmony_ci kfree(confirm); 24078c2ecf20Sopenharmony_ci break; 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci confirm->size = wpa_ie_len; 24118c2ecf20Sopenharmony_ci memcpy(&confirm->data, wpa_ie, wpa_ie_len); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci mgt_set_varlen(priv, oid, confirm, wpa_ie_len); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci kfree(confirm); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci break; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci case DOT11_OID_REASSOCIATEEX: 24208c2ecf20Sopenharmony_ci handle_request(priv, mlme, oid); 24218c2ecf20Sopenharmony_ci send_formatted_event(priv, "Reassociate request (ex)", mlme, 1); 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci if (priv->iw_mode != IW_MODE_MASTER 24248c2ecf20Sopenharmony_ci && mlmeex->state != DOT11_STATE_ASSOCING) 24258c2ecf20Sopenharmony_ci break; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci if (!confirm) 24308c2ecf20Sopenharmony_ci break; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci memcpy(&confirm->address, mlmeex->address, ETH_ALEN); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci confirm->id = mlmeex->id; 24358c2ecf20Sopenharmony_ci confirm->state = 0; /* not used */ 24368c2ecf20Sopenharmony_ci confirm->code = 0; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci if (!wpa_ie_len) { 24418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", 24428c2ecf20Sopenharmony_ci mlmeex->address); 24438c2ecf20Sopenharmony_ci kfree(confirm); 24448c2ecf20Sopenharmony_ci break; 24458c2ecf20Sopenharmony_ci } 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci confirm->size = wpa_ie_len; 24488c2ecf20Sopenharmony_ci memcpy(&confirm->data, wpa_ie, wpa_ie_len); 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci mgt_set_varlen(priv, oid, confirm, wpa_ie_len); 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci kfree(confirm); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci break; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci default: 24578c2ecf20Sopenharmony_ci return -EINVAL; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci return 0; 24618c2ecf20Sopenharmony_ci} 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci/* 24648c2ecf20Sopenharmony_ci * Process a device trap. This is called via schedule_work(), outside of 24658c2ecf20Sopenharmony_ci * interrupt context, no locks held. 24668c2ecf20Sopenharmony_ci */ 24678c2ecf20Sopenharmony_civoid 24688c2ecf20Sopenharmony_ciprism54_process_trap(struct work_struct *work) 24698c2ecf20Sopenharmony_ci{ 24708c2ecf20Sopenharmony_ci struct islpci_mgmtframe *frame = 24718c2ecf20Sopenharmony_ci container_of(work, struct islpci_mgmtframe, ws); 24728c2ecf20Sopenharmony_ci struct net_device *ndev = frame->ndev; 24738c2ecf20Sopenharmony_ci enum oid_num_t n = mgt_oidtonum(frame->header->oid); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci if (n != OID_NUM_LAST) 24768c2ecf20Sopenharmony_ci prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); 24778c2ecf20Sopenharmony_ci islpci_mgt_release(frame); 24788c2ecf20Sopenharmony_ci} 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ciint 24818c2ecf20Sopenharmony_ciprism54_set_mac_address(struct net_device *ndev, void *addr) 24828c2ecf20Sopenharmony_ci{ 24838c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 24848c2ecf20Sopenharmony_ci int ret; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci if (ndev->addr_len != 6) 24878c2ecf20Sopenharmony_ci return -EINVAL; 24888c2ecf20Sopenharmony_ci ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, 24898c2ecf20Sopenharmony_ci &((struct sockaddr *) addr)->sa_data); 24908c2ecf20Sopenharmony_ci if (!ret) 24918c2ecf20Sopenharmony_ci memcpy(priv->ndev->dev_addr, 24928c2ecf20Sopenharmony_ci &((struct sockaddr *) addr)->sa_data, ETH_ALEN); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci return ret; 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_cistatic int 25008c2ecf20Sopenharmony_ciprism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, 25018c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 25028c2ecf20Sopenharmony_ci{ 25038c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 25048c2ecf20Sopenharmony_ci u32 mlme, authen, dot1x, filter, wep; 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci if (islpci_get_state(priv) < PRV_STATE_INIT) 25078c2ecf20Sopenharmony_ci return 0; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci wep = 1; /* For privacy invoked */ 25108c2ecf20Sopenharmony_ci filter = 1; /* Filter out all unencrypted frames */ 25118c2ecf20Sopenharmony_ci dot1x = 0x01; /* To enable eap filter */ 25128c2ecf20Sopenharmony_ci mlme = DOT11_MLME_EXTENDED; 25138c2ecf20Sopenharmony_ci authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 25168c2ecf20Sopenharmony_ci priv->wpa = *uwrq; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci switch (priv->wpa) { 25198c2ecf20Sopenharmony_ci default: 25208c2ecf20Sopenharmony_ci case 0: /* Clears/disables WPA and friends */ 25218c2ecf20Sopenharmony_ci wep = 0; 25228c2ecf20Sopenharmony_ci filter = 0; /* Do not filter un-encrypted data */ 25238c2ecf20Sopenharmony_ci dot1x = 0; 25248c2ecf20Sopenharmony_ci mlme = DOT11_MLME_AUTO; 25258c2ecf20Sopenharmony_ci printk("%s: Disabling WPA\n", ndev->name); 25268c2ecf20Sopenharmony_ci break; 25278c2ecf20Sopenharmony_ci case 2: 25288c2ecf20Sopenharmony_ci case 1: /* WPA */ 25298c2ecf20Sopenharmony_ci printk("%s: Enabling WPA\n", ndev->name); 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); 25358c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); 25368c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); 25378c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); 25388c2ecf20Sopenharmony_ci mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci return 0; 25418c2ecf20Sopenharmony_ci} 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_cistatic int 25448c2ecf20Sopenharmony_ciprism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, 25458c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 25488c2ecf20Sopenharmony_ci *uwrq = priv->wpa; 25498c2ecf20Sopenharmony_ci return 0; 25508c2ecf20Sopenharmony_ci} 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_cistatic int 25538c2ecf20Sopenharmony_ciprism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, 25548c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 25558c2ecf20Sopenharmony_ci{ 25568c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 25578c2ecf20Sopenharmony_ci priv->monitor_type = 25588c2ecf20Sopenharmony_ci (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); 25598c2ecf20Sopenharmony_ci if (priv->iw_mode == IW_MODE_MONITOR) 25608c2ecf20Sopenharmony_ci priv->ndev->type = priv->monitor_type; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci return 0; 25638c2ecf20Sopenharmony_ci} 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_cistatic int 25668c2ecf20Sopenharmony_ciprism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, 25678c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 25688c2ecf20Sopenharmony_ci{ 25698c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 25708c2ecf20Sopenharmony_ci *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); 25718c2ecf20Sopenharmony_ci return 0; 25728c2ecf20Sopenharmony_ci} 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_cistatic int 25758c2ecf20Sopenharmony_ciprism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, 25768c2ecf20Sopenharmony_ci __u32 * uwrq, char *extra) 25778c2ecf20Sopenharmony_ci{ 25788c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci priv->priv_oid = *uwrq; 25818c2ecf20Sopenharmony_ci printk("%s: oid 0x%08X\n", ndev->name, *uwrq); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci return 0; 25848c2ecf20Sopenharmony_ci} 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_cistatic int 25878c2ecf20Sopenharmony_ciprism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, 25888c2ecf20Sopenharmony_ci struct iw_point *data, char *extra) 25898c2ecf20Sopenharmony_ci{ 25908c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 25918c2ecf20Sopenharmony_ci struct islpci_mgmtframe *response; 25928c2ecf20Sopenharmony_ci int ret = -EIO; 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); 25958c2ecf20Sopenharmony_ci data->length = 0; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci if (islpci_get_state(priv) >= PRV_STATE_INIT) { 25988c2ecf20Sopenharmony_ci ret = 25998c2ecf20Sopenharmony_ci islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, 26008c2ecf20Sopenharmony_ci priv->priv_oid, extra, 256, 26018c2ecf20Sopenharmony_ci &response); 26028c2ecf20Sopenharmony_ci printk("%s: ret: %i\n", ndev->name, ret); 26038c2ecf20Sopenharmony_ci if (ret || !response 26048c2ecf20Sopenharmony_ci || response->header->operation == PIMFOR_OP_ERROR) { 26058c2ecf20Sopenharmony_ci if (response) { 26068c2ecf20Sopenharmony_ci islpci_mgt_release(response); 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci printk("%s: EIO\n", ndev->name); 26098c2ecf20Sopenharmony_ci ret = -EIO; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci if (!ret) { 26128c2ecf20Sopenharmony_ci data->length = response->header->length; 26138c2ecf20Sopenharmony_ci memcpy(extra, response->data, data->length); 26148c2ecf20Sopenharmony_ci islpci_mgt_release(response); 26158c2ecf20Sopenharmony_ci printk("%s: len: %i\n", ndev->name, data->length); 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci return ret; 26208c2ecf20Sopenharmony_ci} 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_cistatic int 26238c2ecf20Sopenharmony_ciprism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, 26248c2ecf20Sopenharmony_ci struct iw_point *data, char *extra) 26258c2ecf20Sopenharmony_ci{ 26268c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 26278c2ecf20Sopenharmony_ci struct islpci_mgmtframe *response; 26288c2ecf20Sopenharmony_ci int ret = 0, response_op = PIMFOR_OP_ERROR; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, 26318c2ecf20Sopenharmony_ci data->length); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (islpci_get_state(priv) >= PRV_STATE_INIT) { 26348c2ecf20Sopenharmony_ci ret = 26358c2ecf20Sopenharmony_ci islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, 26368c2ecf20Sopenharmony_ci priv->priv_oid, extra, data->length, 26378c2ecf20Sopenharmony_ci &response); 26388c2ecf20Sopenharmony_ci printk("%s: ret: %i\n", ndev->name, ret); 26398c2ecf20Sopenharmony_ci if (ret || !response 26408c2ecf20Sopenharmony_ci || response->header->operation == PIMFOR_OP_ERROR) { 26418c2ecf20Sopenharmony_ci if (response) { 26428c2ecf20Sopenharmony_ci islpci_mgt_release(response); 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci printk("%s: EIO\n", ndev->name); 26458c2ecf20Sopenharmony_ci ret = -EIO; 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci if (!ret) { 26488c2ecf20Sopenharmony_ci response_op = response->header->operation; 26498c2ecf20Sopenharmony_ci printk("%s: response_op: %i\n", ndev->name, 26508c2ecf20Sopenharmony_ci response_op); 26518c2ecf20Sopenharmony_ci islpci_mgt_release(response); 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci } 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci return (ret ? ret : -EINPROGRESS); 26568c2ecf20Sopenharmony_ci} 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_cistatic int 26598c2ecf20Sopenharmony_ciprism54_set_spy(struct net_device *ndev, 26608c2ecf20Sopenharmony_ci struct iw_request_info *info, 26618c2ecf20Sopenharmony_ci union iwreq_data *uwrq, char *extra) 26628c2ecf20Sopenharmony_ci{ 26638c2ecf20Sopenharmony_ci islpci_private *priv = netdev_priv(ndev); 26648c2ecf20Sopenharmony_ci u32 u; 26658c2ecf20Sopenharmony_ci enum oid_num_t oid = OID_INL_CONFIG; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci down_write(&priv->mib_sem); 26688c2ecf20Sopenharmony_ci mgt_get(priv, OID_INL_CONFIG, &u); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) 26718c2ecf20Sopenharmony_ci /* disable spy */ 26728c2ecf20Sopenharmony_ci u &= ~INL_CONFIG_RXANNEX; 26738c2ecf20Sopenharmony_ci else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) 26748c2ecf20Sopenharmony_ci /* enable spy */ 26758c2ecf20Sopenharmony_ci u |= INL_CONFIG_RXANNEX; 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci mgt_set(priv, OID_INL_CONFIG, &u); 26788c2ecf20Sopenharmony_ci mgt_commit_list(priv, &oid, 1); 26798c2ecf20Sopenharmony_ci up_write(&priv->mib_sem); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci return iw_handler_set_spy(ndev, info, uwrq, extra); 26828c2ecf20Sopenharmony_ci} 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_cistatic const iw_handler prism54_handler[] = { 26858c2ecf20Sopenharmony_ci (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ 26868c2ecf20Sopenharmony_ci (iw_handler) prism54_get_name, /* SIOCGIWNAME */ 26878c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCSIWNWID */ 26888c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCGIWNWID */ 26898c2ecf20Sopenharmony_ci (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ 26908c2ecf20Sopenharmony_ci (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ 26918c2ecf20Sopenharmony_ci (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ 26928c2ecf20Sopenharmony_ci (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ 26938c2ecf20Sopenharmony_ci (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ 26948c2ecf20Sopenharmony_ci (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ 26958c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCSIWRANGE */ 26968c2ecf20Sopenharmony_ci (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ 26978c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCSIWPRIV */ 26988c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCGIWPRIV */ 26998c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCSIWSTATS */ 27008c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCGIWSTATS */ 27018c2ecf20Sopenharmony_ci prism54_set_spy, /* SIOCSIWSPY */ 27028c2ecf20Sopenharmony_ci iw_handler_get_spy, /* SIOCGIWSPY */ 27038c2ecf20Sopenharmony_ci iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ 27048c2ecf20Sopenharmony_ci iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ 27058c2ecf20Sopenharmony_ci (iw_handler) prism54_set_wap, /* SIOCSIWAP */ 27068c2ecf20Sopenharmony_ci (iw_handler) prism54_get_wap, /* SIOCGIWAP */ 27078c2ecf20Sopenharmony_ci (iw_handler) NULL, /* -- hole -- */ 27088c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCGIWAPLIST deprecated */ 27098c2ecf20Sopenharmony_ci (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ 27108c2ecf20Sopenharmony_ci (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ 27118c2ecf20Sopenharmony_ci (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ 27128c2ecf20Sopenharmony_ci (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ 27138c2ecf20Sopenharmony_ci (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ 27148c2ecf20Sopenharmony_ci (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ 27158c2ecf20Sopenharmony_ci (iw_handler) NULL, /* -- hole -- */ 27168c2ecf20Sopenharmony_ci (iw_handler) NULL, /* -- hole -- */ 27178c2ecf20Sopenharmony_ci (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ 27188c2ecf20Sopenharmony_ci (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ 27198c2ecf20Sopenharmony_ci (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ 27208c2ecf20Sopenharmony_ci (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ 27218c2ecf20Sopenharmony_ci (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ 27228c2ecf20Sopenharmony_ci (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ 27238c2ecf20Sopenharmony_ci (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ 27248c2ecf20Sopenharmony_ci (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ 27258c2ecf20Sopenharmony_ci (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ 27268c2ecf20Sopenharmony_ci (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ 27278c2ecf20Sopenharmony_ci (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ 27288c2ecf20Sopenharmony_ci (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ 27298c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCSIWPOWER */ 27308c2ecf20Sopenharmony_ci (iw_handler) NULL, /* SIOCGIWPOWER */ 27318c2ecf20Sopenharmony_ci NULL, /* -- hole -- */ 27328c2ecf20Sopenharmony_ci NULL, /* -- hole -- */ 27338c2ecf20Sopenharmony_ci (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */ 27348c2ecf20Sopenharmony_ci (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */ 27358c2ecf20Sopenharmony_ci (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */ 27368c2ecf20Sopenharmony_ci (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */ 27378c2ecf20Sopenharmony_ci (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */ 27388c2ecf20Sopenharmony_ci (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */ 27398c2ecf20Sopenharmony_ci NULL, /* SIOCSIWPMKSA */ 27408c2ecf20Sopenharmony_ci}; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci/* The low order bit identify a SET (0) or a GET (1) ioctl. */ 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci#define PRISM54_RESET SIOCIWFIRSTPRIV 27458c2ecf20Sopenharmony_ci#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1 27468c2ecf20Sopenharmony_ci#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2 27478c2ecf20Sopenharmony_ci#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3 27488c2ecf20Sopenharmony_ci#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11 27578c2ecf20Sopenharmony_ci#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci#define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14 27608c2ecf20Sopenharmony_ci#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15 27618c2ecf20Sopenharmony_ci#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 27648c2ecf20Sopenharmony_ci#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18 27658c2ecf20Sopenharmony_ci#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20 27668c2ecf20Sopenharmony_ci#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23 27698c2ecf20Sopenharmony_ci#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } 27728c2ecf20Sopenharmony_ci#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } 27738c2ecf20Sopenharmony_ci#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } 27748c2ecf20Sopenharmony_ci#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x } 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x) 27778c2ecf20Sopenharmony_ci#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x) 27788c2ecf20Sopenharmony_ci#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x) 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci/* Note : limited to 128 private ioctls (wireless tools 26) */ 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_cistatic const struct iw_priv_args prism54_private_args[] = { 27838c2ecf20Sopenharmony_ci/*{ cmd, set_args, get_args, name } */ 27848c2ecf20Sopenharmony_ci {PRISM54_RESET, 0, 0, "reset"}, 27858c2ecf20Sopenharmony_ci {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 27868c2ecf20Sopenharmony_ci "get_prismhdr"}, 27878c2ecf20Sopenharmony_ci {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 27888c2ecf20Sopenharmony_ci "set_prismhdr"}, 27898c2ecf20Sopenharmony_ci {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 27908c2ecf20Sopenharmony_ci "getPolicy"}, 27918c2ecf20Sopenharmony_ci {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 27928c2ecf20Sopenharmony_ci "setPolicy"}, 27938c2ecf20Sopenharmony_ci {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, 27948c2ecf20Sopenharmony_ci {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, 27958c2ecf20Sopenharmony_ci "addMac"}, 27968c2ecf20Sopenharmony_ci {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, 27978c2ecf20Sopenharmony_ci "delMac"}, 27988c2ecf20Sopenharmony_ci {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, 27998c2ecf20Sopenharmony_ci "kickMac"}, 28008c2ecf20Sopenharmony_ci {PRISM54_KICK_ALL, 0, 0, "kickAll"}, 28018c2ecf20Sopenharmony_ci {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 28028c2ecf20Sopenharmony_ci "get_wpa"}, 28038c2ecf20Sopenharmony_ci {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 28048c2ecf20Sopenharmony_ci "set_wpa"}, 28058c2ecf20Sopenharmony_ci {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, 28068c2ecf20Sopenharmony_ci "dbg_oid"}, 28078c2ecf20Sopenharmony_ci {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"}, 28088c2ecf20Sopenharmony_ci {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"}, 28098c2ecf20Sopenharmony_ci /* --- sub-ioctls handlers --- */ 28108c2ecf20Sopenharmony_ci {PRISM54_GET_OID, 28118c2ecf20Sopenharmony_ci 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""}, 28128c2ecf20Sopenharmony_ci {PRISM54_SET_OID_U32, 28138c2ecf20Sopenharmony_ci IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, 28148c2ecf20Sopenharmony_ci {PRISM54_SET_OID_STR, 28158c2ecf20Sopenharmony_ci IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, 28168c2ecf20Sopenharmony_ci {PRISM54_SET_OID_ADDR, 28178c2ecf20Sopenharmony_ci IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, 28188c2ecf20Sopenharmony_ci /* --- sub-ioctls definitions --- */ 28198c2ecf20Sopenharmony_ci IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"), 28208c2ecf20Sopenharmony_ci IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"), 28218c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"), 28228c2ecf20Sopenharmony_ci IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"), 28238c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_STATE, "state"), 28248c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_AID, "aid"), 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"), 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"), 28298c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"), 28308c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"), 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"), 28338c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"), 28348c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"), 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"), 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"), 28398c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"), 28408c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"), 28418c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"), 28428c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_PSM, "psm"), 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"), 28458c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_CLIENTS, "clients"), 28468c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"), 28478c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"), 28488c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"), 28498c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"), 28508c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"), 28518c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"), 28528c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"), 28538c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_RATES, "rates"), 28548c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"), 28558c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"), 28568c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"), 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"), 28598c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"), 28608c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"), 28618c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_PROFILES, "profile"), 28628c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"), 28638c2ecf20Sopenharmony_ci IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"), 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_BSSS, "bsss"), 28668c2ecf20Sopenharmony_ci IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"), 28678c2ecf20Sopenharmony_ci IWPRIV_U32(OID_INL_MODE, "mode"), 28688c2ecf20Sopenharmony_ci IWPRIV_U32(OID_INL_CONFIG, "config"), 28698c2ecf20Sopenharmony_ci IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"), 28708c2ecf20Sopenharmony_ci IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"), 28718c2ecf20Sopenharmony_ci IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"), 28728c2ecf20Sopenharmony_ci}; 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_cistatic const iw_handler prism54_private_handler[] = { 28758c2ecf20Sopenharmony_ci (iw_handler) prism54_reset, 28768c2ecf20Sopenharmony_ci (iw_handler) prism54_get_policy, 28778c2ecf20Sopenharmony_ci (iw_handler) prism54_set_policy, 28788c2ecf20Sopenharmony_ci (iw_handler) prism54_get_mac, 28798c2ecf20Sopenharmony_ci (iw_handler) prism54_add_mac, 28808c2ecf20Sopenharmony_ci (iw_handler) NULL, 28818c2ecf20Sopenharmony_ci (iw_handler) prism54_del_mac, 28828c2ecf20Sopenharmony_ci (iw_handler) NULL, 28838c2ecf20Sopenharmony_ci (iw_handler) prism54_kick_mac, 28848c2ecf20Sopenharmony_ci (iw_handler) NULL, 28858c2ecf20Sopenharmony_ci (iw_handler) prism54_kick_all, 28868c2ecf20Sopenharmony_ci (iw_handler) prism54_get_wpa, 28878c2ecf20Sopenharmony_ci (iw_handler) prism54_set_wpa, 28888c2ecf20Sopenharmony_ci (iw_handler) NULL, 28898c2ecf20Sopenharmony_ci (iw_handler) prism54_debug_oid, 28908c2ecf20Sopenharmony_ci (iw_handler) prism54_debug_get_oid, 28918c2ecf20Sopenharmony_ci (iw_handler) prism54_debug_set_oid, 28928c2ecf20Sopenharmony_ci (iw_handler) prism54_get_oid, 28938c2ecf20Sopenharmony_ci (iw_handler) prism54_set_u32, 28948c2ecf20Sopenharmony_ci (iw_handler) NULL, 28958c2ecf20Sopenharmony_ci (iw_handler) prism54_set_raw, 28968c2ecf20Sopenharmony_ci (iw_handler) NULL, 28978c2ecf20Sopenharmony_ci (iw_handler) prism54_set_raw, 28988c2ecf20Sopenharmony_ci (iw_handler) prism54_get_prismhdr, 28998c2ecf20Sopenharmony_ci (iw_handler) prism54_set_prismhdr, 29008c2ecf20Sopenharmony_ci}; 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ciconst struct iw_handler_def prism54_handler_def = { 29038c2ecf20Sopenharmony_ci .num_standard = ARRAY_SIZE(prism54_handler), 29048c2ecf20Sopenharmony_ci .num_private = ARRAY_SIZE(prism54_private_handler), 29058c2ecf20Sopenharmony_ci .num_private_args = ARRAY_SIZE(prism54_private_args), 29068c2ecf20Sopenharmony_ci .standard = (iw_handler *) prism54_handler, 29078c2ecf20Sopenharmony_ci .private = (iw_handler *) prism54_private_handler, 29088c2ecf20Sopenharmony_ci .private_args = (struct iw_priv_args *) prism54_private_args, 29098c2ecf20Sopenharmony_ci .get_wireless_stats = prism54_get_wireless_stats, 29108c2ecf20Sopenharmony_ci}; 2911