diff options
author | Jouni Malinen <j@w1.fi> | 2008-11-26 09:15:24 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-12-05 09:32:11 -0500 |
commit | 72bdcf34380917260da41e3c49e10edee04bc5cd (patch) | |
tree | cbfb8e389f58514febf47ea62781517a9df42f25 | |
parent | 72eaa43a532b4156966444779829a986a4432f11 (diff) |
nl80211: Add frequency configuration (including HT40)
This patch adds new NL80211_CMD_SET_WIPHY attributes
NL80211_ATTR_WIPHY_FREQ and NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET to allow
userspace to set the operating channel (e.g., hostapd for AP mode).
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | include/linux/nl80211.h | 23 | ||||
-rw-r--r-- | include/net/cfg80211.h | 9 | ||||
-rw-r--r-- | include/net/mac80211.h | 3 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 13 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/main.c | 30 | ||||
-rw-r--r-- | net/mac80211/util.c | 1 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 57 |
8 files changed, 131 insertions, 6 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index e08c8bcfb78d..92f79d2bdd8c 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -26,8 +26,9 @@ | |||
26 | * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request | 26 | * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request |
27 | * to get a list of all present wiphys. | 27 | * to get a list of all present wiphys. |
28 | * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or | 28 | * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or |
29 | * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME | 29 | * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, |
30 | * and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS. | 30 | * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or |
31 | * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET. | ||
31 | * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request | 32 | * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request |
32 | * or rename notification. Has attributes %NL80211_ATTR_WIPHY and | 33 | * or rename notification. Has attributes %NL80211_ATTR_WIPHY and |
33 | * %NL80211_ATTR_WIPHY_NAME. | 34 | * %NL80211_ATTR_WIPHY_NAME. |
@@ -180,6 +181,14 @@ enum nl80211_commands { | |||
180 | * /sys/class/ieee80211/<phyname>/index | 181 | * /sys/class/ieee80211/<phyname>/index |
181 | * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) | 182 | * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) |
182 | * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters | 183 | * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters |
184 | * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz | ||
185 | * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ | ||
186 | * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): | ||
187 | * NL80211_SEC_CHAN_NO_HT = HT not allowed (i.e., same as not including | ||
188 | * this attribute) | ||
189 | * NL80211_SEC_CHAN_DISABLED = HT20 only | ||
190 | * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel | ||
191 | * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel | ||
183 | * | 192 | * |
184 | * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on | 193 | * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on |
185 | * @NL80211_ATTR_IFNAME: network interface name | 194 | * @NL80211_ATTR_IFNAME: network interface name |
@@ -315,6 +324,8 @@ enum nl80211_attrs { | |||
315 | NL80211_ATTR_BSS_BASIC_RATES, | 324 | NL80211_ATTR_BSS_BASIC_RATES, |
316 | 325 | ||
317 | NL80211_ATTR_WIPHY_TXQ_PARAMS, | 326 | NL80211_ATTR_WIPHY_TXQ_PARAMS, |
327 | NL80211_ATTR_WIPHY_FREQ, | ||
328 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET, | ||
318 | 329 | ||
319 | /* add attributes here, update the policy in nl80211.c */ | 330 | /* add attributes here, update the policy in nl80211.c */ |
320 | 331 | ||
@@ -329,6 +340,8 @@ enum nl80211_attrs { | |||
329 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY | 340 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY |
330 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES | 341 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES |
331 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS | 342 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS |
343 | #define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ | ||
344 | #define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET | ||
332 | 345 | ||
333 | #define NL80211_MAX_SUPP_RATES 32 | 346 | #define NL80211_MAX_SUPP_RATES 32 |
334 | #define NL80211_MAX_SUPP_REG_RULES 32 | 347 | #define NL80211_MAX_SUPP_REG_RULES 32 |
@@ -742,4 +755,10 @@ enum nl80211_txq_q { | |||
742 | NL80211_TXQ_Q_BK | 755 | NL80211_TXQ_Q_BK |
743 | }; | 756 | }; |
744 | 757 | ||
758 | enum nl80211_sec_chan_offset { | ||
759 | NL80211_SEC_CHAN_NO_HT /* No HT */, | ||
760 | NL80211_SEC_CHAN_DISABLED /* HT20 only */, | ||
761 | NL80211_SEC_CHAN_BELOW /* HT40- */, | ||
762 | NL80211_SEC_CHAN_ABOVE /* HT40+ */ | ||
763 | }; | ||
745 | #endif /* __LINUX_NL80211_H */ | 764 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1d57835d73f2..53b06f6c62ca 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -392,6 +392,9 @@ struct ieee80211_txq_params { | |||
392 | /* from net/wireless.h */ | 392 | /* from net/wireless.h */ |
393 | struct wiphy; | 393 | struct wiphy; |
394 | 394 | ||
395 | /* from net/ieee80211.h */ | ||
396 | struct ieee80211_channel; | ||
397 | |||
395 | /** | 398 | /** |
396 | * struct cfg80211_ops - backend description for wireless configuration | 399 | * struct cfg80211_ops - backend description for wireless configuration |
397 | * | 400 | * |
@@ -450,6 +453,8 @@ struct wiphy; | |||
450 | * @change_bss: Modify parameters for a given BSS. | 453 | * @change_bss: Modify parameters for a given BSS. |
451 | * | 454 | * |
452 | * @set_txq_params: Set TX queue parameters | 455 | * @set_txq_params: Set TX queue parameters |
456 | * | ||
457 | * @set_channel: Set channel | ||
453 | */ | 458 | */ |
454 | struct cfg80211_ops { | 459 | struct cfg80211_ops { |
455 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, | 460 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, |
@@ -513,6 +518,10 @@ struct cfg80211_ops { | |||
513 | 518 | ||
514 | int (*set_txq_params)(struct wiphy *wiphy, | 519 | int (*set_txq_params)(struct wiphy *wiphy, |
515 | struct ieee80211_txq_params *params); | 520 | struct ieee80211_txq_params *params); |
521 | |||
522 | int (*set_channel)(struct wiphy *wiphy, | ||
523 | struct ieee80211_channel *chan, | ||
524 | enum nl80211_sec_chan_offset); | ||
516 | }; | 525 | }; |
517 | 526 | ||
518 | #endif /* __NET_CFG80211_H */ | 527 | #endif /* __NET_CFG80211_H */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6a1d4ea18186..6e823cc6a4b1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -507,6 +507,9 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) | |||
507 | 507 | ||
508 | struct ieee80211_ht_conf { | 508 | struct ieee80211_ht_conf { |
509 | bool enabled; | 509 | bool enabled; |
510 | int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary | ||
511 | * channel below primary; 1 = HT40 enabled, | ||
512 | * secondary channel above primary */ | ||
510 | }; | 513 | }; |
511 | 514 | ||
512 | /** | 515 | /** |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 16423f94801b..7a7a6c176dc5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1095,6 +1095,18 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1095 | return 0; | 1095 | return 0; |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | static int ieee80211_set_channel(struct wiphy *wiphy, | ||
1099 | struct ieee80211_channel *chan, | ||
1100 | enum nl80211_sec_chan_offset sec_chan_offset) | ||
1101 | { | ||
1102 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1103 | |||
1104 | local->oper_channel = chan; | ||
1105 | local->oper_sec_chan_offset = sec_chan_offset; | ||
1106 | |||
1107 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1108 | } | ||
1109 | |||
1098 | struct cfg80211_ops mac80211_config_ops = { | 1110 | struct cfg80211_ops mac80211_config_ops = { |
1099 | .add_virtual_intf = ieee80211_add_iface, | 1111 | .add_virtual_intf = ieee80211_add_iface, |
1100 | .del_virtual_intf = ieee80211_del_iface, | 1112 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1122,4 +1134,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1122 | #endif | 1134 | #endif |
1123 | .change_bss = ieee80211_change_bss, | 1135 | .change_bss = ieee80211_change_bss, |
1124 | .set_txq_params = ieee80211_set_txq_params, | 1136 | .set_txq_params = ieee80211_set_txq_params, |
1137 | .set_channel = ieee80211_set_channel, | ||
1125 | }; | 1138 | }; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 155a20410017..527205f8c1a1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -626,6 +626,7 @@ struct ieee80211_local { | |||
626 | struct delayed_work scan_work; | 626 | struct delayed_work scan_work; |
627 | struct ieee80211_sub_if_data *scan_sdata; | 627 | struct ieee80211_sub_if_data *scan_sdata; |
628 | struct ieee80211_channel *oper_channel, *scan_channel; | 628 | struct ieee80211_channel *oper_channel, *scan_channel; |
629 | enum nl80211_sec_chan_offset oper_sec_chan_offset; | ||
629 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 630 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
630 | size_t scan_ssid_len; | 631 | size_t scan_ssid_len; |
631 | struct list_head bss_list; | 632 | struct list_head bss_list; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index cec9b6d3e1ce..29c3ecf7e914 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -195,20 +195,42 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
195 | struct ieee80211_channel *chan; | 195 | struct ieee80211_channel *chan; |
196 | int ret = 0; | 196 | int ret = 0; |
197 | int power; | 197 | int power; |
198 | enum nl80211_sec_chan_offset sec_chan_offset; | ||
198 | 199 | ||
199 | might_sleep(); | 200 | might_sleep(); |
200 | 201 | ||
201 | if (local->sw_scanning) | 202 | if (local->sw_scanning) { |
202 | chan = local->scan_channel; | 203 | chan = local->scan_channel; |
203 | else | 204 | sec_chan_offset = NL80211_SEC_CHAN_NO_HT; |
205 | } else { | ||
204 | chan = local->oper_channel; | 206 | chan = local->oper_channel; |
207 | sec_chan_offset = local->oper_sec_chan_offset; | ||
208 | } | ||
205 | 209 | ||
206 | if (chan != local->hw.conf.channel) { | 210 | if (chan != local->hw.conf.channel || |
211 | sec_chan_offset != local->hw.conf.ht.sec_chan_offset) { | ||
207 | local->hw.conf.channel = chan; | 212 | local->hw.conf.channel = chan; |
213 | switch (sec_chan_offset) { | ||
214 | case NL80211_SEC_CHAN_NO_HT: | ||
215 | local->hw.conf.ht.enabled = false; | ||
216 | local->hw.conf.ht.sec_chan_offset = 0; | ||
217 | break; | ||
218 | case NL80211_SEC_CHAN_DISABLED: | ||
219 | local->hw.conf.ht.enabled = true; | ||
220 | local->hw.conf.ht.sec_chan_offset = 0; | ||
221 | break; | ||
222 | case NL80211_SEC_CHAN_BELOW: | ||
223 | local->hw.conf.ht.enabled = true; | ||
224 | local->hw.conf.ht.sec_chan_offset = -1; | ||
225 | break; | ||
226 | case NL80211_SEC_CHAN_ABOVE: | ||
227 | local->hw.conf.ht.enabled = true; | ||
228 | local->hw.conf.ht.sec_chan_offset = 1; | ||
229 | break; | ||
230 | } | ||
208 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 231 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
209 | } | 232 | } |
210 | 233 | ||
211 | |||
212 | if (!local->hw.conf.power_level) | 234 | if (!local->hw.conf.power_level) |
213 | power = chan->max_power; | 235 | power = chan->max_power; |
214 | else | 236 | else |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0f841317c7e9..505d68f344ce 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -641,6 +641,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | |||
641 | chan->flags & IEEE80211_CHAN_NO_IBSS) | 641 | chan->flags & IEEE80211_CHAN_NO_IBSS) |
642 | return ret; | 642 | return ret; |
643 | local->oper_channel = chan; | 643 | local->oper_channel = chan; |
644 | local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT; | ||
644 | 645 | ||
645 | if (local->sw_scanning || local->hw_scanning) | 646 | if (local->sw_scanning || local->hw_scanning) |
646 | ret = 0; | 647 | ret = 0; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c9141e3df9ba..9caee6022e3f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -59,6 +59,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
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 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | ||
63 | [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 }, | ||
62 | 64 | ||
63 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
64 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -359,6 +361,61 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
359 | } | 361 | } |
360 | } | 362 | } |
361 | 363 | ||
364 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
365 | enum nl80211_sec_chan_offset sec_chan_offset = | ||
366 | NL80211_SEC_CHAN_NO_HT; | ||
367 | struct ieee80211_channel *chan; | ||
368 | u32 freq, sec_freq; | ||
369 | |||
370 | if (!rdev->ops->set_channel) { | ||
371 | result = -EOPNOTSUPP; | ||
372 | goto bad_res; | ||
373 | } | ||
374 | |||
375 | if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { | ||
376 | sec_chan_offset = nla_get_u32( | ||
377 | info->attrs[ | ||
378 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); | ||
379 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | ||
380 | sec_chan_offset != NL80211_SEC_CHAN_DISABLED && | ||
381 | sec_chan_offset != NL80211_SEC_CHAN_BELOW && | ||
382 | sec_chan_offset != NL80211_SEC_CHAN_ABOVE) { | ||
383 | result = -EINVAL; | ||
384 | goto bad_res; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | ||
389 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
390 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | ||
391 | /* Primary channel not allowed */ | ||
392 | result = -EINVAL; | ||
393 | goto bad_res; | ||
394 | } | ||
395 | if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) | ||
396 | sec_freq = freq - 20; | ||
397 | else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) | ||
398 | sec_freq = freq + 20; | ||
399 | else | ||
400 | sec_freq = 0; | ||
401 | |||
402 | if (sec_freq) { | ||
403 | struct ieee80211_channel *schan; | ||
404 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); | ||
405 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) { | ||
406 | /* Secondary channel not allowed */ | ||
407 | result = -EINVAL; | ||
408 | goto bad_res; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | ||
413 | sec_chan_offset); | ||
414 | if (result) | ||
415 | goto bad_res; | ||
416 | } | ||
417 | |||
418 | |||
362 | bad_res: | 419 | bad_res: |
363 | cfg80211_put_dev(rdev); | 420 | cfg80211_put_dev(rdev); |
364 | return result; | 421 | return result; |