diff options
author | David S. Miller <davem@davemloft.net> | 2012-05-14 18:00:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-14 18:00:48 -0400 |
commit | c597f6653d5734c11b1e3217c7619a37e96e5a1f (patch) | |
tree | 2c24b46bbe265f3284dcec0a001f7af498794964 /net/mac80211 | |
parent | 669d67bf777def468970f2dcba1537edf3b2d329 (diff) | |
parent | 341352d13dae752610342923c53ebe461624ee2c (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.c | 182 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 37 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 15 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 18 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 96 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 1 | ||||
-rw-r--r-- | net/mac80211/util.c | 9 |
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 | ||
453 | static 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 | |||
464 | static 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 | |||
481 | static 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 | |||
559 | do_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 | |||
614 | static 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 | ||
454 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 628 | static 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 | ||
38 | static 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 | |||
49 | static 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 | |||
61 | static 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 | |||
38 | static inline int drv_start(struct ieee80211_local *local) | 75 | static 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 | ||
164 | DEFINE_EVENT(local_u32_evt, drv_get_et_strings, | ||
165 | TP_PROTO(struct ieee80211_local *local, u32 sset), | ||
166 | TP_ARGS(local, sset) | ||
167 | ); | ||
168 | |||
169 | DEFINE_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 | |||
174 | DEFINE_EVENT(local_only_evt, drv_get_et_stats, | ||
175 | TP_PROTO(struct ieee80211_local *local), | ||
176 | TP_ARGS(local) | ||
177 | ); | ||
178 | |||
164 | DEFINE_EVENT(local_only_evt, drv_suspend, | 179 | DEFINE_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); |
1498 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1498 | u8 *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 */ |
1503 | void ieee80211_work_init(struct ieee80211_local *local); | 1504 | void 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 | */ | ||
118 | static 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 | } | ||
148 | out: | ||
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 | ||
1664 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1664 | u8 *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 |