diff options
author | David S. Miller <davem@davemloft.net> | 2008-11-10 16:24:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-10 16:24:44 -0500 |
commit | 23779897546c1effb546ff89b89803d9d955d517 (patch) | |
tree | d4b5d52b5d716a72755ba018382d4b87eae763a4 /net | |
parent | f574179b63e48f5285468b5ee40f3c480221f708 (diff) | |
parent | c4832467a5c8c2ae96d6dad882be4d4ab9eefad7 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 4 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 45 | ||||
-rw-r--r-- | net/mac80211/ht.c | 10 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/main.c | 15 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 2 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 5 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 38 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 2 | ||||
-rw-r--r-- | net/mac80211/scan.c | 2 | ||||
-rw-r--r-- | net/mac80211/tx.c | 1 | ||||
-rw-r--r-- | net/mac80211/wext.c | 16 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 75 | ||||
-rw-r--r-- | net/wireless/reg.c | 192 | ||||
-rw-r--r-- | net/wireless/util.c | 19 |
15 files changed, 349 insertions, 80 deletions
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 29eb41695a82..7cc4e5ee3660 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c | |||
@@ -399,6 +399,10 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, | |||
399 | 399 | ||
400 | /* If a new key was provided, set it up */ | 400 | /* If a new key was provided, set it up */ |
401 | if (erq->length > 0) { | 401 | if (erq->length > 0) { |
402 | #ifdef CONFIG_IEEE80211_DEBUG | ||
403 | DECLARE_SSID_BUF(ssid); | ||
404 | #endif | ||
405 | |||
402 | len = erq->length <= 5 ? 5 : 13; | 406 | len = erq->length <= 5 ? 5 : 13; |
403 | memcpy(sec.keys[key], keybuf, erq->length); | 407 | memcpy(sec.keys[key], keybuf, erq->length); |
404 | if (len > erq->length) | 408 | if (len > erq->length) |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 91f56a48e2b4..16423f94801b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -26,6 +26,8 @@ static bool nl80211_type_check(enum nl80211_iftype type) | |||
26 | #ifdef CONFIG_MAC80211_MESH | 26 | #ifdef CONFIG_MAC80211_MESH |
27 | case NL80211_IFTYPE_MESH_POINT: | 27 | case NL80211_IFTYPE_MESH_POINT: |
28 | #endif | 28 | #endif |
29 | case NL80211_IFTYPE_AP: | ||
30 | case NL80211_IFTYPE_AP_VLAN: | ||
29 | case NL80211_IFTYPE_WDS: | 31 | case NL80211_IFTYPE_WDS: |
30 | return true; | 32 | return true; |
31 | default: | 33 | default: |
@@ -1046,11 +1048,53 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1046 | changed |= BSS_CHANGED_ERP_SLOT; | 1048 | changed |= BSS_CHANGED_ERP_SLOT; |
1047 | } | 1049 | } |
1048 | 1050 | ||
1051 | if (params->basic_rates) { | ||
1052 | int i, j; | ||
1053 | u32 rates = 0; | ||
1054 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1055 | struct ieee80211_supported_band *sband = | ||
1056 | wiphy->bands[local->oper_channel->band]; | ||
1057 | |||
1058 | for (i = 0; i < params->basic_rates_len; i++) { | ||
1059 | int rate = (params->basic_rates[i] & 0x7f) * 5; | ||
1060 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1061 | if (sband->bitrates[j].bitrate == rate) | ||
1062 | rates |= BIT(j); | ||
1063 | } | ||
1064 | } | ||
1065 | sdata->vif.bss_conf.basic_rates = rates; | ||
1066 | changed |= BSS_CHANGED_BASIC_RATES; | ||
1067 | } | ||
1068 | |||
1049 | ieee80211_bss_info_change_notify(sdata, changed); | 1069 | ieee80211_bss_info_change_notify(sdata, changed); |
1050 | 1070 | ||
1051 | return 0; | 1071 | return 0; |
1052 | } | 1072 | } |
1053 | 1073 | ||
1074 | static int ieee80211_set_txq_params(struct wiphy *wiphy, | ||
1075 | struct ieee80211_txq_params *params) | ||
1076 | { | ||
1077 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1078 | struct ieee80211_tx_queue_params p; | ||
1079 | |||
1080 | if (!local->ops->conf_tx) | ||
1081 | return -EOPNOTSUPP; | ||
1082 | |||
1083 | memset(&p, 0, sizeof(p)); | ||
1084 | p.aifs = params->aifs; | ||
1085 | p.cw_max = params->cwmax; | ||
1086 | p.cw_min = params->cwmin; | ||
1087 | p.txop = params->txop; | ||
1088 | if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { | ||
1089 | printk(KERN_DEBUG "%s: failed to set TX queue " | ||
1090 | "parameters for queue %d\n", local->mdev->name, | ||
1091 | params->queue); | ||
1092 | return -EINVAL; | ||
1093 | } | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1054 | struct cfg80211_ops mac80211_config_ops = { | 1098 | struct cfg80211_ops mac80211_config_ops = { |
1055 | .add_virtual_intf = ieee80211_add_iface, | 1099 | .add_virtual_intf = ieee80211_add_iface, |
1056 | .del_virtual_intf = ieee80211_del_iface, | 1100 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1077,4 +1121,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1077 | .get_mesh_params = ieee80211_get_mesh_params, | 1121 | .get_mesh_params = ieee80211_get_mesh_params, |
1078 | #endif | 1122 | #endif |
1079 | .change_bss = ieee80211_change_bss, | 1123 | .change_bss = ieee80211_change_bss, |
1124 | .set_txq_params = ieee80211_set_txq_params, | ||
1080 | }; | 1125 | }; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 08009d4b7d6e..3e231d756776 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -987,7 +987,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
987 | { | 987 | { |
988 | struct ieee80211_hw *hw = &local->hw; | 988 | struct ieee80211_hw *hw = &local->hw; |
989 | u16 capab; | 989 | u16 capab; |
990 | u16 tid; | 990 | u16 tid, start_seq_num; |
991 | u8 *state; | 991 | u8 *state; |
992 | 992 | ||
993 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 993 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
@@ -1024,6 +1024,14 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
1024 | local->hw.ampdu_queues) | 1024 | local->hw.ampdu_queues) |
1025 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 1025 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); |
1026 | 1026 | ||
1027 | if (local->ops->ampdu_action) { | ||
1028 | (void)local->ops->ampdu_action(hw, | ||
1029 | IEEE80211_AMPDU_TX_RESUME, | ||
1030 | &sta->sta, tid, &start_seq_num); | ||
1031 | } | ||
1032 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1033 | printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); | ||
1034 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1027 | spin_unlock_bh(&sta->lock); | 1035 | spin_unlock_bh(&sta->lock); |
1028 | } else { | 1036 | } else { |
1029 | sta->ampdu_mlme.addba_req_num[tid]++; | 1037 | sta->ampdu_mlme.addba_req_num[tid]++; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2c91108e3901..155a20410017 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -212,9 +212,6 @@ struct ieee80211_if_ap { | |||
212 | 212 | ||
213 | struct list_head vlans; | 213 | struct list_head vlans; |
214 | 214 | ||
215 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
216 | size_t ssid_len; | ||
217 | |||
218 | /* yes, this looks ugly, but guarantees that we can later use | 215 | /* yes, this looks ugly, but guarantees that we can later use |
219 | * bitmap_empty :) | 216 | * bitmap_empty :) |
220 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ | 217 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index fa0cc7a1e6b4..d631dc96c323 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -171,19 +171,13 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
171 | conf.changed = changed; | 171 | conf.changed = changed; |
172 | 172 | ||
173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) |
175 | conf.bssid = sdata->u.sta.bssid; | 175 | conf.bssid = sdata->u.sta.bssid; |
176 | conf.ssid = sdata->u.sta.ssid; | 176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
177 | conf.ssid_len = sdata->u.sta.ssid_len; | ||
178 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
179 | conf.bssid = sdata->dev->dev_addr; | 177 | conf.bssid = sdata->dev->dev_addr; |
180 | conf.ssid = sdata->u.ap.ssid; | 178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
181 | conf.ssid_len = sdata->u.ap.ssid_len; | ||
182 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
183 | u8 zero[ETH_ALEN] = { 0 }; | 179 | u8 zero[ETH_ALEN] = { 0 }; |
184 | conf.bssid = zero; | 180 | conf.bssid = zero; |
185 | conf.ssid = zero; | ||
186 | conf.ssid_len = 0; | ||
187 | } else { | 181 | } else { |
188 | WARN_ON(1); | 182 | WARN_ON(1); |
189 | return -EINVAL; | 183 | return -EINVAL; |
@@ -192,9 +186,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
192 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) | 186 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) |
193 | return -EINVAL; | 187 | return -EINVAL; |
194 | 188 | ||
195 | if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID))) | ||
196 | return -EINVAL; | ||
197 | |||
198 | return local->ops->config_interface(local_to_hw(local), | 189 | return local->ops->config_interface(local_to_hw(local), |
199 | &sdata->vif, &conf); | 190 | &sdata->vif, &conf); |
200 | } | 191 | } |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index d3b6e1a648bd..82f568e94365 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -238,7 +238,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
238 | 238 | ||
239 | pos = skb_put(skb, 21); | 239 | pos = skb_put(skb, 21); |
240 | *pos++ = WLAN_EID_MESH_CONFIG; | 240 | *pos++ = WLAN_EID_MESH_CONFIG; |
241 | *pos++ = MESH_CFG_LEN; | 241 | *pos++ = IEEE80211_MESH_CONFIG_LEN; |
242 | /* Version */ | 242 | /* Version */ |
243 | *pos++ = 1; | 243 | *pos++ = 1; |
244 | 244 | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e10471c6ba42..c197ab545e54 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -145,9 +145,6 @@ struct mesh_rmc { | |||
145 | }; | 145 | }; |
146 | 146 | ||
147 | 147 | ||
148 | /* Mesh IEs constants */ | ||
149 | #define MESH_CFG_LEN 19 | ||
150 | |||
151 | /* | 148 | /* |
152 | * MESH_CFG_COMP_LEN Includes: | 149 | * MESH_CFG_COMP_LEN Includes: |
153 | * - Active path selection protocol ID. | 150 | * - Active path selection protocol ID. |
@@ -157,7 +154,7 @@ struct mesh_rmc { | |||
157 | * Does not include mesh capabilities, which may vary across nodes in the same | 154 | * Does not include mesh capabilities, which may vary across nodes in the same |
158 | * mesh | 155 | * mesh |
159 | */ | 156 | */ |
160 | #define MESH_CFG_CMP_LEN 17 | 157 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) |
161 | 158 | ||
162 | /* Default values, timeouts in ms */ | 159 | /* Default values, timeouts in ms */ |
163 | #define MESH_TTL 5 | 160 | #define MESH_TTL 5 |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29fafbe440b7..dee6448c4eb0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1123,7 +1123,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1123 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 1123 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1124 | 1124 | ||
1125 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) | 1125 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) |
1126 | printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name); | 1126 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1127 | sdata->dev->name, reason_code); | ||
1127 | 1128 | ||
1128 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1129 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1129 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || | 1130 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || |
@@ -1154,7 +1155,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1154 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1155 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
1155 | 1156 | ||
1156 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 1157 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) |
1157 | printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name); | 1158 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1159 | sdata->dev->name, reason_code); | ||
1158 | 1160 | ||
1159 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1161 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1160 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 1162 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; |
@@ -1289,29 +1291,35 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1289 | 1291 | ||
1290 | for (i = 0; i < elems.supp_rates_len; i++) { | 1292 | for (i = 0; i < elems.supp_rates_len; i++) { |
1291 | int rate = (elems.supp_rates[i] & 0x7f) * 5; | 1293 | int rate = (elems.supp_rates[i] & 0x7f) * 5; |
1294 | bool is_basic = !!(elems.supp_rates[i] & 0x80); | ||
1292 | 1295 | ||
1293 | if (rate > 110) | 1296 | if (rate > 110) |
1294 | have_higher_than_11mbit = true; | 1297 | have_higher_than_11mbit = true; |
1295 | 1298 | ||
1296 | for (j = 0; j < sband->n_bitrates; j++) { | 1299 | for (j = 0; j < sband->n_bitrates; j++) { |
1297 | if (sband->bitrates[j].bitrate == rate) | 1300 | if (sband->bitrates[j].bitrate == rate) { |
1298 | rates |= BIT(j); | 1301 | rates |= BIT(j); |
1299 | if (elems.supp_rates[i] & 0x80) | 1302 | if (is_basic) |
1300 | basic_rates |= BIT(j); | 1303 | basic_rates |= BIT(j); |
1304 | break; | ||
1305 | } | ||
1301 | } | 1306 | } |
1302 | } | 1307 | } |
1303 | 1308 | ||
1304 | for (i = 0; i < elems.ext_supp_rates_len; i++) { | 1309 | for (i = 0; i < elems.ext_supp_rates_len; i++) { |
1305 | int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; | 1310 | int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; |
1311 | bool is_basic = !!(elems.supp_rates[i] & 0x80); | ||
1306 | 1312 | ||
1307 | if (rate > 110) | 1313 | if (rate > 110) |
1308 | have_higher_than_11mbit = true; | 1314 | have_higher_than_11mbit = true; |
1309 | 1315 | ||
1310 | for (j = 0; j < sband->n_bitrates; j++) { | 1316 | for (j = 0; j < sband->n_bitrates; j++) { |
1311 | if (sband->bitrates[j].bitrate == rate) | 1317 | if (sband->bitrates[j].bitrate == rate) { |
1312 | rates |= BIT(j); | 1318 | rates |= BIT(j); |
1313 | if (elems.ext_supp_rates[i] & 0x80) | 1319 | if (is_basic) |
1314 | basic_rates |= BIT(j); | 1320 | basic_rates |= BIT(j); |
1321 | break; | ||
1322 | } | ||
1315 | } | 1323 | } |
1316 | } | 1324 | } |
1317 | 1325 | ||
@@ -2414,7 +2422,6 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | |||
2414 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | 2422 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) |
2415 | { | 2423 | { |
2416 | struct ieee80211_if_sta *ifsta; | 2424 | struct ieee80211_if_sta *ifsta; |
2417 | int res; | ||
2418 | 2425 | ||
2419 | if (len > IEEE80211_MAX_SSID_LEN) | 2426 | if (len > IEEE80211_MAX_SSID_LEN) |
2420 | return -EINVAL; | 2427 | return -EINVAL; |
@@ -2426,19 +2433,6 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size | |||
2426 | memcpy(ifsta->ssid, ssid, len); | 2433 | memcpy(ifsta->ssid, ssid, len); |
2427 | ifsta->ssid_len = len; | 2434 | ifsta->ssid_len = len; |
2428 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 2435 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
2429 | |||
2430 | res = 0; | ||
2431 | /* | ||
2432 | * Hack! MLME code needs to be cleaned up to have different | ||
2433 | * entry points for configuration and internal selection change | ||
2434 | */ | ||
2435 | if (netif_running(sdata->dev)) | ||
2436 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); | ||
2437 | if (res) { | ||
2438 | printk(KERN_DEBUG "%s: Failed to config new SSID to " | ||
2439 | "the low-level driver\n", sdata->dev->name); | ||
2440 | return res; | ||
2441 | } | ||
2442 | } | 2436 | } |
2443 | 2437 | ||
2444 | if (len) | 2438 | if (len) |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index c643e373fc50..2b3b490a6073 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -225,7 +225,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) | |||
225 | return sample_ndx; | 225 | return sample_ndx; |
226 | } | 226 | } |
227 | 227 | ||
228 | void | 228 | static void |
229 | minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | 229 | minstrel_get_rate(void *priv, struct ieee80211_sta *sta, |
230 | void *priv_sta, struct ieee80211_tx_rate_control *txrc) | 230 | void *priv_sta, struct ieee80211_tx_rate_control *txrc) |
231 | { | 231 | { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 7372d7abb8c0..f5c7c3371929 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -159,7 +159,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i | |||
159 | { | 159 | { |
160 | struct ieee80211_bss *bss; | 160 | struct ieee80211_bss *bss; |
161 | 161 | ||
162 | if (mesh_config_len != MESH_CFG_LEN) | 162 | if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN) |
163 | return NULL; | 163 | return NULL; |
164 | 164 | ||
165 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | 165 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d6392af9cd20..0d81b2cfd1a6 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -698,7 +698,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
698 | left = payload_len - per_fragm; | 698 | left = payload_len - per_fragm; |
699 | for (i = 0; i < num_fragm - 1; i++) { | 699 | for (i = 0; i < num_fragm - 1; i++) { |
700 | struct ieee80211_hdr *fhdr; | 700 | struct ieee80211_hdr *fhdr; |
701 | struct ieee80211_tx_info *info; | ||
702 | size_t copylen; | 701 | size_t copylen; |
703 | 702 | ||
704 | if (left <= 0) | 703 | if (left <= 0) |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 231cab57351f..63f36e9d1af8 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -407,13 +407,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | 409 | ||
410 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
411 | memcpy(sdata->u.ap.ssid, ssid, len); | ||
412 | memset(sdata->u.ap.ssid + len, 0, | ||
413 | IEEE80211_MAX_SSID_LEN - len); | ||
414 | sdata->u.ap.ssid_len = len; | ||
415 | return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); | ||
416 | } | ||
417 | return -EOPNOTSUPP; | 410 | return -EOPNOTSUPP; |
418 | } | 411 | } |
419 | 412 | ||
@@ -437,15 +430,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
437 | return res; | 430 | return res; |
438 | } | 431 | } |
439 | 432 | ||
440 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
441 | len = sdata->u.ap.ssid_len; | ||
442 | if (len > IW_ESSID_MAX_SIZE) | ||
443 | len = IW_ESSID_MAX_SIZE; | ||
444 | memcpy(ssid, sdata->u.ap.ssid, len); | ||
445 | data->length = len; | ||
446 | data->flags = 1; | ||
447 | return 0; | ||
448 | } | ||
449 | return -EOPNOTSUPP; | 433 | return -EOPNOTSUPP; |
450 | } | 434 | } |
451 | 435 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5e1d658a8b5a..e3e1494e769a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -58,6 +58,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
58 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 58 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
60 | .len = BUS_ID_SIZE-1 }, | 60 | .len = BUS_ID_SIZE-1 }, |
61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | ||
61 | 62 | ||
62 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 63 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
63 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 64 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -95,6 +96,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
95 | [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, | 96 | [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, |
96 | [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, | 97 | [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, |
97 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, | 98 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, |
99 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, | ||
100 | .len = NL80211_MAX_SUPP_RATES }, | ||
98 | 101 | ||
99 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, | 102 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, |
100 | 103 | ||
@@ -284,20 +287,76 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
284 | return -ENOBUFS; | 287 | return -ENOBUFS; |
285 | } | 288 | } |
286 | 289 | ||
290 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | ||
291 | [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, | ||
292 | [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, | ||
293 | [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, | ||
294 | [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, | ||
295 | [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, | ||
296 | }; | ||
297 | |||
298 | static int parse_txq_params(struct nlattr *tb[], | ||
299 | struct ieee80211_txq_params *txq_params) | ||
300 | { | ||
301 | if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || | ||
302 | !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || | ||
303 | !tb[NL80211_TXQ_ATTR_AIFS]) | ||
304 | return -EINVAL; | ||
305 | |||
306 | txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); | ||
307 | txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); | ||
308 | txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); | ||
309 | txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); | ||
310 | txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
287 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 315 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
288 | { | 316 | { |
289 | struct cfg80211_registered_device *rdev; | 317 | struct cfg80211_registered_device *rdev; |
290 | int result; | 318 | int result = 0, rem_txq_params = 0; |
291 | 319 | struct nlattr *nl_txq_params; | |
292 | if (!info->attrs[NL80211_ATTR_WIPHY_NAME]) | ||
293 | return -EINVAL; | ||
294 | 320 | ||
295 | rdev = cfg80211_get_dev_from_info(info); | 321 | rdev = cfg80211_get_dev_from_info(info); |
296 | if (IS_ERR(rdev)) | 322 | if (IS_ERR(rdev)) |
297 | return PTR_ERR(rdev); | 323 | return PTR_ERR(rdev); |
298 | 324 | ||
299 | result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 325 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { |
326 | result = cfg80211_dev_rename( | ||
327 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | ||
328 | if (result) | ||
329 | goto bad_res; | ||
330 | } | ||
331 | |||
332 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | ||
333 | struct ieee80211_txq_params txq_params; | ||
334 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; | ||
335 | |||
336 | if (!rdev->ops->set_txq_params) { | ||
337 | result = -EOPNOTSUPP; | ||
338 | goto bad_res; | ||
339 | } | ||
300 | 340 | ||
341 | nla_for_each_nested(nl_txq_params, | ||
342 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | ||
343 | rem_txq_params) { | ||
344 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, | ||
345 | nla_data(nl_txq_params), | ||
346 | nla_len(nl_txq_params), | ||
347 | txq_params_policy); | ||
348 | result = parse_txq_params(tb, &txq_params); | ||
349 | if (result) | ||
350 | goto bad_res; | ||
351 | |||
352 | result = rdev->ops->set_txq_params(&rdev->wiphy, | ||
353 | &txq_params); | ||
354 | if (result) | ||
355 | goto bad_res; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | bad_res: | ||
301 | cfg80211_put_dev(rdev); | 360 | cfg80211_put_dev(rdev); |
302 | return result; | 361 | return result; |
303 | } | 362 | } |
@@ -1613,6 +1672,12 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
1613 | if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) | 1672 | if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) |
1614 | params.use_short_slot_time = | 1673 | params.use_short_slot_time = |
1615 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); | 1674 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); |
1675 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | ||
1676 | params.basic_rates = | ||
1677 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
1678 | params.basic_rates_len = | ||
1679 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
1680 | } | ||
1616 | 1681 | ||
1617 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1682 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1618 | if (err) | 1683 | if (err) |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9dff716d1b02..4c7e39d466c4 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -42,16 +42,33 @@ | |||
42 | #include "core.h" | 42 | #include "core.h" |
43 | #include "reg.h" | 43 | #include "reg.h" |
44 | 44 | ||
45 | /* | 45 | /** |
46 | * wiphy is set if this request's initiator is | 46 | * struct regulatory_request - receipt of last regulatory request |
47 | * REGDOM_SET_BY_COUNTRY_IE or _DRIVER | 47 | * |
48 | * @wiphy: this is set if this request's initiator is | ||
49 | * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This | ||
50 | * can be used by the wireless core to deal with conflicts | ||
51 | * and potentially inform users of which devices specifically | ||
52 | * cased the conflicts. | ||
53 | * @initiator: indicates who sent this request, could be any of | ||
54 | * of those set in reg_set_by, %REGDOM_SET_BY_* | ||
55 | * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested | ||
56 | * regulatory domain. We have a few special codes: | ||
57 | * 00 - World regulatory domain | ||
58 | * 99 - built by driver but a specific alpha2 cannot be determined | ||
59 | * 98 - result of an intersection between two regulatory domains | ||
60 | * @intersect: indicates whether the wireless core should intersect | ||
61 | * the requested regulatory domain with the presently set regulatory | ||
62 | * domain. | ||
48 | */ | 63 | */ |
49 | struct regulatory_request { | 64 | struct regulatory_request { |
50 | struct wiphy *wiphy; | 65 | struct wiphy *wiphy; |
51 | enum reg_set_by initiator; | 66 | enum reg_set_by initiator; |
52 | char alpha2[2]; | 67 | char alpha2[2]; |
68 | bool intersect; | ||
53 | }; | 69 | }; |
54 | 70 | ||
71 | /* Receipt of information from last regulatory request */ | ||
55 | static struct regulatory_request *last_request; | 72 | static struct regulatory_request *last_request; |
56 | 73 | ||
57 | /* To trigger userspace events */ | 74 | /* To trigger userspace events */ |
@@ -321,7 +338,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | |||
321 | 338 | ||
322 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; | 339 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; |
323 | 340 | ||
324 | if (freq_range->max_bandwidth_khz > freq_diff) | 341 | if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff) |
325 | return false; | 342 | return false; |
326 | 343 | ||
327 | return true; | 344 | return true; |
@@ -359,6 +376,143 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, | |||
359 | return 0; | 376 | return 0; |
360 | } | 377 | } |
361 | 378 | ||
379 | /* Helper for regdom_intersect(), this does the real | ||
380 | * mathematical intersection fun */ | ||
381 | static int reg_rules_intersect( | ||
382 | const struct ieee80211_reg_rule *rule1, | ||
383 | const struct ieee80211_reg_rule *rule2, | ||
384 | struct ieee80211_reg_rule *intersected_rule) | ||
385 | { | ||
386 | const struct ieee80211_freq_range *freq_range1, *freq_range2; | ||
387 | struct ieee80211_freq_range *freq_range; | ||
388 | const struct ieee80211_power_rule *power_rule1, *power_rule2; | ||
389 | struct ieee80211_power_rule *power_rule; | ||
390 | u32 freq_diff; | ||
391 | |||
392 | freq_range1 = &rule1->freq_range; | ||
393 | freq_range2 = &rule2->freq_range; | ||
394 | freq_range = &intersected_rule->freq_range; | ||
395 | |||
396 | power_rule1 = &rule1->power_rule; | ||
397 | power_rule2 = &rule2->power_rule; | ||
398 | power_rule = &intersected_rule->power_rule; | ||
399 | |||
400 | freq_range->start_freq_khz = max(freq_range1->start_freq_khz, | ||
401 | freq_range2->start_freq_khz); | ||
402 | freq_range->end_freq_khz = min(freq_range1->end_freq_khz, | ||
403 | freq_range2->end_freq_khz); | ||
404 | freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, | ||
405 | freq_range2->max_bandwidth_khz); | ||
406 | |||
407 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; | ||
408 | if (freq_range->max_bandwidth_khz > freq_diff) | ||
409 | freq_range->max_bandwidth_khz = freq_diff; | ||
410 | |||
411 | power_rule->max_eirp = min(power_rule1->max_eirp, | ||
412 | power_rule2->max_eirp); | ||
413 | power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, | ||
414 | power_rule2->max_antenna_gain); | ||
415 | |||
416 | intersected_rule->flags = (rule1->flags | rule2->flags); | ||
417 | |||
418 | if (!is_valid_reg_rule(intersected_rule)) | ||
419 | return -EINVAL; | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | /** | ||
425 | * regdom_intersect - do the intersection between two regulatory domains | ||
426 | * @rd1: first regulatory domain | ||
427 | * @rd2: second regulatory domain | ||
428 | * | ||
429 | * Use this function to get the intersection between two regulatory domains. | ||
430 | * Once completed we will mark the alpha2 for the rd as intersected, "98", | ||
431 | * as no one single alpha2 can represent this regulatory domain. | ||
432 | * | ||
433 | * Returns a pointer to the regulatory domain structure which will hold the | ||
434 | * resulting intersection of rules between rd1 and rd2. We will | ||
435 | * kzalloc() this structure for you. | ||
436 | */ | ||
437 | static struct ieee80211_regdomain *regdom_intersect( | ||
438 | const struct ieee80211_regdomain *rd1, | ||
439 | const struct ieee80211_regdomain *rd2) | ||
440 | { | ||
441 | int r, size_of_regd; | ||
442 | unsigned int x, y; | ||
443 | unsigned int num_rules = 0, rule_idx = 0; | ||
444 | const struct ieee80211_reg_rule *rule1, *rule2; | ||
445 | struct ieee80211_reg_rule *intersected_rule; | ||
446 | struct ieee80211_regdomain *rd; | ||
447 | /* This is just a dummy holder to help us count */ | ||
448 | struct ieee80211_reg_rule irule; | ||
449 | |||
450 | /* Uses the stack temporarily for counter arithmetic */ | ||
451 | intersected_rule = &irule; | ||
452 | |||
453 | memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule)); | ||
454 | |||
455 | if (!rd1 || !rd2) | ||
456 | return NULL; | ||
457 | |||
458 | /* First we get a count of the rules we'll need, then we actually | ||
459 | * build them. This is to so we can malloc() and free() a | ||
460 | * regdomain once. The reason we use reg_rules_intersect() here | ||
461 | * is it will return -EINVAL if the rule computed makes no sense. | ||
462 | * All rules that do check out OK are valid. */ | ||
463 | |||
464 | for (x = 0; x < rd1->n_reg_rules; x++) { | ||
465 | rule1 = &rd1->reg_rules[x]; | ||
466 | for (y = 0; y < rd2->n_reg_rules; y++) { | ||
467 | rule2 = &rd2->reg_rules[y]; | ||
468 | if (!reg_rules_intersect(rule1, rule2, | ||
469 | intersected_rule)) | ||
470 | num_rules++; | ||
471 | memset(intersected_rule, 0, | ||
472 | sizeof(struct ieee80211_reg_rule)); | ||
473 | } | ||
474 | } | ||
475 | |||
476 | if (!num_rules) | ||
477 | return NULL; | ||
478 | |||
479 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
480 | ((num_rules + 1) * sizeof(struct ieee80211_reg_rule)); | ||
481 | |||
482 | rd = kzalloc(size_of_regd, GFP_KERNEL); | ||
483 | if (!rd) | ||
484 | return NULL; | ||
485 | |||
486 | for (x = 0; x < rd1->n_reg_rules; x++) { | ||
487 | rule1 = &rd1->reg_rules[x]; | ||
488 | for (y = 0; y < rd2->n_reg_rules; y++) { | ||
489 | rule2 = &rd2->reg_rules[y]; | ||
490 | /* This time around instead of using the stack lets | ||
491 | * write to the target rule directly saving ourselves | ||
492 | * a memcpy() */ | ||
493 | intersected_rule = &rd->reg_rules[rule_idx]; | ||
494 | r = reg_rules_intersect(rule1, rule2, | ||
495 | intersected_rule); | ||
496 | /* No need to memset here the intersected rule here as | ||
497 | * we're not using the stack anymore */ | ||
498 | if (r) | ||
499 | continue; | ||
500 | rule_idx++; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | if (rule_idx != num_rules) { | ||
505 | kfree(rd); | ||
506 | return NULL; | ||
507 | } | ||
508 | |||
509 | rd->n_reg_rules = num_rules; | ||
510 | rd->alpha2[0] = '9'; | ||
511 | rd->alpha2[1] = '8'; | ||
512 | |||
513 | return rd; | ||
514 | } | ||
515 | |||
362 | /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may | 516 | /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may |
363 | * want to just have the channel structure use these */ | 517 | * want to just have the channel structure use these */ |
364 | static u32 map_regdom_flags(u32 rd_flags) | 518 | static u32 map_regdom_flags(u32 rd_flags) |
@@ -468,6 +622,10 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) | |||
468 | } | 622 | } |
469 | } | 623 | } |
470 | 624 | ||
625 | /* Return value which can be used by ignore_request() to indicate | ||
626 | * it has been determined we should intersect two regulatory domains */ | ||
627 | #define REG_INTERSECT 1 | ||
628 | |||
471 | /* This has the logic which determines when a new request | 629 | /* This has the logic which determines when a new request |
472 | * should be ignored. */ | 630 | * should be ignored. */ |
473 | static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | 631 | static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, |
@@ -517,14 +675,8 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
517 | return -EALREADY; | 675 | return -EALREADY; |
518 | return 0; | 676 | return 0; |
519 | case REGDOM_SET_BY_USER: | 677 | case REGDOM_SET_BY_USER: |
520 | /* | ||
521 | * If the user wants to override the AP's hint, we may | ||
522 | * need to follow both and use the intersection. For now, | ||
523 | * reject any such attempt (but we don't support country | ||
524 | * IEs right now anyway.) | ||
525 | */ | ||
526 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) | 678 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) |
527 | return -EOPNOTSUPP; | 679 | return REG_INTERSECT; |
528 | return 0; | 680 | return 0; |
529 | } | 681 | } |
530 | 682 | ||
@@ -536,10 +688,14 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | |||
536 | const char *alpha2) | 688 | const char *alpha2) |
537 | { | 689 | { |
538 | struct regulatory_request *request; | 690 | struct regulatory_request *request; |
691 | bool intersect = false; | ||
539 | int r = 0; | 692 | int r = 0; |
540 | 693 | ||
541 | r = ignore_request(wiphy, set_by, alpha2); | 694 | r = ignore_request(wiphy, set_by, alpha2); |
542 | if (r) | 695 | |
696 | if (r == REG_INTERSECT) | ||
697 | intersect = true; | ||
698 | else if (r) | ||
543 | return r; | 699 | return r; |
544 | 700 | ||
545 | switch (set_by) { | 701 | switch (set_by) { |
@@ -556,6 +712,7 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | |||
556 | request->alpha2[1] = alpha2[1]; | 712 | request->alpha2[1] = alpha2[1]; |
557 | request->initiator = set_by; | 713 | request->initiator = set_by; |
558 | request->wiphy = wiphy; | 714 | request->wiphy = wiphy; |
715 | request->intersect = intersect; | ||
559 | 716 | ||
560 | kfree(last_request); | 717 | kfree(last_request); |
561 | last_request = request; | 718 | last_request = request; |
@@ -638,7 +795,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
638 | print_rd_rules(rd); | 795 | print_rd_rules(rd); |
639 | } | 796 | } |
640 | 797 | ||
641 | void print_regdomain_info(const struct ieee80211_regdomain *rd) | 798 | static void print_regdomain_info(const struct ieee80211_regdomain *rd) |
642 | { | 799 | { |
643 | printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", | 800 | printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", |
644 | rd->alpha2[0], rd->alpha2[1]); | 801 | rd->alpha2[0], rd->alpha2[1]); |
@@ -648,6 +805,7 @@ void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
648 | /* Takes ownership of rd only if it doesn't fail */ | 805 | /* Takes ownership of rd only if it doesn't fail */ |
649 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 806 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
650 | { | 807 | { |
808 | const struct ieee80211_regdomain *intersected_rd = NULL; | ||
651 | /* Some basic sanity checks first */ | 809 | /* Some basic sanity checks first */ |
652 | 810 | ||
653 | if (is_world_regdom(rd->alpha2)) { | 811 | if (is_world_regdom(rd->alpha2)) { |
@@ -697,6 +855,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
697 | return -EOPNOTSUPP; | 855 | return -EOPNOTSUPP; |
698 | } | 856 | } |
699 | 857 | ||
858 | if (unlikely(last_request->intersect)) { | ||
859 | intersected_rd = regdom_intersect(rd, cfg80211_regdomain); | ||
860 | if (!intersected_rd) | ||
861 | return -EINVAL; | ||
862 | kfree(rd); | ||
863 | rd = intersected_rd; | ||
864 | } | ||
865 | |||
700 | /* Tada! */ | 866 | /* Tada! */ |
701 | cfg80211_regdomain = rd; | 867 | cfg80211_regdomain = rd; |
702 | 868 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index f54424693a38..e76cc28b0345 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -7,6 +7,25 @@ | |||
7 | #include <asm/bitops.h> | 7 | #include <asm/bitops.h> |
8 | #include "core.h" | 8 | #include "core.h" |
9 | 9 | ||
10 | struct ieee80211_rate * | ||
11 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | ||
12 | u64 basic_rates, int bitrate) | ||
13 | { | ||
14 | struct ieee80211_rate *result = &sband->bitrates[0]; | ||
15 | int i; | ||
16 | |||
17 | for (i = 0; i < sband->n_bitrates; i++) { | ||
18 | if (!(basic_rates & BIT(i))) | ||
19 | continue; | ||
20 | if (sband->bitrates[i].bitrate > bitrate) | ||
21 | continue; | ||
22 | result = &sband->bitrates[i]; | ||
23 | } | ||
24 | |||
25 | return result; | ||
26 | } | ||
27 | EXPORT_SYMBOL(ieee80211_get_response_rate); | ||
28 | |||
10 | int ieee80211_channel_to_frequency(int chan) | 29 | int ieee80211_channel_to_frequency(int chan) |
11 | { | 30 | { |
12 | if (chan < 14) | 31 | if (chan < 14) |