From ff93146589f6f28ba8a46f85e9b319bbd2cc8cfd Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 24 Jan 2012 13:59:40 -0800 Subject: [PATCH] net: wireless: bcmdhd: Update to Version 5.90.195.23 - WFD fixes Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 269 ------------------ drivers/net/wireless/bcmdhd/dhd_linux.c | 2 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 8 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/siutils.c | 5 + drivers/net/wireless/bcmdhd/wl_cfg80211.c | 223 ++++++++++----- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 175 +++++++++++- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 37 +-- 8 files changed, 368 insertions(+), 359 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 058749deba3d..800590cca653 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -34,13 +34,6 @@ extern struct wl_priv *wlcfg_drv_priv; static int dhd_dongle_up = FALSE; static s32 wl_dongle_up(struct net_device *ndev, u32 up); -static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); -static s32 wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align); -static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout); -static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time); -static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol); -static s32 wl_pattern_atoh(s8 *src, s8 *dst); -static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); /** * Function implementations @@ -74,250 +67,6 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) } return err; } - -static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) -{ - s32 err = 0; - - WL_TRACE(("In\n")); - err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_PM error (%d)\n", err)); - } - return err; -} - -static s32 -wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("txglomalign error (%d)\n", err)); - goto dongle_glom_out; - } - /* disable glom option per default */ - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("txglom error (%d)\n", err)); - goto dongle_glom_out; - } -dongle_glom_out: - return err; -} - -static s32 -wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - if (roamvar) { - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("bcn_timeout error (%d)\n", err)); - goto dongle_rom_out; - } - } - /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("roam_off error (%d)\n", err)); - goto dongle_rom_out; - } -dongle_rom_out: - return err; -} - -static s32 -wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, - s32 scan_unassoc_time) -{ - s32 err = 0; - - err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, - sizeof(scan_assoc_time), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("Scan assoc time is not supported\n")); - } else { - WL_ERR(("Scan assoc time error (%d)\n", err)); - } - goto dongle_scantime_out; - } - err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, - sizeof(scan_unassoc_time), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("Scan unassoc time is not supported\n")); - } else { - WL_ERR(("Scan unassoc time error (%d)\n", err)); - } - goto dongle_scantime_out; - } - -dongle_scantime_out: - return err; -} - -static s32 -wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Set ARP offload */ - bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO(("arpoe is not supported\n")); - else - WL_ERR(("arpoe error (%d)\n", err)); - - goto dongle_offload_out; - } - bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO(("arp_ol is not supported\n")); - else - WL_ERR(("arp_ol error (%d)\n", err)); - - goto dongle_offload_out; - } - -dongle_offload_out: - return err; -} - -static s32 wl_pattern_atoh(s8 *src, s8 *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { - WL_ERR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - WL_ERR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - strncpy(num, src, 2); - num[2] = '\0'; - dst[i] = (u8) simple_strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - const s8 *str; - struct wl_pkt_filter pkt_filter; - struct wl_pkt_filter *pkt_filterp; - s32 buf_len; - s32 str_len; - u32 mask_size; - u32 pattern_size; - s8 buf[256]; - s32 err = 0; - - /* add a default packet filter pattern */ - str = "pkt_filter_add"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[str_len] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(100); - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(0); - - /* Parse filter type. */ - pkt_filter.type = htod32(0); - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(0); - - /* Parse pattern filter mask. */ - mask_size = htod32(wl_pattern_atoh("0xff", - (char *)pkt_filterp->u.pattern. - mask_and_pattern)); - - /* Parse pattern filter pattern. */ - pattern_size = htod32(wl_pattern_atoh("0x00", - (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - WL_ERR(("Mask and pattern not the same size\n")); - err = -EINVAL; - goto dongle_filter_out; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - - /* Keep-alive attributes are set in local - * variable (keep_alive_pkt), and - * then memcpy'ed into buffer (keep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)pkt_filterp, &pkt_filter, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - - err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("filter not supported\n")); - } else { - WL_ERR(("filter (%d)\n", err)); - } - goto dongle_filter_out; - } - - /* set mode to allow pattern */ - bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("filter_mode not supported\n")); - } else { - WL_ERR(("filter_mode (%d)\n", err)); - } - goto dongle_filter_out; - } - -dongle_filter_out: - return err; -} - s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) { #ifndef DHD_SDALIGN @@ -342,24 +91,6 @@ s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) WL_ERR(("wl_dongle_up failed\n")); goto default_conf_out; } - err = wl_dongle_power(ndev, PM_FAST); - if (unlikely(err)) { - WL_ERR(("wl_dongle_power failed\n")); - goto default_conf_out; - } - err = wl_dongle_glom(ndev, 0, DHD_SDALIGN); - if (unlikely(err)) { - WL_ERR(("wl_dongle_glom failed\n")); - goto default_conf_out; - } - err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3); - if (unlikely(err)) { - WL_ERR(("wl_dongle_roam failed\n")); - goto default_conf_out; - } - wl_dongle_scantime(ndev, 40, 80); - wl_dongle_offload(ndev, 1, 0xf); - wl_dongle_filter(ndev, 1); dhd_dongle_up = true; default_conf_out: diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 29bd8930f24b..53c507acb7be 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 307603 2012-01-12 01:32:01Z $ + * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $ */ #include diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 80ee7d56cb2a..ff5a75ef1656 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 308574 2012-01-16 22:56:40Z $ + * $Id: dhd_sdio.c 309234 2012-01-19 01:44:16Z $ */ #include @@ -5195,6 +5195,12 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM43239_CHIP_ID) return TRUE; + if (chipid == BCM4336_CHIP_ID) + return TRUE; + if (chipid == BCM43237_CHIP_ID) + return TRUE; + if (chipid == BCM43362_CHIP_ID) + return TRUE; return FALSE; } diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index f82ee1025749..53dd2f736734 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 22 +#define EPI_INCREMENTAL_NUMBER 23 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 22 +#define EPI_VERSION 5, 90, 195, 23 -#define EPI_VERSION_NUM 0x055ac316 +#define EPI_VERSION_NUM 0x055ac317 #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.22" +#define EPI_VERSION_STR "5.90.195.23" #endif diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 1cc977f51ee3..a655ac4ef141 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -1897,6 +1897,11 @@ si_is_sprom_available(si_t *sih) return (sih->chipst & CST4315_SPROM_SEL) != 0; case BCM4319_CHIP_ID: return (sih->chipst & CST4319_SPROM_SEL) != 0; + + case BCM4336_CHIP_ID: + case BCM43362_CHIP_ID: + return (sih->chipst & CST4336_SPROM_PRESENT) != 0; + case BCM4330_CHIP_ID: return (sih->chipst & CST4330_SPROM_PRESENT) != 0; case BCM4313_CHIP_ID: diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 7bab18d6d4a3..455c43c30cd0 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -820,12 +820,14 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &wl->p2p->dev_addr, &wl->p2p->int_addr); } memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); + /* In concurrency case, STA may be already associated in a particular channel. * so retrieve the current channel of primary interface and then start the virtual @@ -1318,6 +1320,25 @@ static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request return err; } +static s32 +wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) +{ + wl_uint32_list_t *list; + s32 err = BCME_OK; + if (valid_chan_list == NULL || size <= 0) + return -ENOMEM; + + memset(valid_chan_list, 0, size); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); + if (err != 0) { + WL_ERR(("get channels failed with %d\n", err)); + } + + return err; +} + static s32 wl_run_escan(struct wl_priv *wl, struct net_device *ndev, struct cfg80211_scan_request *request, uint16 action) @@ -1326,12 +1347,16 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, u32 n_channels; u32 n_ssids; s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); - wl_escan_params_t *params; + wl_escan_params_t *params = NULL; struct cfg80211_scan_request *scan_request = wl->scan_request; + u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; u32 num_chans = 0; + s32 channel; + s32 n_valid_chan; s32 search_state = WL_P2P_DISC_ST_SCAN; - u32 i; + u32 i, j, n_nodfs = 0; u16 *default_chan_list = NULL; + wl_uint32_list_t *list; struct net_device *dev = NULL; WL_DBG(("Enter \n")); @@ -1378,6 +1403,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, } else if (p2p_is_on(wl) && p2p_scan(wl)) { /* P2P SCAN TRIGGER */ + s32 _freq = 0; + n_nodfs = 0; if (scan_request && scan_request->n_channels) { num_chans = scan_request->n_channels; WL_SCAN((" chann number : %d\n", num_chans)); @@ -1388,11 +1415,26 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, err = -ENOMEM; goto exit; } - for (i = 0; i < num_chans; i++) - { - default_chan_list[i] = - ieee80211_frequency_to_channel( - scan_request->channels[i]->center_freq); + if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { + list = (wl_uint32_list_t *) chan_buf; + n_valid_chan = dtoh32(list->count); + for (i = 0; i < num_chans; i++) + { + _freq = scan_request->channels[i]->center_freq; + channel = ieee80211_frequency_to_channel(_freq); + /* remove DFS channels */ + if (channel < 52 || channel > 140) { + for (j = 0; j < n_valid_chan; j++) { + /* allows only supported channel on + * current reguatory + */ + if (channel == (dtoh32(list->element[j]))) + default_chan_list[n_nodfs++] = + channel; + } + } + + } } if (num_chans == 3 && ( (default_chan_list[0] == SOCIAL_CHAN_1) && @@ -1406,8 +1448,11 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, /* If you are already a GO, then do SEARCH only */ WL_INFO(("Already a GO. Do SEARCH Only")); search_state = WL_P2P_DISC_ST_SEARCH; + num_chans = n_nodfs; + } else { WL_INFO(("P2P SCAN STATE START \n")); + num_chans = n_nodfs; } } @@ -1459,6 +1504,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct wl_priv *wl = wiphy_priv(wiphy); struct cfg80211_ssid *ssids; struct wl_scan_req *sr = wl_to_sr(wl); + struct ether_addr primary_mac; wpa_ie_fixed_t *wps_ie; s32 passive_scan; bool iscan_req; @@ -1513,6 +1559,9 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, /* p2p on at the first time */ p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &wl->p2p->dev_addr, &wl->p2p->int_addr); } p2p_scan(wl) = true; } @@ -2655,9 +2704,9 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); memset(&key, 0, sizeof(key)); - key.index = (u32) key_idx; key.flags = WL_PRIMARY_KEY; key.algo = CRYPTO_ALGO_OFF; + key.index = (u32) key_idx; WL_DBG(("key index (%d)\n", key_idx)); /* Set the new key/index */ @@ -3312,7 +3361,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, bool channel_type_valid, unsigned int wait, const u8* buf, size_t len, u64 *cookie) { - struct ether_addr primary_mac; wl_action_frame_t *action_frame; wl_af_params_t *af_params; wifi_p2p_ie_t *p2p_ie; @@ -3328,7 +3376,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, u32 id; u32 retry = 0; bool ack = false; - wifi_p2p_pub_act_frame_t *act_frm; + wifi_p2p_pub_act_frame_t *act_frm = NULL; + wifi_p2p_action_frame_t *p2p_act_frm = NULL; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; s8 eabuf[ETHER_ADDR_STR_LEN]; WL_DBG(("Enter \n")); @@ -3348,8 +3398,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, return -ENODEV; } if (p2p_is_on(wl)) { - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* Suspend P2P discovery search-listen to prevent it from changing the * channel. */ @@ -3400,11 +3448,12 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, goto exit; } else if (ieee80211_is_action(mgmt->frame_control)) { - /* Abort the dwell time of any previous off-channel action frame that may - * be still in effect. Sending off-channel action frames relies on the - * driver's scan engine. If a previous off-channel action frame tx is - * still in progress (including the dwell time), then this new action - * frame will not be sent out. + /* Abort the dwell time of any previous off-channel + * action frame that may be still in effect. Sending + * off-channel action frames relies on the driver's + * scan engine. If a previous off-channel action frame + * tx is still in progress (including the dwell time), + * then this new action frame will not be sent out. */ wl_cfg80211_scan_abort(wl, dev); @@ -3455,50 +3504,80 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, af_params->dwell_time = WL_DWELL_TIME; memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); + if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) { + act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); + WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n", + action_frame->len, af_params->channel, + act_frm->category, act_frm->subtype)); + } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) { + p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data); + WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n", + action_frame->len, af_params->channel, + p2p_act_frm->category, p2p_act_frm->subtype)); + } else if (wl_cfgp2p_is_gas_action(action_frame->data, action_frame->len)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (action_frame->data); + WL_DBG(("Service Discovery action_frame->len: %d chan %d category %d action %d\n", + action_frame->len, af_params->channel, + sd_act_frm->category, sd_act_frm->action)); + + } + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); + /* + * To make sure to send successfully action frame, we have to turn off mpc + */ - act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); - WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n", - action_frame->len, af_params->channel, - act_frm->category, act_frm->subtype)); - /* - * To make sure to send successfully action frame, we have to turn off mpc - */ - if ((IS_PUB_ACT_FRAME(act_frm->category)) && - ((act_frm->subtype == P2P_PAF_GON_REQ) || + if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) || (act_frm->subtype == P2P_PAF_GON_RSP) || (act_frm->subtype == P2P_PAF_GON_CONF) || (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) { wldev_iovar_setint(dev, "mpc", 0); } - if (IS_PUB_ACT_FRAME(act_frm->category)) { - if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) { - af_params->dwell_time = WL_LONG_DWELL_TIME; - } else if ((act_frm->subtype == P2P_PAF_PROVDIS_REQ) || - (act_frm->subtype == P2P_PAF_PROVDIS_RSP)) { - af_params->dwell_time = WL_MED_DWELL_TIME; - } + if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) { + af_params->dwell_time = WL_LONG_DWELL_TIME; + } else if (act_frm && + (act_frm->subtype == P2P_PAF_PROVDIS_REQ || + act_frm->subtype == P2P_PAF_PROVDIS_RSP || + act_frm->subtype == P2P_PAF_GON_RSP)) { + af_params->dwell_time = WL_MED_DWELL_TIME; } + if (IS_P2P_SOCIAL(af_params->channel) && - (IS_P2P_ACT_REQ(act_frm->category, act_frm->subtype) || - IS_GAS_REQ(act_frm->category, act_frm->action)) && + (IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) || + IS_GAS_REQ(sd_act_frm, action_frame->len)) && wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { /* channel offload require P2P IE for Probe request * otherwise, we will use wl_cfgp2p_tx_action_frame directly. * channel offload for action request frame - */ + */ + + /* channel offload for action request frame */ ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); } else { - for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { - ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? - false : true; - if (ack) - break; + ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; + if (!ack) { + if (wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { + /* if the NO ACK occurs, the peer device will be on + * listen channel of the peer + * So, we have to find the peer and send action frame on + * that channel. + */ + ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); + } else { + for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + ack = (wl_cfgp2p_tx_action_frame(wl, dev, + af_params, bssidx)) ? false : true; + if (ack) + break; + } + + } + } + } cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); - if (IS_PUB_ACT_FRAME(act_frm->category) && - (act_frm->subtype == P2P_PAF_GON_CONF)) { + if (act_frm && act_frm->subtype == P2P_PAF_GON_CONF) { wldev_iovar_setint(dev, "mpc", 1); } kfree(af_params); @@ -4235,7 +4314,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif WIPHY_FLAG_4ADDR_STATION; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; #endif WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; @@ -4355,7 +4434,8 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; #if defined(WLP2P) && ENABLE_P2P_INTERFACE - if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) { + if (wl->p2p_net && wl->scan_request && + wl->scan_request->dev == wl->p2p_net) { #else if (p2p_is_on(wl) && p2p_scan(wl)) { #endif @@ -5054,7 +5134,9 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, s32 err = 0; s32 freq; struct net_device *dev = NULL; - wifi_p2p_pub_act_frame_t *act_frm; + wifi_p2p_pub_act_frame_t *act_frm = NULL; + wifi_p2p_action_frame_t *p2p_act_frm = NULL; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; wl_event_rx_frame_data_t *rxframe = (wl_event_rx_frame_data_t*)data; u32 event = ntoh32(e->event_type); @@ -5096,23 +5178,30 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, goto exit; } isfree = true; - act_frm = - (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + act_frm = (wifi_p2p_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + p2p_act_frm = (wifi_p2p_action_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + (void) p2p_act_frm; + } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + (void) sd_act_frm; + } + wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN); /* * After complete GO Negotiation, roll back to mpc mode */ - if (IS_PUB_ACT_FRAME(act_frm->category) && - ((act_frm->subtype == P2P_PAF_GON_CONF)|| - (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { + if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { wldev_iovar_setint(dev, "mpc", 1); } - - if (IS_P2P_ACT_FRAME(act_frm->category) && - (act_frm->subtype == P2P_AF_PRESENCE_REQ)) { - /* TODO Do not submit these frames to supplicant, - * we will handle it in the driver - */ - } } else { mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); } @@ -6592,13 +6681,19 @@ static void wl_delay(u32 ms) s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { - struct wl_priv *wl; + struct wl_priv *wl = wlcfg_drv_priv; struct ether_addr p2pif_addr; struct ether_addr primary_mac; - wl = wlcfg_drv_priv; - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); + if (!wl->p2p) + return -1; + if (!p2p_is_on(wl)) { + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); + } else { + memcpy(p2pdev_addr->octet, + wl->p2p->dev_addr.octet, ETHER_ADDR_LEN); + } return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 6991a9d78559..880123e067dc 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -67,6 +67,170 @@ static const struct net_device_ops wl_cfgp2p_if_ops = { .ndo_start_xmit = wl_cfgp2p_start_xmit, }; +bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + + if (frame == NULL) + return false; + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) + return false; + + if (pact_frm->category == P2P_PUB_AF_CATEGORY && + pact_frm->action == P2P_PUB_AF_ACTION && + pact_frm->oui_type == P2P_VER && + memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { + return true; + } + + return false; +} + +bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) +{ + wifi_p2p_action_frame_t *act_frm; + + if (frame == NULL) + return false; + act_frm = (wifi_p2p_action_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) + return false; + + if (act_frm->category == P2P_AF_CATEGORY && + act_frm->type == P2P_VER && + memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { + return true; + } + + return false; +} +bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) +{ + + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + + if (frame == NULL) + return false; + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1) + return false; + if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) + return false; + + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) + return true; + else + return false; + +} +void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + wifi_p2p_action_frame_t *act_frm; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + if (!frame || frame_len <= 2) + return; + + if (wl_cfgp2p_is_pub_action(frame, frame_len)) { + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + switch (pact_frm->subtype) { + case P2P_PAF_GON_REQ: + CFGP2P_DBG(("%s P2P Group Owner Negotiation Req Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_GON_RSP: + CFGP2P_DBG(("%s P2P Group Owner Negotiation Rsp Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_GON_CONF: + CFGP2P_DBG(("%s P2P Group Owner Negotiation Confirm Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_INVITE_REQ: + CFGP2P_DBG(("%s P2P Invitation Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_INVITE_RSP: + CFGP2P_DBG(("%s P2P Invitation Response Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_DEVDIS_REQ: + CFGP2P_DBG(("%s P2P Device Discoverability Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_DEVDIS_RSP: + CFGP2P_DBG(("%s P2P Device Discoverability Response Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_PROVDIS_REQ: + CFGP2P_DBG(("%s P2P Provision Discovery Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_PROVDIS_RSP: + CFGP2P_DBG(("%s P2P Provision Discovery Response Frame\n", + (tx)? "TX": "RX")); + break; + default: + CFGP2P_DBG(("%s Unknown P2P Public Action Frame\n", + (tx)? "TX": "RX")); + + } + + } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { + act_frm = (wifi_p2p_action_frame_t *)frame; + switch (act_frm->subtype) { + case P2P_AF_NOTICE_OF_ABSENCE: + CFGP2P_DBG(("%s P2P Notice of Absence Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_AF_PRESENCE_REQ: + CFGP2P_DBG(("%s P2P Presence Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_AF_PRESENCE_RSP: + CFGP2P_DBG(("%s P2P Presence Response Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_AF_GO_DISC_REQ: + CFGP2P_DBG(("%s P2P Discoverability Request Frame\n", + (tx)? "TX": "RX")); + break; + default: + CFGP2P_DBG(("%s Unknown P2P Action Frame\n", + (tx)? "TX": "RX")); + } + + } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + switch (sd_act_frm->action) { + case P2PSD_ACTION_ID_GAS_IREQ: + CFGP2P_DBG(("%s P2P GAS Initial Request\n", + (tx)? "TX" : "RX")); + break; + case P2PSD_ACTION_ID_GAS_IRESP: + CFGP2P_DBG(("%s P2P GAS Initial Response\n", + (tx)? "TX" : "RX")); + break; + case P2PSD_ACTION_ID_GAS_CREQ: + CFGP2P_DBG(("%s P2P GAS Comback Request\n", + (tx)? "TX" : "RX")); + break; + case P2PSD_ACTION_ID_GAS_CRESP: + CFGP2P_DBG(("%s P2P GAS Comback Response\n", + (tx)? "TX" : "RX")); + break; + default: + CFGP2P_DBG(("%s Unknown P2P GAS Frame\n", + (tx)? "TX" : "RX")); + } + } +} + /* * Initialize variables related to P2P * @@ -1373,7 +1537,8 @@ wl_cfgp2p_down(struct wl_priv *wl) return 0; } -s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +s32 +wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) { s32 ret = -1; int count, start, duration; @@ -1446,7 +1611,8 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf return ret; } -s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) +s32 +wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) { wifi_p2p_noa_desc_t *noa_desc; int len = 0, i; @@ -1488,7 +1654,8 @@ s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf return len * 2; } -s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +s32 +wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) { int ps, ctw; int ret = -1; @@ -1552,7 +1719,7 @@ wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) len -= 4; /* exclude OUI + OUI_TYPE */ while (len >= 3) { - /* attribute id */ + /* attribute id */ subelt_id = *subel; subel += 1; len -= 1; diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index d50b00f8394c..1e5b1197e92d 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -101,13 +101,13 @@ enum wl_cfgp2p_status { #define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie) #define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data) #define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) -#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ +#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:test_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ +#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:set_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ +#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:clear_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0: change_bit(WLP2P_STATUS_ ## stat, \ +#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) #define p2p_on(wl) ((wl)->p2p->on) #define p2p_scan(wl) ((wl)->p2p->scan) @@ -140,7 +140,14 @@ enum wl_cfgp2p_status { } \ } while (0) - +extern bool +wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); +extern void +wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len); extern s32 wl_cfgp2p_init_priv(struct wl_priv *wl); extern void @@ -260,17 +267,15 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); #define WL_P2P_WILDCARD_SSID_LEN 7 #define WL_P2P_INTERFACE_PREFIX "p2p" #define WL_P2P_TEMP_CHAN "11" -#define IS_PUB_ACT_FRAME(category) ((category == P2P_PUB_AF_CATEGORY)) -#define IS_P2P_ACT_FRAME(category) ((category == P2P_AF_CATEGORY)) - -#define IS_P2P_ACTION(categry, action) (IS_PUB_ACT_FRAME(category) && (action == P2P_PUB_AF_ACTION)) -#define IS_GAS_REQ(category, action) (IS_PUB_ACT_FRAME(category) && \ - ((action == P2PSD_ACTION_ID_GAS_IREQ) || \ - (action == P2PSD_ACTION_ID_GAS_CREQ))) -#define IS_P2P_ACT_REQ(category, subtype) (IS_PUB_ACT_FRAME(category) && \ - ((subtype == P2P_PAF_GON_REQ) || \ - (subtype == P2P_PAF_INVITE_REQ) || \ - (subtype == P2P_PAF_PROVDIS_REQ))) + + +#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ + ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ + (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) +#define IS_P2P_PUB_ACT_REQ(frame, len) (wl_cfgp2p_is_pub_action(frame, len) && \ + ((frame->subtype == P2P_PAF_GON_REQ) || \ + (frame->subtype == P2P_PAF_INVITE_REQ) || \ + (frame->subtype == P2P_PAF_PROVDIS_REQ))) #define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) #endif /* _wl_cfgp2p_h_ */ -- 2.34.1