ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);
}
+void ieee80211_send_pspoll(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_pspoll *pspoll;
+ struct sk_buff *skb;
+ u16 fc;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for "
+ "pspoll frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
+ memset(pspoll, 0, sizeof(*pspoll));
+ fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
+ pspoll->frame_control = cpu_to_le16(fc);
+ pspoll->aid = cpu_to_le16(ifsta->aid);
+
+ /* aid in PS-Poll has its two MSBs each set to 1 */
+ pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
+
+ memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN);
+ memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
+
+ ieee80211_tx_skb(sdata, skb, 0);
+
+ return;
+}
+
/* MLME */
static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss)
}
}
-static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc)
+static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid)
{
u8 mask;
u8 index, indexn1, indexn2;
index = aid / 8;
mask = 1 << (aid & 7);
- if (tim->bitmap_ctrl & 0x01)
- *is_mc = true;
-
indexn1 = tim->bitmap_ctrl & 0xfe;
indexn2 = elems->tim_len + indexn1 - 4;
sdata->dev->name, ifsta->bssid);
ifsta->state = IEEE80211_STA_MLME_DISABLED;
ieee80211_sta_send_apinfo(sdata, ifsta);
+
+ /*
+ * Most likely AP is not in the range so remove the
+ * bss information associated to the AP
+ */
+ ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
return;
}
sdata->dev->name, ifsta->bssid);
ifsta->state = IEEE80211_STA_MLME_DISABLED;
ieee80211_sta_send_apinfo(sdata, ifsta);
+ ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
return;
}
netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(sdata->dev);
- ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr);
+ ieee80211_sta_tear_down_BA_sessions(sta);
if (self_disconnected) {
if (deauth)
ieee80211_sta_send_apinfo(sdata, ifsta);
- if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
+ if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
ifsta->state = IEEE80211_STA_MLME_DISABLED;
+ ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
+ }
rcu_read_unlock();
sdata->dev->name, ifsta->bssid);
ifsta->state = IEEE80211_STA_MLME_DISABLED;
ieee80211_sta_send_apinfo(sdata, ifsta);
+ ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
return;
}
struct ieee80211_bss *bss)
{
struct ieee80211_local *local = sdata->local;
- int res, rates, i, j;
+ int res = 0, rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
union iwreq_data wrqu;
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+
+ if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) &&
+ memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) == 0)
+ return res;
+
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
sdata->u.sta.ie_proberesp_len);
if (!skb) {
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- /* Remove possible STA entries from other IBSS networks. */
- sta_info_flush_delayed(sdata);
-
- if (local->ops->reset_tsf) {
- /* Reset own TSF to allow time synchronization work. */
- local->ops->reset_tsf(local_to_hw(local));
+ if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) {
+ /* Remove possible STA entries from other IBSS networks. */
+ sta_info_flush_delayed(sdata);
}
+
memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
if (res)
struct ieee802_11_elems elems;
struct ieee80211_local *local = sdata->local;
u32 changed = 0;
- bool erp_valid, directed_tim, is_mc = false;
+ bool erp_valid, directed_tim;
u8 erp_value = 0;
/* Process beacon from the current BSS */
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK &&
local->hw.conf.flags & IEEE80211_CONF_PS) {
- directed_tim = check_tim(&elems, ifsta->aid, &is_mc);
-
- if (directed_tim || is_mc) {
- local->hw.conf.flags &= ~IEEE80211_CONF_PS;
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- ieee80211_send_nullfunc(local, sdata, 0);
+ directed_tim = ieee80211_check_tim(&elems, ifsta->aid);
+
+ if (directed_tim) {
+ if (local->hw.conf.dynamic_ps_timeout > 0) {
+ local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+ ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_PS);
+ ieee80211_send_nullfunc(local, sdata, 0);
+ } else {
+ local->pspolling = true;
+
+ /*
+ * Here is assumed that the driver will be
+ * able to send ps-poll frame and receive a
+ * response even though power save mode is
+ * enabled, but some drivers might require
+ * to disable power save here. This needs
+ * to be investigated.
+ */
+ ieee80211_send_pspoll(local, sdata);
+ }
}
}
if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
ifsta = &sdata->u.sta;
- if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
- (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) &&
- !ieee80211_sta_active_ibss(sdata)))
+ if ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) ||
+ !ieee80211_sta_active_ibss(sdata))
ieee80211_sta_find_ibss(sdata, ifsta);
}