aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-11-10 16:24:44 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-10 16:24:44 -0500
commit23779897546c1effb546ff89b89803d9d955d517 (patch)
treed4b5d52b5d716a72755ba018382d4b87eae763a4 /net
parentf574179b63e48f5285468b5ee40f3c480221f708 (diff)
parentc4832467a5c8c2ae96d6dad882be4d4ab9eefad7 (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.c4
-rw-r--r--net/mac80211/cfg.c45
-rw-r--r--net/mac80211/ht.c10
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/main.c15
-rw-r--r--net/mac80211/mesh.c2
-rw-r--r--net/mac80211/mesh.h5
-rw-r--r--net/mac80211/mlme.c38
-rw-r--r--net/mac80211/rc80211_minstrel.c2
-rw-r--r--net/mac80211/scan.c2
-rw-r--r--net/mac80211/tx.c1
-rw-r--r--net/mac80211/wext.c16
-rw-r--r--net/wireless/nl80211.c75
-rw-r--r--net/wireless/reg.c192
-rw-r--r--net/wireless/util.c19
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
1074static 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
1054struct cfg80211_ops mac80211_config_ops = { 1098struct 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,
2414int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) 2422int 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
228void 228static void
229minstrel_get_rate(void *priv, struct ieee80211_sta *sta, 229minstrel_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
290static 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
298static 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
287static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) 315static 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
359bad_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 */
49struct regulatory_request { 64struct 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 */
55static struct regulatory_request *last_request; 72static 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 */
381static 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 */
437static 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 */
364static u32 map_regdom_flags(u32 rd_flags) 518static 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. */
473static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, 631static 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
641void print_regdomain_info(const struct ieee80211_regdomain *rd) 798static 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 */
649static int __set_regdom(const struct ieee80211_regdomain *rd) 806static 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
10struct ieee80211_rate *
11ieee80211_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}
27EXPORT_SYMBOL(ieee80211_get_response_rate);
28
10int ieee80211_channel_to_frequency(int chan) 29int ieee80211_channel_to_frequency(int chan)
11{ 30{
12 if (chan < 14) 31 if (chan < 14)