diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfg80211.c | 91 |
1 files changed, 61 insertions, 30 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 4b83d2a..839f907 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -100,7 +100,10 @@ static const struct ieee80211_regdomain brcm_regdom = { * we need cfg80211 to allow it (reg_flags = 0); so that * hostapd could request auto channel by sending down ch 14 */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), + REG_RULE(2484-10, 2484+10, 20, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_OFDM), /* IEEE 802.11a, channel 36..64 */ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), /* IEEE 802.11a, channel 100..165 */ @@ -735,7 +738,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 mode = 0; #if defined(WL_ENABLE_P2P_IF) s32 dhd_mode = 0; -#endif +#endif /* (WL_ENABLE_P2P_IF) */ chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; @@ -807,7 +810,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-EAGAIN); } } - if (!p2p_is_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); @@ -819,7 +822,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - + wldev_iovar_setint(_ndev, "mpc", 0); + wl_notify_escan_complete(wl, _ndev, true, true); /* 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 * interface on that. @@ -874,8 +878,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, else if (type == NL80211_IFTYPE_P2P_GO) dhd_mode = P2P_GO_ENABLED; DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); -#endif - +#endif /* (WL_ENABLE_P2P_IF) */ + /* Start the P2P I/F with PM disabled. Enable PM from + * the framework + */ if ((type == NL80211_IFTYPE_P2P_CLIENT) || ( type == NL80211_IFTYPE_P2P_GO)) vwdev->ps = NL80211_PS_DISABLED; @@ -920,7 +926,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); if (wl->p2p->vif_created) { - if (wl->scan_request) { + if (wl_get_drv_status(wl, SCANNING, dev)) { wl_notify_escan_complete(wl, dev, true, true); } wldev_iovar_setint(dev, "mpc", 1); @@ -948,7 +954,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) WL_DBG(("IFDEL operation done\n")); #if defined(WL_ENABLE_P2P_IF) DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); -#endif +#endif /* (WL_ENABLE_P2P_IF)) */ } else { WL_ERR(("IFDEL didn't complete properly\n")); } @@ -972,7 +978,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); - WL_DBG(("Enter \n")); + WL_DBG(("Enter type %d\n", type)); switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: @@ -1003,8 +1009,10 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, wl_set_mode_by_netdev(wl, ndev, mode); if (wl->p2p_supported && wl->p2p->vif_created) { WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, - p2p_on(wl))); + p2p_on(wl))); wldev_iovar_setint(ndev, "mpc", 0); + wl_notify_escan_complete(wl, ndev, true, true); + /* 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 interface on that. @@ -1121,6 +1129,7 @@ wl_cfg80211_ifdel_ops(struct net_device *ndev) WL_DBG(("index : %d\n", index)); } + /* Wake up any waiting thread */ wake_up_interruptible(&wl->netif_change_event); @@ -2007,7 +2016,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); if (is_wps_conn(sme)) { - err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + if (sme->privacy) + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + else + /* WPS-2.0 allowes no security */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); } else { WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); err = wldev_iovar_setint_bsscfg(dev, "wsec", @@ -2847,7 +2860,6 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, err = -ENODEV; if (!wl_get_drv_status(wl, CONNECTED, dev) || (dhd_is_associated(dhd, NULL, &err) == FALSE)) { - WL_ERR(("NOT assoc: %d\n", err)); goto get_station_err; } @@ -3168,7 +3180,7 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) /* Our scan params have 1 channel and 0 ssids */ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | - (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); *out_params_size = params_size; /* rtn size to the caller */ return params; @@ -3195,7 +3207,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ndev = dev; } - if (wl->scan_request) { + if (wl_get_drv_status(wl, SCANNING, ndev)) { wl_notify_escan_complete(wl, ndev, true, true); } target_channel = ieee80211_frequency_to_channel(channel->center_freq); @@ -3207,7 +3219,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, *cookie = id; cfg80211_ready_on_channel(dev, *cookie, channel, channel_type, duration, GFP_KERNEL); - if (!p2p_is_on(wl)) { + if (wl->p2p && !wl->p2p->on) { get_primary_mac(wl, &primary_mac); wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); @@ -3331,7 +3343,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *channel, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, - const u8* buf, size_t len, u64 *cookie) + const u8* buf, size_t len, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) + bool no_cck, +#endif + u64 *cookie) { wl_action_frame_t *action_frame; wl_af_params_t *af_params; @@ -3418,6 +3434,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, WL_DBG(("Disconnect STA : %s scb_val.val %d\n", bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val)); + /* Wait for the deauth event to come, supplicant will do the delete iface immediately + * and we will have problem in sending deauth frame if we delete the bss in firmware + */ + wl_delay(400); cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -3521,7 +3541,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, } if (IS_P2P_SOCIAL(af_params->channel) && - (IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) || + (IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], 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 @@ -3534,7 +3554,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, } else { ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (!ack) { - for (retry = 1; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + for (retry = 1; retry < retry_cnt; retry++) { ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (ack) @@ -4771,17 +4791,24 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, bool act; s32 err = 0; u32 event = ntoh32(e->event_type); + u32 reason; if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { wl_notify_connect_status_ap(wl, ndev, e, data); } else { WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", ntoh32(e->event_type), ntoh32(e->status), ndev)); + if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) { + reason = ntoh32(e->reason); + wl->deauth_reason = reason; + WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason)); + } if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl->deauth_reason = 0; if (wl_is_ibssmode(wl, ndev)) { printk("cfg80211_ibss_joined\n"); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, @@ -4809,7 +4836,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_get_drv_status(wl, CONNECTED, ndev)) { scb_val_t scbval; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - printk("link down, call cfg80211_disconnected\n"); wl_clr_drv_status(wl, CONNECTED, ndev); if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { /* To make sure disconnect, explictly send dissassoc @@ -4821,7 +4847,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, scbval.val = htod32(scbval.val); wldev_ioctl(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason)); + cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL); wl_link_down(wl); wl_init_prof(wl, ndev); } @@ -5821,7 +5848,7 @@ static void wl_scan_timeout(unsigned long data) if (wl->scan_request) { WL_ERR(("timer expired\n")); if (wl->escan_on) - wl_notify_escan_complete(wl, wl->escan_info.ndev, false, true); + wl_notify_escan_complete(wl, wl->escan_info.ndev, true, false); else wl_notify_iscan_complete(wl_to_iscan(wl), true); } @@ -5877,7 +5904,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, struct wl_priv *wl = wlcfg_drv_priv; WL_DBG(("Enter \n")); - if (!wdev || dev == wl_to_prmry_ndev(wl)) + if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) return NOTIFY_DONE; switch (state) { case NETDEV_UNREGISTER: @@ -5942,7 +5969,7 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, } } } - if (!in_atomic()) + if (timer_pending(&wl->scan_timeout)) del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); @@ -5984,7 +6011,6 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_scan_results_t *list; u32 bi_length; u32 i; - u8 *p2p_dev_addr = NULL; WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); @@ -6033,8 +6059,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, } if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { - p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); - if (p2p_dev_addr && !memcmp(p2p_dev_addr, + if (!memcmp(bi->BSSID.octet, wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) { s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec)); WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel)); @@ -6187,6 +6212,7 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->iscan_kickstart = false; wl->active_scan = true; wl->rf_blocked = false; + wl->deauth_reason = 0; spin_lock_init(&wl->cfgdrv_lock); mutex_init(&wl->ioctl_buf_sync); init_waitqueue_head(&wl->netif_change_event); @@ -6711,12 +6737,16 @@ s32 wl_update_wiphybands(struct wl_priv *wl) } if ((index >= 0) && nmode) { wiphy->bands[index]->ht_cap.cap = - IEEE80211_HT_CAP_DSSSCCK40 - | IEEE80211_HT_CAP_MAX_AMSDU | IEEE80211_HT_CAP_RX_STBC; + IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 | + IEEE80211_HT_CAP_MAX_AMSDU; wiphy->bands[index]->ht_cap.ht_supported = TRUE; - wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; + wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; } + + if ((index >= 0) && bw_40) { + wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } } wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); @@ -7043,7 +7073,8 @@ static void wl_init_eq_lock(struct wl_priv *wl) static void wl_delay(u32 ms) { - if (in_atomic() || ms < 1000 / HZ) { + if (ms < 1000 / HZ) { + cond_resched(); mdelay(ms); } else { msleep(ms); |