1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -924,7 +924,7 @@ struct cfg80211_disassoc_request {
* @privacy: this is a protected network, keys will be configured
* after joining
* @basic_rates: bitmap of basic rates to use when creating the IBSS
- * @mcast_rate: multicast tx rate (in 100 kbps)
+ * @mcast_rate: per-band multicast rate index + 1 (0: disabled)
*/
struct cfg80211_ibss_params {
u8 *ssid;
@@ -936,7 +936,7 @@ struct cfg80211_ibss_params {
u32 basic_rates;
bool channel_fixed;
bool privacy;
- int mcast_rate;
+ int mcast_rate[IEEE80211_NUM_BANDS];
};
/**
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -219,7 +219,7 @@ enum ieee80211_bss_change {
* @basic_rates: bitmap of basic rates, each bit stands for an
* index into the rate table configured by the driver in
* the current band.
- * @mcast_rate: multicast rate for AP and Ad-Hoc (in 100 kbps)
+ * @mcast_rate: per-band multicast rate index + 1 (0: disabled)
* @bssid: The BSSID for this BSS
* @enable_beacon: whether beaconing should be enabled or not
* @channel_type: Channel type for this BSS -- the hardware might be
@@ -259,7 +259,7 @@ struct ieee80211_bss_conf {
u16 assoc_capability;
u64 timestamp;
u32 basic_rates;
- u32 mcast_rate;
+ int mcast_rate[IEEE80211_NUM_BANDS];
u16 ht_operation_mode;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -915,7 +915,8 @@ int ieee80211_ibss_join(struct ieee80211
sdata->u.ibss.privacy = params->privacy;
sdata->u.ibss.basic_rates = params->basic_rates;
- sdata->vif.bss_conf.mcast_rate = params->mcast_rate;
+ memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate,
+ sizeof(params->mcast_rate));
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -211,20 +211,11 @@ static bool rc_no_data_or_no_ack(struct
return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc);
}
-static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u32 mcast_rate,
+static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
struct ieee80211_supported_band *sband)
{
u8 i;
- if (mcast_rate) {
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sband->bitrates[i].bitrate == mcast_rate) {
- *idx = i;
- return;
- }
- }
- }
-
if (basic_rates == 0)
return; /* assume basic rates unknown and accept rate */
if (*idx < 0)
@@ -247,17 +238,25 @@ bool rate_control_send_low(struct ieee80
struct ieee80211_tx_rate_control *txrc)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+ struct ieee80211_supported_band *sband = txrc->sband;
+ int mcast_rate;
if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
info->control.rates[0].count =
(info->flags & IEEE80211_TX_CTL_NO_ACK) ?
1 : txrc->hw->max_rate_tries;
- if (!sta && txrc->bss)
+ if (!sta && txrc->bss) {
+ mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
+ if (mcast_rate > 0) {
+ info->control.rates[0].idx = mcast_rate - 1;
+ return true;
+ }
+
rc_send_low_broadcast(&info->control.rates[0].idx,
txrc->bss_conf->basic_rates,
- txrc->bss_conf->mcast_rate,
- txrc->sband);
+ sband);
+ }
return true;
}
return false;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3600,6 +3600,34 @@ static int nl80211_disassociate(struct s
local_state_change);
}
+static bool
+nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev,
+ int mcast_rate[IEEE80211_NUM_BANDS],
+ int rateval)
+{
+ struct wiphy *wiphy = &rdev->wiphy;
+ bool found = false;
+ int band, i;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ struct ieee80211_supported_band *sband;
+
+ sband = wiphy->bands[band];
+ if (!sband)
+ continue;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].bitrate == rateval) {
+ mcast_rate[band] = i + 1;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ return found;
+}
+
static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -3683,9 +3711,11 @@ static int nl80211_join_ibss(struct sk_b
return -EINVAL;
}
}
- if (info->attrs[NL80211_ATTR_MCAST_RATE])
- ibss.mcast_rate =
- nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
+
+ if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
+ !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
+ nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
+ return -EINVAL;
if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
connkeys = nl80211_parse_connkeys(rdev,
|