diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/agg-tx.c | 10 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 2 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 5 | ||||
-rw-r--r-- | net/mac80211/iface.c | 4 | ||||
-rw-r--r-- | net/mac80211/main.c | 3 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 6 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 5 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 65 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 6 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 12 | ||||
-rw-r--r-- | net/mac80211/wep.c | 15 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 10 |
14 files changed, 95 insertions, 53 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5b7053c5873..7cf07158805 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -421,16 +421,22 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) struct tid_ampdu_tx *tid_tx; unsigned long timeout; - tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid); - if (!tid_tx) + rcu_read_lock(); + tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]); + if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { + rcu_read_unlock(); return; + } timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout); if (time_is_after_jiffies(timeout)) { mod_timer(&tid_tx->session_timer, timeout); + rcu_read_unlock(); return; } + rcu_read_unlock(); + #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); #endif diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ea0122dbd2b..7ed433c66d6 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -509,6 +509,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); +IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC); #endif #define DEBUGFS_ADD_MODE(name, mode) \ @@ -608,6 +609,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPRannInterval); MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); MESHPARAMS_ADD(rssi_threshold); + MESHPARAMS_ADD(ht_opmode); #undef MESHPARAMS_ADD } #endif diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3ad33a82462..33d9d0c3e3d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -163,6 +163,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sizeof(struct ieee80211_ht_operation)); pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); + /* + * Note: According to 802.11n-2009 9.13.3.1, HT Protection + * field and RIFS Mode are reserved in IBSS mode, therefore + * keep them at 0 + */ pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, chan, channel_type, 0); } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 856237c5c1f..d4c19a7773d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -206,8 +206,10 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; - else + else if (local->hw.queues >= IEEE80211_NUM_ACS) sdata->vif.hw_queue[i] = i; + else + sdata->vif.hw_queue[i] = 0; } sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b70f7f09da6..f5548e95325 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -596,6 +596,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; + local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI | + IEEE80211_RADIOTAP_MCS_HAVE_BW; local->user_power_level = -1; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 0675a2fec6a..2913113c583 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -109,8 +109,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, /* Disallow HT40+/- mismatch */ if (ie->ht_operation && - local->_oper_channel_type > NL80211_CHAN_HT20 && - sta_channel_type > NL80211_CHAN_HT20 && + (local->_oper_channel_type == NL80211_CHAN_HT40MINUS || + local->_oper_channel_type == NL80211_CHAN_HT40PLUS) && + (sta_channel_type == NL80211_CHAN_HT40MINUS || + sta_channel_type == NL80211_CHAN_HT40PLUS) && local->_oper_channel_type != sta_channel_type) goto mismatch; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 27e0c2f0679..9b59658e865 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -603,7 +603,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); - ifmsh->mshstats.fwded_mcast++; + if (!is_multicast_ether_addr(da)) + ifmsh->mshstats.fwded_unicast++; + else + ifmsh->mshstats.fwded_mcast++; ifmsh->mshstats.fwded_frames++; } } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8cc8461b48a..60ef235c9d9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -105,15 +105,15 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, return sta; } -/** mesh_set_ht_prot_mode - set correct HT protection mode +/* + * mesh_set_ht_prot_mode - set correct HT protection mode * - * Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for - * HT mesh STA in a MBSS. Three HT protection modes are supported for now, - * non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed - * mode is selected if any non-HT peers are present in our MBSS. - * 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support - * HT and atleast one HT20 peer is present. Otherwise no-protection mode is - * selected. + * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT + * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT + * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is + * selected if any non-HT peers are present in our MBSS. 20MHz-protection mode + * is selected if all peers in our 20/40MHz MBSS support HT and atleast one + * HT20 peer is present. Otherwise no-protection mode is selected. */ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) { @@ -128,21 +128,22 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (sdata == sta->sdata && - sta->plink_state == NL80211_PLINK_ESTAB) { - switch (sta->ch_type) { - case NL80211_CHAN_NO_HT: - mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", - sdata->vif.addr, sta->sta.addr); - non_ht_sta = true; - goto out; - case NL80211_CHAN_HT20: - mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", - sdata->vif.addr, sta->sta.addr); - ht20_sta = true; - default: - break; - } + if (sdata != sta->sdata || + sta->plink_state != NL80211_PLINK_ESTAB) + continue; + + switch (sta->ch_type) { + case NL80211_CHAN_NO_HT: + mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", + sdata->vif.addr, sta->sta.addr); + non_ht_sta = true; + goto out; + case NL80211_CHAN_HT20: + mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", + sdata->vif.addr, sta->sta.addr); + ht20_sta = true; + default: + break; } } out: @@ -346,6 +347,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, addr); if (!sta) { + /* Userspace handles peer allocation when security is enabled */ + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { + cfg80211_notify_new_peer_candidate(sdata->dev, addr, + elems->ie_start, + elems->total_len, + GFP_ATOMIC); + return NULL; + } + sta = mesh_plink_alloc(sdata, addr); if (!sta) return NULL; @@ -387,15 +397,6 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, { struct sta_info *sta; - /* Userspace handles peer allocation when security is enabled */ - if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { - cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, - elems->ie_start, - elems->total_len, - GFP_KERNEL); - return; - } - rcu_read_lock(); sta = mesh_peer_init(sdata, hw_addr, elems); if (!sta) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b3b3c264ff6..04c30630898 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1522,6 +1522,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) * anymore. The timeout will be reset if the frame is ACKed by * the AP. */ + ifmgd->probe_send_count++; + if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { ifmgd->nullfunc_failed = false; ieee80211_send_nullfunc(sdata->local, sdata, 0); @@ -1538,7 +1540,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) 0, (u32) -1, true, false); } - ifmgd->probe_send_count++; ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); run_again(ifmgd, ifmgd->probe_timeout); if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8257a09eeed..7bcecf73aaf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -204,14 +204,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->flag & RX_FLAG_HT) { rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); - *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS | - IEEE80211_RADIOTAP_MCS_HAVE_GI | - IEEE80211_RADIOTAP_MCS_HAVE_BW; + *pos++ = local->hw.radiotap_mcs_details; *pos = 0; if (status->flag & RX_FLAG_SHORT_GI) *pos |= IEEE80211_RADIOTAP_MCS_SGI; if (status->flag & RX_FLAG_40MHZ) *pos |= IEEE80211_RADIOTAP_MCS_BW_40; + if (status->flag & RX_FLAG_HT_GF) + *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; pos++; *pos++ = status->rate_idx; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5f827a6b0d8..847215bb2a6 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -153,7 +153,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, /* Don't calculate ACKs for QoS Frames with NoAck Policy set */ if (ieee80211_is_data_qos(hdr->frame_control) && - *(ieee80211_get_qos_ctl(hdr)) | IEEE80211_QOS_CTL_ACK_POLICY_NOACK) + *(ieee80211_get_qos_ctl(hdr)) & IEEE80211_QOS_CTL_ACK_POLICY_NOACK) dur = 0; else /* Time needed to transmit ACK diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22f2216b397..a44c6807df0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1371,6 +1371,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } + /* add back keys */ + list_for_each_entry(sdata, &local->interfaces, list) + if (ieee80211_sdata_running(sdata)) + ieee80211_enable_keys(sdata); + + wake_up: /* * Clear the WLAN_STA_BLOCK_BA flag so new aggregation * sessions can be established after a resume. @@ -1392,12 +1398,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) mutex_unlock(&local->sta_mtx); } - /* add back keys */ - list_for_each_entry(sdata, &local->interfaces, list) - if (ieee80211_sdata_running(sdata)) - ieee80211_enable_keys(sdata); - - wake_up: ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 7aa31bbfaa3..c04d401dae9 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -92,6 +92,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, int keylen, int keyidx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int hdrlen; u8 *newhdr; @@ -104,6 +105,13 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); + + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return newhdr + hdrlen; + + skb_set_network_header(skb, skb_network_offset(skb) + WEP_IV_LEN); ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } @@ -313,14 +321,15 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = info->control.hw_key; - if (!info->control.hw_key) { + if (!hw_key) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } else if (info->control.hw_key->flags & - IEEE80211_KEY_FLAG_GENERATE_IV) { + } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) || + (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key->conf.keylen, tx->key->conf.keyidx)) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 0ae23c60968..bdb53aba888 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -183,7 +183,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) u8 *pos; if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { /* hwaccel - with no need for software-generated IV */ return 0; } @@ -202,8 +203,14 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos = skb_push(skb, TKIP_IV_LEN); memmove(pos, pos + TKIP_IV_LEN, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + TKIP_IV_LEN); pos += hdrlen; + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return 0; + /* Increase IV for the frame */ spin_lock_irqsave(&key->u.tkip.txlock, flags); key->u.tkip.tx.iv16++; @@ -422,6 +429,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + CCMP_HDR_LEN); /* the HW only needs room for the IV, but not the actual IV */ if (info->control.hw_key && |