aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-05-14 18:00:48 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-14 18:00:48 -0400
commitc597f6653d5734c11b1e3217c7619a37e96e5a1f (patch)
tree2c24b46bbe265f3284dcec0a001f7af498794964 /net/mac80211
parent669d67bf777def468970f2dcba1537edf3b2d329 (diff)
parent341352d13dae752610342923c53ebe461624ee2c (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c182
-rw-r--r--net/mac80211/driver-ops.h37
-rw-r--r--net/mac80211/driver-trace.h15
-rw-r--r--net/mac80211/ibss.c2
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mesh.c18
-rw-r--r--net/mac80211/mesh_plink.c96
-rw-r--r--net/mac80211/mlme.c2
-rw-r--r--net/mac80211/sta_info.h1
-rw-r--r--net/mac80211/util.c9
10 files changed, 343 insertions, 22 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7e6781f8c57e..495831ee48f1 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -450,6 +450,180 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
450 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); 450 sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
451} 451}
452 452
453static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
454 "rx_packets", "rx_bytes", "wep_weak_iv_count",
455 "rx_duplicates", "rx_fragments", "rx_dropped",
456 "tx_packets", "tx_bytes", "tx_fragments",
457 "tx_filtered", "tx_retry_failed", "tx_retries",
458 "beacon_loss", "sta_state", "txrate", "rxrate", "signal",
459 "channel", "noise", "ch_time", "ch_time_busy",
460 "ch_time_ext_busy", "ch_time_rx", "ch_time_tx"
461};
462#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats)
463
464static int ieee80211_get_et_sset_count(struct wiphy *wiphy,
465 struct net_device *dev,
466 int sset)
467{
468 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
469 int rv = 0;
470
471 if (sset == ETH_SS_STATS)
472 rv += STA_STATS_LEN;
473
474 rv += drv_get_et_sset_count(sdata, sset);
475
476 if (rv == 0)
477 return -EOPNOTSUPP;
478 return rv;
479}
480
481static void ieee80211_get_et_stats(struct wiphy *wiphy,
482 struct net_device *dev,
483 struct ethtool_stats *stats,
484 u64 *data)
485{
486 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
487 struct sta_info *sta;
488 struct ieee80211_local *local = sdata->local;
489 struct station_info sinfo;
490 struct survey_info survey;
491 int i, q;
492#define STA_STATS_SURVEY_LEN 7
493
494 memset(data, 0, sizeof(u64) * STA_STATS_LEN);
495
496#define ADD_STA_STATS(sta) \
497 do { \
498 data[i++] += sta->rx_packets; \
499 data[i++] += sta->rx_bytes; \
500 data[i++] += sta->wep_weak_iv_count; \
501 data[i++] += sta->num_duplicates; \
502 data[i++] += sta->rx_fragments; \
503 data[i++] += sta->rx_dropped; \
504 \
505 data[i++] += sta->tx_packets; \
506 data[i++] += sta->tx_bytes; \
507 data[i++] += sta->tx_fragments; \
508 data[i++] += sta->tx_filtered_count; \
509 data[i++] += sta->tx_retry_failed; \
510 data[i++] += sta->tx_retry_count; \
511 data[i++] += sta->beacon_loss_count; \
512 } while (0)
513
514 /* For Managed stations, find the single station based on BSSID
515 * and use that. For interface types, iterate through all available
516 * stations and add stats for any station that is assigned to this
517 * network device.
518 */
519
520 rcu_read_lock();
521
522 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
523 sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
524
525 if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
526 goto do_survey;
527
528 i = 0;
529 ADD_STA_STATS(sta);
530
531 data[i++] = sta->sta_state;
532
533 sinfo.filled = 0;
534 sta_set_sinfo(sta, &sinfo);
535
536 if (sinfo.filled | STATION_INFO_TX_BITRATE)
537 data[i] = 100000 *
538 cfg80211_calculate_bitrate(&sinfo.txrate);
539 i++;
540 if (sinfo.filled | STATION_INFO_RX_BITRATE)
541 data[i] = 100000 *
542 cfg80211_calculate_bitrate(&sinfo.rxrate);
543 i++;
544
545 if (sinfo.filled | STATION_INFO_SIGNAL_AVG)
546 data[i] = (u8)sinfo.signal_avg;
547 i++;
548 } else {
549 list_for_each_entry_rcu(sta, &local->sta_list, list) {
550 /* Make sure this station belongs to the proper dev */
551 if (sta->sdata->dev != dev)
552 continue;
553
554 i = 0;
555 ADD_STA_STATS(sta);
556 }
557 }
558
559do_survey:
560 i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
561 /* Get survey stats for current channel */
562 q = 0;
563 while (true) {
564 survey.filled = 0;
565 if (drv_get_survey(local, q, &survey) != 0) {
566 survey.filled = 0;
567 break;
568 }
569
570 if (survey.channel &&
571 (local->oper_channel->center_freq ==
572 survey.channel->center_freq))
573 break;
574 q++;
575 }
576
577 if (survey.filled)
578 data[i++] = survey.channel->center_freq;
579 else
580 data[i++] = 0;
581 if (survey.filled & SURVEY_INFO_NOISE_DBM)
582 data[i++] = (u8)survey.noise;
583 else
584 data[i++] = -1LL;
585 if (survey.filled & SURVEY_INFO_CHANNEL_TIME)
586 data[i++] = survey.channel_time;
587 else
588 data[i++] = -1LL;
589 if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
590 data[i++] = survey.channel_time_busy;
591 else
592 data[i++] = -1LL;
593 if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
594 data[i++] = survey.channel_time_ext_busy;
595 else
596 data[i++] = -1LL;
597 if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX)
598 data[i++] = survey.channel_time_rx;
599 else
600 data[i++] = -1LL;
601 if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX)
602 data[i++] = survey.channel_time_tx;
603 else
604 data[i++] = -1LL;
605
606 rcu_read_unlock();
607
608 if (WARN_ON(i != STA_STATS_LEN))
609 return;
610
611 drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
612}
613
614static void ieee80211_get_et_strings(struct wiphy *wiphy,
615 struct net_device *dev,
616 u32 sset, u8 *data)
617{
618 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
619 int sz_sta_stats = 0;
620
621 if (sset == ETH_SS_STATS) {
622 sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
623 memcpy(data, *ieee80211_gstrings_sta_stats, sz_sta_stats);
624 }
625 drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
626}
453 627
454static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, 628static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
455 int idx, u8 *mac, struct station_info *sinfo) 629 int idx, u8 *mac, struct station_info *sinfo)
@@ -1364,6 +1538,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
1364 return -ENOTSUPP; 1538 return -ENOTSUPP;
1365 conf->rssi_threshold = nconf->rssi_threshold; 1539 conf->rssi_threshold = nconf->rssi_threshold;
1366 } 1540 }
1541 if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) {
1542 conf->ht_opmode = nconf->ht_opmode;
1543 sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
1544 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
1545 }
1367 return 0; 1546 return 0;
1368} 1547}
1369 1548
@@ -2794,4 +2973,7 @@ struct cfg80211_ops mac80211_config_ops = {
2794#ifdef CONFIG_PM 2973#ifdef CONFIG_PM
2795 .set_wakeup = ieee80211_set_wakeup, 2974 .set_wakeup = ieee80211_set_wakeup,
2796#endif 2975#endif
2976 .get_et_sset_count = ieee80211_get_et_sset_count,
2977 .get_et_stats = ieee80211_get_et_stats,
2978 .get_et_strings = ieee80211_get_et_strings,
2797}; 2979};
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4a0e559cb26b..6d33a0c743ab 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -35,6 +35,43 @@ static inline void drv_tx_frags(struct ieee80211_local *local,
35 local->ops->tx_frags(&local->hw, vif, sta, skbs); 35 local->ops->tx_frags(&local->hw, vif, sta, skbs);
36} 36}
37 37
38static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata,
39 u32 sset, u8 *data)
40{
41 struct ieee80211_local *local = sdata->local;
42 if (local->ops->get_et_strings) {
43 trace_drv_get_et_strings(local, sset);
44 local->ops->get_et_strings(&local->hw, &sdata->vif, sset, data);
45 trace_drv_return_void(local);
46 }
47}
48
49static inline void drv_get_et_stats(struct ieee80211_sub_if_data *sdata,
50 struct ethtool_stats *stats,
51 u64 *data)
52{
53 struct ieee80211_local *local = sdata->local;
54 if (local->ops->get_et_stats) {
55 trace_drv_get_et_stats(local);
56 local->ops->get_et_stats(&local->hw, &sdata->vif, stats, data);
57 trace_drv_return_void(local);
58 }
59}
60
61static inline int drv_get_et_sset_count(struct ieee80211_sub_if_data *sdata,
62 int sset)
63{
64 struct ieee80211_local *local = sdata->local;
65 int rv = 0;
66 if (local->ops->get_et_sset_count) {
67 trace_drv_get_et_sset_count(local, sset);
68 rv = local->ops->get_et_sset_count(&local->hw, &sdata->vif,
69 sset);
70 trace_drv_return_int(local, rv);
71 }
72 return rv;
73}
74
38static inline int drv_start(struct ieee80211_local *local) 75static inline int drv_start(struct ieee80211_local *local)
39{ 76{
40 int ret; 77 int ret;
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 7c0754bed61b..6de00b2c268c 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -161,6 +161,21 @@ DEFINE_EVENT(local_only_evt, drv_start,
161 TP_ARGS(local) 161 TP_ARGS(local)
162); 162);
163 163
164DEFINE_EVENT(local_u32_evt, drv_get_et_strings,
165 TP_PROTO(struct ieee80211_local *local, u32 sset),
166 TP_ARGS(local, sset)
167);
168
169DEFINE_EVENT(local_u32_evt, drv_get_et_sset_count,
170 TP_PROTO(struct ieee80211_local *local, u32 sset),
171 TP_ARGS(local, sset)
172);
173
174DEFINE_EVENT(local_only_evt, drv_get_et_stats,
175 TP_PROTO(struct ieee80211_local *local),
176 TP_ARGS(local)
177);
178
164DEFINE_EVENT(local_only_evt, drv_suspend, 179DEFINE_EVENT(local_only_evt, drv_suspend,
165 TP_PROTO(struct ieee80211_local *local), 180 TP_PROTO(struct ieee80211_local *local),
166 TP_ARGS(local) 181 TP_ARGS(local)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d307d3b3e32a..ebafba61c2ff 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -164,7 +164,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
164 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, 164 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
165 sband->ht_cap.cap); 165 sband->ht_cap.cap);
166 pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, 166 pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
167 chan, channel_type); 167 chan, channel_type, 0);
168 } 168 }
169 169
170 if (local->hw.queues >= IEEE80211_NUM_ACS) { 170 if (local->hw.queues >= IEEE80211_NUM_ACS) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index fabee974bf6d..3f3cd50fff16 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1497,7 +1497,8 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
1497 u16 cap); 1497 u16 cap);
1498u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 1498u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
1499 struct ieee80211_channel *channel, 1499 struct ieee80211_channel *channel,
1500 enum nl80211_channel_type channel_type); 1500 enum nl80211_channel_type channel_type,
1501 u16 prot_mode);
1501 1502
1502/* internal work items */ 1503/* internal work items */
1503void ieee80211_work_init(struct ieee80211_local *local); 1504void ieee80211_work_init(struct ieee80211_local *local);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 775627166e48..0675a2fec6a6 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -76,6 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
76 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 76 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
77 struct ieee80211_local *local = sdata->local; 77 struct ieee80211_local *local = sdata->local;
78 u32 basic_rates = 0; 78 u32 basic_rates = 0;
79 enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT;
79 80
80 /* 81 /*
81 * As support for each feature is added, check for matching 82 * As support for each feature is added, check for matching
@@ -102,10 +103,15 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
102 if (sdata->vif.bss_conf.basic_rates != basic_rates) 103 if (sdata->vif.bss_conf.basic_rates != basic_rates)
103 goto mismatch; 104 goto mismatch;
104 105
105 /* disallow peering with mismatched channel types for now */ 106 if (ie->ht_operation)
107 sta_channel_type =
108 ieee80211_ht_oper_to_channel_type(ie->ht_operation);
109
110 /* Disallow HT40+/- mismatch */
106 if (ie->ht_operation && 111 if (ie->ht_operation &&
107 (local->_oper_channel_type != 112 local->_oper_channel_type > NL80211_CHAN_HT20 &&
108 ieee80211_ht_oper_to_channel_type(ie->ht_operation))) 113 sta_channel_type > NL80211_CHAN_HT20 &&
114 local->_oper_channel_type != sta_channel_type)
109 goto mismatch; 115 goto mismatch;
110 116
111 return true; 117 return true;
@@ -396,7 +402,8 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
396 return -ENOMEM; 402 return -ENOMEM;
397 403
398 pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); 404 pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
399 ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type); 405 ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type,
406 sdata->vif.bss_conf.ht_operation_mode);
400 407
401 return 0; 408 return 0;
402} 409}
@@ -588,12 +595,15 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
588 set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); 595 set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
589 ieee80211_mesh_root_setup(ifmsh); 596 ieee80211_mesh_root_setup(ifmsh);
590 ieee80211_queue_work(&local->hw, &sdata->work); 597 ieee80211_queue_work(&local->hw, &sdata->work);
598 sdata->vif.bss_conf.ht_operation_mode =
599 ifmsh->mshcfg.ht_opmode;
591 sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; 600 sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
592 sdata->vif.bss_conf.basic_rates = 601 sdata->vif.bss_conf.basic_rates =
593 ieee80211_mandatory_rates(sdata->local, 602 ieee80211_mandatory_rates(sdata->local,
594 sdata->local->hw.conf.channel->band); 603 sdata->local->hw.conf.channel->band);
595 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | 604 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
596 BSS_CHANGED_BEACON_ENABLED | 605 BSS_CHANGED_BEACON_ENABLED |
606 BSS_CHANGED_HT |
597 BSS_CHANGED_BASIC_RATES | 607 BSS_CHANGED_BASIC_RATES |
598 BSS_CHANGED_BEACON_INT); 608 BSS_CHANGED_BEACON_INT);
599} 609}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 1ff2a5c63e43..8cc8461b48a0 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -102,12 +102,70 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
102 102
103 set_sta_flag(sta, WLAN_STA_WME); 103 set_sta_flag(sta, WLAN_STA_WME);
104 104
105 if (sta_info_insert(sta))
106 return NULL;
107
108 return sta; 105 return sta;
109} 106}
110 107
108/** mesh_set_ht_prot_mode - set correct HT protection mode
109 *
110 * Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for
111 * HT mesh STA in a MBSS. Three HT protection modes are supported for now,
112 * non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed
113 * mode is selected if any non-HT peers are present in our MBSS.
114 * 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support
115 * HT and atleast one HT20 peer is present. Otherwise no-protection mode is
116 * selected.
117 */
118static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
119{
120 struct ieee80211_local *local = sdata->local;
121 struct sta_info *sta;
122 u32 changed = 0;
123 u16 ht_opmode;
124 bool non_ht_sta = false, ht20_sta = false;
125
126 if (local->_oper_channel_type == NL80211_CHAN_NO_HT)
127 return 0;
128
129 rcu_read_lock();
130 list_for_each_entry_rcu(sta, &local->sta_list, list) {
131 if (sdata == sta->sdata &&
132 sta->plink_state == NL80211_PLINK_ESTAB) {
133 switch (sta->ch_type) {
134 case NL80211_CHAN_NO_HT:
135 mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
136 sdata->vif.addr, sta->sta.addr);
137 non_ht_sta = true;
138 goto out;
139 case NL80211_CHAN_HT20:
140 mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
141 sdata->vif.addr, sta->sta.addr);
142 ht20_sta = true;
143 default:
144 break;
145 }
146 }
147 }
148out:
149 rcu_read_unlock();
150
151 if (non_ht_sta)
152 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
153 else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20)
154 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
155 else
156 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
157
158 if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
159 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
160 sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
161 changed = BSS_CHANGED_HT;
162 mpl_dbg("mesh_plink %pM: protection mode changed to %d",
163 sdata->vif.addr, ht_opmode);
164 }
165
166 return changed;
167}
168
111/** 169/**
112 * __mesh_plink_deactivate - deactivate mesh peer link 170 * __mesh_plink_deactivate - deactivate mesh peer link
113 * 171 *
@@ -281,6 +339,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
281 struct ieee80211_supported_band *sband; 339 struct ieee80211_supported_band *sband;
282 u32 rates, basic_rates = 0; 340 u32 rates, basic_rates = 0;
283 struct sta_info *sta; 341 struct sta_info *sta;
342 bool insert = false;
284 343
285 sband = local->hw.wiphy->bands[band]; 344 sband = local->hw.wiphy->bands[band];
286 rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); 345 rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
@@ -290,6 +349,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
290 sta = mesh_plink_alloc(sdata, addr); 349 sta = mesh_plink_alloc(sdata, addr);
291 if (!sta) 350 if (!sta)
292 return NULL; 351 return NULL;
352 insert = true;
293 } 353 }
294 354
295 spin_lock_bh(&sta->lock); 355 spin_lock_bh(&sta->lock);
@@ -303,9 +363,21 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
303 else 363 else
304 memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); 364 memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
305 365
366 if (elems->ht_operation) {
367 if (!(elems->ht_operation->ht_param &
368 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
369 sta->sta.ht_cap.cap &=
370 ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
371 sta->ch_type =
372 ieee80211_ht_oper_to_channel_type(elems->ht_operation);
373 }
374
306 rate_control_rate_init(sta); 375 rate_control_rate_init(sta);
307 spin_unlock_bh(&sta->lock); 376 spin_unlock_bh(&sta->lock);
308 377
378 if (insert && sta_info_insert(sta))
379 return NULL;
380
309 return sta; 381 return sta;
310} 382}
311 383
@@ -487,9 +559,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
487 enum plink_event event; 559 enum plink_event event;
488 enum ieee80211_self_protected_actioncode ftype; 560 enum ieee80211_self_protected_actioncode ftype;
489 size_t baselen; 561 size_t baselen;
490 bool deactivated, matches_local = true; 562 bool matches_local = true;
491 u8 ie_len; 563 u8 ie_len;
492 u8 *baseaddr; 564 u8 *baseaddr;
565 u32 changed = 0;
493 __le16 plid, llid, reason; 566 __le16 plid, llid, reason;
494#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG 567#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
495 static const char *mplstates[] = { 568 static const char *mplstates[] = {
@@ -775,7 +848,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
775 sta->plink_state = NL80211_PLINK_ESTAB; 848 sta->plink_state = NL80211_PLINK_ESTAB;
776 spin_unlock_bh(&sta->lock); 849 spin_unlock_bh(&sta->lock);
777 mesh_plink_inc_estab_count(sdata); 850 mesh_plink_inc_estab_count(sdata);
778 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); 851 changed |= mesh_set_ht_prot_mode(sdata);
852 changed |= BSS_CHANGED_BEACON;
779 mpl_dbg("Mesh plink with %pM ESTABLISHED\n", 853 mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
780 sta->sta.addr); 854 sta->sta.addr);
781 break; 855 break;
@@ -810,7 +884,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
810 sta->plink_state = NL80211_PLINK_ESTAB; 884 sta->plink_state = NL80211_PLINK_ESTAB;
811 spin_unlock_bh(&sta->lock); 885 spin_unlock_bh(&sta->lock);
812 mesh_plink_inc_estab_count(sdata); 886 mesh_plink_inc_estab_count(sdata);
813 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); 887 changed |= mesh_set_ht_prot_mode(sdata);
888 changed |= BSS_CHANGED_BEACON;
814 mpl_dbg("Mesh plink with %pM ESTABLISHED\n", 889 mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
815 sta->sta.addr); 890 sta->sta.addr);
816 mesh_plink_frame_tx(sdata, 891 mesh_plink_frame_tx(sdata,
@@ -828,13 +903,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
828 case CLS_ACPT: 903 case CLS_ACPT:
829 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); 904 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
830 sta->reason = reason; 905 sta->reason = reason;
831 deactivated = __mesh_plink_deactivate(sta); 906 __mesh_plink_deactivate(sta);
832 sta->plink_state = NL80211_PLINK_HOLDING; 907 sta->plink_state = NL80211_PLINK_HOLDING;
833 llid = sta->llid; 908 llid = sta->llid;
834 mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); 909 mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
835 spin_unlock_bh(&sta->lock); 910 spin_unlock_bh(&sta->lock);
836 if (deactivated) 911 changed |= mesh_set_ht_prot_mode(sdata);
837 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); 912 changed |= BSS_CHANGED_BEACON;
838 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, 913 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
839 sta->sta.addr, llid, plid, reason); 914 sta->sta.addr, llid, plid, reason);
840 break; 915 break;
@@ -881,4 +956,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
881 } 956 }
882 957
883 rcu_read_unlock(); 958 rcu_read_unlock();
959
960 if (changed)
961 ieee80211_bss_info_change_notify(sdata, changed);
884} 962}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b1c617fdabd6..52cd301245ae 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -210,7 +210,7 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
210 disable_40 = true; 210 disable_40 = true;
211 211
212 if (sta && (!reconfig || 212 if (sta && (!reconfig ||
213 (disable_40 != !!(sta->sta.ht_cap.cap & 213 (disable_40 != !(sta->sta.ht_cap.cap &
214 IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) { 214 IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
215 215
216 if (disable_40) 216 if (disable_40)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index e920b229fb8c..3bb24a121c95 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -362,6 +362,7 @@ struct sta_info {
362 struct timer_list plink_timer; 362 struct timer_list plink_timer;
363 s64 t_offset; 363 s64 t_offset;
364 s64 t_offset_setpoint; 364 s64 t_offset_setpoint;
365 enum nl80211_channel_type ch_type;
365#endif 366#endif
366 367
367#ifdef CONFIG_MAC80211_DEBUGFS 368#ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d9a747d387f0..22f2216b397e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1663,7 +1663,8 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
1663 1663
1664u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 1664u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
1665 struct ieee80211_channel *channel, 1665 struct ieee80211_channel *channel,
1666 enum nl80211_channel_type channel_type) 1666 enum nl80211_channel_type channel_type,
1667 u16 prot_mode)
1667{ 1668{
1668 struct ieee80211_ht_operation *ht_oper; 1669 struct ieee80211_ht_operation *ht_oper;
1669 /* Build HT Information */ 1670 /* Build HT Information */
@@ -1689,11 +1690,7 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
1689 channel_type != NL80211_CHAN_HT20) 1690 channel_type != NL80211_CHAN_HT20)
1690 ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; 1691 ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
1691 1692
1692 /* 1693 ht_oper->operation_mode = cpu_to_le16(prot_mode);
1693 * Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
1694 * RIFS Mode are reserved in IBSS mode, therefore keep them at 0
1695 */
1696 ht_oper->operation_mode = 0x0000;
1697 ht_oper->stbc_param = 0x0000; 1694 ht_oper->stbc_param = 0x0000;
1698 1695
1699 /* It seems that Basic MCS set and Supported MCS set 1696 /* It seems that Basic MCS set and Supported MCS set