diff options
author | Simon Shields <keepcalm444@gmail.com> | 2016-02-02 18:50:31 +1100 |
---|---|---|
committer | Simon Shields <keepcalm444@gmail.com> | 2016-02-07 13:11:19 -0800 |
commit | ab9d1a800a5a963e99f34c5f6fe62be33293ff80 (patch) | |
tree | a724afad2417c8136e2b4906d9938fe2af201261 /drivers/net/wireless/bcmdhd/wl_iw.c | |
parent | 43eae3bb1ab429b1b88bd8c8558b685987f09521 (diff) | |
download | kernel_samsung_smdk4412-ab9d1a800a5a963e99f34c5f6fe62be33293ff80.zip kernel_samsung_smdk4412-ab9d1a800a5a963e99f34c5f6fe62be33293ff80.tar.gz kernel_samsung_smdk4412-ab9d1a800a5a963e99f34c5f6fe62be33293ff80.tar.bz2 |
bcmdhd: update from i9305 source drop
Change-Id: I9ca02d8460a92d6664072253f4204d61f01df49b
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_iw.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_iw.c | 721 |
1 files changed, 398 insertions, 323 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index b2acd6a..c78f279 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2014, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.c 367054 2012-11-06 15:06:04Z $ + * $Id: wl_iw.c 425990 2013-09-26 07:28:16Z $ */ #if defined(USE_IW) @@ -38,7 +38,6 @@ #include <linux/if_arp.h> #include <asm/uaccess.h> - typedef const struct si_pub si_t; #include <wlioctl.h> @@ -47,7 +46,7 @@ typedef const struct si_pub si_t; #include <wl_iw.h> #ifdef BCMWAPI_WPI - +/* these items should evetually go into wireless.h of the linux system headfile dir */ #ifndef IW_ENCODE_ALG_SM4 #define IW_ENCODE_ALG_SM4 0x20 #endif @@ -71,9 +70,9 @@ typedef const struct si_pub si_t; #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT #define IW_AUTH_KEY_MGMT_WAPI_CERT 8 #endif -#endif - +#endif /* BCMWAPI_WPI */ +/* Broadcom extensions to WEXT, linux upstream has obsoleted WEXT */ #ifndef IW_AUTH_KEY_MGMT_FT_802_1X #define IW_AUTH_KEY_MGMT_FT_802_1X 0x04 #endif @@ -82,22 +81,29 @@ typedef const struct si_pub si_t; #define IW_AUTH_KEY_MGMT_FT_PSK 0x08 #endif +#ifndef IW_ENC_CAPA_FW_ROAM_ENABLE +#define IW_ENC_CAPA_FW_ROAM_ENABLE 0x00000020 +#endif + +/* FC9: wireless.h 2.6.25-14.fc9.i686 is missing these, even though WIRELESS_EXT is set to latest + * version 22. + */ #ifndef IW_ENCODE_ALG_PMK #define IW_ENCODE_ALG_PMK 4 #endif #ifndef IW_ENC_CAPA_4WAY_HANDSHAKE #define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 #endif - +/* End FC9. */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) #include <linux/rtnetlink.h> #endif #if defined(SOFTAP) struct net_device *ap_net_dev = NULL; -tsk_ctl_t ap_eth_ctl; -#endif +tsk_ctl_t ap_eth_ctl; /* apsta AP netdev waiter thread */ +#endif /* SOFTAP */ extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen); @@ -106,13 +112,13 @@ uint wl_msg_level = WL_ERROR_VAL; #define MAX_WLIW_IOCTL_LEN 1024 - -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i +/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */ +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); extern int dhd_wait_pend8021x(struct net_device *dev); @@ -120,26 +126,32 @@ extern int dhd_wait_pend8021x(struct net_device *dev); #if WIRELESS_EXT < 19 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) -#endif +#endif /* WIRELESS_EXT < 19 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define DAEMONIZE(a) do { \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); \ + } while (0) +#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) #define DAEMONIZE(a) daemonize(a); \ allow_signal(SIGKILL); \ allow_signal(SIGTERM); -#else +#else /* Linux 2.4 (w/o preemption patch) */ #define RAISE_RX_SOFTIRQ() \ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) #define DAEMONIZE(a) daemonize(); \ do { if (a) \ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ } while (0); -#endif +#endif /* LINUX_VERSION_CODE */ #define ISCAN_STATE_IDLE 0 #define ISCAN_STATE_SCANING 1 - +/* the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */ #define WLC_IW_ISCAN_MAXLEN 2048 typedef struct iscan_buf { struct iscan_buf * next; @@ -155,7 +167,10 @@ typedef struct iscan_info { iscan_buf_t * list_hdr; iscan_buf_t * list_cur; - + /* Thread to work on iscan */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + struct task_struct *kthread; +#endif long sysioc_pid; struct semaphore sysioc_sem; struct completion sysioc_exited; @@ -168,19 +183,19 @@ static void wl_iw_timerfunc(ulong data); static void wl_iw_set_event_mask(struct net_device *dev); static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); - +/* priv_link becomes netdev->priv and is the link between netdev and wlif struct */ typedef struct priv_link { wl_iw_t *wliw; } priv_link_t; - +/* dev to priv_link */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) #define WL_DEV_LINK(dev) (priv_link_t*)(dev->priv) #else #define WL_DEV_LINK(dev) (priv_link_t*)netdev_priv(dev) #endif - +/* dev to wl_iw_t */ #define IW_DEV_IF(dev) ((wl_iw_t*)(WL_DEV_LINK(dev))->wliw) static void swap_key_from_BE( @@ -230,11 +245,6 @@ dev_wlc_ioctl( strcpy(ifr.ifr_name, dev->name); ifr.ifr_data = (caddr_t) &ioc; -#ifndef LINUX_HYBRID - - dev_open(dev); -#endif - fs = get_fs(); set_fs(get_ds()); #if defined(WL_USE_NETDEV_OPS) @@ -247,7 +257,10 @@ dev_wlc_ioctl( return ret; } - +/* +set named driver variable to int value and return error indication +calling example: dev_wlc_intvar_set(dev, "arate", rate) +*/ static int dev_wlc_intvar_set( @@ -323,9 +336,12 @@ dev_wlc_bufvar_set( kfree(ioctlbuf); return error; } -#endif - +#endif /* WIRELESS_EXT > 17 */ +/* +get named driver variable to int value and return error indication +calling example: dev_wlc_bufvar_get(dev, "arate", &rate) +*/ static int dev_wlc_bufvar_get( @@ -352,7 +368,10 @@ dev_wlc_bufvar_get( return (error); } - +/* +get named driver variable to int value and return error indication +calling example: dev_wlc_intvar_get(dev, "arate", &rate) +*/ static int dev_wlc_intvar_get( @@ -378,17 +397,17 @@ dev_wlc_intvar_get( return (error); } - +/* Maintain backward compatibility */ #if WIRELESS_EXT < 13 struct iw_request_info { - __u16 cmd; - __u16 flags; + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ }; typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, void *wrqu, char *extra); -#endif +#endif /* WIRELESS_EXT < 13 */ #if WIRELESS_EXT > 12 static int @@ -437,7 +456,10 @@ wl_iw_set_pm( error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); return error; } -#endif + +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ +#endif /* WIRELESS_EXT > 12 */ int wl_iw_send_priv_event( @@ -553,14 +575,14 @@ wl_iw_set_freq( WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name)); - + /* Setting by channel number */ if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { chan = fwrq->m; } - + /* Setting by frequency */ else { - + /* Convert to MHz as best we can */ if (fwrq->e >= 6) { fwrq->e -= 6; while (fwrq->e--) @@ -569,9 +591,9 @@ wl_iw_set_freq( while (fwrq->e++ < 6) fwrq->m /= 10; } - + /* handle 4.9GHz frequencies as Japan 4 GHz based channelization */ if (fwrq->m > 4000 && fwrq->m < 5000) - sf = WF_CHAN_FACTOR_4_G; + sf = WF_CHAN_FACTOR_4_G; /* start factor for 4 GHz */ chan = wf_mhz2channel(fwrq->m, sf); } @@ -579,7 +601,7 @@ wl_iw_set_freq( if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) return error; - + /* -EINPROGRESS: Call commit handler */ return -EINPROGRESS; } @@ -599,7 +621,7 @@ wl_iw_get_freq( if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) return error; - + /* Return radio channel in channel form */ fwrq->m = dtoh32(ci.hw_channel); fwrq->e = dtoh32(0); return 0; @@ -637,7 +659,7 @@ wl_iw_set_mode( (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap)))) return error; - + /* -EINPROGRESS: Call commit handler */ return -EINPROGRESS; } @@ -697,10 +719,10 @@ wl_iw_get_range( dwrq->length = sizeof(struct iw_range); memset(range, 0, sizeof(*range)); - + /* We don't use nwids */ range->min_nwid = range->max_nwid = 0; - + /* Set available channels/frequencies */ list->count = htod32(MAXCHANNEL); if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) return error; @@ -718,31 +740,31 @@ wl_iw_get_range( } range->num_frequency = range->num_channels = i; - + /* Link quality (use NDIS cutoffs) */ range->max_qual.qual = 5; - - range->max_qual.level = 0x100 - 200; - - range->max_qual.noise = 0x100 - 200; - + /* Signal level (use RSSI) */ + range->max_qual.level = 0x100 - 200; /* -200 dBm */ + /* Noise level (use noise) */ + range->max_qual.noise = 0x100 - 200; /* -200 dBm */ + /* Signal level threshold range (?) */ range->sensitivity = 65535; #if WIRELESS_EXT > 11 - + /* Link quality (use NDIS cutoffs) */ range->avg_qual.qual = 3; - + /* Signal level (use RSSI) */ range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD; - - range->avg_qual.noise = 0x100 - 75; -#endif + /* Noise level (use noise) */ + range->avg_qual.noise = 0x100 - 75; /* -75 dBm */ +#endif /* WIRELESS_EXT > 11 */ - + /* Set available bitrates */ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) return error; rateset.count = dtoh32(rateset.count); range->num_bitrates = rateset.count; for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) - range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; + range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; /* convert to bps */ if ((error = dev_wlc_intvar_get(dev, "nmode", &nmode))) return error; if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)))) @@ -772,22 +794,26 @@ wl_iw_get_range( nrate_list2copy = 3; } range->num_bitrates += 8; + ASSERT(range->num_bitrates < IW_MAX_BITRATES); for (k = 0; i < range->num_bitrates; k++, i++) { - + /* convert to bps */ range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; } } - + /* Set an indication of the max TCP throughput + * in bit/s that we can expect using this interface. + * May be use for QoS stuff... Jean II + */ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) return error; i = dtoh32(i); if (i == WLC_PHY_TYPE_A) - range->throughput = 24000000; + range->throughput = 24000000; /* 24 Mbits/s */ else - range->throughput = 1500000; + range->throughput = 1500000; /* 1.5 Mbits/s */ - + /* RTS and fragmentation thresholds */ range->min_rts = 0; range->max_rts = 2347; range->min_frag = 256; @@ -804,7 +830,7 @@ wl_iw_get_range( #endif range->encoding_size[3] = AES_KEY_SIZE; - + /* Do not support power micro-management */ range->min_pmp = 0; range->max_pmp = 0; range->min_pmt = 0; @@ -812,7 +838,7 @@ wl_iw_get_range( range->pmp_flags = 0; range->pm_capa = 0; - + /* Transmit Power - values are in mW */ range->num_txpower = 2; range->txpower[0] = 1; range->txpower[1] = 255; @@ -822,17 +848,17 @@ wl_iw_get_range( range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 19; - + /* Only support retry limits */ range->retry_capa = IW_RETRY_LIMIT; range->retry_flags = IW_RETRY_LIMIT; range->r_time_flags = 0; - + /* SRL and LRL limits */ range->min_retry = 1; range->max_retry = 255; - + /* Retry lifetime limits unsupported */ range->min_r_time = 0; range->max_r_time = 0; -#endif +#endif /* WIRELESS_EXT > 10 */ #if WIRELESS_EXT > 17 range->enc_capa = IW_ENC_CAPA_WPA; @@ -840,17 +866,22 @@ wl_iw_get_range( range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; range->enc_capa |= IW_ENC_CAPA_WPA2; - + /* Determine driver FBT capability. */ if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) { if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) { - + /* Tell the host (e.g. wpa_supplicant) to let driver do the handshake */ range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE; } } - +#ifdef BCMFW_ROAM_ENABLE_WEXT + /* Advertise firmware roam capability to the external supplicant */ + range->enc_capa |= IW_ENC_CAPA_FW_ROAM_ENABLE; +#endif /* BCMFW_ROAM_ENABLE_WEXT */ + + /* Event capability (kernel) */ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); - + /* Event capability (driver) */ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); @@ -860,10 +891,10 @@ wl_iw_get_range( IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); #if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID) - + /* FC7 wireless.h defines EXT 22 but doesn't define scan_capa bits */ range->scan_capa = IW_SCAN_CAPA_ESSID; #endif -#endif +#endif /* WIRELESS_EXT > 17 */ return 0; } @@ -956,7 +987,7 @@ wl_iw_set_wap( return -EINVAL; } - + /* Ignore "auto" or "off" */ if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { scb_val_t scbval; bzero(&scbval, sizeof(scb_val_t)); @@ -965,8 +996,10 @@ wl_iw_set_wap( } return 0; } - - + /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data), + * eabuf))); + */ + /* Reassociate to the specified AP */ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { WL_ERROR(("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error)); return error; @@ -988,7 +1021,7 @@ wl_iw_get_wap( awrq->sa_family = ARPHRD_ETHER; memset(awrq->sa_data, 0, ETHER_ADDR_LEN); - + /* Ignore error (may be down or disassociated) */ (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); return 0; @@ -1034,7 +1067,7 @@ wl_iw_mlme( return error; } -#endif +#endif /* WIRELESS_EXT > 17 */ static int wl_iw_get_aplist( @@ -1056,7 +1089,7 @@ wl_iw_get_aplist( if (!extra) return -EINVAL; - + /* Get scan results (too large to put on the stack) */ list = kmalloc(buflen, GFP_KERNEL); if (!list) return -ENOMEM; @@ -1077,23 +1110,23 @@ wl_iw_get_aplist( ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + buflen)); - + /* Infrastructure only */ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - + /* BSSID */ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); qual[dwrq->length].noise = 0x100 + bi->phy_noise; - + /* Updated qual, level, and noise */ #if WIRELESS_EXT > 18 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else qual[dwrq->length].updated = 7; -#endif +#endif /* WIRELESS_EXT > 18 */ dwrq->length++; } @@ -1102,7 +1135,7 @@ wl_iw_get_aplist( if (dwrq->length) { memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); - + /* Provided qual */ dwrq->flags = 1; } @@ -1136,7 +1169,7 @@ wl_iw_iscan_get_aplist( } buf = iscan->list_hdr; - + /* Get scan results (too large to put on the stack) */ while (buf) { list = &((wl_iscan_results_t*)buf->iscan_buf)->results; ASSERT(list->version == WL_BSS_INFO_VERSION); @@ -1147,23 +1180,23 @@ wl_iw_iscan_get_aplist( ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)); - + /* Infrastructure only */ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - + /* BSSID */ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); qual[dwrq->length].noise = 0x100 + bi->phy_noise; - + /* Updated qual, level, and noise */ #if WIRELESS_EXT > 18 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else qual[dwrq->length].updated = 7; -#endif +#endif /* WIRELESS_EXT > 18 */ dwrq->length++; } @@ -1171,7 +1204,7 @@ wl_iw_iscan_get_aplist( } if (dwrq->length) { memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); - + /* Provided qual */ dwrq->flags = 1; } @@ -1191,11 +1224,11 @@ wl_iw_set_scan( WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); - + /* default Broadcast scan */ memset(&ssid, 0, sizeof(ssid)); #if WIRELESS_EXT > 17 - + /* check for given essid */ if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { struct iw_scan_req *req = (struct iw_scan_req *)extra; @@ -1205,7 +1238,7 @@ wl_iw_set_scan( } } #endif - + /* Ignore error (most likely scan in progress) */ (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid)); return 0; @@ -1224,7 +1257,7 @@ wl_iw_iscan_set_scan( WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); - + /* use backup if our thread is not successful */ if ((!iscan) || (iscan->sysioc_pid < 0)) { return wl_iw_set_scan(dev, info, wrqu, extra); } @@ -1232,11 +1265,11 @@ wl_iw_iscan_set_scan( return 0; } - + /* default Broadcast scan */ memset(&ssid, 0, sizeof(ssid)); #if WIRELESS_EXT > 17 - + /* check for given essid */ if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { struct iw_scan_req *req = (struct iw_scan_req *)extra; @@ -1265,21 +1298,21 @@ wl_iw_iscan_set_scan( static bool ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) { - - +/* Is this body of this tlvs entry a WPA entry? If */ +/* not update the tlvs buffer pointer/length */ uint8 *ie = *wpaie; - + /* If the contents match the WPA_OUI and type=1 */ if ((ie[1] >= 6) && !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { return TRUE; } - + /* point to the next ie */ ie += ie[1] + 2; - + /* calculate the length of the rest of the buffer */ *tlvs_len -= (int)(ie - *tlvs); - + /* update the pointer to the start of the buffer */ *tlvs = ie; return FALSE; } @@ -1287,25 +1320,25 @@ ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) static bool ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) { - - +/* Is this body of this tlvs entry a WPS entry? If */ +/* not update the tlvs buffer pointer/length */ uint8 *ie = *wpsie; - + /* If the contents match the WPA_OUI and type=4 */ if ((ie[1] >= 4) && !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { return TRUE; } - + /* point to the next ie */ ie += ie[1] + 2; - + /* calculate the length of the rest of the buffer */ *tlvs_len -= (int)(ie - *tlvs); - + /* update the pointer to the start of the buffer */ *tlvs = ie; return FALSE; } -#endif +#endif /* WIRELESS_EXT > 17 */ #ifdef BCMWAPI_WPI static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, @@ -1329,13 +1362,20 @@ static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, return pos - buf; } - +/** + * wpa_snprintf_hex - Print data as a hex string into a buffer + * @buf: Memory area to use as the output buffer + * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) + * @data: Data to be printed + * @len: Length of data in bytes + * Returns: Number of bytes written + */ static int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) { return _wpa_snprintf_hex(buf, buf_size, data, len, 0); } -#endif +#endif /* BCMWAPI_WPI */ static int wl_iw_handle_scanresults_ies(char **event_p, char *end, @@ -1351,7 +1391,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, event = *event_p; if (bi->ie_length) { - + /* look for wpa/rsn ies in the ie list... */ bcm_tlv_t *ie; uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); int ptr_len = bi->ie_length; @@ -1371,7 +1411,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { - + /* look for WPS IE */ if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie->len + 2; @@ -1401,7 +1441,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, iwe.cmd = IWEVGENIE; iwe.u.data.length = ie->len + 2; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); -#else +#else /* using CUSTOM event */ iwe.cmd = IWEVCUSTOM; custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2); iwe.u.data.length = custom_event_len; @@ -1419,14 +1459,14 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len); event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf); kfree(buf); -#endif +#endif /* WAPI_IE_USE_GENIE */ break; } -#endif +#endif /* BCMWAPI_WPI */ *event_p = event; } -#endif +#endif /* WIRELESS_EXT > 17 */ return 0; } static int @@ -1450,14 +1490,14 @@ wl_iw_get_scan( if (!extra) return -EINVAL; - + /* Check for scan in progress */ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) return error; ci.scan_channel = dtoh32(ci.scan_channel); if (ci.scan_channel) return -EAGAIN; - + /* Get scan results (too large to put on the stack) */ list = kmalloc(buflen, GFP_KERNEL); if (!list) return -ENOMEM; @@ -1478,19 +1518,19 @@ wl_iw_get_scan( ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + buflen)); - + /* First entry must be the BSSID */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); - + /* SSID */ iwe.u.data.length = dtoh32(bi->SSID_len); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - + /* Mode */ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (dtoh16(bi->capability) & DOT11_CAP_ESS) @@ -1500,7 +1540,7 @@ wl_iw_get_scan( event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); } - + /* Channel */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? @@ -1508,17 +1548,17 @@ wl_iw_get_scan( iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); - + /* Channel quality */ iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); iwe.u.qual.noise = 0x100 + bi->phy_noise; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); - + /* WPA, WPA2, WPS, WAPI IEs */ wl_iw_handle_scanresults_ies(&event, end, info, bi); - + /* Encryption */ iwe.cmd = SIOCGIWENCODE; if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; @@ -1527,11 +1567,11 @@ wl_iw_get_scan( iwe.u.data.length = 0; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - + /* Rates */ if (bi->rateset.count) { value = event + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; - + /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; @@ -1545,7 +1585,7 @@ wl_iw_get_scan( kfree(list); dwrq->length = event - extra; - dwrq->flags = 0; + dwrq->flags = 0; /* todo */ return 0; } @@ -1572,18 +1612,18 @@ wl_iw_iscan_get_scan( if (!extra) return -EINVAL; - + /* use backup if our thread is not successful */ if ((!iscan) || (iscan->sysioc_pid < 0)) { return wl_iw_get_scan(dev, info, dwrq, extra); } - + /* Check for scan in progress */ if (iscan->iscan_state == ISCAN_STATE_SCANING) return -EAGAIN; apcnt = 0; p_buf = iscan->list_hdr; - + /* Get scan results */ while (p_buf != iscan->list_cur) { list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; @@ -1597,23 +1637,23 @@ wl_iw_iscan_get_scan( ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)); - + /* overflow check cover fields before wpa IEs */ if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end) return -E2BIG; - + /* First entry must be the BSSID */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); - + /* SSID */ iwe.u.data.length = dtoh32(bi->SSID_len); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - + /* Mode */ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (dtoh16(bi->capability) & DOT11_CAP_ESS) @@ -1623,7 +1663,7 @@ wl_iw_iscan_get_scan( event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); } - + /* Channel */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? @@ -1631,17 +1671,17 @@ wl_iw_iscan_get_scan( iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); - + /* Channel quality */ iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); iwe.u.qual.noise = 0x100 + bi->phy_noise; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); - + /* WPA, WPA2, WPS, WAPI IEs */ wl_iw_handle_scanresults_ies(&event, end, info, bi); - + /* Encryption */ iwe.cmd = SIOCGIWENCODE; if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; @@ -1650,14 +1690,14 @@ wl_iw_iscan_get_scan( iwe.u.data.length = 0; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - + /* Rates */ if (bi->rateset.count <= sizeof(bi->rateset.rates)) { if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) return -E2BIG; value = event + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; - + /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; @@ -1668,15 +1708,15 @@ wl_iw_iscan_get_scan( } } p_buf = p_buf->next; - } + } /* while (p_buf) */ dwrq->length = event - extra; - dwrq->flags = 0; + dwrq->flags = 0; /* todo */ return 0; } -#endif +#endif /* WIRELESS_EXT > 13 */ static int @@ -1692,7 +1732,7 @@ wl_iw_set_essid( WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); - + /* default Broadcast SSID */ memset(&ssid, 0, sizeof(ssid)); if (dwrq->length && extra) { #if WIRELESS_EXT > 20 @@ -1706,7 +1746,7 @@ wl_iw_set_essid( if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) return error; } - + /* If essid null then it is "iwconfig <interface> essid off" command */ else { scb_val_t scbval; bzero(&scbval, sizeof(scb_val_t)); @@ -1739,12 +1779,12 @@ wl_iw_get_essid( ssid.SSID_len = dtoh32(ssid.SSID_len); - + /* Get the current SSID */ memcpy(extra, ssid.SSID, ssid.SSID_len); dwrq->length = ssid.SSID_len; - dwrq->flags = 1; + dwrq->flags = 1; /* active */ return 0; } @@ -1763,7 +1803,7 @@ wl_iw_set_nick( if (!extra) return -EINVAL; - + /* Check the size of the string */ if (dwrq->length > sizeof(iw->nickname)) return -E2BIG; @@ -1805,47 +1845,53 @@ static int wl_iw_set_rate( WL_TRACE(("%s: SIOCSIWRATE\n", dev->name)); - + /* Get current rateset */ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) return error; rateset.count = dtoh32(rateset.count); if (vwrq->value < 0) { - + /* Select maximum rate */ rate = rateset.rates[rateset.count - 1] & 0x7f; } else if (vwrq->value < rateset.count) { - + /* Select rate by rateset index */ rate = rateset.rates[vwrq->value] & 0x7f; } else { - + /* Specified rate in bps */ rate = vwrq->value / 500000; } if (vwrq->fixed) { - + /* + Set rate override, + Since the is a/b/g-blind, both a/bg_rate are enforced. + */ error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); error_a = dev_wlc_intvar_set(dev, "a_rate", rate); if (error_bg && error_a) return (error_bg | error_a); } else { - - + /* + clear rate override + Since the is a/b/g-blind, both a/bg_rate are enforced. + */ + /* 0 is for clearing rate override */ error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); - + /* 0 is for clearing rate override */ error_a = dev_wlc_intvar_set(dev, "a_rate", 0); if (error_bg && error_a) return (error_bg | error_a); - + /* Remove rates above selected rate */ for (i = 0; i < rateset.count; i++) if ((rateset.rates[i] & 0x7f) > rate) break; rateset.count = htod32(i); - + /* Set current rateset */ if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) return error; } @@ -1864,7 +1910,7 @@ static int wl_iw_get_rate( WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); - + /* Report the current tx rate */ if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) return error; rate = dtoh32(rate); @@ -1979,7 +2025,7 @@ wl_iw_set_txpow( uint16 txpwrmw; WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); - + /* Make sure radio is off or on as far as software is concerned */ disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; disable += WL_RADIO_SW_DISABLE << 16; @@ -1987,15 +2033,15 @@ wl_iw_set_txpow( if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable)))) return error; - + /* If Radio is off, nothing more to do */ if (disable & WL_RADIO_SW_DISABLE) return 0; - + /* Only handle mW */ if (!(vwrq->flags & IW_TXPOW_MWATT)) return -EINVAL; - + /* Value < 0 means just "on" or "off" */ if (vwrq->value < 0) return 0; @@ -2047,31 +2093,31 @@ wl_iw_set_retry( WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); - + /* Do not handle "off" or "lifetime" */ if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) return -EINVAL; - + /* Handle "[min|max] limit" */ if (vwrq->flags & IW_RETRY_LIMIT) { - + /* "max limit" or just "limit" */ #if WIRELESS_EXT > 20 if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { #else if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { -#endif +#endif /* WIRELESS_EXT > 20 */ lrl = htod32(vwrq->value); if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) return error; } - + /* "min limit" or just "limit" */ #if WIRELESS_EXT > 20 if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { #else if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { -#endif +#endif /* WIRELESS_EXT > 20 */ srl = htod32(vwrq->value); if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) @@ -2094,13 +2140,13 @@ wl_iw_get_retry( WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); - vwrq->disabled = 0; + vwrq->disabled = 0; /* Can't be disabled */ - + /* Do not handle lifetime queries */ if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) return -EINVAL; - + /* Get retry limits */ if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) || (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl)))) return error; @@ -2108,7 +2154,7 @@ wl_iw_get_retry( lrl = dtoh32(lrl); srl = dtoh32(srl); - + /* Note : by default, display the min retry number */ if (vwrq->flags & IW_RETRY_MAX) { vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; vwrq->value = lrl; @@ -2121,7 +2167,7 @@ wl_iw_get_retry( return 0; } -#endif +#endif /* WIRELESS_EXT > 10 */ static int wl_iw_set_encode( @@ -2139,7 +2185,7 @@ wl_iw_set_encode( memset(&key, 0, sizeof(key)); if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { - + /* Find the current key */ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { val = htod32(key.index); if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) @@ -2148,7 +2194,7 @@ wl_iw_set_encode( if (val) break; } - + /* Default to 0 */ if (key.index == DOT11_MAX_DEFAULT_KEYS) key.index = 0; } else { @@ -2157,15 +2203,15 @@ wl_iw_set_encode( return -EINVAL; } - + /* Interpret "off" to mean no encryption */ wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED; if ((error = dev_wlc_intvar_set(dev, "wsec", wsec))) return error; - + /* Old API used to pass a NULL pointer instead of IW_ENCODE_NOKEY */ if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) { - + /* Just select a new current key */ val = htod32(key.index); if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val)))) return error; @@ -2197,13 +2243,13 @@ wl_iw_set_encode( return -EINVAL; } - + /* Set the new key/index */ swap_key_from_BE(&key); if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)))) return error; } - + /* Interpret "restricted" to mean shared key authentication */ val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0; val = htod32(val); if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)))) @@ -2225,11 +2271,11 @@ wl_iw_get_encode( WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name)); - + /* assure default values of zero for things we don't touch */ bzero(&key, sizeof(wl_wsec_key_t)); if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { - + /* Find the current key */ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { val = key.index; if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) @@ -2244,7 +2290,7 @@ wl_iw_get_encode( if (key.index >= DOT11_MAX_DEFAULT_KEYS) key.index = 0; - + /* Get info */ if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) || (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth)))) @@ -2254,21 +2300,21 @@ wl_iw_get_encode( wsec = dtoh32(wsec); auth = dtoh32(auth); - + /* Get key length */ dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len); - + /* Get flags */ dwrq->flags = key.index + 1; if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) { - + /* Interpret "off" to mean no encryption */ dwrq->flags |= IW_ENCODE_DISABLED; } if (auth) { - + /* Interpret "restricted" to mean shared key authentication */ dwrq->flags |= IW_ENCODE_RESTRICTED; } - + /* Get key */ if (dwrq->length && extra) memcpy(extra, key.data, dwrq->length); @@ -2378,34 +2424,34 @@ wl_iw_set_encodeext( memset(&key, 0, sizeof(key)); iwe = (struct iw_encode_ext *)extra; - + /* disable encryption completely */ if (dwrq->flags & IW_ENCODE_DISABLED) { } - + /* get the key index */ key.index = 0; if (dwrq->flags & IW_ENCODE_INDEX) key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; key.len = iwe->key_len; - + /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */ if (!ETHER_ISMULTI(iwe->addr.sa_data)) bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); - + /* check for key index change */ if (key.len == 0) { if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { WL_WSEC(("Changing the the primary Key to %d\n", key.index)); - + /* change the key index .... */ key.index = htod32(key.index); error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &key.index, sizeof(key.index)); if (error) return error; } - + /* key delete */ else { swap_key_from_BE(&key); error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); @@ -2413,7 +2459,10 @@ wl_iw_set_encodeext( return error; } } - + /* This case is used to allow an external 802.1x supplicant + * to pass the PMK to the in-driver supplicant for use in + * the 4-way handshake. + */ else if (iwe->alg == IW_ENCODE_ALG_PMK) { int j; wsec_pmk_t pmk; @@ -2421,7 +2470,7 @@ wl_iw_set_encodeext( char* charptr = keystring; uint len; - + /* copy the raw hex key to the appropriate format */ for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { sprintf(charptr, "%02x", iwe->key[j]); charptr += 2; @@ -2455,7 +2504,7 @@ wl_iw_set_encodeext( bcopy(keybuf, &key.data[16], sizeof(keybuf)); } - + /* rx iv */ if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { uchar *ivptr; ivptr = (uchar *)iwe->rx_seq; @@ -2591,7 +2640,7 @@ wl_iw_set_pmksa( dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); return 0; } -#endif +#endif /* WIRELESS_EXT > 17 */ static int wl_iw_get_encodeext( @@ -2631,7 +2680,7 @@ wl_iw_set_wpaauth( switch (paramid) { case IW_AUTH_WPA_VERSION: - + /* supported wpa version disabled or wpa or wpa2 */ if (paramval & IW_AUTH_WPA_VERSION_DISABLED) val = WPA_AUTH_DISABLED; else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) @@ -2692,7 +2741,9 @@ wl_iw_set_wpaauth( if ((error = dev_wlc_intvar_set(dev, "wsec", val))) return error; - + /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way + * handshake. + */ if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) { if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) { if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val & AES_ENABLED)) { @@ -2742,7 +2793,7 @@ wl_iw_set_wpaauth( break; case IW_AUTH_80211_AUTH_ALG: - + /* open shared */ WL_ERROR(("Setting the D11auth %d\n", paramval)); if (paramval & IW_AUTH_ALG_OPEN_SYSTEM) val = 0; @@ -2762,7 +2813,7 @@ wl_iw_set_wpaauth( return error; } else { - + /* If WPA is enabled, wpa_auth is set elsewhere */ } break; @@ -2778,7 +2829,7 @@ wl_iw_set_wpaauth( case IW_AUTH_ROAMING_CONTROL: WL_TRACE(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); - + /* driver control or user space app control */ break; case IW_AUTH_PRIVACY_INVOKED: { @@ -2796,7 +2847,7 @@ wl_iw_set_wpaauth( return error; if (!WSEC_ENABLED(wsec)) { - + /* if privacy is true, but wsec is false, we are a WPS enrollee */ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); return error; @@ -2812,7 +2863,7 @@ wl_iw_set_wpaauth( } -#endif +#endif /* WIRELESS_EXT > 17 */ #ifdef BCMWAPI_WPI @@ -2836,7 +2887,7 @@ wl_iw_set_wpaauth( break; -#endif +#endif /* BCMWAPI_WPI */ default: break; @@ -2865,7 +2916,7 @@ wl_iw_get_wpaauth( switch (paramid) { case IW_AUTH_WPA_VERSION: - + /* supported wpa version disabled or wpa or wpa2 */ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) return error; if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) @@ -2885,7 +2936,7 @@ wl_iw_get_wpaauth( break; case IW_AUTH_KEY_MGMT: - + /* psk, 1x */ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) return error; if (VAL_PSK(val)) @@ -2907,7 +2958,7 @@ wl_iw_get_wpaauth( break; case IW_AUTH_80211_AUTH_ALG: - + /* open, shared, leap */ if ((error = dev_wlc_intvar_get(dev, "auth", &val))) return error; if (!val) @@ -2928,103 +2979,109 @@ wl_iw_get_wpaauth( case IW_AUTH_ROAMING_CONTROL: WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); - + /* driver control or user space app control */ break; case IW_AUTH_PRIVACY_INVOKED: paramval = iw->privacy_invoked; break; -#endif +#endif /* WIRELESS_EXT > 17 */ } vwrq->value = paramval; return 0; } -#endif +#endif /* WIRELESS_EXT > 17 */ static const iw_handler wl_iw_handler[] = { - (iw_handler) wl_iw_config_commit, - (iw_handler) wl_iw_get_name, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_set_freq, - (iw_handler) wl_iw_get_freq, - (iw_handler) wl_iw_set_mode, - (iw_handler) wl_iw_get_mode, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_get_range, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_set_spy, - (iw_handler) wl_iw_get_spy, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_set_wap, - (iw_handler) wl_iw_get_wap, + (iw_handler) wl_iw_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) wl_iw_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) wl_iw_set_freq, /* SIOCSIWFREQ */ + (iw_handler) wl_iw_get_freq, /* SIOCGIWFREQ */ + (iw_handler) wl_iw_set_mode, /* SIOCSIWMODE */ + (iw_handler) wl_iw_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) wl_iw_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) wl_iw_set_spy, /* SIOCSIWSPY */ + (iw_handler) wl_iw_get_spy, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wl_iw_set_wap, /* SIOCSIWAP */ + (iw_handler) wl_iw_get_wap, /* SIOCGIWAP */ #if WIRELESS_EXT > 17 - (iw_handler) wl_iw_mlme, + (iw_handler) wl_iw_mlme, /* SIOCSIWMLME */ #else - (iw_handler) NULL, + (iw_handler) NULL, /* -- hole -- */ #endif - (iw_handler) wl_iw_iscan_get_aplist, + (iw_handler) wl_iw_iscan_get_aplist, /* SIOCGIWAPLIST */ #if WIRELESS_EXT > 13 - (iw_handler) wl_iw_iscan_set_scan, - (iw_handler) wl_iw_iscan_get_scan, -#else - (iw_handler) NULL, - (iw_handler) NULL, -#endif - (iw_handler) wl_iw_set_essid, - (iw_handler) wl_iw_get_essid, - (iw_handler) wl_iw_set_nick, - (iw_handler) wl_iw_get_nick, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_set_rate, - (iw_handler) wl_iw_get_rate, - (iw_handler) wl_iw_set_rts, - (iw_handler) wl_iw_get_rts, - (iw_handler) wl_iw_set_frag, - (iw_handler) wl_iw_get_frag, - (iw_handler) wl_iw_set_txpow, - (iw_handler) wl_iw_get_txpow, + (iw_handler) wl_iw_iscan_set_scan, /* SIOCSIWSCAN */ + (iw_handler) wl_iw_iscan_get_scan, /* SIOCGIWSCAN */ +#else /* WIRELESS_EXT > 13 */ + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#endif /* WIRELESS_EXT > 13 */ + (iw_handler) wl_iw_set_essid, /* SIOCSIWESSID */ + (iw_handler) wl_iw_get_essid, /* SIOCGIWESSID */ + (iw_handler) wl_iw_set_nick, /* SIOCSIWNICKN */ + (iw_handler) wl_iw_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wl_iw_set_rate, /* SIOCSIWRATE */ + (iw_handler) wl_iw_get_rate, /* SIOCGIWRATE */ + (iw_handler) wl_iw_set_rts, /* SIOCSIWRTS */ + (iw_handler) wl_iw_get_rts, /* SIOCGIWRTS */ + (iw_handler) wl_iw_set_frag, /* SIOCSIWFRAG */ + (iw_handler) wl_iw_get_frag, /* SIOCGIWFRAG */ + (iw_handler) wl_iw_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) wl_iw_get_txpow, /* SIOCGIWTXPOW */ #if WIRELESS_EXT > 10 - (iw_handler) wl_iw_set_retry, - (iw_handler) wl_iw_get_retry, -#endif - (iw_handler) wl_iw_set_encode, - (iw_handler) wl_iw_get_encode, - (iw_handler) wl_iw_set_power, - (iw_handler) wl_iw_get_power, + (iw_handler) wl_iw_set_retry, /* SIOCSIWRETRY */ + (iw_handler) wl_iw_get_retry, /* SIOCGIWRETRY */ +#endif /* WIRELESS_EXT > 10 */ + (iw_handler) wl_iw_set_encode, /* SIOCSIWENCODE */ + (iw_handler) wl_iw_get_encode, /* SIOCGIWENCODE */ + (iw_handler) wl_iw_set_power, /* SIOCSIWPOWER */ + (iw_handler) wl_iw_get_power, /* SIOCGIWPOWER */ #if WIRELESS_EXT > 17 - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_set_wpaie, - (iw_handler) wl_iw_get_wpaie, - (iw_handler) wl_iw_set_wpaauth, - (iw_handler) wl_iw_get_wpaauth, - (iw_handler) wl_iw_set_encodeext, - (iw_handler) wl_iw_get_encodeext, - (iw_handler) wl_iw_set_pmksa, -#endif + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wl_iw_set_wpaie, /* SIOCSIWGENIE */ + (iw_handler) wl_iw_get_wpaie, /* SIOCGIWGENIE */ + (iw_handler) wl_iw_set_wpaauth, /* SIOCSIWAUTH */ + (iw_handler) wl_iw_get_wpaauth, /* SIOCGIWAUTH */ + (iw_handler) wl_iw_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) wl_iw_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) wl_iw_set_pmksa, /* SIOCSIWPMKSA */ +#endif /* WIRELESS_EXT > 17 */ }; #if WIRELESS_EXT > 12 enum { WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, WL_IW_SET_VLANMODE, - WL_IW_SET_PM + WL_IW_SET_PM, +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ + WL_IW_SET_LAST }; static iw_handler wl_iw_priv_handler[] = { wl_iw_set_leddc, wl_iw_set_vlanmode, - wl_iw_set_pm + wl_iw_set_pm, +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ + NULL }; static struct iw_priv_args wl_iw_priv_args[] = { @@ -3045,7 +3102,10 @@ static struct iw_priv_args wl_iw_priv_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_pm" - } + }, +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ + { 0, 0, 0, { 0 } } }; const struct iw_handler_def wl_iw_handler_def = @@ -3058,9 +3118,9 @@ const struct iw_handler_def wl_iw_handler_def = .private_args = wl_iw_priv_args, #if WIRELESS_EXT >= 19 get_wireless_stats: dhd_get_wireless_stats, -#endif +#endif /* WIRELESS_EXT >= 19 */ }; -#endif +#endif /* WIRELESS_EXT > 12 */ int wl_iw_ioctl( @@ -3115,7 +3175,7 @@ wl_iw_ioctl( else max_tokens = IW_SCAN_MAX_DATA; break; -#endif +#endif /* WIRELESS_EXT > 13 */ case SIOCSIWSPY: token_size = sizeof(struct sockaddr); @@ -3160,24 +3220,26 @@ wl_iw_ioctl( return ret; } - +/* Convert a connection status event into a connection status string. + * Returns TRUE if a matching connection status string was found. + */ bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen) { typedef struct conn_fail_event_map_t { - uint32 inEvent; - uint32 inStatus; - uint32 inReason; - const char* outName; - const char* outCause; + uint32 inEvent; /* input: event type to match */ + uint32 inStatus; /* input: event status code to match */ + uint32 inReason; /* input: event reason code to match */ + const char* outName; /* output: failure type */ + const char* outCause; /* output: failure cause */ } conn_fail_event_map_t; - + /* Map of WLC_E events to connection failure strings */ # define WL_IW_DONT_CARE 9999 const conn_fail_event_map_t event_map [] = { - - + /* inEvent inStatus inReason */ + /* outName outCause */ {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE, "Conn", "Success"}, {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE, @@ -3216,7 +3278,7 @@ wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, const char* cause = NULL; int i; - + /* Search the event map table for a matching event */ for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { const conn_fail_event_map_t* row = &event_map[i]; if (row->inEvent == event_type && @@ -3228,7 +3290,7 @@ wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, } } - + /* If found, generate a connection failure string and return TRUE */ if (cause) { memset(stringBuf, 0, buflen); snprintf(stringBuf, buflen, "%s %s %02d %02d", @@ -3241,7 +3303,10 @@ wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, } #if (WIRELESS_EXT > 14) - +/* Check if we have received an event that indicates connection failure + * If so, generate a connection failure report string. + * The caller supplies a buffer to hold the generated string. + */ static bool wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) { @@ -3256,11 +3321,11 @@ wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) return FALSE; } } -#endif +#endif /* WIRELESS_EXT > 14 */ #ifndef IW_CUSTOM_MAX -#define IW_CUSTOM_MAX 256 -#endif +#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */ +#endif /* IW_CUSTOM_MAX */ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) @@ -3326,7 +3391,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) WL_TRACE(("wl_iw_event status %d \n", status)); } break; -#endif +#endif /* WIRELESS_EXT > 14 */ #if WIRELESS_EXT > 17 case WLC_E_MIC_ERROR: { struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra; @@ -3382,7 +3447,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } break; } -#endif +#endif /* WIRELESS_EXT > 17 */ case WLC_E_SCAN_COMPLETE: #if WIRELESS_EXT > 14 @@ -3395,7 +3460,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) break; default: - + /* Cannot translate event */ break; } @@ -3407,16 +3472,18 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } #if WIRELESS_EXT > 14 - + /* Look for WLC events that indicate a connection failure. + * If found, generate an IWEVCUSTOM event. + */ memset(extra, 0, sizeof(extra)); if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { cmd = IWEVCUSTOM; wrqu.data.length = strlen(extra); wireless_send_event(dev, cmd, &wrqu, extra); } -#endif +#endif /* WIRELESS_EXT > 14 */ -#endif +#endif /* WIRELESS_EXT > 13 */ } int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) @@ -3453,14 +3520,14 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat else wstats->qual.qual = 5; - + /* Wraps to 0 if RSSI is 0 */ wstats->qual.level = 0x100 + rssi; wstats->qual.noise = 0x100 + phy_noise; #if WIRELESS_EXT > 18 wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); #else wstats->qual.updated |= 7; -#endif +#endif /* WIRELESS_EXT > 18 */ #if WIRELESS_EXT > 11 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t))); @@ -3497,7 +3564,7 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt))); WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant))); -#endif +#endif /* WIRELESS_EXT > 11 */ done: return res; @@ -3518,7 +3585,7 @@ static void wl_iw_set_event_mask(struct net_device *dev) { char eventmask[WL_EVENTING_MASK_LEN]; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; + char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf)); bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); @@ -3576,7 +3643,7 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) params->action = htod16(action); params->scan_duration = htod16(0); - + /* params_size += OFFSETOF(wl_iscan_params_t, params); */ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, iscan->ioctlbuf, WLC_IOCTL_SMLEN); } @@ -3595,7 +3662,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) wl_scan_results_t *results; uint32 status; - + /* buffers are allocated on demand */ if (iscan->list_cur) { buf = iscan->list_cur; iscan->list_cur = buf->next; @@ -3647,7 +3714,7 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan) memset(&wrqu, 0, sizeof(wrqu)); - + /* wext expects to get no data for SIOCGIWSCAN Event */ wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); } @@ -3680,12 +3747,12 @@ _iscan_sysioc_thread(void *data) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_lock(); #endif - + /* make sure our buffer size is enough before going next round */ wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_unlock(); #endif - + /* Reschedule the timer */ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); add_timer(&iscan->timer); iscan->timer_on = 1; @@ -3697,7 +3764,7 @@ _iscan_sysioc_thread(void *data) break; case WL_SCAN_RESULTS_PENDING: WL_TRACE(("iscanresults pending\n")); - + /* Reschedule the timer */ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); add_timer(&iscan->timer); iscan->timer_on = 1; @@ -3727,14 +3794,17 @@ wl_iw_attach(struct net_device *dev, void * dhdp) if (!iscan) return -ENOMEM; memset(iscan, 0, sizeof(iscan_info_t)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + iscan->kthread = NULL; +#endif iscan->sysioc_pid = -1; - + /* we only care about main interface so save a global here */ g_iscan = iscan; iscan->dev = dev; iscan->iscan_state = ISCAN_STATE_IDLE; - + /* Set up the timer */ iscan->timer_ms = 2000; init_timer(&iscan->timer); iscan->timer.data = (ulong)iscan; @@ -3742,7 +3812,12 @@ wl_iw_attach(struct net_device *dev, void * dhdp) sema_init(&iscan->sysioc_sem, 0); init_completion(&iscan->sysioc_exited); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + iscan->kthread = kthread_run(_iscan_sysioc_thread, iscan, "iscan_sysioc"); + iscan->sysioc_pid = iscan->kthread->pid; +#else iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); +#endif if (iscan->sysioc_pid < 0) return -ENOMEM; return 0; @@ -3768,4 +3843,4 @@ void wl_iw_detach(void) g_iscan = NULL; } -#endif +#endif /* USE_IW */ |