#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
-/* mgmt header + 1 byte category code */
-#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
-
-#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
-#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
-#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
-#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
-
-/* next values represent the buffer size for A-MPDU frame.
- * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
-#define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_MAX_AMPDU_BUF 0x40
-
/* utils */
static int ecw2cw(int ecw)
{
return NULL;
}
-/* frame sending functions */
-void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- int encrypt)
+static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
+ struct ieee80211_supported_band *sband,
+ u64 *rates)
{
- skb->dev = sdata->local->mdev;
- skb_set_mac_header(skb, 0);
- skb_set_network_header(skb, 0);
- skb_set_transport_header(skb, 0);
+ int i, j, count;
+ *rates = 0;
+ count = 0;
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int rate = (bss->supp_rates[i] & 0x7F) * 5;
- skb->iif = sdata->dev->ifindex;
- skb->do_not_encrypt = !encrypt;
+ for (j = 0; j < sband->n_bitrates; j++)
+ if (sband->bitrates[j].bitrate == rate) {
+ *rates |= BIT(j);
+ count++;
+ break;
+ }
+ }
- dev_queue_xmit(skb);
+ return count;
}
+/* frame sending functions */
static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta,
int transaction, u8 *extra, size_t extra_len,
if (extra)
memcpy(skb_put(skb, extra_len), extra, extra_len);
- ieee80211_sta_tx(sdata, skb, encrypt);
+ ieee80211_tx_skb(sdata, skb, encrypt);
}
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
*pos = rate->bitrate / 5;
}
- ieee80211_sta_tx(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 0);
}
-/* MLME */
-static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta_bss *bss,
- int ibss)
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = sdata->local;
- int i, have_higher_than_11mbit = 0;
-
-
- /* cf. IEEE 802.11 9.2.12 */
- for (i = 0; i < bss->supp_rates_len; i++)
- if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
- have_higher_than_11mbit = 1;
-
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
- have_higher_than_11mbit)
- sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
- else
- sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
-
-
- if (local->ops->conf_tx) {
- struct ieee80211_tx_queue_params qparam;
-
- memset(&qparam, 0, sizeof(qparam));
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos, *ies, *ht_add_ie;
+ int i, len, count, rates_len, supp_rates_len;
+ u16 capab;
+ struct ieee80211_sta_bss *bss;
+ int wmm = 0;
+ struct ieee80211_supported_band *sband;
+ u64 rates = 0;
- qparam.aifs = 2;
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
+ ifsta->ssid_len);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
- !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
- qparam.cw_min = 31;
- else
- qparam.cw_min = 15;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- qparam.cw_max = 1023;
- qparam.txop = 0;
+ capab = ifsta->capab;
- for (i = 0; i < local_to_hw(local)->queues; i++)
- local->ops->conf_tx(local_to_hw(local), i, &qparam);
+ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
}
-}
-static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
- struct ieee80211_if_sta *ifsta,
- u8 *wmm_param, size_t wmm_param_len)
-{
- struct ieee80211_tx_queue_params params;
- size_t left;
- int count;
- u8 *pos;
+ bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+ local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
+ if (bss) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+ capab |= WLAN_CAPABILITY_PRIVACY;
+ if (bss->wmm_used)
+ wmm = 1;
- if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
- return;
+ /* get all rates supported by the device and the AP as
+ * some APs don't like getting a superset of their rates
+ * in the association request (e.g. D-Link DAP 1353 in
+ * b-only mode) */
+ rates_len = ieee80211_compatible_rates(bss, sband, &rates);
- if (!wmm_param)
- return;
+ if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+ (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+ capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
- if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
- return;
- count = wmm_param[6] & 0x0f;
- if (count == ifsta->wmm_last_param_set)
- return;
- ifsta->wmm_last_param_set = count;
+ ieee80211_rx_bss_put(local, bss);
+ } else {
+ rates = ~0;
+ rates_len = sband->n_bitrates;
+ }
- pos = wmm_param + 8;
- left = wmm_param_len - 8;
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- memset(¶ms, 0, sizeof(params));
+ if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
+ skb_put(skb, 10);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_REASSOC_REQ);
+ mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
+ mgmt->u.reassoc_req.listen_interval =
+ cpu_to_le16(local->hw.conf.listen_interval);
+ memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
+ ETH_ALEN);
+ } else {
+ skb_put(skb, 4);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ASSOC_REQ);
+ mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
+ mgmt->u.reassoc_req.listen_interval =
+ cpu_to_le16(local->hw.conf.listen_interval);
+ }
- if (!local->ops->conf_tx)
- return;
+ /* SSID */
+ ies = pos = skb_put(skb, 2 + ifsta->ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ifsta->ssid_len;
+ memcpy(pos, ifsta->ssid, ifsta->ssid_len);
- local->wmm_acm = 0;
- for (; left >= 4; left -= 4, pos += 4) {
- int aci = (pos[0] >> 5) & 0x03;
- int acm = (pos[0] >> 4) & 0x01;
- int queue;
+ /* add all rates which were marked to be used above */
+ supp_rates_len = rates_len;
+ if (supp_rates_len > 8)
+ supp_rates_len = 8;
- switch (aci) {
- case 1:
- queue = 3;
- if (acm)
- local->wmm_acm |= BIT(0) | BIT(3);
- break;
- case 2:
- queue = 1;
- if (acm)
- local->wmm_acm |= BIT(4) | BIT(5);
- break;
- case 3:
- queue = 0;
- if (acm)
- local->wmm_acm |= BIT(6) | BIT(7);
- break;
- case 0:
- default:
- queue = 2;
- if (acm)
- local->wmm_acm |= BIT(1) | BIT(2);
- break;
- }
+ len = sband->n_bitrates;
+ pos = skb_put(skb, supp_rates_len + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = supp_rates_len;
- params.aifs = pos[0] & 0x0f;
- params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
- params.cw_min = ecw2cw(pos[1] & 0x0f);
- params.txop = get_unaligned_le16(pos + 2);
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
- "cWmin=%d cWmax=%d txop=%d\n",
- local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
- params.cw_max, params.txop);
-#endif
- /* TODO: handle ACM (block TX, fallback to next lowest allowed
- * AC for now) */
- if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) {
- printk(KERN_DEBUG "%s: failed to set TX queue "
- "parameters for queue %d\n", local->mdev->name, queue);
+ count = 0;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (BIT(i) & rates) {
+ int rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ if (++count == 8)
+ break;
}
}
-}
-static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
- bool use_protection,
- bool use_short_preamble)
-{
- struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- DECLARE_MAC_BUF(mac);
-#endif
- u32 changed = 0;
+ if (rates_len > count) {
+ pos = skb_put(skb, rates_len - count + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = rates_len - count;
- if (use_protection != bss_conf->use_cts_prot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
- "%s)\n",
- sdata->dev->name,
- use_protection ? "enabled" : "disabled",
- print_mac(mac, ifsta->bssid));
+ for (i++; i < sband->n_bitrates; i++) {
+ if (BIT(i) & rates) {
+ int rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
}
-#endif
- bss_conf->use_cts_prot = use_protection;
- changed |= BSS_CHANGED_ERP_CTS_PROT;
}
- if (use_short_preamble != bss_conf->use_short_preamble) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: switched to %s barker preamble"
- " (BSSID=%s)\n",
- sdata->dev->name,
- use_short_preamble ? "short" : "long",
- print_mac(mac, ifsta->bssid));
+ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
+ /* 1. power capabilities */
+ pos = skb_put(skb, 4);
+ *pos++ = WLAN_EID_PWR_CAPABILITY;
+ *pos++ = 2;
+ *pos++ = 0; /* min tx power */
+ *pos++ = local->hw.conf.channel->max_power; /* max tx power */
+
+ /* 2. supported channels */
+ /* TODO: get this in reg domain format */
+ pos = skb_put(skb, 2 * sband->n_channels + 2);
+ *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
+ *pos++ = 2 * sband->n_channels;
+ for (i = 0; i < sband->n_channels; i++) {
+ *pos++ = ieee80211_frequency_to_channel(
+ sband->channels[i].center_freq);
+ *pos++ = 1; /* one channel in the subband*/
}
-#endif
- bss_conf->use_short_preamble = use_short_preamble;
- changed |= BSS_CHANGED_ERP_PREAMBLE;
+ }
+
+ if (ifsta->extra_ie) {
+ pos = skb_put(skb, ifsta->extra_ie_len);
+ memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
+ }
+
+ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
+ pos = skb_put(skb, 9);
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+ *pos++ = 0x50;
+ *pos++ = 0xf2;
+ *pos++ = 2; /* WME */
+ *pos++ = 0; /* WME info */
+ *pos++ = 1; /* WME ver */
+ *pos++ = 0;
+ }
+
+ /* wmm support is a must to HT */
+ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+ sband->ht_info.ht_supported &&
+ (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) {
+ struct ieee80211_ht_addt_info *ht_add_info =
+ (struct ieee80211_ht_addt_info *)ht_add_ie;
+ u16 cap = sband->ht_info.cap;
+ __le16 tmp;
+ u32 flags = local->hw.conf.channel->flags;
+
+ switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+ if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ case IEEE80211_HT_IE_CHA_SEC_BELOW:
+ if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ }
+
+ tmp = cpu_to_le16(cap);
+ pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+ memcpy(pos, &tmp, sizeof(u16));
+ pos += sizeof(u16);
+ /* TODO: needs a define here for << 2 */
+ *pos++ = sband->ht_info.ampdu_factor |
+ (sband->ht_info.ampdu_density << 2);
+ memcpy(pos, sband->ht_info.supp_mcs_set, 16);
+ }
+
+ kfree(ifsta->assocreq_ies);
+ ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
+ ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);
+ if (ifsta->assocreq_ies)
+ memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
+
+ ieee80211_tx_skb(sdata, skb, 0);
+}
+
+
+static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
+ u16 stype, u16 reason)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for "
+ "deauth/disassoc frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
+ skb_put(skb, 2);
+ /* u.deauth.reason_code == u.disassoc.reason_code */
+ mgmt->u.deauth.reason_code = cpu_to_le16(reason);
+
+ ieee80211_tx_skb(sdata, skb, 0);
+}
+
+/* MLME */
+static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_local *local = sdata->local;
+ int i, have_higher_than_11mbit = 0;
+
+ /* cf. IEEE 802.11 9.2.12 */
+ for (i = 0; i < bss->supp_rates_len; i++)
+ if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
+ have_higher_than_11mbit = 1;
+
+ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+ have_higher_than_11mbit)
+ sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+ else
+ sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+ ieee80211_set_wmm_default(sdata);
+}
+
+static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
+ struct ieee80211_if_sta *ifsta,
+ u8 *wmm_param, size_t wmm_param_len)
+{
+ struct ieee80211_tx_queue_params params;
+ size_t left;
+ int count;
+ u8 *pos;
+
+ if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+ return;
+
+ if (!wmm_param)
+ return;
+
+ if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
+ return;
+ count = wmm_param[6] & 0x0f;
+ if (count == ifsta->wmm_last_param_set)
+ return;
+ ifsta->wmm_last_param_set = count;
+
+ pos = wmm_param + 8;
+ left = wmm_param_len - 8;
+
+ memset(¶ms, 0, sizeof(params));
+
+ if (!local->ops->conf_tx)
+ return;
+
+ local->wmm_acm = 0;
+ for (; left >= 4; left -= 4, pos += 4) {
+ int aci = (pos[0] >> 5) & 0x03;
+ int acm = (pos[0] >> 4) & 0x01;
+ int queue;
+
+ switch (aci) {
+ case 1:
+ queue = 3;
+ if (acm)
+ local->wmm_acm |= BIT(0) | BIT(3);
+ break;
+ case 2:
+ queue = 1;
+ if (acm)
+ local->wmm_acm |= BIT(4) | BIT(5);
+ break;
+ case 3:
+ queue = 0;
+ if (acm)
+ local->wmm_acm |= BIT(6) | BIT(7);
+ break;
+ case 0:
+ default:
+ queue = 2;
+ if (acm)
+ local->wmm_acm |= BIT(1) | BIT(2);
+ break;
+ }
+
+ params.aifs = pos[0] & 0x0f;
+ params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+ params.cw_min = ecw2cw(pos[1] & 0x0f);
+ params.txop = get_unaligned_le16(pos + 2);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
+ "cWmin=%d cWmax=%d txop=%d\n",
+ local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
+ params.cw_max, params.txop);
+#endif
+ /* TODO: handle ACM (block TX, fallback to next lowest allowed
+ * AC for now) */
+ if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) {
+ printk(KERN_DEBUG "%s: failed to set TX queue "
+ "parameters for queue %d\n", local->mdev->name, queue);
+ }
+ }
+}
+
+static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
+ bool use_protection,
+ bool use_short_preamble)
+{
+ struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ DECLARE_MAC_BUF(mac);
+#endif
+ u32 changed = 0;
+
+ if (use_protection != bss_conf->use_cts_prot) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+ "%s)\n",
+ sdata->dev->name,
+ use_protection ? "enabled" : "disabled",
+ print_mac(mac, ifsta->bssid));
+ }
+#endif
+ bss_conf->use_cts_prot = use_protection;
+ changed |= BSS_CHANGED_ERP_CTS_PROT;
+ }
+
+ if (use_short_preamble != bss_conf->use_short_preamble) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: switched to %s barker preamble"
+ " (BSSID=%s)\n",
+ sdata->dev->name,
+ use_short_preamble ? "short" : "long",
+ print_mac(mac, ifsta->bssid));
+ }
+#endif
+ bss_conf->use_short_preamble = use_short_preamble;
+ changed |= BSS_CHANGED_ERP_PREAMBLE;
}
return changed;
return changed;
}
-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
- struct ieee80211_ht_info *ht_info)
-{
-
- if (ht_info == NULL)
- return -EINVAL;
-
- memset(ht_info, 0, sizeof(*ht_info));
-
- if (ht_cap_ie) {
- u8 ampdu_info = ht_cap_ie->ampdu_params_info;
-
- ht_info->ht_supported = 1;
- ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
- ht_info->ampdu_factor =
- ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
- ht_info->ampdu_density =
- (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
- memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
- } else
- ht_info->ht_supported = 0;
-
- return 0;
-}
-
-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
- struct ieee80211_ht_addt_info *ht_add_info_ie,
- struct ieee80211_ht_bss_info *bss_info)
-{
- if (bss_info == NULL)
- return -EINVAL;
-
- memset(bss_info, 0, sizeof(*bss_info));
-
- if (ht_add_info_ie) {
- u16 op_mode;
- op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
-
- bss_info->primary_channel = ht_add_info_ie->control_chan;
- bss_info->bss_cap = ht_add_info_ie->ht_param;
- bss_info->bss_op_mode = (u8)(op_mode & 0xff);
- }
-
- return 0;
-}
-
static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
}
-static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
- struct ieee80211_supported_band *sband,
- u64 *rates)
-{
- int i, j, count;
- *rates = 0;
- count = 0;
- for (i = 0; i < bss->supp_rates_len; i++) {
- int rate = (bss->supp_rates[i] & 0x7F) * 5;
-
- for (j = 0; j < sband->n_bitrates; j++)
- if (sband->bitrates[j].bitrate == rate) {
- *rates |= BIT(j);
- count++;
- break;
- }
- }
-
- return count;
-}
-
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- u8 *pos, *ies, *ht_add_ie;
- int i, len, count, rates_len, supp_rates_len;
- u16 capab;
- struct ieee80211_sta_bss *bss;
- int wmm = 0;
- struct ieee80211_supported_band *sband;
- u64 rates = 0;
-
- skb = dev_alloc_skb(local->hw.extra_tx_headroom +
- sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
- ifsta->ssid_len);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
- "frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- capab = ifsta->capab;
-
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
- if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
- capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
- if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
- capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
- }
-
- bss = ieee80211_rx_bss_get(local, ifsta->bssid,
- local->hw.conf.channel->center_freq,
- ifsta->ssid, ifsta->ssid_len);
- if (bss) {
- if (bss->capability & WLAN_CAPABILITY_PRIVACY)
- capab |= WLAN_CAPABILITY_PRIVACY;
- if (bss->wmm_used)
- wmm = 1;
-
- /* get all rates supported by the device and the AP as
- * some APs don't like getting a superset of their rates
- * in the association request (e.g. D-Link DAP 1353 in
- * b-only mode) */
- rates_len = ieee80211_compatible_rates(bss, sband, &rates);
-
- if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
- (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
- capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
-
- ieee80211_rx_bss_put(local, bss);
- } else {
- rates = ~0;
- rates_len = sband->n_bitrates;
- }
-
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-
- if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
- skb_put(skb, 10);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_REASSOC_REQ);
- mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
- mgmt->u.reassoc_req.listen_interval =
- cpu_to_le16(local->hw.conf.listen_interval);
- memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
- ETH_ALEN);
- } else {
- skb_put(skb, 4);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ASSOC_REQ);
- mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
- mgmt->u.reassoc_req.listen_interval =
- cpu_to_le16(local->hw.conf.listen_interval);
- }
-
- /* SSID */
- ies = pos = skb_put(skb, 2 + ifsta->ssid_len);
- *pos++ = WLAN_EID_SSID;
- *pos++ = ifsta->ssid_len;
- memcpy(pos, ifsta->ssid, ifsta->ssid_len);
-
- /* add all rates which were marked to be used above */
- supp_rates_len = rates_len;
- if (supp_rates_len > 8)
- supp_rates_len = 8;
-
- len = sband->n_bitrates;
- pos = skb_put(skb, supp_rates_len + 2);
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = supp_rates_len;
-
- count = 0;
- for (i = 0; i < sband->n_bitrates; i++) {
- if (BIT(i) & rates) {
- int rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- if (++count == 8)
- break;
- }
- }
-
- if (rates_len > count) {
- pos = skb_put(skb, rates_len - count + 2);
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = rates_len - count;
-
- for (i++; i < sband->n_bitrates; i++) {
- if (BIT(i) & rates) {
- int rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
- }
- }
-
- if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
- /* 1. power capabilities */
- pos = skb_put(skb, 4);
- *pos++ = WLAN_EID_PWR_CAPABILITY;
- *pos++ = 2;
- *pos++ = 0; /* min tx power */
- *pos++ = local->hw.conf.channel->max_power; /* max tx power */
-
- /* 2. supported channels */
- /* TODO: get this in reg domain format */
- pos = skb_put(skb, 2 * sband->n_channels + 2);
- *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
- *pos++ = 2 * sband->n_channels;
- for (i = 0; i < sband->n_channels; i++) {
- *pos++ = ieee80211_frequency_to_channel(
- sband->channels[i].center_freq);
- *pos++ = 1; /* one channel in the subband*/
- }
- }
-
- if (ifsta->extra_ie) {
- pos = skb_put(skb, ifsta->extra_ie_len);
- memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
- }
-
- if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- pos = skb_put(skb, 9);
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 7; /* len */
- *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
- *pos++ = 0x50;
- *pos++ = 0xf2;
- *pos++ = 2; /* WME */
- *pos++ = 0; /* WME info */
- *pos++ = 1; /* WME ver */
- *pos++ = 0;
- }
-
- /* wmm support is a must to HT */
- if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
- sband->ht_info.ht_supported &&
- (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) {
- struct ieee80211_ht_addt_info *ht_add_info =
- (struct ieee80211_ht_addt_info *)ht_add_ie;
- u16 cap = sband->ht_info.cap;
- __le16 tmp;
- u32 flags = local->hw.conf.channel->flags;
-
- switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
- case IEEE80211_HT_IE_CHA_SEC_ABOVE:
- if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
- cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
- cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
- break;
- case IEEE80211_HT_IE_CHA_SEC_BELOW:
- if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
- cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
- cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
- break;
- }
-
- tmp = cpu_to_le16(cap);
- pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
- *pos++ = WLAN_EID_HT_CAPABILITY;
- *pos++ = sizeof(struct ieee80211_ht_cap);
- memset(pos, 0, sizeof(struct ieee80211_ht_cap));
- memcpy(pos, &tmp, sizeof(u16));
- pos += sizeof(u16);
- /* TODO: needs a define here for << 2 */
- *pos++ = sband->ht_info.ampdu_factor |
- (sband->ht_info.ampdu_density << 2);
- memcpy(pos, sband->ht_info.supp_mcs_set, 16);
- }
-
- kfree(ifsta->assocreq_ies);
- ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
- ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);
- if (ifsta->assocreq_ies)
- memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-
-static void ieee80211_send_deauth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta, u16 reason)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
-
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for deauth "
- "frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_DEAUTH);
- skb_put(skb, 2);
- mgmt->u.deauth.reason_code = cpu_to_le16(reason);
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
-{
- if (!sdata || !sdata->default_key ||
- sdata->default_key->conf.alg != ALG_WEP)
- return 0;
- return 1;
-}
-
-static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta, u16 reason)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
-
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc "
- "frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_DISASSOC);
- skb_put(skb, 2);
- mgmt->u.disassoc.reason_code = cpu_to_le16(reason);
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta, bool deauth,
- bool self_disconnected, u16 reason)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta, bool deauth,
+ bool self_disconnected, u16 reason)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
if (self_disconnected) {
if (deauth)
- ieee80211_send_deauth(sdata, ifsta, reason);
+ ieee80211_send_deauth_disassoc(sdata,
+ IEEE80211_STYPE_DEAUTH, reason);
else
- ieee80211_send_disassoc(sdata, ifsta, reason);
+ ieee80211_send_deauth_disassoc(sdata,
+ IEEE80211_STYPE_DISASSOC, reason);
}
ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
sta_info_destroy(sta);
}
+static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
+{
+ if (!sdata || !sdata->default_key ||
+ sdata->default_key->conf.alg != ALG_WEP)
+ return 0;
+ return 1;
+}
+
static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
elems.challenge_len + 2, 1);
}
-static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
- u8 dialog_token, u16 status, u16 policy,
- u16 buf_size, u16 timeout)
-{
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- u16 capab;
-
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer "
- "for addba resp frame\n", sdata->dev->name);
- return;
- }
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, da, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
- memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
- mgmt->u.action.category = WLAN_CATEGORY_BACK;
- mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
- mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
-
- capab = (u16)(policy << 1); /* bit 1 aggregation policy */
- capab |= (u16)(tid << 2); /* bit 5:2 TID number */
- capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
-
- mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
- mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
- mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
-
- ieee80211_sta_tx(sdata, skb, 0);
-
- return;
-}
-
-void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, const u8 *da,
- u16 tid, u8 dialog_token, u16 start_seq_num,
- u16 agg_size, u16 timeout)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- u16 capab;
-
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer "
- "for addba request frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, da, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
- memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
-
- mgmt->u.action.category = WLAN_CATEGORY_BACK;
- mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
-
- mgmt->u.action.u.addba_req.dialog_token = dialog_token;
- capab = (u16)(1 << 1); /* bit 1 aggregation policy */
- capab |= (u16)(tid << 2); /* bit 5:2 TID number */
- capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
-
- mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
-
- mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
- mgmt->u.action.u.addba_req.start_seq_num =
- cpu_to_le16(start_seq_num << 4);
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-/*
- * After accepting the AddBA Request we activated a timer,
- * resetting it after each frame that arrives from the originator.
- * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
- */
-static void sta_rx_agg_session_timer_expired(unsigned long data)
-{
- /* not an elegant detour, but there is no choice as the timer passes
- * only one argument, and various sta_info are needed here, so init
- * flow in sta_info_create gives the TID as data, while the timer_to_id
- * array gives the sta through container_of */
- u8 *ptid = (u8 *)data;
- u8 *timer_to_id = ptid - *ptid;
- struct sta_info *sta = container_of(timer_to_id, struct sta_info,
- timer_to_tid[0]);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
- ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr,
- (u16)*ptid, WLAN_BACK_TIMER,
- WLAN_REASON_QSTA_TIMEOUT);
-}
-
-static void ieee80211_sta_process_addba_request(struct ieee80211_local *local,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- struct ieee80211_hw *hw = &local->hw;
- struct ieee80211_conf *conf = &hw->conf;
- struct sta_info *sta;
- struct tid_ampdu_rx *tid_agg_rx;
- u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
- u8 dialog_token;
- int ret = -EOPNOTSUPP;
- DECLARE_MAC_BUF(mac);
-
- rcu_read_lock();
-
- sta = sta_info_get(local, mgmt->sa);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- /* extract session parameters from addba request frame */
- dialog_token = mgmt->u.action.u.addba_req.dialog_token;
- timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
- start_seq_num =
- le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
-
- capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
- ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
-
- status = WLAN_STATUS_REQUEST_DECLINED;
-
- /* sanity check for incoming parameters:
- * check if configuration can support the BA policy
- * and if buffer size does not exceeds max value */
- if (((ba_policy != 1)
- && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
- || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
- status = WLAN_STATUS_INVALID_QOS_PARAM;
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "AddBA Req with bad params from "
- "%s on tid %u. policy %d, buffer size %d\n",
- print_mac(mac, mgmt->sa), tid, ba_policy,
- buf_size);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto end_no_lock;
- }
- /* determine default buffer size */
- if (buf_size == 0) {
- struct ieee80211_supported_band *sband;
-
- sband = local->hw.wiphy->bands[conf->channel->band];
- buf_size = IEEE80211_MIN_AMPDU_BUF;
- buf_size = buf_size << sband->ht_info.ampdu_factor;
- }
-
-
- /* examine state machine */
- spin_lock_bh(&sta->lock);
-
- if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "unexpected AddBA Req from "
- "%s on tid %u\n",
- print_mac(mac, mgmt->sa), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto end;
- }
-
- /* prepare A-MPDU MLME for Rx aggregation */
- sta->ampdu_mlme.tid_rx[tid] =
- kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
- if (!sta->ampdu_mlme.tid_rx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
- tid);
-#endif
- goto end;
- }
- /* rx timer */
- sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
- sta_rx_agg_session_timer_expired;
- sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
- (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
- tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
-
- /* prepare reordering buffer */
- tid_agg_rx->reorder_buf =
- kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
- if (!tid_agg_rx->reorder_buf) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "can not allocate reordering buffer "
- "to tid %d\n", tid);
-#endif
- kfree(sta->ampdu_mlme.tid_rx[tid]);
- goto end;
- }
- memset(tid_agg_rx->reorder_buf, 0,
- buf_size * sizeof(struct sk_buff *));
-
- if (local->ops->ampdu_action)
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
- sta->addr, tid, &start_seq_num);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- if (ret) {
- kfree(tid_agg_rx->reorder_buf);
- kfree(tid_agg_rx);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
- goto end;
- }
-
- /* change state and send addba resp */
- sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
- tid_agg_rx->dialog_token = dialog_token;
- tid_agg_rx->ssn = start_seq_num;
- tid_agg_rx->head_seq_num = start_seq_num;
- tid_agg_rx->buf_size = buf_size;
- tid_agg_rx->timeout = timeout;
- tid_agg_rx->stored_mpdu_num = 0;
- status = WLAN_STATUS_SUCCESS;
-end:
- spin_unlock_bh(&sta->lock);
-
-end_no_lock:
- ieee80211_send_addba_resp(sta->sdata, sta->addr, tid,
- dialog_token, status, 1, buf_size, timeout);
- rcu_read_unlock();
-}
-
-static void ieee80211_sta_process_addba_resp(struct ieee80211_local *local,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
- u16 capab;
- u16 tid;
- u8 *state;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, mgmt->sa);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
-
- spin_lock_bh(&sta->lock);
-
- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->lock);
- goto addba_resp_exit;
- }
-
- if (mgmt->u.action.u.addba_resp.dialog_token !=
- sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
- spin_unlock_bh(&sta->lock);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto addba_resp_exit;
- }
-
- del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
- == WLAN_STATUS_SUCCESS) {
- *state |= HT_ADDBA_RECEIVED_MSK;
- sta->ampdu_mlme.addba_req_num[tid] = 0;
-
- if (*state == HT_AGG_STATE_OPERATIONAL)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-
- spin_unlock_bh(&sta->lock);
- } else {
- sta->ampdu_mlme.addba_req_num[tid]++;
- /* this will allow the state check in stop_BA_session */
- *state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
- WLAN_BACK_INITIATOR);
- }
-
-addba_resp_exit:
- rcu_read_unlock();
-}
-
-void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid,
- u16 initiator, u16 reason_code)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- u16 params;
-
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer "
- "for delba frame\n", sdata->dev->name);
- return;
- }
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, da, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
- memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
-
- mgmt->u.action.category = WLAN_CATEGORY_BACK;
- mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
- params = (u16)(initiator << 11); /* bit 11 initiator */
- params |= (u16)(tid << 12); /* bit 15:12 TID number */
-
- mgmt->u.action.u.delba.params = cpu_to_le16(params);
- mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_bar *bar;
- u16 bar_control = 0;
-
- skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer for "
- "bar frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
- bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
- memset(bar, 0, sizeof(*bar));
- bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
- IEEE80211_STYPE_BACK_REQ);
- memcpy(bar->ra, ra, ETH_ALEN);
- memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
- bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
- bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
- bar_control |= (u16)(tid << 12);
- bar->control = cpu_to_le16(bar_control);
- bar->start_seq_num = cpu_to_le16(ssn);
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
- u16 initiator, u16 reason)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
- int ret, i;
- DECLARE_MAC_BUF(mac);
-
- rcu_read_lock();
-
- sta = sta_info_get(local, ra);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- /* check if TID is in operational state */
- spin_lock_bh(&sta->lock);
- if (sta->ampdu_mlme.tid_state_rx[tid]
- != HT_AGG_STATE_OPERATIONAL) {
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
- return;
- }
- sta->ampdu_mlme.tid_state_rx[tid] =
- HT_AGG_STATE_REQ_STOP_BA_MSK |
- (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
- spin_unlock_bh(&sta->lock);
-
- /* stop HW Rx aggregation. ampdu_action existence
- * already verified in session init so we add the BUG_ON */
- BUG_ON(!local->ops->ampdu_action);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n",
- print_mac(mac, ra), tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
- ra, tid, NULL);
- if (ret)
- printk(KERN_DEBUG "HW problem - can not stop rx "
- "aggregation for tid %d\n", tid);
-
- /* shutdown timer has not expired */
- if (initiator != WLAN_BACK_TIMER)
- del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
- /* check if this is a self generated aggregation halt */
- if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
- ieee80211_send_delba(sdata, ra, tid, 0, reason);
-
- /* free the reordering buffer */
- for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
- if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
- /* release the reordered frames */
- dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
- sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
- sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
- }
- }
- /* free resources */
- kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
- kfree(sta->ampdu_mlme.tid_rx[tid]);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
- sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
-
- rcu_read_unlock();
-}
-
-
-static void ieee80211_sta_process_delba(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len)
-{
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
- u16 tid, params;
- u16 initiator;
- DECLARE_MAC_BUF(mac);
-
- rcu_read_lock();
-
- sta = sta_info_get(local, mgmt->sa);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- params = le16_to_cpu(mgmt->u.action.u.delba.params);
- tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
- initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
- print_mac(mac, mgmt->sa),
- initiator ? "initiator" : "recipient", tid,
- mgmt->u.action.u.delba.reason_code);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- if (initiator == WLAN_BACK_INITIATOR)
- ieee80211_sta_stop_rx_ba_session(sdata, sta->addr, tid,
- WLAN_BACK_INITIATOR, 0);
- else { /* WLAN_BACK_RECIPIENT */
- spin_lock_bh(&sta->lock);
- sta->ampdu_mlme.tid_state_tx[tid] =
- HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
- WLAN_BACK_RECIPIENT);
- }
- rcu_read_unlock();
-}
-
-/*
- * After sending add Block Ack request we activated a timer until
- * add Block Ack response will arrive from the recipient.
- * If this timer expires sta_addba_resp_timer_expired will be executed.
- */
-void sta_addba_resp_timer_expired(unsigned long data)
-{
- /* not an elegant detour, but there is no choice as the timer passes
- * only one argument, and both sta_info and TID are needed, so init
- * flow in sta_info_create gives the TID as data, while the timer_to_id
- * array gives the sta through container_of */
- u16 tid = *(u8 *)data;
- struct sta_info *temp_sta = container_of((void *)data,
- struct sta_info, timer_to_tid[tid]);
-
- struct ieee80211_local *local = temp_sta->local;
- struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
- u8 *state;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, temp_sta->addr);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- /* check if the TID waits for addBA response */
- spin_lock_bh(&sta->lock);
- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->lock);
- *state = HT_AGG_STATE_IDLE;
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "timer expired on tid %d but we are not "
- "expecting addBA response there", tid);
-#endif
- goto timer_expired_exit;
- }
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
-
- /* go through the state check in stop_BA_session */
- *state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
- WLAN_BACK_INITIATOR);
-
-timer_expired_exit:
- rcu_read_unlock();
-}
-
-void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
-{
- struct ieee80211_local *local = sdata->local;
- int i;
-
- for (i = 0; i < STA_TID_NUM; i++) {
- ieee80211_stop_tx_ba_session(&local->hw, addr, i,
- WLAN_BACK_INITIATOR);
- ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
- WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_LEAVE_QBSS);
- }
-}
-
-static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_msrment_ie *request_ie,
- const u8 *da, const u8 *bssid,
- u8 dialog_token)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *msr_report;
-
- skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
- sizeof(struct ieee80211_msrment_ie));
-
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer for "
- "measurement report frame\n", sdata->dev->name);
- return;
- }
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
- msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
- memset(msr_report, 0, 24);
- memcpy(msr_report->da, da, ETH_ALEN);
- memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(msr_report->bssid, bssid, ETH_ALEN);
- msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
- msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
- msr_report->u.action.u.measurement.action_code =
- WLAN_ACTION_SPCT_MSR_RPRT;
- msr_report->u.action.u.measurement.dialog_token = dialog_token;
-
- msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
- msr_report->u.action.u.measurement.length =
- sizeof(struct ieee80211_msrment_ie);
-
- memset(&msr_report->u.action.u.measurement.msr_elem, 0,
- sizeof(struct ieee80211_msrment_ie));
- msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
- msr_report->u.action.u.measurement.msr_elem.mode |=
- IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
- msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
-
- ieee80211_sta_tx(sdata, skb, 0);
-}
-
-static void ieee80211_sta_process_measurement_req(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- /*
- * Ignoring measurement request is spec violation.
- * Mandatory measurements must be reported optional
- * measurements might be refused or reported incapable
- * For now just refuse
- * TODO: Answer basic measurement as unmeasured
- */
- ieee80211_send_refuse_measurement_request(sdata,
- &mgmt->u.action.u.measurement.msr_elem,
- mgmt->sa, mgmt->bssid,
- mgmt->u.action.u.measurement.dialog_token);
-}
-
-
static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
}
ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
- ieee80211_sta_def_wmm_params(sdata, bss, 1);
+ ieee80211_sta_def_wmm_params(sdata, bss);
ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n",
sdata->dev->name, print_mac(mac, resp->da));
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- ieee80211_sta_tx(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 0);
}
static void ieee80211_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
size_t len,
struct ieee80211_rx_status *rx_status)
{
- struct ieee80211_local *local = sdata->local;
-
- /* all categories we currently handle have action_code */
- if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+ /* currently we only handle mesh interface action frames here */
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
return;
switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_SPECTRUM_MGMT:
- if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
- break;
- switch (mgmt->u.action.u.measurement.action_code) {
- case WLAN_ACTION_SPCT_MSR_REQ:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.measurement)))
- break;
- ieee80211_sta_process_measurement_req(sdata, mgmt, len);
- break;
- }
- break;
- case WLAN_CATEGORY_BACK:
- switch (mgmt->u.action.u.addba_req.action_code) {
- case WLAN_ACTION_ADDBA_REQ:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.addba_req)))
- break;
- ieee80211_sta_process_addba_request(local, mgmt, len);
- break;
- case WLAN_ACTION_ADDBA_RESP:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.addba_resp)))
- break;
- ieee80211_sta_process_addba_resp(local, mgmt, len);
- break;
- case WLAN_ACTION_DELBA:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.delba)))
- break;
- ieee80211_sta_process_delba(sdata, mgmt, len);
- break;
- }
- break;
case PLINK_CATEGORY:
- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+ mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
break;
case MESH_PATH_SEL_CATEGORY:
- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_rx_path_sel_frame(sdata, mgmt, len);
+ mesh_rx_path_sel_frame(sdata, mgmt, len);
break;
}
}
}
-static void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time)
-{
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta, *tmp;
- LIST_HEAD(tmp_list);
- DECLARE_MAC_BUF(mac);
- unsigned long flags;
-
- spin_lock_irqsave(&local->sta_lock, flags);
- list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
- if (time_after(jiffies, sta->last_rx + exp_time)) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
- sdata->dev->name, print_mac(mac, sta->addr));
-#endif
- __sta_info_unlink(&sta);
- if (sta)
- list_add(&sta->list, &tmp_list);
- }
- spin_unlock_irqrestore(&local->sta_lock, flags);
-
- list_for_each_entry_safe(sta, tmp, &tmp_list, list)
- sta_info_destroy(sta);
-}
-
-
static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
ieee80211_sta_set_ssid(sdata, selected->ssid,
selected->ssid_len);
ieee80211_sta_set_bssid(sdata, selected->bssid);
- ieee80211_sta_def_wmm_params(sdata, selected, 0);
+ ieee80211_sta_def_wmm_params(sdata, selected);
/* Send out direct probe if no probe resp was received or
* the one we have is outdated
ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
- if (ifsta->scan_ssid_len)
- ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len);
- else
- ieee80211_sta_start_scan(sdata, NULL, 0);
+ ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len);
return;
}
}
}
+static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_sta_timer((unsigned long)sdata);
+}
+
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
!ieee80211_sta_active_ibss(sdata)))
ieee80211_sta_find_ibss(sdata, ifsta);
}
+
+ /* Restart STA timers */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list)
+ ieee80211_restart_sta_timer(sdata);
+ rcu_read_unlock();
}