diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 13 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/iface.c | 10 | ||||
-rw-r--r-- | net/mac80211/main.c | 30 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 20 | ||||
-rw-r--r-- | net/mac80211/rx.c | 35 | ||||
-rw-r--r-- | net/mac80211/tx.c | 11 | ||||
-rw-r--r-- | net/mac80211/util.c | 1 | ||||
-rw-r--r-- | net/mac80211/wext.c | 120 | ||||
-rw-r--r-- | net/wireless/Makefile | 1 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 57 | ||||
-rw-r--r-- | net/wireless/reg.c | 5 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 139 |
13 files changed, 299 insertions, 144 deletions
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/iface.c b/net/mac80211/iface.c index 46082125f3e1..5abbc3f07dd6 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -435,7 +435,11 @@ static int ieee80211_stop(struct net_device *dev) | |||
435 | break; | 435 | break; |
436 | case NL80211_IFTYPE_STATION: | 436 | case NL80211_IFTYPE_STATION: |
437 | case NL80211_IFTYPE_ADHOC: | 437 | case NL80211_IFTYPE_ADHOC: |
438 | sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED; | 438 | /* Announce that we are leaving the network. */ |
439 | if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED) | ||
440 | ieee80211_sta_deauthenticate(sdata, | ||
441 | WLAN_REASON_DEAUTH_LEAVING); | ||
442 | |||
439 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); | 443 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); |
440 | del_timer_sync(&sdata->u.sta.timer); | 444 | del_timer_sync(&sdata->u.sta.timer); |
441 | /* | 445 | /* |
@@ -694,6 +698,10 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
694 | if (type == sdata->vif.type) | 698 | if (type == sdata->vif.type) |
695 | return 0; | 699 | return 0; |
696 | 700 | ||
701 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ | ||
702 | if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) | ||
703 | return -EOPNOTSUPP; | ||
704 | |||
697 | /* | 705 | /* |
698 | * We could, here, on changes between IBSS/STA/MESH modes, | 706 | * We could, here, on changes between IBSS/STA/MESH modes, |
699 | * invoke an MLME function instead that disassociates etc. | 707 | * invoke an MLME function instead that disassociates etc. |
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/mlme.c b/net/mac80211/mlme.c index 7600ac9b87fe..87b2ac85d911 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -855,16 +855,26 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
855 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) | 855 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) |
856 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 856 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
857 | 857 | ||
858 | sta_info_unlink(&sta); | ||
859 | |||
860 | rcu_read_unlock(); | 858 | rcu_read_unlock(); |
861 | 859 | ||
862 | sta_info_destroy(sta); | ||
863 | |||
864 | local->hw.conf.ht.enabled = false; | 860 | local->hw.conf.ht.enabled = false; |
865 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); | 861 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); |
866 | 862 | ||
867 | ieee80211_bss_info_change_notify(sdata, changed); | 863 | ieee80211_bss_info_change_notify(sdata, changed); |
864 | |||
865 | rcu_read_lock(); | ||
866 | |||
867 | sta = sta_info_get(local, ifsta->bssid); | ||
868 | if (!sta) { | ||
869 | rcu_read_unlock(); | ||
870 | return; | ||
871 | } | ||
872 | |||
873 | sta_info_unlink(&sta); | ||
874 | |||
875 | rcu_read_unlock(); | ||
876 | |||
877 | sta_info_destroy(sta); | ||
868 | } | 878 | } |
869 | 879 | ||
870 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | 880 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) |
@@ -2002,7 +2012,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | |||
2002 | } | 2012 | } |
2003 | } | 2013 | } |
2004 | 2014 | ||
2005 | if (hidden_ssid && ifsta->ssid_len == ssid_len) | 2015 | if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0)) |
2006 | return 1; | 2016 | return 1; |
2007 | 2017 | ||
2008 | if (ssid_len == 1 && ssid[0] == ' ') | 2018 | if (ssid_len == 1 && ssid[0] == ' ') |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 648a1d0e6c82..14be095b8528 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -654,9 +654,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
654 | static void ap_sta_ps_start(struct sta_info *sta) | 654 | static void ap_sta_ps_start(struct sta_info *sta) |
655 | { | 655 | { |
656 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 656 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
657 | struct ieee80211_local *local = sdata->local; | ||
657 | 658 | ||
658 | atomic_inc(&sdata->bss->num_sta_ps); | 659 | atomic_inc(&sdata->bss->num_sta_ps); |
659 | set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); | 660 | set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); |
661 | if (local->ops->sta_notify_ps) | ||
662 | local->ops->sta_notify_ps(local_to_hw(local), STA_NOTIFY_SLEEP, | ||
663 | &sta->sta); | ||
660 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 664 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
661 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", | 665 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", |
662 | sdata->dev->name, sta->sta.addr, sta->sta.aid); | 666 | sdata->dev->name, sta->sta.addr, sta->sta.aid); |
@@ -673,6 +677,9 @@ static int ap_sta_ps_end(struct sta_info *sta) | |||
673 | atomic_dec(&sdata->bss->num_sta_ps); | 677 | atomic_dec(&sdata->bss->num_sta_ps); |
674 | 678 | ||
675 | clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); | 679 | clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); |
680 | if (local->ops->sta_notify_ps) | ||
681 | local->ops->sta_notify_ps(local_to_hw(local), STA_NOTIFY_AWAKE, | ||
682 | &sta->sta); | ||
676 | 683 | ||
677 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 684 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
678 | sta_info_clear_tim_bit(sta); | 685 | sta_info_clear_tim_bit(sta); |
@@ -741,17 +748,29 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
741 | sta->last_qual = rx->status->qual; | 748 | sta->last_qual = rx->status->qual; |
742 | sta->last_noise = rx->status->noise; | 749 | sta->last_noise = rx->status->noise; |
743 | 750 | ||
751 | /* | ||
752 | * Change STA power saving mode only at the end of a frame | ||
753 | * exchange sequence. | ||
754 | */ | ||
744 | if (!ieee80211_has_morefrags(hdr->frame_control) && | 755 | if (!ieee80211_has_morefrags(hdr->frame_control) && |
745 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 756 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
746 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 757 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { |
747 | /* Change STA power saving mode only in the end of a frame | 758 | if (test_sta_flags(sta, WLAN_STA_PS)) { |
748 | * exchange sequence */ | 759 | /* |
749 | if (test_sta_flags(sta, WLAN_STA_PS) && | 760 | * Ignore doze->wake transitions that are |
750 | !ieee80211_has_pm(hdr->frame_control)) | 761 | * indicated by non-data frames, the standard |
751 | rx->sent_ps_buffered += ap_sta_ps_end(sta); | 762 | * is unclear here, but for example going to |
752 | else if (!test_sta_flags(sta, WLAN_STA_PS) && | 763 | * PS mode and then scanning would cause a |
753 | ieee80211_has_pm(hdr->frame_control)) | 764 | * doze->wake transition for the probe request, |
754 | ap_sta_ps_start(sta); | 765 | * and that is clearly undesirable. |
766 | */ | ||
767 | if (ieee80211_is_data(hdr->frame_control) && | ||
768 | !ieee80211_has_pm(hdr->frame_control)) | ||
769 | rx->sent_ps_buffered += ap_sta_ps_end(sta); | ||
770 | } else { | ||
771 | if (ieee80211_has_pm(hdr->frame_control)) | ||
772 | ap_sta_ps_start(sta); | ||
773 | } | ||
755 | } | 774 | } |
756 | 775 | ||
757 | /* Drop data::nullfunc frames silently, since they are used only to | 776 | /* Drop data::nullfunc frames silently, since they are used only to |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0d81b2cfd1a6..d7761e95e4cf 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1779,8 +1779,7 @@ void ieee80211_tx_pending(unsigned long data) | |||
1779 | 1779 | ||
1780 | /* functions for drivers to get certain frames */ | 1780 | /* functions for drivers to get certain frames */ |
1781 | 1781 | ||
1782 | static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | 1782 | static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, |
1783 | struct ieee80211_if_ap *bss, | ||
1784 | struct sk_buff *skb, | 1783 | struct sk_buff *skb, |
1785 | struct beacon_data *beacon) | 1784 | struct beacon_data *beacon) |
1786 | { | 1785 | { |
@@ -1848,7 +1847,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1848 | struct ieee80211_local *local = hw_to_local(hw); | 1847 | struct ieee80211_local *local = hw_to_local(hw); |
1849 | struct sk_buff *skb = NULL; | 1848 | struct sk_buff *skb = NULL; |
1850 | struct ieee80211_tx_info *info; | 1849 | struct ieee80211_tx_info *info; |
1851 | struct net_device *bdev; | ||
1852 | struct ieee80211_sub_if_data *sdata = NULL; | 1850 | struct ieee80211_sub_if_data *sdata = NULL; |
1853 | struct ieee80211_if_ap *ap = NULL; | 1851 | struct ieee80211_if_ap *ap = NULL; |
1854 | struct ieee80211_if_sta *ifsta = NULL; | 1852 | struct ieee80211_if_sta *ifsta = NULL; |
@@ -1861,7 +1859,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1861 | rcu_read_lock(); | 1859 | rcu_read_lock(); |
1862 | 1860 | ||
1863 | sdata = vif_to_sdata(vif); | 1861 | sdata = vif_to_sdata(vif); |
1864 | bdev = sdata->dev; | ||
1865 | 1862 | ||
1866 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 1863 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
1867 | ap = &sdata->u.ap; | 1864 | ap = &sdata->u.ap; |
@@ -1889,12 +1886,12 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1889 | * of the tim bitmap in mac80211 and the driver. | 1886 | * of the tim bitmap in mac80211 and the driver. |
1890 | */ | 1887 | */ |
1891 | if (local->tim_in_locked_section) { | 1888 | if (local->tim_in_locked_section) { |
1892 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | 1889 | ieee80211_beacon_add_tim(ap, skb, beacon); |
1893 | } else { | 1890 | } else { |
1894 | unsigned long flags; | 1891 | unsigned long flags; |
1895 | 1892 | ||
1896 | spin_lock_irqsave(&local->sta_lock, flags); | 1893 | spin_lock_irqsave(&local->sta_lock, flags); |
1897 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | 1894 | ieee80211_beacon_add_tim(ap, skb, beacon); |
1898 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1895 | spin_unlock_irqrestore(&local->sta_lock, flags); |
1899 | } | 1896 | } |
1900 | 1897 | ||
@@ -2016,14 +2013,12 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2016 | struct sk_buff *skb = NULL; | 2013 | struct sk_buff *skb = NULL; |
2017 | struct sta_info *sta; | 2014 | struct sta_info *sta; |
2018 | struct ieee80211_tx_data tx; | 2015 | struct ieee80211_tx_data tx; |
2019 | struct net_device *bdev; | ||
2020 | struct ieee80211_sub_if_data *sdata; | 2016 | struct ieee80211_sub_if_data *sdata; |
2021 | struct ieee80211_if_ap *bss = NULL; | 2017 | struct ieee80211_if_ap *bss = NULL; |
2022 | struct beacon_data *beacon; | 2018 | struct beacon_data *beacon; |
2023 | struct ieee80211_tx_info *info; | 2019 | struct ieee80211_tx_info *info; |
2024 | 2020 | ||
2025 | sdata = vif_to_sdata(vif); | 2021 | sdata = vif_to_sdata(vif); |
2026 | bdev = sdata->dev; | ||
2027 | bss = &sdata->u.ap; | 2022 | bss = &sdata->u.ap; |
2028 | 2023 | ||
2029 | if (!bss) | 2024 | if (!bss) |
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/mac80211/wext.c b/net/mac80211/wext.c index b3ce28d35611..4e1fdcfacb0c 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -135,48 +135,6 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
135 | return -EOPNOTSUPP; | 135 | return -EOPNOTSUPP; |
136 | } | 136 | } |
137 | 137 | ||
138 | static int ieee80211_ioctl_giwname(struct net_device *dev, | ||
139 | struct iw_request_info *info, | ||
140 | char *name, char *extra) | ||
141 | { | ||
142 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
143 | struct ieee80211_supported_band *sband; | ||
144 | u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0; | ||
145 | |||
146 | |||
147 | sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
148 | if (sband) { | ||
149 | is_a = 1; | ||
150 | is_ht |= sband->ht_cap.ht_supported; | ||
151 | } | ||
152 | |||
153 | sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
154 | if (sband) { | ||
155 | int i; | ||
156 | /* Check for mandatory rates */ | ||
157 | for (i = 0; i < sband->n_bitrates; i++) { | ||
158 | if (sband->bitrates[i].bitrate == 10) | ||
159 | is_b = 1; | ||
160 | if (sband->bitrates[i].bitrate == 60) | ||
161 | is_g = 1; | ||
162 | } | ||
163 | is_ht |= sband->ht_cap.ht_supported; | ||
164 | } | ||
165 | |||
166 | strcpy(name, "IEEE 802.11"); | ||
167 | if (is_a) | ||
168 | strcat(name, "a"); | ||
169 | if (is_b) | ||
170 | strcat(name, "b"); | ||
171 | if (is_g) | ||
172 | strcat(name, "g"); | ||
173 | if (is_ht) | ||
174 | strcat(name, "n"); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | |||
180 | static int ieee80211_ioctl_giwrange(struct net_device *dev, | 138 | static int ieee80211_ioctl_giwrange(struct net_device *dev, |
181 | struct iw_request_info *info, | 139 | struct iw_request_info *info, |
182 | struct iw_point *data, char *extra) | 140 | struct iw_point *data, char *extra) |
@@ -266,78 +224,6 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
266 | } | 224 | } |
267 | 225 | ||
268 | 226 | ||
269 | static int ieee80211_ioctl_siwmode(struct net_device *dev, | ||
270 | struct iw_request_info *info, | ||
271 | __u32 *mode, char *extra) | ||
272 | { | ||
273 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
274 | struct ieee80211_local *local = sdata->local; | ||
275 | int type; | ||
276 | |||
277 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
278 | return -EOPNOTSUPP; | ||
279 | |||
280 | switch (*mode) { | ||
281 | case IW_MODE_INFRA: | ||
282 | type = NL80211_IFTYPE_STATION; | ||
283 | break; | ||
284 | case IW_MODE_ADHOC: | ||
285 | /* Setting ad-hoc mode on non ibss channel is not | ||
286 | * supported. | ||
287 | */ | ||
288 | if (local->oper_channel && | ||
289 | (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) | ||
290 | return -EOPNOTSUPP; | ||
291 | |||
292 | type = NL80211_IFTYPE_ADHOC; | ||
293 | break; | ||
294 | case IW_MODE_REPEAT: | ||
295 | type = NL80211_IFTYPE_WDS; | ||
296 | break; | ||
297 | case IW_MODE_MONITOR: | ||
298 | type = NL80211_IFTYPE_MONITOR; | ||
299 | break; | ||
300 | default: | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | |||
304 | return ieee80211_if_change_type(sdata, type); | ||
305 | } | ||
306 | |||
307 | |||
308 | static int ieee80211_ioctl_giwmode(struct net_device *dev, | ||
309 | struct iw_request_info *info, | ||
310 | __u32 *mode, char *extra) | ||
311 | { | ||
312 | struct ieee80211_sub_if_data *sdata; | ||
313 | |||
314 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
315 | switch (sdata->vif.type) { | ||
316 | case NL80211_IFTYPE_AP: | ||
317 | *mode = IW_MODE_MASTER; | ||
318 | break; | ||
319 | case NL80211_IFTYPE_STATION: | ||
320 | *mode = IW_MODE_INFRA; | ||
321 | break; | ||
322 | case NL80211_IFTYPE_ADHOC: | ||
323 | *mode = IW_MODE_ADHOC; | ||
324 | break; | ||
325 | case NL80211_IFTYPE_MONITOR: | ||
326 | *mode = IW_MODE_MONITOR; | ||
327 | break; | ||
328 | case NL80211_IFTYPE_WDS: | ||
329 | *mode = IW_MODE_REPEAT; | ||
330 | break; | ||
331 | case NL80211_IFTYPE_AP_VLAN: | ||
332 | *mode = IW_MODE_SECOND; /* FIXME */ | ||
333 | break; | ||
334 | default: | ||
335 | *mode = IW_MODE_AUTO; | ||
336 | break; | ||
337 | } | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, | 227 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, |
342 | struct iw_request_info *info, | 228 | struct iw_request_info *info, |
343 | struct iw_freq *freq, char *extra) | 229 | struct iw_freq *freq, char *extra) |
@@ -1146,13 +1032,13 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, | |||
1146 | static const iw_handler ieee80211_handler[] = | 1032 | static const iw_handler ieee80211_handler[] = |
1147 | { | 1033 | { |
1148 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | 1034 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ |
1149 | (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */ | 1035 | (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ |
1150 | (iw_handler) NULL, /* SIOCSIWNWID */ | 1036 | (iw_handler) NULL, /* SIOCSIWNWID */ |
1151 | (iw_handler) NULL, /* SIOCGIWNWID */ | 1037 | (iw_handler) NULL, /* SIOCGIWNWID */ |
1152 | (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ | 1038 | (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ |
1153 | (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ | 1039 | (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ |
1154 | (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */ | 1040 | (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ |
1155 | (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */ | 1041 | (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ |
1156 | (iw_handler) NULL, /* SIOCSIWSENS */ | 1042 | (iw_handler) NULL, /* SIOCSIWSENS */ |
1157 | (iw_handler) NULL, /* SIOCGIWSENS */ | 1043 | (iw_handler) NULL, /* SIOCGIWSENS */ |
1158 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | 1044 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index cc547edb111f..9bc412c83430 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -6,4 +6,5 @@ obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | |||
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o |
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | ||
9 | cfg80211-$(CONFIG_NL80211) += nl80211.o | 10 | cfg80211-$(CONFIG_NL80211) += nl80211.o |
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; |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0990059f7e48..4f877535e666 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -989,6 +989,9 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
989 | u32 checksum = 0; | 989 | u32 checksum = 0; |
990 | enum environment_cap env = ENVIRON_ANY; | 990 | enum environment_cap env = ENVIRON_ANY; |
991 | 991 | ||
992 | if (!last_request) | ||
993 | return; | ||
994 | |||
992 | mutex_lock(&cfg80211_drv_mutex); | 995 | mutex_lock(&cfg80211_drv_mutex); |
993 | 996 | ||
994 | /* IE len must be evenly divisible by 2 */ | 997 | /* IE len must be evenly divisible by 2 */ |
@@ -1330,7 +1333,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
1330 | /* Caller must hold cfg80211_drv_mutex */ | 1333 | /* Caller must hold cfg80211_drv_mutex */ |
1331 | void reg_device_remove(struct wiphy *wiphy) | 1334 | void reg_device_remove(struct wiphy *wiphy) |
1332 | { | 1335 | { |
1333 | if (!last_request->wiphy) | 1336 | if (!last_request || !last_request->wiphy) |
1334 | return; | 1337 | return; |
1335 | if (last_request->wiphy != wiphy) | 1338 | if (last_request->wiphy != wiphy) |
1336 | return; | 1339 | return; |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c new file mode 100644 index 000000000000..58e489fd4aed --- /dev/null +++ b/net/wireless/wext-compat.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * cfg80211 - wext compat code | ||
3 | * | ||
4 | * This is temporary code until all wireless functionality is migrated | ||
5 | * into cfg80211, when that happens all the exports here go away and | ||
6 | * we directly assign the wireless handlers of wireless interfaces. | ||
7 | * | ||
8 | * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> | ||
9 | */ | ||
10 | |||
11 | #include <linux/wireless.h> | ||
12 | #include <linux/nl80211.h> | ||
13 | #include <net/iw_handler.h> | ||
14 | #include <net/wireless.h> | ||
15 | #include <net/cfg80211.h> | ||
16 | #include "core.h" | ||
17 | |||
18 | int cfg80211_wext_giwname(struct net_device *dev, | ||
19 | struct iw_request_info *info, | ||
20 | char *name, char *extra) | ||
21 | { | ||
22 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
23 | struct ieee80211_supported_band *sband; | ||
24 | bool is_ht = false, is_a = false, is_b = false, is_g = false; | ||
25 | |||
26 | if (!wdev) | ||
27 | return -EOPNOTSUPP; | ||
28 | |||
29 | sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
30 | if (sband) { | ||
31 | is_a = true; | ||
32 | is_ht |= sband->ht_cap.ht_supported; | ||
33 | } | ||
34 | |||
35 | sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
36 | if (sband) { | ||
37 | int i; | ||
38 | /* Check for mandatory rates */ | ||
39 | for (i = 0; i < sband->n_bitrates; i++) { | ||
40 | if (sband->bitrates[i].bitrate == 10) | ||
41 | is_b = true; | ||
42 | if (sband->bitrates[i].bitrate == 60) | ||
43 | is_g = true; | ||
44 | } | ||
45 | is_ht |= sband->ht_cap.ht_supported; | ||
46 | } | ||
47 | |||
48 | strcpy(name, "IEEE 802.11"); | ||
49 | if (is_a) | ||
50 | strcat(name, "a"); | ||
51 | if (is_b) | ||
52 | strcat(name, "b"); | ||
53 | if (is_g) | ||
54 | strcat(name, "g"); | ||
55 | if (is_ht) | ||
56 | strcat(name, "n"); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | EXPORT_SYMBOL(cfg80211_wext_giwname); | ||
61 | |||
62 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | ||
63 | u32 *mode, char *extra) | ||
64 | { | ||
65 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
66 | struct cfg80211_registered_device *rdev; | ||
67 | struct vif_params vifparams; | ||
68 | enum nl80211_iftype type; | ||
69 | |||
70 | if (!wdev) | ||
71 | return -EOPNOTSUPP; | ||
72 | |||
73 | rdev = wiphy_to_dev(wdev->wiphy); | ||
74 | |||
75 | if (!rdev->ops->change_virtual_intf) | ||
76 | return -EOPNOTSUPP; | ||
77 | |||
78 | /* don't support changing VLANs, you just re-create them */ | ||
79 | if (wdev->iftype == NL80211_IFTYPE_AP_VLAN) | ||
80 | return -EOPNOTSUPP; | ||
81 | |||
82 | switch (*mode) { | ||
83 | case IW_MODE_INFRA: | ||
84 | type = NL80211_IFTYPE_STATION; | ||
85 | break; | ||
86 | case IW_MODE_ADHOC: | ||
87 | type = NL80211_IFTYPE_ADHOC; | ||
88 | break; | ||
89 | case IW_MODE_REPEAT: | ||
90 | type = NL80211_IFTYPE_WDS; | ||
91 | break; | ||
92 | case IW_MODE_MONITOR: | ||
93 | type = NL80211_IFTYPE_MONITOR; | ||
94 | break; | ||
95 | default: | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | memset(&vifparams, 0, sizeof(vifparams)); | ||
100 | |||
101 | return rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, | ||
102 | NULL, &vifparams); | ||
103 | } | ||
104 | EXPORT_SYMBOL(cfg80211_wext_siwmode); | ||
105 | |||
106 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | ||
107 | u32 *mode, char *extra) | ||
108 | { | ||
109 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
110 | |||
111 | if (!wdev) | ||
112 | return -EOPNOTSUPP; | ||
113 | |||
114 | switch (wdev->iftype) { | ||
115 | case NL80211_IFTYPE_AP: | ||
116 | *mode = IW_MODE_MASTER; | ||
117 | break; | ||
118 | case NL80211_IFTYPE_STATION: | ||
119 | *mode = IW_MODE_INFRA; | ||
120 | break; | ||
121 | case NL80211_IFTYPE_ADHOC: | ||
122 | *mode = IW_MODE_ADHOC; | ||
123 | break; | ||
124 | case NL80211_IFTYPE_MONITOR: | ||
125 | *mode = IW_MODE_MONITOR; | ||
126 | break; | ||
127 | case NL80211_IFTYPE_WDS: | ||
128 | *mode = IW_MODE_REPEAT; | ||
129 | break; | ||
130 | case NL80211_IFTYPE_AP_VLAN: | ||
131 | *mode = IW_MODE_SECOND; /* FIXME */ | ||
132 | break; | ||
133 | default: | ||
134 | *mode = IW_MODE_AUTO; | ||
135 | break; | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | EXPORT_SYMBOL(cfg80211_wext_giwmode); | ||