-
-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();
-}
-
-/*
- * 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);
-}
-
-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,
- size_t len)
-{
- u16 auth_alg, auth_transaction, status_code;
- DECLARE_MAC_BUF(mac);
-
- if (ifsta->state != IEEE80211_AUTHENTICATE &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
- return;
-
- if (len < 24 + 6)
- return;
-
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
- return;
-
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
- return;
-
- auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
- auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
- status_code = le16_to_cpu(mgmt->u.auth.status_code);
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
- /*
- * IEEE 802.11 standard does not require authentication in IBSS
- * networks and most implementations do not seem to use it.
- * However, try to reply to authentication attempts if someone
- * has actually implemented this.
- */
- if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
- return;
- ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
- }
-
- if (auth_alg != ifsta->auth_alg ||
- auth_transaction != ifsta->auth_transaction)
- return;
-
- if (status_code != WLAN_STATUS_SUCCESS) {
- if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
- u8 algs[3];
- const int num_algs = ARRAY_SIZE(algs);
- int i, pos;
- algs[0] = algs[1] = algs[2] = 0xff;
- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
- algs[0] = WLAN_AUTH_OPEN;
- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
- algs[1] = WLAN_AUTH_SHARED_KEY;
- if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
- algs[2] = WLAN_AUTH_LEAP;
- if (ifsta->auth_alg == WLAN_AUTH_OPEN)
- pos = 0;
- else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY)
- pos = 1;
- else
- pos = 2;
- for (i = 0; i < num_algs; i++) {
- pos++;
- if (pos >= num_algs)
- pos = 0;
- if (algs[pos] == ifsta->auth_alg ||
- algs[pos] == 0xff)
- continue;
- if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
- !ieee80211_sta_wep_configured(sdata))
- continue;
- ifsta->auth_alg = algs[pos];
- break;
- }
- }
- return;
- }
-
- switch (ifsta->auth_alg) {
- case WLAN_AUTH_OPEN:
- case WLAN_AUTH_LEAP:
- ieee80211_auth_completed(sdata, ifsta);
- break;
- case WLAN_AUTH_SHARED_KEY:
- if (ifsta->auth_transaction == 4)
- ieee80211_auth_completed(sdata, ifsta);
- else
- ieee80211_auth_challenge(sdata, ifsta, mgmt, len);
- break;
- }
-}
-
-
-static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- u16 reason_code;
- DECLARE_MAC_BUF(mac);
-
- if (len < 24 + 2)
- return;
-
- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
- return;
-
- reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
-
- if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
- printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name);
-
- if (ifsta->state == IEEE80211_AUTHENTICATE ||
- ifsta->state == IEEE80211_ASSOCIATE ||
- ifsta->state == IEEE80211_ASSOCIATED) {
- ifsta->state = IEEE80211_AUTHENTICATE;
- mod_timer(&ifsta->timer, jiffies +
- IEEE80211_RETRY_AUTH_INTERVAL);
- }
-
- ieee80211_set_disassoc(sdata, ifsta, 1);
- ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED;
-}
-
-
-static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- u16 reason_code;
- DECLARE_MAC_BUF(mac);
-
- if (len < 24 + 2)
- return;
-
- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
- return;
-
- reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
-
- if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
- printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name);
-
- if (ifsta->state == IEEE80211_ASSOCIATED) {
- ifsta->state = IEEE80211_ASSOCIATE;
- mod_timer(&ifsta->timer, jiffies +
- IEEE80211_RETRY_AUTH_INTERVAL);
- }
-
- ieee80211_set_disassoc(sdata, ifsta, 0);
-}
-
-
-static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_mgmt *mgmt,
- size_t len,
- int reassoc)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
- struct sta_info *sta;
- u64 rates, basic_rates;
- u16 capab_info, status_code, aid;
- struct ieee802_11_elems elems;
- struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
- u8 *pos;
- int i, j;
- DECLARE_MAC_BUF(mac);
- bool have_higher_than_11mbit = false;
-
- /* AssocResp and ReassocResp have identical structure, so process both
- * of them in this function. */
-
- if (ifsta->state != IEEE80211_ASSOCIATE)
- return;
-
- if (len < 24 + 6)
- return;
-
- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
- return;
-
- capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
- status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
- aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
-
- printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x "
- "status=%d aid=%d)\n",
- sdata->dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
- capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
-
- if (status_code != WLAN_STATUS_SUCCESS) {
- printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
- sdata->dev->name, status_code);
- /* if this was a reassociation, ensure we try a "full"
- * association next time. This works around some broken APs
- * which do not correctly reject reassociation requests. */
- ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- return;
- }
-
- if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
- printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
- "set\n", sdata->dev->name, aid);
- aid &= ~(BIT(15) | BIT(14));
-
- pos = mgmt->u.assoc_resp.variable;
- ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-
- if (!elems.supp_rates) {
- printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
- sdata->dev->name);
- return;
- }
-
- printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
- ifsta->aid = aid;
- ifsta->ap_capab = capab_info;
-
- kfree(ifsta->assocresp_ies);
- ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt);
- ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL);
- if (ifsta->assocresp_ies)
- memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
-
- rcu_read_lock();
-
- /* Add STA entry for the AP */
- sta = sta_info_get(local, ifsta->bssid);
- if (!sta) {
- struct ieee80211_sta_bss *bss;
- int err;
-
- sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
- if (!sta) {
- printk(KERN_DEBUG "%s: failed to alloc STA entry for"
- " the AP\n", sdata->dev->name);
- rcu_read_unlock();
- return;
- }
- bss = ieee80211_rx_bss_get(local, ifsta->bssid,
- local->hw.conf.channel->center_freq,
- ifsta->ssid, ifsta->ssid_len);
- if (bss) {
- sta->last_signal = bss->signal;
- sta->last_qual = bss->qual;
- sta->last_noise = bss->noise;
- ieee80211_rx_bss_put(local, bss);
- }
-
- err = sta_info_insert(sta);
- if (err) {
- printk(KERN_DEBUG "%s: failed to insert STA entry for"
- " the AP (error %d)\n", sdata->dev->name, err);
- rcu_read_unlock();
- return;
- }
- /* update new sta with its last rx activity */
- sta->last_rx = jiffies;
- }
-
- /*
- * FIXME: Do we really need to update the sta_info's information here?
- * We already know about the AP (we found it in our list) so it
- * should already be filled with the right info, no?
- * As is stands, all this is racy because typically we assume
- * the information that is filled in here (except flags) doesn't
- * change while a STA structure is alive. As such, it should move
- * to between the sta_info_alloc() and sta_info_insert() above.
- */
-
- set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
- WLAN_STA_AUTHORIZED);
-
- rates = 0;
- basic_rates = 0;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- for (i = 0; i < elems.supp_rates_len; i++) {
- int rate = (elems.supp_rates[i] & 0x7f) * 5;
-
- if (rate > 110)
- have_higher_than_11mbit = true;
-
- for (j = 0; j < sband->n_bitrates; j++) {
- if (sband->bitrates[j].bitrate == rate)
- rates |= BIT(j);
- if (elems.supp_rates[i] & 0x80)
- basic_rates |= BIT(j);
- }
- }
-
- for (i = 0; i < elems.ext_supp_rates_len; i++) {
- int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-
- if (rate > 110)
- have_higher_than_11mbit = true;
-
- for (j = 0; j < sband->n_bitrates; j++) {
- if (sband->bitrates[j].bitrate == rate)
- rates |= BIT(j);
- if (elems.ext_supp_rates[i] & 0x80)
- basic_rates |= BIT(j);
- }
- }
-
- sta->supp_rates[local->hw.conf.channel->band] = rates;
- sdata->basic_rates = basic_rates;
-
- /* cf. IEEE 802.11 9.2.12 */
- 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 (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
- (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- struct ieee80211_ht_bss_info bss_info;
- ieee80211_ht_cap_ie_to_ht_info(
- (struct ieee80211_ht_cap *)
- elems.ht_cap_elem, &sta->ht_info);
- ieee80211_ht_addt_info_ie_to_ht_bss_info(
- (struct ieee80211_ht_addt_info *)
- elems.ht_info_elem, &bss_info);
- ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info);