diff options
author | Ecco Park <eccopark@broadcom.com> | 2013-08-29 03:57:52 +0900 |
---|---|---|
committer | Ziyan <jaraidaniel@gmail.com> | 2016-05-01 23:35:24 +0200 |
commit | 533cb9d9908bde24c4ef475767bb0b642bb12d13 (patch) | |
tree | 4d2d1f25da20b587f642989d3a7a7fd5b4c1b654 /drivers | |
parent | 10c3ec82c9ccc65fd266f45ceac395b1f5f1db2f (diff) | |
download | kernel_samsung_tuna-533cb9d9908bde24c4ef475767bb0b642bb12d13.zip kernel_samsung_tuna-533cb9d9908bde24c4ef475767bb0b642bb12d13.tar.gz kernel_samsung_tuna-533cb9d9908bde24c4ef475767bb0b642bb12d13.tar.bz2 |
net: wireless: bcmdhd: Update to version 1.88.45
1. Remove WL_SUPPORT_AUTO_CHANNEL codes
2. add codes for WL_IFACE_COMB_NUM_CHANNELS and
WL_CFG80211_P2P_DEV_IF to support concurent mode.
(Google Bug : [9892309] support Wifi direct 5GHZ channels)
but, remove the WL_IFACE_COM_NUM_CHANELS in Makefile
3. refactoring the codes for hidden ap roaming
Signed-off-by: Ecco Park <eccopark@broadcom.com>
Conflicts:
drivers/net/wireless/bcmdhd/Makefile
drivers/net/wireless/bcmdhd/wl_android.c
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfgp2p.c
drivers/net/wireless/bcmdhd/wl_cfgp2p.h
Change-Id: If8283f26714196aa971c186c57758c0e64ce87df
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_linux.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_pno.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_pno.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_sdio.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/include/epivers.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_android.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfg80211.c | 658 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfg80211.h | 33 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 165 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 29 |
10 files changed, 479 insertions, 442 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 8559cca..98401b0 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,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: dhd_linux.c 419132 2013-08-19 21:33:05Z $ + * $Id: dhd_linux.c 419821 2013-08-22 21:43:26Z $ */ #include <typedefs.h> @@ -3616,7 +3616,7 @@ dhd_get_concurrent_capabilites(dhd_pub_t *dhd) ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; if (mchan_supported) ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) /* For customer_hw4, although ICS, * we still support concurrent mode */ diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c index 5b86a1a..3a5d27d 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -22,7 +22,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: dhd_pno.c 419138 2013-08-19 22:11:30Z $ + * $Id: dhd_pno.c 420056 2013-08-24 00:53:12Z $ */ #include <typedefs.h> #include <osl.h> diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h index 25f54a5..1e02db1 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd/dhd_pno.h @@ -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: dhd_pno.h 419666 2013-08-22 03:35:55Z eccopark $ + * $Id: dhd_pno.h 419969 2013-08-23 18:54:36Z $ */ #ifndef __DHD_PNO_H__ diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 43af7c0..33bfb45 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -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: dhd_sdio.c 418699 2013-08-16 10:37:13Z $ + * $Id: dhd_sdio.c 419981 2013-08-23 19:49:45Z $ */ #include <typedefs.h> diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 883a373..21184c5 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -30,26 +30,26 @@ #define EPI_MINOR_VERSION 88 -#define EPI_RC_NUMBER 42 +#define EPI_RC_NUMBER 45 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 88, 42, 0 +#define EPI_VERSION 1, 88, 45, 0 -#define EPI_VERSION_NUM 0x01582a00 +#define EPI_VERSION_NUM 0x01582d00 -#define EPI_VERSION_DEV 1.88.42 +#define EPI_VERSION_DEV 1.88.45 /* Driver Version String, ASCII, 32 chars max */ #ifdef BCMINTERNAL -#define EPI_VERSION_STR "1.88.42 (r BCMINT)" +#define EPI_VERSION_STR "1.88.45 (r BCMINT)" #else #ifdef WLTEST -#define EPI_VERSION_STR "1.88.42 (r WLTEST)" +#define EPI_VERSION_STR "1.88.45 (r WLTEST)" #else -#define EPI_VERSION_STR "1.88.42 (r)" +#define EPI_VERSION_STR "1.88.45 (r)" #endif #endif /* BCMINTERNAL */ diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 9bd822f..c848a05 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -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_android.c 419132 2013-08-19 21:33:05Z $ + * $Id: wl_android.c 420671 2013-08-28 11:37:19Z $ */ #include <linux/module.h> @@ -88,9 +88,6 @@ #define CMD_SETROAMMODE "SETROAMMODE" #define CMD_MIRACAST "MIRACAST" -#if defined(WL_SUPPORT_AUTO_CHANNEL) -#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" -#endif /* WL_SUPPORT_AUTO_CHANNEL */ /* CCX Private Commands */ @@ -1002,13 +999,6 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); -#if defined(WL_SUPPORT_AUTO_CHANNEL) - else if (strnicmp(command, CMD_GET_BEST_CHANNELS, - strlen(CMD_GET_BEST_CHANNELS)) == 0) { - bytes_written = wl_cfg80211_get_best_channels(net, command, - priv_cmd.total_len); - } -#endif /* WL_SUPPORT_AUTO_CHANNEL */ else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index a09136c..9f99c81 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -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_cfg80211.c 419132 2013-08-19 21:33:05Z $ + * $Id: wl_cfg80211.c 419844 2013-08-23 00:07:03Z $ */ #include <typedefs.h> #include <linuxver.h> @@ -137,6 +137,69 @@ static const struct ieee80211_regdomain brcm_regdom = { REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } }; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) +/* + * Possible interface combinations supported by driver + * + * ADHOC Mode - #ADHOC <= 1 on channels = 1 + * SoftAP Mode - #AP <= 1 on channels = 1 + * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1 + * on channels = 2 + */ +static const struct ieee80211_iface_limit softap_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_limit sta_p2p_limits[] = { + /* + * During P2P-GO removal, P2P-GO is first changed to STA and later only + * removed. So setting maximum possible number of STA interfaces as 2 to + * accommodate the above behaviour. + */ + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; + +static const struct ieee80211_iface_combination +softap_iface_combinations[] = { + { + .num_different_channels = 1, + .max_interfaces = 1, + .limits = softap_limits, + .n_limits = ARRAY_SIZE(softap_limits), + }, +}; + +static const struct ieee80211_iface_combination +sta_p2p_iface_combinations[] = { + { + .num_different_channels = 2, + .max_interfaces = 3, + .limits = sta_p2p_limits, + .n_limits = ARRAY_SIZE(sta_p2p_limits), + }, +}; +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ /* Data Element Definitions */ #define WPS_ID_CONFIG_METHODS 0x1008 @@ -196,9 +259,14 @@ static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); +#else static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request); +#endif /* WL_CFG80211_P2P_DEV_IF */ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); @@ -214,10 +282,21 @@ static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm); +#else static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm); +#else static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool unicast, bool multicast); @@ -349,6 +428,7 @@ static void wl_ch_to_chanspec(int ch, */ static void wl_rst_ie(struct wl_priv *wl); static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v); +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size); static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); @@ -362,8 +442,8 @@ wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ static s32 wl_inform_bss(struct wl_priv *wl); -static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done); -static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done); +static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi); +static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev); static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); s32 wl_cfg80211_channel_to_freq(u32 channel); @@ -825,6 +905,13 @@ wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) }, +#if defined(WL_CFG80211_P2P_DEV_IF) + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ }; static void swap_key_from_BE(struct wl_wsec_key *key) @@ -972,7 +1059,7 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) static bcm_struct_cfgdev * wl_cfg80211_add_monitor_if(char *name) { -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); return ERR_PTR(-EOPNOTSUPP); #else @@ -981,12 +1068,16 @@ wl_cfg80211_add_monitor_if(char *name) dhd_add_monitor(name, &ndev); WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); return ndev_to_cfgdev(ndev); -#endif +#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ } static bcm_struct_cfgdev * wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, +#if defined(WL_CFG80211_P2P_DEV_IF) + const char *name, +#else char *name, +#endif /* WL_CFG80211_P2P_DEV_IF */ enum nl80211_iftype type, u32 *flags, struct vif_params *params) { @@ -1029,6 +1120,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, return NULL; case NL80211_IFTYPE_MONITOR: return wl_cfg80211_add_monitor_if(name); +#if defined(WL_CFG80211_P2P_DEV_IF) + case NL80211_IFTYPE_P2P_DEVICE: + return wl_cfgp2p_add_p2p_disc_if(); +#endif /* WL_CFG80211_P2P_DEV_IF */ case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: wlif_type = WL_P2P_IF_CLIENT; @@ -1227,6 +1322,11 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) s32 index = -1; WL_DBG(("Enter\n")); +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + return wl_cfgp2p_del_p2p_disc_if(cfgdev); + } +#endif /* WL_CFG80211_P2P_DEV_IF */ dev = cfgdev_to_wlc_ndev(cfgdev, wl); if (wl_cfgp2p_find_idx(wl, dev, &index) != BCME_OK) { @@ -2262,12 +2362,20 @@ scan_out: return err; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +#else static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) +#endif /* WL_CFG80211_P2P_DEV_IF */ { s32 err = 0; struct wl_priv *wl = wiphy_priv(wiphy); +#if defined(WL_CFG80211_P2P_DEV_IF) + struct net_device *ndev = wl_to_prmry_ndev(wl); +#endif /* WL_CFG80211_P2P_DEV_IF */ WL_DBG(("Enter \n")); RETURN_EIO_IF_NOT_UP(wl); @@ -2484,6 +2592,8 @@ wl_cfg80211_ibss_vsie_delete(struct net_device *dev) /* change the command from "add" to "del" */ strncpy(wl->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1); + wl->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + ret = wldev_iovar_setbuf(dev, "ie", wl->ibss_vsie, wl->ibss_vsie_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); @@ -3287,9 +3397,15 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, return err; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm) +#else static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ { struct wl_priv *wl = wiphy_priv(wiphy); @@ -3298,9 +3414,11 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, s32 err = 0; s32 disable = 0; s32 txpwrqdbm; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS) +#if defined(WL_CFG80211_P2P_DEV_IF) + s32 dbm = MBM_TO_DBM(mbm); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) dbm = MBM_TO_DBM(dbm); -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ RETURN_EIO_IF_NOT_UP(wl); switch (type) { @@ -3334,7 +3452,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, txpwrmw = (u16) dbm; txpwrqdbm = (s32)bcm_mw_to_qdbm(txpwrmw); #ifdef SUPPORT_WL_TXPOWER - if (dbm == -1) + if (type == NL80211_TX_POWER_AUTOMATIC) txpwrqdbm = 127; txpwrqdbm |= WL_TXPWR_OVERRIDE; #endif /* SUPPORT_WL_TXPOWER */ @@ -3348,7 +3466,12 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, return err; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm) +#else static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ { struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *ndev = wl_to_prmry_ndev(wl); @@ -4166,11 +4289,17 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) return params; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) +#else static s32 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, struct ieee80211_channel * channel, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ { s32 target_channel; u32 id; @@ -4280,8 +4409,13 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, exit: if (err == BCME_OK) { WL_INFO(("Success\n")); +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_ready_on_channel(cfgdev, *cookie, channel, + duration, GFP_KERNEL); +#else cfg80211_ready_on_channel(cfgdev, *cookie, channel, channel_type, duration, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ } else { WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); } @@ -4294,7 +4428,13 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, { s32 err = 0; +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + WL_DBG((" enter ) on P2P dedicated discover interface\n")); + } +#else WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex)); +#endif /* WL_CFG80211_P2P_DEV_IF */ return err; } @@ -4731,6 +4871,13 @@ exit: } #define MAX_NUM_OF_ASSOCIATED_DEV 64 +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, bool offchan, + unsigned int wait, const u8* buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#else static s32 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, struct ieee80211_channel *channel, bool offchan, @@ -4744,6 +4891,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, bool dont_wait_for_ack, #endif u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ { wl_action_frame_t *action_frame; wl_af_params_t *af_params; @@ -5601,6 +5749,9 @@ wl_cfg80211_parse_ap_ies( goto fail; } + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { /* SoftAP mode */ struct ieee80211_mgmt *mgmt; @@ -5610,10 +5761,6 @@ wl_cfg80211_parse_ap_ies( vndr_ie_len = info->probe_resp_len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); } - } else { - /* Other mode */ - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; } /* Parse Probe Response IEs */ @@ -5648,6 +5795,9 @@ wl_cfg80211_set_ies( WL_DBG(("Applied Vndr IEs for Beacon \n")); } + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { /* SoftAP mode */ struct ieee80211_mgmt *mgmt; @@ -5657,10 +5807,6 @@ wl_cfg80211_set_ies( vndr_ie_len = info->probe_resp_len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); } - } else { - /* Other mode */ - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; } /* Set Probe Response IEs to FW */ @@ -5840,14 +5986,14 @@ wl_cfg80211_start_ap( if (!check_dev_role_integrity(wl, dev_role)) goto fail; -#if 0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +#if defined(WL_CFG80211_P2P_DEV_IF) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) if ((err = wl_cfg80211_set_channel(wiphy, dev, dev->ieee80211_ptr->preset_chandef.chan, NL80211_CHAN_HT20) < 0)) { WL_ERR(("Set channel failed \n")); goto fail; } -#endif +#endif /* WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 6, 0)) */ if ((err = wl_cfg80211_bcn_set_params(info, dev, dev_role, bssidx)) < 0) { @@ -6242,6 +6388,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, .del_virtual_intf = wl_cfg80211_del_virtual_iface, .change_virtual_intf = wl_cfg80211_change_virtual_iface, +#if defined(WL_CFG80211_P2P_DEV_IF) + .start_p2p_device = wl_cfgp2p_start_p2p_device, + .stop_p2p_device = wl_cfgp2p_stop_p2p_device, +#endif /* WL_CFG80211_P2P_DEV_IF */ .scan = wl_cfg80211_scan, .set_wiphy_params = wl_cfg80211_set_wiphy_params, .join_ibss = wl_cfg80211_join_ibss, @@ -6267,10 +6417,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { .mgmt_tx = wl_cfg80211_mgmt_tx, .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, .change_bss = wl_cfg80211_change_bss, -#if !0 && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) +#if !defined(WL_CFG80211_P2P_DEV_IF) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) .set_channel = wl_cfg80211_set_channel, -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) +#endif /* !WL_CFG80211_P2P_DEV_IF && (LINUX_VERSION < VERSION(3, 6, 0)) */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) .set_beacon = wl_cfg80211_add_set_beacon, .add_beacon = wl_cfg80211_add_set_beacon, #else @@ -6354,6 +6504,10 @@ wl_cfg80211_reg_notifier( static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *data) { s32 err = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) + dhd_pub_t *dhd = (dhd_pub_t *)data; +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); @@ -6379,8 +6533,30 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #if !defined(WL_ENABLE_P2P_IF) | BIT(NL80211_IFTYPE_MONITOR) #endif /* !WL_ENABLE_P2P_IF */ +#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) +#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_DEVICE) +#endif /* WL_CFG80211_P2P_DEV_IF */ | BIT(NL80211_IFTYPE_AP); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) + if (dhd && dhd->op_mode == DHD_FLAG_HOSTAP_MODE) { + WL_DBG(("Setting interface combinations for SoftAP mode\n")); + wdev->wiphy->iface_combinations = softap_iface_combinations; + wdev->wiphy->n_iface_combinations = + ARRAY_SIZE(softap_iface_combinations); + } else { + WL_DBG(("Setting interface combinations for STA+P2P mode\n")); + wdev->wiphy->iface_combinations = sta_p2p_iface_combinations; + wdev->wiphy->n_iface_combinations = + ARRAY_SIZE(sta_p2p_iface_combinations); + } +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; @@ -6438,6 +6614,12 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev WL_ERR(("Couldn not register wiphy device (%d)\n", err)); wiphy_free(wdev->wiphy); } + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) + wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; +#endif /* ((LINUX_VER >= 3.0) && (LINUX_VER <= 3.3)) && WL_IFACE_COMB_NUM_CHANNELS */ + return err; } @@ -6471,14 +6653,14 @@ static s32 wl_inform_bss(struct wl_priv *wl) WL_DBG(("scanned AP count (%d)\n", bss_list->count)); bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { - err = wl_inform_single_bss(wl, bi, 0); + err = wl_inform_single_bss(wl, bi); if (unlikely(err)) break; } return err; } -static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done) +static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) { struct wiphy *wiphy = wl_to_wiphy(wl); struct ieee80211_mgmt *mgmt; @@ -6493,7 +6675,6 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 i u32 freq; s32 err = 0; gfp_t aflags; - u8 *ie_offset = NULL; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { WL_DBG(("Beacon is larger than buffer. Discarding\n")); @@ -6533,37 +6714,8 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 i beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); beacon_proberesp->capab_info = cpu_to_le16(bi->capability); wl_rst_ie(wl); - - ie_offset = ((u8 *) bi) + bi->ie_offset; - - if (is_roam_done && ((int)(*(ie_offset)) == WLAN_EID_SSID && - ((int)(*(ie_offset+1)) == 0 || (int)(*(ie_offset+2)) == 0))) { - u8 *ie_new_offset = NULL; - uint8 ie_new_length; - - WL_ERR(("WAR trace: Changing the SSID Info, from beacon %d\n", - bi->flags & WL_BSS_FLAGS_FROM_BEACON)); - - ie_new_offset = (u8 *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (ie_new_offset) { - *(ie_new_offset) = WLAN_EID_SSID; - *(ie_new_offset+1) = bi->SSID_len; - memcpy(ie_new_offset+2, bi->SSID, bi->SSID_len); - ie_new_length = bi->ie_length - *(ie_offset+1) + bi->SSID_len; - - /* Copy the remaining IE apart from SSID IE from bi */ - memcpy(ie_new_offset+2 + bi->SSID_len, - ie_offset+2 + *(ie_offset+1), - bi->ie_length - 2 - *(ie_offset+1)); - wl_mrg_ie(wl, ie_new_offset, ie_new_length); - kfree(ie_new_offset); - } else { - wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); - } - } else { - wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); - } - + wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length); + wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - offsetof(struct wl_cfg80211_bss_info, frame_buf)); notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, @@ -6898,7 +7050,7 @@ wl_notify_connect_status_ibss(struct wl_priv *wl, struct net_device *ndev, MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr))); wl_get_assoc_ies(wl, ndev); wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(wl, ndev, 1); + wl_update_bss_info(wl, ndev); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); } else { @@ -6907,7 +7059,7 @@ wl_notify_connect_status_ibss(struct wl_priv *wl, struct net_device *ndev, wl_link_up(wl); wl_get_assoc_ies(wl, ndev); wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); - wl_update_bss_info(wl, ndev, 1); + wl_update_bss_info(wl, ndev); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); wl_set_drv_status(wl, CONNECTED, ndev); active = true; @@ -7178,7 +7330,7 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, } } -static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done) +static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) { struct cfg80211_bss *bss; struct wl_bss_info *bi; @@ -7188,7 +7340,6 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is s32 dtim_period; size_t ie_len; u8 *ie; - u8 *ssidie; u8 *curbssid; s32 err = 0; struct wiphy *wiphy; @@ -7213,17 +7364,11 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is } bi = (struct wl_bss_info *)(wl->extra_buf + 4); if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { + WL_ERR(("Bssid doesn't match\n")); err = -EIO; goto update_bss_info_out; } - - ie = ((u8 *)bi) + bi->ie_offset; - ie_len = bi->ie_length; - ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len); - if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0]) - memcpy(ssidie + 2, bi->SSID, bi->SSID_len); - - err = wl_inform_single_bss(wl, bi, is_roam_done); + err = wl_inform_single_bss(wl, bi); if (unlikely(err)) goto update_bss_info_out; @@ -7232,8 +7377,13 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is beacon_interval = cpu_to_le16(bi->beacon_period); } else { WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); +#if defined(WL_CFG80211_P2P_DEV_IF) + ie = (u8 *)bss->ies->data; + ie_len = bss->ies->len; +#else ie = bss->information_elements; ie_len = bss->len_information_elements; +#endif /* WL_CFG80211_P2P_DEV_IF */ beacon_interval = bss->beacon_interval; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) cfg80211_put_bss(wiphy, bss); @@ -7263,6 +7413,9 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); update_bss_info_out: + if (unlikely(err)) { + WL_ERR(("Failed with error %d\n", err)); + } mutex_unlock(&wl->usr_sync); return err; } @@ -7287,7 +7440,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, wl_get_assoc_ies(wl, ndev); wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - wl_update_bss_info(wl, ndev, 1); + wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) @@ -7370,7 +7523,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, wl_get_assoc_ies(wl, ndev); wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - wl_update_bss_info(wl, ndev, 0); + wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); wl_set_drv_status(wl, CONNECTED, ndev); if (ndev != wl_to_prmry_ndev(wl)) { @@ -9248,9 +9401,11 @@ void wl_cfg80211_detach(void *para) wl_cfgp2p_deinit_priv(wl); } -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) + wl_cfgp2p_del_p2p_disc_if(wl->p2p_wdev); +#elif defined(WL_ENABLE_P2P_IF) wl_cfg80211_detach_p2p(); -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ wl_cfg80211_ibss_vsie_free(wl); wl_deinit_priv(wl); @@ -9270,7 +9425,7 @@ static void wl_wakeup_event(struct wl_priv *wl) } } -#if defined(WL_ENABLE_P2P_IF) +#if (defined(WL_CFG80211_P2P_DEV_IF) || defined(WL_ENABLE_P2P_IF)) static int wl_is_p2p_event(struct wl_event_q *e) { switch (e->etype) { @@ -9306,7 +9461,7 @@ static int wl_is_p2p_event(struct wl_event_q *e) return FALSE; } } -#endif +#endif /* BCMDONGLEHOST && (WL_CFG80211_P2P_DEV_IF || WL_ENABLE_P2P_IF) */ static s32 wl_event_handler(void *data) { @@ -9329,19 +9484,28 @@ static s32 wl_event_handler(void *data) * there is no corresponding bsscfg for P2P interface. Map it to p2p0 * interface. */ -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) + if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_wdev)) { + cfgdev = wl_to_p2p_wdev(wl); + } else { + cfgdev = ndev_to_wdev(dhd_idx2net((struct dhd_pub *)(wl->pub), + e->emsg.ifidx)); + } +#elif defined(WL_ENABLE_P2P_IF) if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { cfgdev = wl->p2p_net; } else { cfgdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); } -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ if (!cfgdev) { -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) + cfgdev = wl_to_prmry_wdev(wl); +#elif defined(WL_ENABLE_P2P_IF) cfgdev = wl_to_prmry_ndev(wl); -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ } if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { wl->evt_handler[e->etype] (wl, cfgdev, &e->emsg, e->edata); @@ -10160,6 +10324,29 @@ static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) return err; } +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size) +{ + u8 *ssidie; + ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); + if (!ssidie) + return; + if (ssidie[1] != bi->SSID_len) { + if (ssidie[1]) { + WL_ERR(("%s: Wrong SSID len: %d != %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); + return; + } + memmove(ssidie + bi->SSID_len + 2, ssidie + 2, *ie_size - (ssidie + 2 - ie_stream)); + memcpy(ssidie + 2, bi->SSID, bi->SSID_len); + *ie_size = *ie_size + bi->SSID_len; + ssidie[1] = bi->SSID_len; + return; + } + if (*(ssidie + 2) == '\0') + memcpy(ssidie + 2, bi->SSID, bi->SSID_len); + return; +} + static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) { struct wl_ie *ie = wl_to_ie(wl); @@ -10436,323 +10623,6 @@ exit: return ret; } -#ifdef WL_SUPPORT_AUTO_CHANNEL -static s32 -wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev) -{ - u32 val = 0; - s32 ret = BCME_ERROR; - struct wl_priv *wl = wlcfg_drv_priv; - - /* Disable mpc, to avoid automatic interface down. */ - val = 0; - - ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &wl->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", ret)); - goto done; - } - - /* Set interface up, explicitly. */ - val = 1; - - ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); - if (ret < 0) { - WL_ERR(("set interface up failed, error = %d\n", ret)); - goto done; - } - - /* Stop all scan explicitly, till auto channel selection complete. */ - wl_set_drv_status(wl, SCANNING, ndev); - ret = wl_notify_escan_complete(wl, ndev, true, true); - if (ret < 0) { - WL_ERR(("set scan abort failed, error = %d\n", ret)); - goto done; - } - -done: - return ret; -} - -static bool -wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec) -{ - bool valid = false; - - /* channel 1 to 14 */ - if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) { - valid = true; - } - /* channel 36 to 48 */ - else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) { - valid = true; - } - /* channel 149 to 161 */ - else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) { - valid = true; - } - else { - valid = false; - WL_INFO(("invalid P2P chanspec, channel = %d, chanspec = %04x\n", - CHSPEC_CHANNEL(chanspec), chanspec)); - } - - return valid; -} - -static s32 -wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen) -{ - s32 ret = BCME_ERROR; - struct wl_priv *wl = NULL; - wl_uint32_list_t *list = NULL; - chanspec_t chanspec = 0; - - memset(buf, 0, buflen); - - wl = wlcfg_drv_priv; - list = (wl_uint32_list_t *)buf; - list->count = htod32(WL_NUMCHANSPECS); - - /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ - chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | - WL_CHANSPEC_CTL_SB_NONE); - chanspec = wl_chspec_host_to_driver(chanspec); - - ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, - sizeof(chanspec), buf, buflen, 0, &wl->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); - } - - return ret; -} - -static s32 -wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen) -{ - u32 channel = 0; - s32 ret = BCME_ERROR; - s32 i = 0; - s32 j = 0; - struct wl_priv *wl = NULL; - wl_uint32_list_t *list = NULL; - chanspec_t chanspec = 0; - - memset(buf, 0, buflen); - - wl = wlcfg_drv_priv; - list = (wl_uint32_list_t *)buf; - list->count = htod32(WL_NUMCHANSPECS); - - /* Restrict channels to 5GHz, 20MHz BW, no SB. */ - chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | - WL_CHANSPEC_CTL_SB_NONE); - chanspec = wl_chspec_host_to_driver(chanspec); - - ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec, - sizeof(chanspec), buf, buflen, 0, &wl->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("get 'chanspecs' failed, error = %d\n", ret)); - goto done; - } - - /* Skip DFS and inavlid P2P channel. */ - for (i = 0, j = 0; i < dtoh32(list->count); i++) { - chanspec = (chanspec_t) dtoh32(list->element[i]); - channel = CHSPEC_CHANNEL(chanspec); - - ret = wldev_iovar_getint(ndev, "per_chan_info", &channel); - if (ret < 0) { - WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_RADAR(channel) || - !(wl_cfg80211_valid_chanspec_p2p(chanspec))) { - continue; - } else { - list->element[j] = list->element[i]; - } - - j++; - } - - list->count = j; - -done: - return ret; -} - -static s32 -wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, - int *channel) -{ - s32 ret = BCME_ERROR; - int chosen = 0; - int retry = 0; - - /* Start auto channel selection scan. */ - ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true); - if (ret < 0) { - WL_ERR(("can't start auto channel scan, error = %d\n", ret)); - *channel = 0; - goto done; - } - - /* Wait for auto channel selection, worst case possible delay is 5250ms. */ - retry = CHAN_SEL_RETRY_COUNT; - - while (retry--) { - OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); - - ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), - false); - if ((ret == 0) && (dtoh32(chosen) != 0)) { - *channel = (u16)(chosen & 0x00FF); - WL_INFO(("selected channel = %d\n", *channel)); - break; - } - WL_INFO(("attempt = %d, ret = %d, chosen = %d\n", - (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); - } - - if (retry <= 0) { - WL_ERR(("failure, auto channel selection timed out\n")); - *channel = 0; - ret = BCME_ERROR; - } - -done: - return ret; -} - -static s32 -wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev) -{ - u32 val = 0; - s32 ret = BCME_ERROR; - struct wl_priv *wl = wlcfg_drv_priv; - - /* Clear scan stop driver status. */ - wl_clr_drv_status(wl, SCANNING, ndev); - - /* Enable mpc back to 1, irrespective of initial state. */ - val = 1; - - ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val, - sizeof(val), wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, - &wl->ioctl_buf_sync); - if (ret < 0) { - WL_ERR(("set 'mpc' failed, error = %d\n", ret)); - } - - return ret; -} - -s32 -wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len) -{ - int channel = 0; - s32 ret = BCME_ERROR; - u8 *buf = NULL; - char *pos = cmd; - struct wl_priv *wl = NULL; - struct net_device *ndev = NULL; - - memset(cmd, 0, total_len); - - buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); - if (buf == NULL) { - WL_ERR(("failed to allocate chanspec buffer\n")); - return -ENOMEM; - } - - /* - * Always use primary interface, irrespective of interface on which - * command came. - */ - wl = wlcfg_drv_priv; - ndev = wl_to_prmry_ndev(wl); - - /* - * Make sure that FW and driver are in right state to do auto channel - * selection scan. - */ - ret = wl_cfg80211_set_auto_channel_scan_state(ndev); - if (ret < 0) { - WL_ERR(("can't set auto channel scan state, error = %d\n", ret)); - goto done; - } - - /* Best channel selection in 2.4GHz band. */ - ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); - if (ret < 0) { - WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret)); - goto done; - } - - ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, - &channel); - if (ret < 0) { - WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_2G(channel)) { - channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); - } else { - WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel)); - channel = 0; - } - - sprintf(pos, "%04d ", channel); - pos += 5; - - /* Best channel selection in 5GHz band. */ - ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); - if (ret < 0) { - WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret)); - goto done; - } - - ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE, - &channel); - if (ret < 0) { - WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret)); - goto done; - } - - if (CHANNEL_IS_5G(channel)) { - channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); - } else { - WL_ERR(("invalid 5GHz channel, channel = %d\n", channel)); - channel = 0; - } - - sprintf(pos, "%04d ", channel); - pos += 5; - - /* Set overall best channel same as 5GHz best channel. */ - sprintf(pos, "%04d ", channel); - pos += 5; - -done: - if (NULL != buf) { - kfree(buf); - } - - /* Restore FW and driver back to normal state. */ - ret = wl_cfg80211_restore_auto_channel_scan_state(ndev); - if (ret < 0) { - WL_ERR(("can't restore auto channel scan state, error = %d\n", ret)); - } - - return (pos - cmd); -} -#endif /* WL_SUPPORT_AUTO_CHANNEL */ static const struct rfkill_ops wl_rfkill_ops = { .set_block = wl_rfkill_set diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 5d9d950..f414623 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -788,21 +788,33 @@ wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) #define ndev_to_wlc_ndev(ndev, wl) (ndev) #endif /* WL_ENABLE_P2P_IF */ -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) +#define wdev_to_wlc_ndev(wdev, wl) \ + ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \ + wl_to_prmry_ndev(wl) : wdev_to_ndev(wdev)) +#define cfgdev_to_wlc_ndev(cfgdev, wl) wdev_to_wlc_ndev(cfgdev, wl) +#elif defined(WL_ENABLE_P2P_IF) #define cfgdev_to_wlc_ndev(cfgdev, wl) ndev_to_wlc_ndev(cfgdev, wl) #else #define cfgdev_to_wlc_ndev(cfgdev, wl) (cfgdev) -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) +#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev) +#else #define ndev_to_cfgdev(ndev) (ndev) +#endif /* WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) +#define scan_req_match(wl) (((wl) && (wl->scan_request) && \ + (wl->scan_request->wdev == wl->p2p_wdev)) ? true : false) +#elif defined(WL_ENABLE_P2P_IF) #define scan_req_match(wl) (((wl) && (wl->scan_request) && \ (wl->scan_request->dev == wl->p2p_net)) ? true : false) #else #define scan_req_match(wl) (((wl) && p2p_is_on(wl) && p2p_scan(wl)) ? \ true : false) -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ #define wl_to_sr(w) (w->scan_req_int) #if defined(STATIC_WL_PRIV_STRUCT) @@ -868,19 +880,6 @@ extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, enum wl_management_type type); extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); -#ifdef WL_SUPPORT_AUTO_CHANNEL -#define CHANSPEC_BUF_SIZE 1024 -#define CHAN_SEL_IOCTL_DELAY 300 -#define CHAN_SEL_RETRY_COUNT 15 -#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \ - (channel & WL_CHAN_PASSIVE)) ? true : false) -#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \ - true : false) -#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \ - true : false) -extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command, - int total_len); -#endif /* WL_SUPPORT_AUTO_CHANNEL */ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); extern s32 wl_mode_to_nl80211_iftype(s32 mode); int wl_cfg80211_do_driver_init(struct net_device *net); diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index ee72863..1816e60 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -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_cfgp2p.c 417759 2013-08-12 12:29:43Z $ + * $Id: wl_cfgp2p.c 419821 2013-08-22 21:43:26Z $ * */ #include <typedefs.h> @@ -1559,8 +1559,13 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ if (ndev && (ndev->ieee80211_ptr != NULL)) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_remain_on_channel_expired(cfgdev, wl->last_roc_id, + &wl->remain_on_chan, GFP_KERNEL); +#else cfg80211_remain_on_channel_expired(cfgdev, wl->last_roc_id, &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ } } if (wl_add_remove_eventmsg(wl_to_prmry_ndev(wl), @@ -1610,8 +1615,13 @@ wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, del_timer_sync(&wl->p2p->listen_timer); if (notify) if (ndev && ndev->ieee80211_ptr) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_remain_on_channel_expired(wdev, wl->last_roc_id, + &wl->remain_on_chan, GFP_KERNEL); +#else cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ } } return 0; @@ -1982,10 +1992,13 @@ wl_cfgp2p_down(struct wl_priv *wl) struct wireless_dev *wdev = NULL; s32 i = 0, index = -1; -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) + ndev = wl_to_prmry_ndev(wl); + wdev = wl_to_p2p_wdev(wl); +#elif defined(WL_ENABLE_P2P_IF) ndev = wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl); wdev = ndev_to_wdev(ndev); -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ wl_cfgp2p_cancel_listen(wl, ndev, wdev, TRUE); for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { @@ -1993,6 +2006,9 @@ wl_cfgp2p_down(struct wl_priv *wl) if (index != WL_INVALID) wl_cfgp2p_clear_management_ie(wl, index); } +#if defined(WL_CFG80211_P2P_DEV_IF) + wl_cfgp2p_del_p2p_disc_if(wdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ wl_cfgp2p_deinit_priv(wl); return 0; } @@ -2432,6 +2448,7 @@ static int wl_cfgp2p_if_open(struct net_device *net) if (!wdev || !wl || !wl->p2p) return -EINVAL; WL_TRACE(("Enter\n")); +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, * do it here. This will make sure that in concurrent mode, supplicant * is not dependent on a particular order of interface initialization. @@ -2440,6 +2457,7 @@ static int wl_cfgp2p_if_open(struct net_device *net) */ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ wl_cfg80211_do_driver_init(net); return 0; @@ -2468,9 +2486,11 @@ static int wl_cfgp2p_if_stop(struct net_device *net) spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); if (clear_flag) wl_clr_drv_status(wl, SCANNING, net); +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO))); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ return 0; } @@ -2479,3 +2499,142 @@ bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) return (if_ops == &wl_cfgp2p_if_ops); } #endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(void) +{ + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + struct wireless_dev *wdev = NULL; + struct ether_addr primary_mac; + + if (!wl) + return NULL; + + WL_TRACE(("Enter\n")); + + if (wl->p2p_wdev) { + CFGP2P_ERR(("p2p_wdev defined already.\n")); + return NULL; + } + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return NULL; + } + + memset(&primary_mac, 0, sizeof(primary_mac)); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &wl->p2p->dev_addr, &wl->p2p->int_addr); + + wdev->wiphy = wl->wdev->wiphy; + wdev->iftype = NL80211_IFTYPE_P2P_DEVICE; + memcpy(wdev->address, &wl->p2p->dev_addr, ETHER_ADDR_LEN); + + /* store p2p wdev ptr for further reference. */ + wl->p2p_wdev = wdev; + + CFGP2P_ERR(("P2P interface registered\n")); + + return wdev; +} + +int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + + if (!wl) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + ret = wl_cfgp2p_set_firm_p2p(wl); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret)); + goto exit; + } + + ret = wl_cfgp2p_enable_discovery(wl, wl_to_prmry_ndev(wl), NULL, 0); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret)); + goto exit; + } + + p2p_on(wl) = true; + + CFGP2P_DBG(("P2P interface started\n")); + +exit: + return ret; +} + +void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + int clear_flag = 0; + unsigned long flags = 0; + struct net_device *ndev = NULL; + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + + if (!wl || !wdev) + return; + + WL_TRACE(("Enter\n")); + + ndev = wdev_to_wlc_ndev(wdev, wl); + + spin_lock_irqsave(&wl->cfgdrv_lock, flags); + if (wl->scan_request && wl->scan_request->wdev == wdev) { + cfg80211_scan_done(wl->scan_request, true); + wl->scan_request = NULL; + clear_flag = 1; + } + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + + if (clear_flag) + wl_clr_drv_status(wl, SCANNING, ndev); + + ret = wl_cfgp2p_disable_discovery(wl); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret)); + goto exit; + } + + p2p_on(wl) = false; + + CFGP2P_DBG(("P2P interface stopped\n")); + +exit: + return; +} + +int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev) +{ + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + + if (!wdev) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + cfg80211_unregister_wdev(wdev); + + kfree(wdev); + + wl->p2p_wdev = NULL; + + CFGP2P_ERR(("P2P interface unregistered\n")); + + return 0; +} +#endif /* WL_CFG80211_P2P_DEV_IF */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index e121f4e..a2da8fd 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -188,20 +188,25 @@ enum wl_cfgp2p_status { add_timer(timer); \ } while (0); -#if !0 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#if !defined(WL_CFG80211_P2P_DEV_IF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) #define WL_CFG80211_P2P_DEV_IF -#endif +#endif /* !WL_CFG80211_P2P_DEV_IF && (LINUX_VERSION >= VERSION(3, 8, 0)) */ -#if defined(WL_ENABLE_P2P_IF) && (0 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) +#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) #error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \ or kernel version is 3.8.0 or above -#endif +#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */ -#if !defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)) #error WLP2P not defined #endif +#if defined(WL_CFG80211_P2P_DEV_IF) +#define bcm_struct_cfgdev struct wireless_dev +#else #define bcm_struct_cfgdev struct net_device +#endif /* WL_CFG80211_P2P_DEV_IF */ extern void wl_cfgp2p_listen_expired(unsigned long data); @@ -341,6 +346,20 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); extern bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); +#if defined(WL_CFG80211_P2P_DEV_IF) +extern struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(void); + +extern int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ + /* WiFi Direct */ #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 |