aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/wl_cfg80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c91
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);