diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 48 | ||||
-rw-r--r-- | net/mac80211/Kconfig | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 14 | ||||
-rw-r--r-- | net/mac80211/key.h | 37 | ||||
-rw-r--r-- | net/mac80211/main.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 207 | ||||
-rw-r--r-- | net/mac80211/rx.c | 7 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 1 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 40 | ||||
-rw-r--r-- | net/mac80211/tkip.c | 30 | ||||
-rw-r--r-- | net/mac80211/tx.c | 204 | ||||
-rw-r--r-- | net/mac80211/wep.c | 39 | ||||
-rw-r--r-- | net/mac80211/wext.c | 50 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 20 | ||||
-rw-r--r-- | net/rfkill/rfkill-input.c | 98 | ||||
-rw-r--r-- | net/rfkill/rfkill-input.h | 1 | ||||
-rw-r--r-- | net/rfkill/rfkill.c | 304 | ||||
-rw-r--r-- | net/socket.c | 10 | ||||
-rw-r--r-- | net/wireless/wext.c | 582 |
19 files changed, 1151 insertions, 545 deletions
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 822606b615ca..973832dd7faf 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c | |||
@@ -43,8 +43,9 @@ static const char *ieee80211_modes[] = { | |||
43 | 43 | ||
44 | #define MAX_CUSTOM_LEN 64 | 44 | #define MAX_CUSTOM_LEN 64 |
45 | static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | 45 | static char *ieee80211_translate_scan(struct ieee80211_device *ieee, |
46 | char *start, char *stop, | 46 | char *start, char *stop, |
47 | struct ieee80211_network *network) | 47 | struct ieee80211_network *network, |
48 | struct iw_request_info *info) | ||
48 | { | 49 | { |
49 | char custom[MAX_CUSTOM_LEN]; | 50 | char custom[MAX_CUSTOM_LEN]; |
50 | char *p; | 51 | char *p; |
@@ -57,7 +58,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
57 | iwe.cmd = SIOCGIWAP; | 58 | iwe.cmd = SIOCGIWAP; |
58 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 59 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
59 | memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); | 60 | memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); |
60 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); | 61 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); |
61 | 62 | ||
62 | /* Remaining entries will be displayed in the order we provide them */ | 63 | /* Remaining entries will be displayed in the order we provide them */ |
63 | 64 | ||
@@ -66,17 +67,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
66 | iwe.u.data.flags = 1; | 67 | iwe.u.data.flags = 1; |
67 | if (network->flags & NETWORK_EMPTY_ESSID) { | 68 | if (network->flags & NETWORK_EMPTY_ESSID) { |
68 | iwe.u.data.length = sizeof("<hidden>"); | 69 | iwe.u.data.length = sizeof("<hidden>"); |
69 | start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); | 70 | start = iwe_stream_add_point(info, start, stop, |
71 | &iwe, "<hidden>"); | ||
70 | } else { | 72 | } else { |
71 | iwe.u.data.length = min(network->ssid_len, (u8) 32); | 73 | iwe.u.data.length = min(network->ssid_len, (u8) 32); |
72 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 74 | start = iwe_stream_add_point(info, start, stop, |
75 | &iwe, network->ssid); | ||
73 | } | 76 | } |
74 | 77 | ||
75 | /* Add the protocol name */ | 78 | /* Add the protocol name */ |
76 | iwe.cmd = SIOCGIWNAME; | 79 | iwe.cmd = SIOCGIWNAME; |
77 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", | 80 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", |
78 | ieee80211_modes[network->mode]); | 81 | ieee80211_modes[network->mode]); |
79 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); | 82 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); |
80 | 83 | ||
81 | /* Add mode */ | 84 | /* Add mode */ |
82 | iwe.cmd = SIOCGIWMODE; | 85 | iwe.cmd = SIOCGIWMODE; |
@@ -86,7 +89,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
86 | else | 89 | else |
87 | iwe.u.mode = IW_MODE_ADHOC; | 90 | iwe.u.mode = IW_MODE_ADHOC; |
88 | 91 | ||
89 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); | 92 | start = iwe_stream_add_event(info, start, stop, |
93 | &iwe, IW_EV_UINT_LEN); | ||
90 | } | 94 | } |
91 | 95 | ||
92 | /* Add channel and frequency */ | 96 | /* Add channel and frequency */ |
@@ -95,7 +99,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
95 | iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); | 99 | iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); |
96 | iwe.u.freq.e = 6; | 100 | iwe.u.freq.e = 6; |
97 | iwe.u.freq.i = 0; | 101 | iwe.u.freq.i = 0; |
98 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); | 102 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); |
99 | 103 | ||
100 | /* Add encryption capability */ | 104 | /* Add encryption capability */ |
101 | iwe.cmd = SIOCGIWENCODE; | 105 | iwe.cmd = SIOCGIWENCODE; |
@@ -104,12 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
104 | else | 108 | else |
105 | iwe.u.data.flags = IW_ENCODE_DISABLED; | 109 | iwe.u.data.flags = IW_ENCODE_DISABLED; |
106 | iwe.u.data.length = 0; | 110 | iwe.u.data.length = 0; |
107 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 111 | start = iwe_stream_add_point(info, start, stop, |
112 | &iwe, network->ssid); | ||
108 | 113 | ||
109 | /* Add basic and extended rates */ | 114 | /* Add basic and extended rates */ |
110 | /* Rate : stuffing multiple values in a single event require a bit | 115 | /* Rate : stuffing multiple values in a single event require a bit |
111 | * more of magic - Jean II */ | 116 | * more of magic - Jean II */ |
112 | current_val = start + IW_EV_LCP_LEN; | 117 | current_val = start + iwe_stream_lcp_len(info); |
113 | iwe.cmd = SIOCGIWRATE; | 118 | iwe.cmd = SIOCGIWRATE; |
114 | /* Those two flags are ignored... */ | 119 | /* Those two flags are ignored... */ |
115 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | 120 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; |
@@ -124,17 +129,19 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
124 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | 129 | /* Bit rate given in 500 kb/s units (+ 0x80) */ |
125 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); | 130 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); |
126 | /* Add new value to event */ | 131 | /* Add new value to event */ |
127 | current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); | 132 | current_val = iwe_stream_add_value(info, start, current_val, |
133 | stop, &iwe, IW_EV_PARAM_LEN); | ||
128 | } | 134 | } |
129 | for (; j < network->rates_ex_len; j++) { | 135 | for (; j < network->rates_ex_len; j++) { |
130 | rate = network->rates_ex[j] & 0x7F; | 136 | rate = network->rates_ex[j] & 0x7F; |
131 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | 137 | /* Bit rate given in 500 kb/s units (+ 0x80) */ |
132 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); | 138 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); |
133 | /* Add new value to event */ | 139 | /* Add new value to event */ |
134 | current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); | 140 | current_val = iwe_stream_add_value(info, start, current_val, |
141 | stop, &iwe, IW_EV_PARAM_LEN); | ||
135 | } | 142 | } |
136 | /* Check if we added any rate */ | 143 | /* Check if we added any rate */ |
137 | if((current_val - start) > IW_EV_LCP_LEN) | 144 | if ((current_val - start) > iwe_stream_lcp_len(info)) |
138 | start = current_val; | 145 | start = current_val; |
139 | 146 | ||
140 | /* Add quality statistics */ | 147 | /* Add quality statistics */ |
@@ -181,14 +188,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
181 | iwe.u.qual.level = network->stats.signal; | 188 | iwe.u.qual.level = network->stats.signal; |
182 | } | 189 | } |
183 | 190 | ||
184 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); | 191 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); |
185 | 192 | ||
186 | iwe.cmd = IWEVCUSTOM; | 193 | iwe.cmd = IWEVCUSTOM; |
187 | p = custom; | 194 | p = custom; |
188 | 195 | ||
189 | iwe.u.data.length = p - custom; | 196 | iwe.u.data.length = p - custom; |
190 | if (iwe.u.data.length) | 197 | if (iwe.u.data.length) |
191 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 198 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
192 | 199 | ||
193 | memset(&iwe, 0, sizeof(iwe)); | 200 | memset(&iwe, 0, sizeof(iwe)); |
194 | if (network->wpa_ie_len) { | 201 | if (network->wpa_ie_len) { |
@@ -196,7 +203,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
196 | memcpy(buf, network->wpa_ie, network->wpa_ie_len); | 203 | memcpy(buf, network->wpa_ie, network->wpa_ie_len); |
197 | iwe.cmd = IWEVGENIE; | 204 | iwe.cmd = IWEVGENIE; |
198 | iwe.u.data.length = network->wpa_ie_len; | 205 | iwe.u.data.length = network->wpa_ie_len; |
199 | start = iwe_stream_add_point(start, stop, &iwe, buf); | 206 | start = iwe_stream_add_point(info, start, stop, &iwe, buf); |
200 | } | 207 | } |
201 | 208 | ||
202 | memset(&iwe, 0, sizeof(iwe)); | 209 | memset(&iwe, 0, sizeof(iwe)); |
@@ -205,7 +212,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
205 | memcpy(buf, network->rsn_ie, network->rsn_ie_len); | 212 | memcpy(buf, network->rsn_ie, network->rsn_ie_len); |
206 | iwe.cmd = IWEVGENIE; | 213 | iwe.cmd = IWEVGENIE; |
207 | iwe.u.data.length = network->rsn_ie_len; | 214 | iwe.u.data.length = network->rsn_ie_len; |
208 | start = iwe_stream_add_point(start, stop, &iwe, buf); | 215 | start = iwe_stream_add_point(info, start, stop, &iwe, buf); |
209 | } | 216 | } |
210 | 217 | ||
211 | /* Add EXTRA: Age to display seconds since last beacon/probe response | 218 | /* Add EXTRA: Age to display seconds since last beacon/probe response |
@@ -217,7 +224,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
217 | jiffies_to_msecs(jiffies - network->last_scanned)); | 224 | jiffies_to_msecs(jiffies - network->last_scanned)); |
218 | iwe.u.data.length = p - custom; | 225 | iwe.u.data.length = p - custom; |
219 | if (iwe.u.data.length) | 226 | if (iwe.u.data.length) |
220 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 227 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
221 | 228 | ||
222 | /* Add spectrum management information */ | 229 | /* Add spectrum management information */ |
223 | iwe.cmd = -1; | 230 | iwe.cmd = -1; |
@@ -238,7 +245,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
238 | 245 | ||
239 | if (iwe.cmd == IWEVCUSTOM) { | 246 | if (iwe.cmd == IWEVCUSTOM) { |
240 | iwe.u.data.length = p - custom; | 247 | iwe.u.data.length = p - custom; |
241 | start = iwe_stream_add_point(start, stop, &iwe, custom); | 248 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
242 | } | 249 | } |
243 | 250 | ||
244 | return start; | 251 | return start; |
@@ -272,7 +279,8 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, | |||
272 | 279 | ||
273 | if (ieee->scan_age == 0 || | 280 | if (ieee->scan_age == 0 || |
274 | time_after(network->last_scanned + ieee->scan_age, jiffies)) | 281 | time_after(network->last_scanned + ieee->scan_age, jiffies)) |
275 | ev = ieee80211_translate_scan(ieee, ev, stop, network); | 282 | ev = ieee80211_translate_scan(ieee, ev, stop, network, |
283 | info); | ||
276 | else | 284 | else |
277 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" | 285 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" |
278 | "%s)' due to age (%dms).\n", | 286 | "%s)' due to age (%dms).\n", |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 590e00b2766c..0d3661d9b6a0 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -150,7 +150,7 @@ config MAC80211_LOWTX_FRAME_DUMP | |||
150 | If unsure, say N and insert the debugging code | 150 | If unsure, say N and insert the debugging code |
151 | you require into the driver you are debugging. | 151 | you require into the driver you are debugging. |
152 | 152 | ||
153 | config TKIP_DEBUG | 153 | config MAC80211_TKIP_DEBUG |
154 | bool "TKIP debugging" | 154 | bool "TKIP debugging" |
155 | depends on MAC80211_DEBUG | 155 | depends on MAC80211_DEBUG |
156 | 156 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 14fccf16b80f..af352c05c983 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
26 | #include <net/wireless.h> | 26 | #include <net/wireless.h> |
27 | #include <net/iw_handler.h> | ||
27 | #include "key.h" | 28 | #include "key.h" |
28 | #include "sta_info.h" | 29 | #include "sta_info.h" |
29 | 30 | ||
@@ -790,6 +791,10 @@ struct ieee802_11_elems { | |||
790 | u8 *preq; | 791 | u8 *preq; |
791 | u8 *prep; | 792 | u8 *prep; |
792 | u8 *perr; | 793 | u8 *perr; |
794 | u8 *ch_switch_elem; | ||
795 | u8 *country_elem; | ||
796 | u8 *pwr_constr_elem; | ||
797 | u8 *quiet_elem; /* first quite element */ | ||
793 | 798 | ||
794 | /* length of them, respectively */ | 799 | /* length of them, respectively */ |
795 | u8 ssid_len; | 800 | u8 ssid_len; |
@@ -814,6 +819,11 @@ struct ieee802_11_elems { | |||
814 | u8 preq_len; | 819 | u8 preq_len; |
815 | u8 prep_len; | 820 | u8 prep_len; |
816 | u8 perr_len; | 821 | u8 perr_len; |
822 | u8 ch_switch_elem_len; | ||
823 | u8 country_elem_len; | ||
824 | u8 pwr_constr_elem_len; | ||
825 | u8 quiet_elem_len; | ||
826 | u8 num_of_quiet_elem; /* can be more the one */ | ||
817 | }; | 827 | }; |
818 | 828 | ||
819 | static inline struct ieee80211_local *hw_to_local( | 829 | static inline struct ieee80211_local *hw_to_local( |
@@ -867,7 +877,9 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid); | |||
867 | int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); | 877 | int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); |
868 | void ieee80211_sta_req_auth(struct net_device *dev, | 878 | void ieee80211_sta_req_auth(struct net_device *dev, |
869 | struct ieee80211_if_sta *ifsta); | 879 | struct ieee80211_if_sta *ifsta); |
870 | int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); | 880 | int ieee80211_sta_scan_results(struct net_device *dev, |
881 | struct iw_request_info *info, | ||
882 | char *buf, size_t len); | ||
871 | ieee80211_rx_result ieee80211_sta_rx_scan( | 883 | ieee80211_rx_result ieee80211_sta_rx_scan( |
872 | struct net_device *dev, struct sk_buff *skb, | 884 | struct net_device *dev, struct sk_buff *skb, |
873 | struct ieee80211_rx_status *rx_status); | 885 | struct ieee80211_rx_status *rx_status); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index a0f774aafa45..425816e0996c 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -16,31 +16,18 @@ | |||
16 | #include <linux/rcupdate.h> | 16 | #include <linux/rcupdate.h> |
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | 18 | ||
19 | /* ALG_TKIP | 19 | #define WEP_IV_LEN 4 |
20 | * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block: | 20 | #define WEP_ICV_LEN 4 |
21 | * Temporal Encryption Key (128 bits) | 21 | #define ALG_TKIP_KEY_LEN 32 |
22 | * Temporal Authenticator Tx MIC Key (64 bits) | 22 | #define ALG_CCMP_KEY_LEN 16 |
23 | * Temporal Authenticator Rx MIC Key (64 bits) | 23 | #define CCMP_HDR_LEN 8 |
24 | */ | 24 | #define CCMP_MIC_LEN 8 |
25 | 25 | #define CCMP_TK_LEN 16 | |
26 | #define WEP_IV_LEN 4 | 26 | #define CCMP_PN_LEN 6 |
27 | #define WEP_ICV_LEN 4 | 27 | #define TKIP_IV_LEN 8 |
28 | 28 | #define TKIP_ICV_LEN 4 | |
29 | #define ALG_TKIP_KEY_LEN 32 | 29 | |
30 | /* Starting offsets for each key */ | 30 | #define NUM_RX_DATA_QUEUES 17 |
31 | #define ALG_TKIP_TEMP_ENCR_KEY 0 | ||
32 | #define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16 | ||
33 | #define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24 | ||
34 | #define TKIP_IV_LEN 8 | ||
35 | #define TKIP_ICV_LEN 4 | ||
36 | |||
37 | #define ALG_CCMP_KEY_LEN 16 | ||
38 | #define CCMP_HDR_LEN 8 | ||
39 | #define CCMP_MIC_LEN 8 | ||
40 | #define CCMP_TK_LEN 16 | ||
41 | #define CCMP_PN_LEN 6 | ||
42 | |||
43 | #define NUM_RX_DATA_QUEUES 17 | ||
44 | 31 | ||
45 | struct ieee80211_local; | 32 | struct ieee80211_local; |
46 | struct ieee80211_sub_if_data; | 33 | struct ieee80211_sub_if_data; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5c5396edad32..b661ee5bb824 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -1691,7 +1691,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1691 | list_add_tail(&sdata->list, &local->interfaces); | 1691 | list_add_tail(&sdata->list, &local->interfaces); |
1692 | 1692 | ||
1693 | name = wiphy_dev(local->hw.wiphy)->driver->name; | 1693 | name = wiphy_dev(local->hw.wiphy)->driver->name; |
1694 | local->hw.workqueue = create_singlethread_workqueue(name); | 1694 | local->hw.workqueue = create_freezeable_workqueue(name); |
1695 | if (!local->hw.workqueue) { | 1695 | if (!local->hw.workqueue) { |
1696 | result = -ENOMEM; | 1696 | result = -ENOMEM; |
1697 | goto fail_workqueue; | 1697 | goto fail_workqueue; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 55659a730dc1..7b4d4d46843b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -204,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
204 | elems->perr = pos; | 204 | elems->perr = pos; |
205 | elems->perr_len = elen; | 205 | elems->perr_len = elen; |
206 | break; | 206 | break; |
207 | case WLAN_EID_CHANNEL_SWITCH: | ||
208 | elems->ch_switch_elem = pos; | ||
209 | elems->ch_switch_elem_len = elen; | ||
210 | break; | ||
211 | case WLAN_EID_QUIET: | ||
212 | if (!elems->quiet_elem) { | ||
213 | elems->quiet_elem = pos; | ||
214 | elems->quiet_elem_len = elen; | ||
215 | } | ||
216 | elems->num_of_quiet_elem++; | ||
217 | break; | ||
218 | case WLAN_EID_COUNTRY: | ||
219 | elems->country_elem = pos; | ||
220 | elems->country_elem_len = elen; | ||
221 | break; | ||
222 | case WLAN_EID_PWR_CONSTRAINT: | ||
223 | elems->pwr_constr_elem = pos; | ||
224 | elems->pwr_constr_elem_len = elen; | ||
225 | break; | ||
207 | default: | 226 | default: |
208 | break; | 227 | break; |
209 | } | 228 | } |
@@ -1701,6 +1720,71 @@ void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr) | |||
1701 | } | 1720 | } |
1702 | } | 1721 | } |
1703 | 1722 | ||
1723 | static void ieee80211_send_refuse_measurement_request(struct net_device *dev, | ||
1724 | struct ieee80211_msrment_ie *request_ie, | ||
1725 | const u8 *da, const u8 *bssid, | ||
1726 | u8 dialog_token) | ||
1727 | { | ||
1728 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1729 | struct sk_buff *skb; | ||
1730 | struct ieee80211_mgmt *msr_report; | ||
1731 | |||
1732 | skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom + | ||
1733 | sizeof(struct ieee80211_msrment_ie)); | ||
1734 | |||
1735 | if (!skb) { | ||
1736 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
1737 | "measurement report frame\n", dev->name); | ||
1738 | return; | ||
1739 | } | ||
1740 | |||
1741 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1742 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); | ||
1743 | memset(msr_report, 0, 24); | ||
1744 | memcpy(msr_report->da, da, ETH_ALEN); | ||
1745 | memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN); | ||
1746 | memcpy(msr_report->bssid, bssid, ETH_ALEN); | ||
1747 | msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
1748 | IEEE80211_STYPE_ACTION); | ||
1749 | |||
1750 | skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement)); | ||
1751 | msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
1752 | msr_report->u.action.u.measurement.action_code = | ||
1753 | WLAN_ACTION_SPCT_MSR_RPRT; | ||
1754 | msr_report->u.action.u.measurement.dialog_token = dialog_token; | ||
1755 | |||
1756 | msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT; | ||
1757 | msr_report->u.action.u.measurement.length = | ||
1758 | sizeof(struct ieee80211_msrment_ie); | ||
1759 | |||
1760 | memset(&msr_report->u.action.u.measurement.msr_elem, 0, | ||
1761 | sizeof(struct ieee80211_msrment_ie)); | ||
1762 | msr_report->u.action.u.measurement.msr_elem.token = request_ie->token; | ||
1763 | msr_report->u.action.u.measurement.msr_elem.mode |= | ||
1764 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | ||
1765 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | ||
1766 | |||
1767 | ieee80211_sta_tx(dev, skb, 0); | ||
1768 | } | ||
1769 | |||
1770 | static void ieee80211_sta_process_measurement_req(struct net_device *dev, | ||
1771 | struct ieee80211_mgmt *mgmt, | ||
1772 | size_t len) | ||
1773 | { | ||
1774 | /* | ||
1775 | * Ignoring measurement request is spec violation. | ||
1776 | * Mandatory measurements must be reported optional | ||
1777 | * measurements might be refused or reported incapable | ||
1778 | * For now just refuse | ||
1779 | * TODO: Answer basic measurement as unmeasured | ||
1780 | */ | ||
1781 | ieee80211_send_refuse_measurement_request(dev, | ||
1782 | &mgmt->u.action.u.measurement.msr_elem, | ||
1783 | mgmt->sa, mgmt->bssid, | ||
1784 | mgmt->u.action.u.measurement.dialog_token); | ||
1785 | } | ||
1786 | |||
1787 | |||
1704 | static void ieee80211_rx_mgmt_auth(struct net_device *dev, | 1788 | static void ieee80211_rx_mgmt_auth(struct net_device *dev, |
1705 | struct ieee80211_if_sta *ifsta, | 1789 | struct ieee80211_if_sta *ifsta, |
1706 | struct ieee80211_mgmt *mgmt, | 1790 | struct ieee80211_mgmt *mgmt, |
@@ -1753,11 +1837,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, | |||
1753 | auth_transaction, status_code); | 1837 | auth_transaction, status_code); |
1754 | 1838 | ||
1755 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { | 1839 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { |
1756 | /* IEEE 802.11 standard does not require authentication in IBSS | 1840 | /* |
1841 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1757 | * networks and most implementations do not seem to use it. | 1842 | * networks and most implementations do not seem to use it. |
1758 | * However, try to reply to authentication attempts if someone | 1843 | * However, try to reply to authentication attempts if someone |
1759 | * has actually implemented this. | 1844 | * has actually implemented this. |
1760 | * TODO: Could implement shared key authentication. */ | 1845 | */ |
1761 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { | 1846 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { |
1762 | printk(KERN_DEBUG "%s: unexpected IBSS authentication " | 1847 | printk(KERN_DEBUG "%s: unexpected IBSS authentication " |
1763 | "frame (alg=%d transaction=%d)\n", | 1848 | "frame (alg=%d transaction=%d)\n", |
@@ -3025,11 +3110,24 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, | |||
3025 | struct ieee80211_rx_status *rx_status) | 3110 | struct ieee80211_rx_status *rx_status) |
3026 | { | 3111 | { |
3027 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3112 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3113 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
3028 | 3114 | ||
3029 | if (len < IEEE80211_MIN_ACTION_SIZE) | 3115 | if (len < IEEE80211_MIN_ACTION_SIZE) |
3030 | return; | 3116 | return; |
3031 | 3117 | ||
3032 | switch (mgmt->u.action.category) { | 3118 | switch (mgmt->u.action.category) { |
3119 | case WLAN_CATEGORY_SPECTRUM_MGMT: | ||
3120 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | ||
3121 | break; | ||
3122 | switch (mgmt->u.action.u.chan_switch.action_code) { | ||
3123 | case WLAN_ACTION_SPCT_MSR_REQ: | ||
3124 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
3125 | sizeof(mgmt->u.action.u.measurement))) | ||
3126 | break; | ||
3127 | ieee80211_sta_process_measurement_req(dev, mgmt, len); | ||
3128 | break; | ||
3129 | } | ||
3130 | break; | ||
3033 | case WLAN_CATEGORY_BACK: | 3131 | case WLAN_CATEGORY_BACK: |
3034 | switch (mgmt->u.action.u.addba_req.action_code) { | 3132 | switch (mgmt->u.action.u.addba_req.action_code) { |
3035 | case WLAN_ACTION_ADDBA_REQ: | 3133 | case WLAN_ACTION_ADDBA_REQ: |
@@ -3173,33 +3271,32 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, | |||
3173 | struct ieee80211_rx_status *rx_status) | 3271 | struct ieee80211_rx_status *rx_status) |
3174 | { | 3272 | { |
3175 | struct ieee80211_mgmt *mgmt; | 3273 | struct ieee80211_mgmt *mgmt; |
3176 | u16 fc; | 3274 | __le16 fc; |
3177 | 3275 | ||
3178 | if (skb->len < 2) | 3276 | if (skb->len < 2) |
3179 | return RX_DROP_UNUSABLE; | 3277 | return RX_DROP_UNUSABLE; |
3180 | 3278 | ||
3181 | mgmt = (struct ieee80211_mgmt *) skb->data; | 3279 | mgmt = (struct ieee80211_mgmt *) skb->data; |
3182 | fc = le16_to_cpu(mgmt->frame_control); | 3280 | fc = mgmt->frame_control; |
3183 | 3281 | ||
3184 | if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) | 3282 | if (ieee80211_is_ctl(fc)) |
3185 | return RX_CONTINUE; | 3283 | return RX_CONTINUE; |
3186 | 3284 | ||
3187 | if (skb->len < 24) | 3285 | if (skb->len < 24) |
3188 | return RX_DROP_MONITOR; | 3286 | return RX_DROP_MONITOR; |
3189 | 3287 | ||
3190 | if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { | 3288 | if (ieee80211_is_probe_resp(fc)) { |
3191 | if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { | 3289 | ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); |
3192 | ieee80211_rx_mgmt_probe_resp(dev, mgmt, | 3290 | dev_kfree_skb(skb); |
3193 | skb->len, rx_status); | 3291 | return RX_QUEUED; |
3194 | dev_kfree_skb(skb); | ||
3195 | return RX_QUEUED; | ||
3196 | } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { | ||
3197 | ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, | ||
3198 | rx_status); | ||
3199 | dev_kfree_skb(skb); | ||
3200 | return RX_QUEUED; | ||
3201 | } | ||
3202 | } | 3292 | } |
3293 | |||
3294 | if (ieee80211_is_beacon(fc)) { | ||
3295 | ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); | ||
3296 | dev_kfree_skb(skb); | ||
3297 | return RX_QUEUED; | ||
3298 | } | ||
3299 | |||
3203 | return RX_CONTINUE; | 3300 | return RX_CONTINUE; |
3204 | } | 3301 | } |
3205 | 3302 | ||
@@ -3777,7 +3874,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
3777 | { | 3874 | { |
3778 | struct sk_buff *skb; | 3875 | struct sk_buff *skb; |
3779 | struct ieee80211_hdr *nullfunc; | 3876 | struct ieee80211_hdr *nullfunc; |
3780 | u16 fc; | 3877 | __le16 fc; |
3781 | 3878 | ||
3782 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | 3879 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); |
3783 | if (!skb) { | 3880 | if (!skb) { |
@@ -3789,11 +3886,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
3789 | 3886 | ||
3790 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | 3887 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); |
3791 | memset(nullfunc, 0, 24); | 3888 | memset(nullfunc, 0, 24); |
3792 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | 3889 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | |
3793 | IEEE80211_FCTL_TODS; | 3890 | IEEE80211_FCTL_TODS); |
3794 | if (powersave) | 3891 | if (powersave) |
3795 | fc |= IEEE80211_FCTL_PM; | 3892 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); |
3796 | nullfunc->frame_control = cpu_to_le16(fc); | 3893 | nullfunc->frame_control = fc; |
3797 | memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); | 3894 | memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); |
3798 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | 3895 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); |
3799 | memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); | 3896 | memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); |
@@ -4087,6 +4184,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len) | |||
4087 | 4184 | ||
4088 | static char * | 4185 | static char * |
4089 | ieee80211_sta_scan_result(struct net_device *dev, | 4186 | ieee80211_sta_scan_result(struct net_device *dev, |
4187 | struct iw_request_info *info, | ||
4090 | struct ieee80211_sta_bss *bss, | 4188 | struct ieee80211_sta_bss *bss, |
4091 | char *current_ev, char *end_buf) | 4189 | char *current_ev, char *end_buf) |
4092 | { | 4190 | { |
@@ -4101,7 +4199,7 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4101 | iwe.cmd = SIOCGIWAP; | 4199 | iwe.cmd = SIOCGIWAP; |
4102 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 4200 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
4103 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | 4201 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); |
4104 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4202 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4105 | IW_EV_ADDR_LEN); | 4203 | IW_EV_ADDR_LEN); |
4106 | 4204 | ||
4107 | memset(&iwe, 0, sizeof(iwe)); | 4205 | memset(&iwe, 0, sizeof(iwe)); |
@@ -4109,13 +4207,13 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4109 | if (bss_mesh_cfg(bss)) { | 4207 | if (bss_mesh_cfg(bss)) { |
4110 | iwe.u.data.length = bss_mesh_id_len(bss); | 4208 | iwe.u.data.length = bss_mesh_id_len(bss); |
4111 | iwe.u.data.flags = 1; | 4209 | iwe.u.data.flags = 1; |
4112 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4210 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4113 | bss_mesh_id(bss)); | 4211 | &iwe, bss_mesh_id(bss)); |
4114 | } else { | 4212 | } else { |
4115 | iwe.u.data.length = bss->ssid_len; | 4213 | iwe.u.data.length = bss->ssid_len; |
4116 | iwe.u.data.flags = 1; | 4214 | iwe.u.data.flags = 1; |
4117 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4215 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4118 | bss->ssid); | 4216 | &iwe, bss->ssid); |
4119 | } | 4217 | } |
4120 | 4218 | ||
4121 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) | 4219 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) |
@@ -4128,22 +4226,22 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4128 | iwe.u.mode = IW_MODE_MASTER; | 4226 | iwe.u.mode = IW_MODE_MASTER; |
4129 | else | 4227 | else |
4130 | iwe.u.mode = IW_MODE_ADHOC; | 4228 | iwe.u.mode = IW_MODE_ADHOC; |
4131 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4229 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, |
4132 | IW_EV_UINT_LEN); | 4230 | &iwe, IW_EV_UINT_LEN); |
4133 | } | 4231 | } |
4134 | 4232 | ||
4135 | memset(&iwe, 0, sizeof(iwe)); | 4233 | memset(&iwe, 0, sizeof(iwe)); |
4136 | iwe.cmd = SIOCGIWFREQ; | 4234 | iwe.cmd = SIOCGIWFREQ; |
4137 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); | 4235 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); |
4138 | iwe.u.freq.e = 0; | 4236 | iwe.u.freq.e = 0; |
4139 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4237 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4140 | IW_EV_FREQ_LEN); | 4238 | IW_EV_FREQ_LEN); |
4141 | 4239 | ||
4142 | memset(&iwe, 0, sizeof(iwe)); | 4240 | memset(&iwe, 0, sizeof(iwe)); |
4143 | iwe.cmd = SIOCGIWFREQ; | 4241 | iwe.cmd = SIOCGIWFREQ; |
4144 | iwe.u.freq.m = bss->freq; | 4242 | iwe.u.freq.m = bss->freq; |
4145 | iwe.u.freq.e = 6; | 4243 | iwe.u.freq.e = 6; |
4146 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4244 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4147 | IW_EV_FREQ_LEN); | 4245 | IW_EV_FREQ_LEN); |
4148 | memset(&iwe, 0, sizeof(iwe)); | 4246 | memset(&iwe, 0, sizeof(iwe)); |
4149 | iwe.cmd = IWEVQUAL; | 4247 | iwe.cmd = IWEVQUAL; |
@@ -4151,7 +4249,7 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4151 | iwe.u.qual.level = bss->signal; | 4249 | iwe.u.qual.level = bss->signal; |
4152 | iwe.u.qual.noise = bss->noise; | 4250 | iwe.u.qual.noise = bss->noise; |
4153 | iwe.u.qual.updated = local->wstats_flags; | 4251 | iwe.u.qual.updated = local->wstats_flags; |
4154 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | 4252 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
4155 | IW_EV_QUAL_LEN); | 4253 | IW_EV_QUAL_LEN); |
4156 | 4254 | ||
4157 | memset(&iwe, 0, sizeof(iwe)); | 4255 | memset(&iwe, 0, sizeof(iwe)); |
@@ -4161,35 +4259,36 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4161 | else | 4259 | else |
4162 | iwe.u.data.flags = IW_ENCODE_DISABLED; | 4260 | iwe.u.data.flags = IW_ENCODE_DISABLED; |
4163 | iwe.u.data.length = 0; | 4261 | iwe.u.data.length = 0; |
4164 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); | 4262 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4263 | &iwe, ""); | ||
4165 | 4264 | ||
4166 | if (bss && bss->wpa_ie) { | 4265 | if (bss && bss->wpa_ie) { |
4167 | memset(&iwe, 0, sizeof(iwe)); | 4266 | memset(&iwe, 0, sizeof(iwe)); |
4168 | iwe.cmd = IWEVGENIE; | 4267 | iwe.cmd = IWEVGENIE; |
4169 | iwe.u.data.length = bss->wpa_ie_len; | 4268 | iwe.u.data.length = bss->wpa_ie_len; |
4170 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4269 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4171 | bss->wpa_ie); | 4270 | &iwe, bss->wpa_ie); |
4172 | } | 4271 | } |
4173 | 4272 | ||
4174 | if (bss && bss->rsn_ie) { | 4273 | if (bss && bss->rsn_ie) { |
4175 | memset(&iwe, 0, sizeof(iwe)); | 4274 | memset(&iwe, 0, sizeof(iwe)); |
4176 | iwe.cmd = IWEVGENIE; | 4275 | iwe.cmd = IWEVGENIE; |
4177 | iwe.u.data.length = bss->rsn_ie_len; | 4276 | iwe.u.data.length = bss->rsn_ie_len; |
4178 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4277 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4179 | bss->rsn_ie); | 4278 | &iwe, bss->rsn_ie); |
4180 | } | 4279 | } |
4181 | 4280 | ||
4182 | if (bss && bss->ht_ie) { | 4281 | if (bss && bss->ht_ie) { |
4183 | memset(&iwe, 0, sizeof(iwe)); | 4282 | memset(&iwe, 0, sizeof(iwe)); |
4184 | iwe.cmd = IWEVGENIE; | 4283 | iwe.cmd = IWEVGENIE; |
4185 | iwe.u.data.length = bss->ht_ie_len; | 4284 | iwe.u.data.length = bss->ht_ie_len; |
4186 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 4285 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
4187 | bss->ht_ie); | 4286 | &iwe, bss->ht_ie); |
4188 | } | 4287 | } |
4189 | 4288 | ||
4190 | if (bss && bss->supp_rates_len > 0) { | 4289 | if (bss && bss->supp_rates_len > 0) { |
4191 | /* display all supported rates in readable format */ | 4290 | /* display all supported rates in readable format */ |
4192 | char *p = current_ev + IW_EV_LCP_LEN; | 4291 | char *p = current_ev + iwe_stream_lcp_len(info); |
4193 | int i; | 4292 | int i; |
4194 | 4293 | ||
4195 | memset(&iwe, 0, sizeof(iwe)); | 4294 | memset(&iwe, 0, sizeof(iwe)); |
@@ -4200,7 +4299,7 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4200 | for (i = 0; i < bss->supp_rates_len; i++) { | 4299 | for (i = 0; i < bss->supp_rates_len; i++) { |
4201 | iwe.u.bitrate.value = ((bss->supp_rates[i] & | 4300 | iwe.u.bitrate.value = ((bss->supp_rates[i] & |
4202 | 0x7f) * 500000); | 4301 | 0x7f) * 500000); |
4203 | p = iwe_stream_add_value(current_ev, p, | 4302 | p = iwe_stream_add_value(info, current_ev, p, |
4204 | end_buf, &iwe, IW_EV_PARAM_LEN); | 4303 | end_buf, &iwe, IW_EV_PARAM_LEN); |
4205 | } | 4304 | } |
4206 | current_ev = p; | 4305 | current_ev = p; |
@@ -4214,7 +4313,8 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4214 | iwe.cmd = IWEVCUSTOM; | 4313 | iwe.cmd = IWEVCUSTOM; |
4215 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); | 4314 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); |
4216 | iwe.u.data.length = strlen(buf); | 4315 | iwe.u.data.length = strlen(buf); |
4217 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4316 | current_ev = iwe_stream_add_point(info, current_ev, |
4317 | end_buf, | ||
4218 | &iwe, buf); | 4318 | &iwe, buf); |
4219 | kfree(buf); | 4319 | kfree(buf); |
4220 | } | 4320 | } |
@@ -4229,31 +4329,36 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4229 | iwe.cmd = IWEVCUSTOM; | 4329 | iwe.cmd = IWEVCUSTOM; |
4230 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | 4330 | sprintf(buf, "Mesh network (version %d)", cfg[0]); |
4231 | iwe.u.data.length = strlen(buf); | 4331 | iwe.u.data.length = strlen(buf); |
4232 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4332 | current_ev = iwe_stream_add_point(info, current_ev, |
4333 | end_buf, | ||
4233 | &iwe, buf); | 4334 | &iwe, buf); |
4234 | sprintf(buf, "Path Selection Protocol ID: " | 4335 | sprintf(buf, "Path Selection Protocol ID: " |
4235 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | 4336 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], |
4236 | cfg[4]); | 4337 | cfg[4]); |
4237 | iwe.u.data.length = strlen(buf); | 4338 | iwe.u.data.length = strlen(buf); |
4238 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4339 | current_ev = iwe_stream_add_point(info, current_ev, |
4340 | end_buf, | ||
4239 | &iwe, buf); | 4341 | &iwe, buf); |
4240 | sprintf(buf, "Path Selection Metric ID: " | 4342 | sprintf(buf, "Path Selection Metric ID: " |
4241 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | 4343 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], |
4242 | cfg[8]); | 4344 | cfg[8]); |
4243 | iwe.u.data.length = strlen(buf); | 4345 | iwe.u.data.length = strlen(buf); |
4244 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4346 | current_ev = iwe_stream_add_point(info, current_ev, |
4347 | end_buf, | ||
4245 | &iwe, buf); | 4348 | &iwe, buf); |
4246 | sprintf(buf, "Congestion Control Mode ID: " | 4349 | sprintf(buf, "Congestion Control Mode ID: " |
4247 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | 4350 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], |
4248 | cfg[11], cfg[12]); | 4351 | cfg[11], cfg[12]); |
4249 | iwe.u.data.length = strlen(buf); | 4352 | iwe.u.data.length = strlen(buf); |
4250 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4353 | current_ev = iwe_stream_add_point(info, current_ev, |
4354 | end_buf, | ||
4251 | &iwe, buf); | 4355 | &iwe, buf); |
4252 | sprintf(buf, "Channel Precedence: " | 4356 | sprintf(buf, "Channel Precedence: " |
4253 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | 4357 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], |
4254 | cfg[15], cfg[16]); | 4358 | cfg[15], cfg[16]); |
4255 | iwe.u.data.length = strlen(buf); | 4359 | iwe.u.data.length = strlen(buf); |
4256 | current_ev = iwe_stream_add_point(current_ev, end_buf, | 4360 | current_ev = iwe_stream_add_point(info, current_ev, |
4361 | end_buf, | ||
4257 | &iwe, buf); | 4362 | &iwe, buf); |
4258 | kfree(buf); | 4363 | kfree(buf); |
4259 | } | 4364 | } |
@@ -4263,7 +4368,9 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
4263 | } | 4368 | } |
4264 | 4369 | ||
4265 | 4370 | ||
4266 | int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) | 4371 | int ieee80211_sta_scan_results(struct net_device *dev, |
4372 | struct iw_request_info *info, | ||
4373 | char *buf, size_t len) | ||
4267 | { | 4374 | { |
4268 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 4375 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
4269 | char *current_ev = buf; | 4376 | char *current_ev = buf; |
@@ -4276,8 +4383,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) | |||
4276 | spin_unlock_bh(&local->sta_bss_lock); | 4383 | spin_unlock_bh(&local->sta_bss_lock); |
4277 | return -E2BIG; | 4384 | return -E2BIG; |
4278 | } | 4385 | } |
4279 | current_ev = ieee80211_sta_scan_result(dev, bss, current_ev, | 4386 | current_ev = ieee80211_sta_scan_result(dev, info, bss, |
4280 | end_buf); | 4387 | current_ev, end_buf); |
4281 | } | 4388 | } |
4282 | spin_unlock_bh(&local->sta_bss_lock); | 4389 | spin_unlock_bh(&local->sta_bss_lock); |
4283 | return current_ev - buf; | 4390 | return current_ev - buf; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c32a0bcd53b7..8962d1355f04 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -61,7 +61,7 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, | |||
61 | int present_fcs_len, | 61 | int present_fcs_len, |
62 | int radiotap_len) | 62 | int radiotap_len) |
63 | { | 63 | { |
64 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 64 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
65 | 65 | ||
66 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | 66 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) |
67 | return 1; | 67 | return 1; |
@@ -2123,7 +2123,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2123 | struct tid_ampdu_rx *tid_agg_rx; | 2123 | struct tid_ampdu_rx *tid_agg_rx; |
2124 | u16 sc; | 2124 | u16 sc; |
2125 | u16 mpdu_seq_num; | 2125 | u16 mpdu_seq_num; |
2126 | u8 ret = 0, *qc; | 2126 | u8 ret = 0; |
2127 | int tid; | 2127 | int tid; |
2128 | 2128 | ||
2129 | sta = sta_info_get(local, hdr->addr2); | 2129 | sta = sta_info_get(local, hdr->addr2); |
@@ -2135,8 +2135,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2135 | if (!ieee80211_is_data_qos(hdr->frame_control)) | 2135 | if (!ieee80211_is_data_qos(hdr->frame_control)) |
2136 | goto end_reorder; | 2136 | goto end_reorder; |
2137 | 2137 | ||
2138 | qc = ieee80211_get_qos_ctl(hdr); | 2138 | tid = *ieee80211_get_qos_ctl(hdr) & QOS_CONTROL_TID_MASK; |
2139 | tid = qc[0] & QOS_CONTROL_TID_MASK; | ||
2140 | 2139 | ||
2141 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) | 2140 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) |
2142 | goto end_reorder; | 2141 | goto end_reorder; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c24770cb02c5..b3c733162fc1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
235 | return NULL; | 235 | return NULL; |
236 | 236 | ||
237 | spin_lock_init(&sta->lock); | 237 | spin_lock_init(&sta->lock); |
238 | spin_lock_init(&sta->flaglock); | ||
238 | 239 | ||
239 | memcpy(sta->addr, addr, ETH_ALEN); | 240 | memcpy(sta->addr, addr, ETH_ALEN); |
240 | sta->local = local; | 241 | sta->local = local; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 95753f860acf..fd228c198e31 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -164,6 +164,7 @@ struct sta_ampdu_mlme { | |||
164 | * @aid: STA's unique AID (1..2007, 0 = not assigned yet), | 164 | * @aid: STA's unique AID (1..2007, 0 = not assigned yet), |
165 | * only used in AP (and IBSS?) mode | 165 | * only used in AP (and IBSS?) mode |
166 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 166 | * @flags: STA flags, see &enum ieee80211_sta_info_flags |
167 | * @flaglock: spinlock for flags accesses | ||
167 | * @ps_tx_buf: buffer of frames to transmit to this station | 168 | * @ps_tx_buf: buffer of frames to transmit to this station |
168 | * when it leaves power saving state | 169 | * when it leaves power saving state |
169 | * @tx_filtered: buffer of frames we already tried to transmit | 170 | * @tx_filtered: buffer of frames we already tried to transmit |
@@ -186,6 +187,7 @@ struct sta_info { | |||
186 | struct rate_control_ref *rate_ctrl; | 187 | struct rate_control_ref *rate_ctrl; |
187 | void *rate_ctrl_priv; | 188 | void *rate_ctrl_priv; |
188 | spinlock_t lock; | 189 | spinlock_t lock; |
190 | spinlock_t flaglock; | ||
189 | struct ieee80211_ht_info ht_info; | 191 | struct ieee80211_ht_info ht_info; |
190 | u64 supp_rates[IEEE80211_NUM_BANDS]; | 192 | u64 supp_rates[IEEE80211_NUM_BANDS]; |
191 | u8 addr[ETH_ALEN]; | 193 | u8 addr[ETH_ALEN]; |
@@ -198,7 +200,10 @@ struct sta_info { | |||
198 | */ | 200 | */ |
199 | u8 pin_status; | 201 | u8 pin_status; |
200 | 202 | ||
201 | /* frequently updated information, locked with lock spinlock */ | 203 | /* |
204 | * frequently updated, locked with own spinlock (flaglock), | ||
205 | * use the accessors defined below | ||
206 | */ | ||
202 | u32 flags; | 207 | u32 flags; |
203 | 208 | ||
204 | /* | 209 | /* |
@@ -293,34 +298,41 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) | |||
293 | 298 | ||
294 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) | 299 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) |
295 | { | 300 | { |
296 | spin_lock_bh(&sta->lock); | 301 | unsigned long irqfl; |
302 | |||
303 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
297 | sta->flags |= flags; | 304 | sta->flags |= flags; |
298 | spin_unlock_bh(&sta->lock); | 305 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
299 | } | 306 | } |
300 | 307 | ||
301 | static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) | 308 | static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) |
302 | { | 309 | { |
303 | spin_lock_bh(&sta->lock); | 310 | unsigned long irqfl; |
311 | |||
312 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
304 | sta->flags &= ~flags; | 313 | sta->flags &= ~flags; |
305 | spin_unlock_bh(&sta->lock); | 314 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
306 | } | 315 | } |
307 | 316 | ||
308 | static inline void set_and_clear_sta_flags(struct sta_info *sta, | 317 | static inline void set_and_clear_sta_flags(struct sta_info *sta, |
309 | const u32 set, const u32 clear) | 318 | const u32 set, const u32 clear) |
310 | { | 319 | { |
311 | spin_lock_bh(&sta->lock); | 320 | unsigned long irqfl; |
321 | |||
322 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
312 | sta->flags |= set; | 323 | sta->flags |= set; |
313 | sta->flags &= ~clear; | 324 | sta->flags &= ~clear; |
314 | spin_unlock_bh(&sta->lock); | 325 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
315 | } | 326 | } |
316 | 327 | ||
317 | static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) | 328 | static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) |
318 | { | 329 | { |
319 | u32 ret; | 330 | u32 ret; |
331 | unsigned long irqfl; | ||
320 | 332 | ||
321 | spin_lock_bh(&sta->lock); | 333 | spin_lock_irqsave(&sta->flaglock, irqfl); |
322 | ret = sta->flags & flags; | 334 | ret = sta->flags & flags; |
323 | spin_unlock_bh(&sta->lock); | 335 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
324 | 336 | ||
325 | return ret; | 337 | return ret; |
326 | } | 338 | } |
@@ -329,11 +341,12 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta, | |||
329 | const u32 flags) | 341 | const u32 flags) |
330 | { | 342 | { |
331 | u32 ret; | 343 | u32 ret; |
344 | unsigned long irqfl; | ||
332 | 345 | ||
333 | spin_lock_bh(&sta->lock); | 346 | spin_lock_irqsave(&sta->flaglock, irqfl); |
334 | ret = sta->flags & flags; | 347 | ret = sta->flags & flags; |
335 | sta->flags &= ~flags; | 348 | sta->flags &= ~flags; |
336 | spin_unlock_bh(&sta->lock); | 349 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
337 | 350 | ||
338 | return ret; | 351 | return ret; |
339 | } | 352 | } |
@@ -341,10 +354,11 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta, | |||
341 | static inline u32 get_sta_flags(struct sta_info *sta) | 354 | static inline u32 get_sta_flags(struct sta_info *sta) |
342 | { | 355 | { |
343 | u32 ret; | 356 | u32 ret; |
357 | unsigned long irqfl; | ||
344 | 358 | ||
345 | spin_lock_bh(&sta->lock); | 359 | spin_lock_irqsave(&sta->flaglock, irqfl); |
346 | ret = sta->flags; | 360 | ret = sta->flags; |
347 | spin_unlock_bh(&sta->lock); | 361 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
348 | 362 | ||
349 | return ret; | 363 | return ret; |
350 | } | 364 | } |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index e710243d82e2..995f7af3d25e 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -164,10 +164,10 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | |||
164 | iv16 = data[2] | (data[0] << 8); | 164 | iv16 = data[2] | (data[0] << 8); |
165 | iv32 = get_unaligned_le32(&data[4]); | 165 | iv32 = get_unaligned_le32(&data[4]); |
166 | 166 | ||
167 | tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY]; | 167 | tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
168 | ctx = &key->u.tkip.tx; | 168 | ctx = &key->u.tkip.tx; |
169 | 169 | ||
170 | #ifdef CONFIG_TKIP_DEBUG | 170 | #ifdef CONFIG_MAC80211_TKIP_DEBUG |
171 | printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", | 171 | printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", |
172 | iv16, iv32); | 172 | iv16, iv32); |
173 | 173 | ||
@@ -177,7 +177,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | |||
177 | printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " | 177 | printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " |
178 | "fragmented packet\n"); | 178 | "fragmented packet\n"); |
179 | } | 179 | } |
180 | #endif /* CONFIG_TKIP_DEBUG */ | 180 | #endif |
181 | 181 | ||
182 | /* Update the p1k only when the iv16 in the packet wraps around, this | 182 | /* Update the p1k only when the iv16 in the packet wraps around, this |
183 | * might occur after the wrap around of iv16 in the key in case of | 183 | * might occur after the wrap around of iv16 in the key in case of |
@@ -205,7 +205,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | |||
205 | { | 205 | { |
206 | u8 rc4key[16]; | 206 | u8 rc4key[16]; |
207 | struct tkip_ctx *ctx = &key->u.tkip.tx; | 207 | struct tkip_ctx *ctx = &key->u.tkip.tx; |
208 | const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY]; | 208 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
209 | 209 | ||
210 | /* Calculate per-packet key */ | 210 | /* Calculate per-packet key */ |
211 | if (ctx->iv16 == 0 || !ctx->initialized) | 211 | if (ctx->iv16 == 0 || !ctx->initialized) |
@@ -231,7 +231,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
231 | u32 iv16; | 231 | u32 iv16; |
232 | u8 rc4key[16], keyid, *pos = payload; | 232 | u8 rc4key[16], keyid, *pos = payload; |
233 | int res; | 233 | int res; |
234 | const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY]; | 234 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
235 | 235 | ||
236 | if (payload_len < 12) | 236 | if (payload_len < 12) |
237 | return -1; | 237 | return -1; |
@@ -240,7 +240,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
240 | keyid = pos[3]; | 240 | keyid = pos[3]; |
241 | iv32 = get_unaligned_le32(pos + 4); | 241 | iv32 = get_unaligned_le32(pos + 4); |
242 | pos += 8; | 242 | pos += 8; |
243 | #ifdef CONFIG_TKIP_DEBUG | 243 | #ifdef CONFIG_MAC80211_TKIP_DEBUG |
244 | { | 244 | { |
245 | int i; | 245 | int i; |
246 | printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len); | 246 | printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len); |
@@ -250,7 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
250 | printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n", | 250 | printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n", |
251 | iv16, iv32); | 251 | iv16, iv32); |
252 | } | 252 | } |
253 | #endif /* CONFIG_TKIP_DEBUG */ | 253 | #endif |
254 | 254 | ||
255 | if (!(keyid & (1 << 5))) | 255 | if (!(keyid & (1 << 5))) |
256 | return TKIP_DECRYPT_NO_EXT_IV; | 256 | return TKIP_DECRYPT_NO_EXT_IV; |
@@ -262,14 +262,14 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
262 | (iv32 < key->u.tkip.rx[queue].iv32 || | 262 | (iv32 < key->u.tkip.rx[queue].iv32 || |
263 | (iv32 == key->u.tkip.rx[queue].iv32 && | 263 | (iv32 == key->u.tkip.rx[queue].iv32 && |
264 | iv16 <= key->u.tkip.rx[queue].iv16))) { | 264 | iv16 <= key->u.tkip.rx[queue].iv16))) { |
265 | #ifdef CONFIG_TKIP_DEBUG | 265 | #ifdef CONFIG_MAC80211_TKIP_DEBUG |
266 | DECLARE_MAC_BUF(mac); | 266 | DECLARE_MAC_BUF(mac); |
267 | printk(KERN_DEBUG "TKIP replay detected for RX frame from " | 267 | printk(KERN_DEBUG "TKIP replay detected for RX frame from " |
268 | "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", | 268 | "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", |
269 | print_mac(mac, ta), | 269 | print_mac(mac, ta), |
270 | iv32, iv16, key->u.tkip.rx[queue].iv32, | 270 | iv32, iv16, key->u.tkip.rx[queue].iv32, |
271 | key->u.tkip.rx[queue].iv16); | 271 | key->u.tkip.rx[queue].iv16); |
272 | #endif /* CONFIG_TKIP_DEBUG */ | 272 | #endif |
273 | return TKIP_DECRYPT_REPLAY; | 273 | return TKIP_DECRYPT_REPLAY; |
274 | } | 274 | } |
275 | 275 | ||
@@ -283,23 +283,23 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
283 | key->u.tkip.rx[queue].iv32 != iv32) { | 283 | key->u.tkip.rx[queue].iv32 != iv32) { |
284 | /* IV16 wrapped around - perform TKIP phase 1 */ | 284 | /* IV16 wrapped around - perform TKIP phase 1 */ |
285 | tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); | 285 | tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); |
286 | #ifdef CONFIG_TKIP_DEBUG | 286 | #ifdef CONFIG_MAC80211_TKIP_DEBUG |
287 | { | 287 | { |
288 | int i; | 288 | int i; |
289 | u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; | ||
289 | DECLARE_MAC_BUF(mac); | 290 | DECLARE_MAC_BUF(mac); |
290 | printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" | 291 | printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" |
291 | " TK=", print_mac(mac, ta)); | 292 | " TK=", print_mac(mac, ta)); |
292 | for (i = 0; i < 16; i++) | 293 | for (i = 0; i < 16; i++) |
293 | printk("%02x ", | 294 | printk("%02x ", |
294 | key->conf.key[ | 295 | key->conf.key[key_offset + i]); |
295 | ALG_TKIP_TEMP_ENCR_KEY + i]); | ||
296 | printk("\n"); | 296 | printk("\n"); |
297 | printk(KERN_DEBUG "TKIP decrypt: P1K="); | 297 | printk(KERN_DEBUG "TKIP decrypt: P1K="); |
298 | for (i = 0; i < 5; i++) | 298 | for (i = 0; i < 5; i++) |
299 | printk("%04x ", key->u.tkip.rx[queue].p1k[i]); | 299 | printk("%04x ", key->u.tkip.rx[queue].p1k[i]); |
300 | printk("\n"); | 300 | printk("\n"); |
301 | } | 301 | } |
302 | #endif /* CONFIG_TKIP_DEBUG */ | 302 | #endif |
303 | if (key->local->ops->update_tkip_key && | 303 | if (key->local->ops->update_tkip_key && |
304 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 304 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { |
305 | u8 bcast[ETH_ALEN] = | 305 | u8 bcast[ETH_ALEN] = |
@@ -316,7 +316,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
316 | } | 316 | } |
317 | 317 | ||
318 | tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); | 318 | tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); |
319 | #ifdef CONFIG_TKIP_DEBUG | 319 | #ifdef CONFIG_MAC80211_TKIP_DEBUG |
320 | { | 320 | { |
321 | int i; | 321 | int i; |
322 | printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key="); | 322 | printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key="); |
@@ -324,7 +324,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
324 | printk("%02x ", rc4key[i]); | 324 | printk("%02x ", rc4key[i]); |
325 | printk("\n"); | 325 | printk("\n"); |
326 | } | 326 | } |
327 | #endif /* CONFIG_TKIP_DEBUG */ | 327 | #endif |
328 | 328 | ||
329 | res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); | 329 | res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); |
330 | done: | 330 | done: |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ce06e791bf43..52ab85c4341b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -52,9 +52,8 @@ static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdat | |||
52 | static void ieee80211_dump_frame(const char *ifname, const char *title, | 52 | static void ieee80211_dump_frame(const char *ifname, const char *title, |
53 | const struct sk_buff *skb) | 53 | const struct sk_buff *skb) |
54 | { | 54 | { |
55 | const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 55 | const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
56 | u16 fc; | 56 | unsigned int hdrlen; |
57 | int hdrlen; | ||
58 | DECLARE_MAC_BUF(mac); | 57 | DECLARE_MAC_BUF(mac); |
59 | 58 | ||
60 | printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); | 59 | printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); |
@@ -63,13 +62,12 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, | |||
63 | return; | 62 | return; |
64 | } | 63 | } |
65 | 64 | ||
66 | fc = le16_to_cpu(hdr->frame_control); | 65 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
67 | hdrlen = ieee80211_get_hdrlen(fc); | ||
68 | if (hdrlen > skb->len) | 66 | if (hdrlen > skb->len) |
69 | hdrlen = skb->len; | 67 | hdrlen = skb->len; |
70 | if (hdrlen >= 4) | 68 | if (hdrlen >= 4) |
71 | printk(" FC=0x%04x DUR=0x%04x", | 69 | printk(" FC=0x%04x DUR=0x%04x", |
72 | fc, le16_to_cpu(hdr->duration_id)); | 70 | le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id)); |
73 | if (hdrlen >= 10) | 71 | if (hdrlen >= 10) |
74 | printk(" A1=%s", print_mac(mac, hdr->addr1)); | 72 | printk(" A1=%s", print_mac(mac, hdr->addr1)); |
75 | if (hdrlen >= 16) | 73 | if (hdrlen >= 16) |
@@ -87,8 +85,8 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title, | |||
87 | } | 85 | } |
88 | #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ | 86 | #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ |
89 | 87 | ||
90 | static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | 88 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, |
91 | int next_frag_len) | 89 | int next_frag_len) |
92 | { | 90 | { |
93 | int rate, mrate, erp, dur, i; | 91 | int rate, mrate, erp, dur, i; |
94 | struct ieee80211_rate *txrate; | 92 | struct ieee80211_rate *txrate; |
@@ -140,7 +138,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
140 | 138 | ||
141 | /* data/mgmt */ | 139 | /* data/mgmt */ |
142 | if (0 /* FIX: data/mgmt during CFP */) | 140 | if (0 /* FIX: data/mgmt during CFP */) |
143 | return 32768; | 141 | return cpu_to_le16(32768); |
144 | 142 | ||
145 | if (group_addr) /* Group address as the destination - no ACK */ | 143 | if (group_addr) /* Group address as the destination - no ACK */ |
146 | return 0; | 144 | return 0; |
@@ -210,7 +208,7 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
210 | tx->sdata->bss_conf.use_short_preamble); | 208 | tx->sdata->bss_conf.use_short_preamble); |
211 | } | 209 | } |
212 | 210 | ||
213 | return dur; | 211 | return cpu_to_le16(dur); |
214 | } | 212 | } |
215 | 213 | ||
216 | static int inline is_ieee80211_device(struct net_device *dev, | 214 | static int inline is_ieee80211_device(struct net_device *dev, |
@@ -281,7 +279,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
281 | { | 279 | { |
282 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 280 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
283 | 281 | ||
284 | if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) | 282 | if (ieee80211_hdrlen(hdr->frame_control) >= 24) |
285 | ieee80211_include_sequence(tx->sdata, hdr); | 283 | ieee80211_include_sequence(tx->sdata, hdr); |
286 | 284 | ||
287 | return TX_CONTINUE; | 285 | return TX_CONTINUE; |
@@ -542,9 +540,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
542 | static ieee80211_tx_result | 540 | static ieee80211_tx_result |
543 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | 541 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) |
544 | { | 542 | { |
545 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 543 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
546 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
547 | u16 dur; | ||
548 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 544 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
549 | struct ieee80211_supported_band *sband; | 545 | struct ieee80211_supported_band *sband; |
550 | 546 | ||
@@ -595,21 +591,13 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | |||
595 | /* Transmit data frames using short preambles if the driver supports | 591 | /* Transmit data frames using short preambles if the driver supports |
596 | * short preambles at the selected rate and short preambles are | 592 | * short preambles at the selected rate and short preambles are |
597 | * available on the network at the current point in time. */ | 593 | * available on the network at the current point in time. */ |
598 | if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && | 594 | if (ieee80211_is_data(hdr->frame_control) && |
599 | (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && | 595 | (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && |
600 | tx->sdata->bss_conf.use_short_preamble && | 596 | tx->sdata->bss_conf.use_short_preamble && |
601 | (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { | 597 | (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { |
602 | info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; | 598 | info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; |
603 | } | 599 | } |
604 | 600 | ||
605 | /* Setup duration field for the first fragment of the frame. Duration | ||
606 | * for remaining fragments will be updated when they are being sent | ||
607 | * to low-level driver in ieee80211_tx(). */ | ||
608 | dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), | ||
609 | (tx->flags & IEEE80211_TX_FRAGMENTED) ? | ||
610 | tx->extra_frag[0]->len : 0); | ||
611 | hdr->duration_id = cpu_to_le16(dur); | ||
612 | |||
613 | if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || | 601 | if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || |
614 | (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { | 602 | (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { |
615 | struct ieee80211_rate *rate; | 603 | struct ieee80211_rate *rate; |
@@ -647,7 +635,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | |||
647 | static ieee80211_tx_result | 635 | static ieee80211_tx_result |
648 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | 636 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) |
649 | { | 637 | { |
650 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 638 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
651 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; | 639 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; |
652 | struct sk_buff **frags, *first, *frag; | 640 | struct sk_buff **frags, *first, *frag; |
653 | int i; | 641 | int i; |
@@ -670,7 +658,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
670 | 658 | ||
671 | first = tx->skb; | 659 | first = tx->skb; |
672 | 660 | ||
673 | hdrlen = ieee80211_get_hdrlen(tx->fc); | 661 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
674 | payload_len = first->len - hdrlen; | 662 | payload_len = first->len - hdrlen; |
675 | per_fragm = frag_threshold - hdrlen - FCS_LEN; | 663 | per_fragm = frag_threshold - hdrlen - FCS_LEN; |
676 | num_fragm = DIV_ROUND_UP(payload_len, per_fragm); | 664 | num_fragm = DIV_ROUND_UP(payload_len, per_fragm); |
@@ -711,6 +699,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
711 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); | 699 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); |
712 | copylen = left > per_fragm ? per_fragm : left; | 700 | copylen = left > per_fragm ? per_fragm : left; |
713 | memcpy(skb_put(frag, copylen), pos, copylen); | 701 | memcpy(skb_put(frag, copylen), pos, copylen); |
702 | memcpy(frag->cb, first->cb, sizeof(frag->cb)); | ||
703 | skb_copy_queue_mapping(frag, first); | ||
714 | 704 | ||
715 | pos += copylen; | 705 | pos += copylen; |
716 | left -= copylen; | 706 | left -= copylen; |
@@ -755,6 +745,36 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
755 | } | 745 | } |
756 | 746 | ||
757 | static ieee80211_tx_result | 747 | static ieee80211_tx_result |
748 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | ||
749 | { | ||
750 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | ||
751 | int next_len, i; | ||
752 | int group_addr = is_multicast_ether_addr(hdr->addr1); | ||
753 | |||
754 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) { | ||
755 | hdr->duration_id = ieee80211_duration(tx, group_addr, 0); | ||
756 | return TX_CONTINUE; | ||
757 | } | ||
758 | |||
759 | hdr->duration_id = ieee80211_duration(tx, group_addr, | ||
760 | tx->extra_frag[0]->len); | ||
761 | |||
762 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
763 | if (i + 1 < tx->num_extra_frag) { | ||
764 | next_len = tx->extra_frag[i + 1]->len; | ||
765 | } else { | ||
766 | next_len = 0; | ||
767 | tx->rate_idx = tx->last_frag_rate_idx; | ||
768 | } | ||
769 | |||
770 | hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data; | ||
771 | hdr->duration_id = ieee80211_duration(tx, 0, next_len); | ||
772 | } | ||
773 | |||
774 | return TX_CONTINUE; | ||
775 | } | ||
776 | |||
777 | static ieee80211_tx_result | ||
758 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | 778 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) |
759 | { | 779 | { |
760 | int i; | 780 | int i; |
@@ -788,6 +808,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = | |||
788 | ieee80211_tx_h_fragment, | 808 | ieee80211_tx_h_fragment, |
789 | /* handlers after fragment must be aware of tx info fragmentation! */ | 809 | /* handlers after fragment must be aware of tx info fragmentation! */ |
790 | ieee80211_tx_h_encrypt, | 810 | ieee80211_tx_h_encrypt, |
811 | ieee80211_tx_h_calculate_duration, | ||
791 | ieee80211_tx_h_stats, | 812 | ieee80211_tx_h_stats, |
792 | NULL | 813 | NULL |
793 | }; | 814 | }; |
@@ -1083,13 +1104,46 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1083 | return IEEE80211_TX_OK; | 1104 | return IEEE80211_TX_OK; |
1084 | } | 1105 | } |
1085 | 1106 | ||
1107 | /* | ||
1108 | * Invoke TX handlers, return 0 on success and non-zero if the | ||
1109 | * frame was dropped or queued. | ||
1110 | */ | ||
1111 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | ||
1112 | { | ||
1113 | struct ieee80211_local *local = tx->local; | ||
1114 | struct sk_buff *skb = tx->skb; | ||
1115 | ieee80211_tx_handler *handler; | ||
1116 | ieee80211_tx_result res = TX_DROP; | ||
1117 | int i; | ||
1118 | |||
1119 | for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { | ||
1120 | res = (*handler)(tx); | ||
1121 | if (res != TX_CONTINUE) | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | if (unlikely(res == TX_DROP)) { | ||
1126 | I802_DEBUG_INC(local->tx_handlers_drop); | ||
1127 | dev_kfree_skb(skb); | ||
1128 | for (i = 0; i < tx->num_extra_frag; i++) | ||
1129 | if (tx->extra_frag[i]) | ||
1130 | dev_kfree_skb(tx->extra_frag[i]); | ||
1131 | kfree(tx->extra_frag); | ||
1132 | return -1; | ||
1133 | } else if (unlikely(res == TX_QUEUED)) { | ||
1134 | I802_DEBUG_INC(local->tx_handlers_queued); | ||
1135 | return -1; | ||
1136 | } | ||
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1086 | static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | 1141 | static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) |
1087 | { | 1142 | { |
1088 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1143 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1089 | struct sta_info *sta; | 1144 | struct sta_info *sta; |
1090 | ieee80211_tx_handler *handler; | ||
1091 | struct ieee80211_tx_data tx; | 1145 | struct ieee80211_tx_data tx; |
1092 | ieee80211_tx_result res = TX_DROP, res_prepare; | 1146 | ieee80211_tx_result res_prepare; |
1093 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1147 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1094 | int ret, i; | 1148 | int ret, i; |
1095 | u16 queue; | 1149 | u16 queue; |
@@ -1118,44 +1172,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1118 | tx.channel = local->hw.conf.channel; | 1172 | tx.channel = local->hw.conf.channel; |
1119 | info->band = tx.channel->band; | 1173 | info->band = tx.channel->band; |
1120 | 1174 | ||
1121 | for (handler = ieee80211_tx_handlers; *handler != NULL; | 1175 | if (invoke_tx_handlers(&tx)) |
1122 | handler++) { | 1176 | goto out; |
1123 | res = (*handler)(&tx); | ||
1124 | if (res != TX_CONTINUE) | ||
1125 | break; | ||
1126 | } | ||
1127 | |||
1128 | if (WARN_ON(tx.skb != skb)) | ||
1129 | goto drop; | ||
1130 | |||
1131 | if (unlikely(res == TX_DROP)) { | ||
1132 | I802_DEBUG_INC(local->tx_handlers_drop); | ||
1133 | goto drop; | ||
1134 | } | ||
1135 | |||
1136 | if (unlikely(res == TX_QUEUED)) { | ||
1137 | I802_DEBUG_INC(local->tx_handlers_queued); | ||
1138 | rcu_read_unlock(); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | if (tx.extra_frag) { | ||
1143 | for (i = 0; i < tx.num_extra_frag; i++) { | ||
1144 | int next_len, dur; | ||
1145 | struct ieee80211_hdr *hdr = | ||
1146 | (struct ieee80211_hdr *) | ||
1147 | tx.extra_frag[i]->data; | ||
1148 | |||
1149 | if (i + 1 < tx.num_extra_frag) { | ||
1150 | next_len = tx.extra_frag[i + 1]->len; | ||
1151 | } else { | ||
1152 | next_len = 0; | ||
1153 | tx.rate_idx = tx.last_frag_rate_idx; | ||
1154 | } | ||
1155 | dur = ieee80211_duration(&tx, 0, next_len); | ||
1156 | hdr->duration_id = cpu_to_le16(dur); | ||
1157 | } | ||
1158 | } | ||
1159 | 1177 | ||
1160 | retry: | 1178 | retry: |
1161 | ret = __ieee80211_tx(local, skb, &tx); | 1179 | ret = __ieee80211_tx(local, skb, &tx); |
@@ -1198,6 +1216,7 @@ retry: | |||
1198 | store->last_frag_rate_ctrl_probe = | 1216 | store->last_frag_rate_ctrl_probe = |
1199 | !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); | 1217 | !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); |
1200 | } | 1218 | } |
1219 | out: | ||
1201 | rcu_read_unlock(); | 1220 | rcu_read_unlock(); |
1202 | return 0; | 1221 | return 0; |
1203 | 1222 | ||
@@ -1379,7 +1398,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1379 | struct ieee80211_tx_info *info; | 1398 | struct ieee80211_tx_info *info; |
1380 | struct ieee80211_sub_if_data *sdata; | 1399 | struct ieee80211_sub_if_data *sdata; |
1381 | int ret = 1, head_need; | 1400 | int ret = 1, head_need; |
1382 | u16 ethertype, hdrlen, meshhdrlen = 0, fc; | 1401 | u16 ethertype, hdrlen, meshhdrlen = 0; |
1402 | __le16 fc; | ||
1383 | struct ieee80211_hdr hdr; | 1403 | struct ieee80211_hdr hdr; |
1384 | struct ieee80211s_hdr mesh_hdr; | 1404 | struct ieee80211s_hdr mesh_hdr; |
1385 | const u8 *encaps_data; | 1405 | const u8 *encaps_data; |
@@ -1402,12 +1422,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1402 | /* convert Ethernet header to proper 802.11 header (based on | 1422 | /* convert Ethernet header to proper 802.11 header (based on |
1403 | * operation mode) */ | 1423 | * operation mode) */ |
1404 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1424 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
1405 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; | 1425 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
1406 | 1426 | ||
1407 | switch (sdata->vif.type) { | 1427 | switch (sdata->vif.type) { |
1408 | case IEEE80211_IF_TYPE_AP: | 1428 | case IEEE80211_IF_TYPE_AP: |
1409 | case IEEE80211_IF_TYPE_VLAN: | 1429 | case IEEE80211_IF_TYPE_VLAN: |
1410 | fc |= IEEE80211_FCTL_FROMDS; | 1430 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1411 | /* DA BSSID SA */ | 1431 | /* DA BSSID SA */ |
1412 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1432 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
1413 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1433 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); |
@@ -1415,7 +1435,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1415 | hdrlen = 24; | 1435 | hdrlen = 24; |
1416 | break; | 1436 | break; |
1417 | case IEEE80211_IF_TYPE_WDS: | 1437 | case IEEE80211_IF_TYPE_WDS: |
1418 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | 1438 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1419 | /* RA TA DA SA */ | 1439 | /* RA TA DA SA */ |
1420 | memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); | 1440 | memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); |
1421 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1441 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); |
@@ -1425,7 +1445,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1425 | break; | 1445 | break; |
1426 | #ifdef CONFIG_MAC80211_MESH | 1446 | #ifdef CONFIG_MAC80211_MESH |
1427 | case IEEE80211_IF_TYPE_MESH_POINT: | 1447 | case IEEE80211_IF_TYPE_MESH_POINT: |
1428 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | 1448 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1429 | /* RA TA DA SA */ | 1449 | /* RA TA DA SA */ |
1430 | if (is_multicast_ether_addr(skb->data)) | 1450 | if (is_multicast_ether_addr(skb->data)) |
1431 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1451 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -1455,7 +1475,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1455 | break; | 1475 | break; |
1456 | #endif | 1476 | #endif |
1457 | case IEEE80211_IF_TYPE_STA: | 1477 | case IEEE80211_IF_TYPE_STA: |
1458 | fc |= IEEE80211_FCTL_TODS; | 1478 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
1459 | /* BSSID SA DA */ | 1479 | /* BSSID SA DA */ |
1460 | memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); | 1480 | memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); |
1461 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1481 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
@@ -1490,7 +1510,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1490 | /* receiver and we are QoS enabled, use a QoS type frame */ | 1510 | /* receiver and we are QoS enabled, use a QoS type frame */ |
1491 | if (sta_flags & WLAN_STA_WME && | 1511 | if (sta_flags & WLAN_STA_WME && |
1492 | ieee80211_num_regular_queues(&local->hw) >= 4) { | 1512 | ieee80211_num_regular_queues(&local->hw) >= 4) { |
1493 | fc |= IEEE80211_STYPE_QOS_DATA; | 1513 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
1494 | hdrlen += 2; | 1514 | hdrlen += 2; |
1495 | } | 1515 | } |
1496 | 1516 | ||
@@ -1518,7 +1538,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1518 | goto fail; | 1538 | goto fail; |
1519 | } | 1539 | } |
1520 | 1540 | ||
1521 | hdr.frame_control = cpu_to_le16(fc); | 1541 | hdr.frame_control = fc; |
1522 | hdr.duration_id = 0; | 1542 | hdr.duration_id = 0; |
1523 | hdr.seq_ctrl = 0; | 1543 | hdr.seq_ctrl = 0; |
1524 | 1544 | ||
@@ -1587,7 +1607,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1587 | h_pos += meshhdrlen; | 1607 | h_pos += meshhdrlen; |
1588 | } | 1608 | } |
1589 | 1609 | ||
1590 | if (fc & IEEE80211_STYPE_QOS_DATA) { | 1610 | if (ieee80211_is_data_qos(fc)) { |
1591 | __le16 *qos_control; | 1611 | __le16 *qos_control; |
1592 | 1612 | ||
1593 | qos_control = (__le16*) skb_push(skb, 2); | 1613 | qos_control = (__le16*) skb_push(skb, 2); |
@@ -1845,8 +1865,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1845 | mgmt = (struct ieee80211_mgmt *) | 1865 | mgmt = (struct ieee80211_mgmt *) |
1846 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | 1866 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); |
1847 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 1867 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); |
1848 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | 1868 | mgmt->frame_control = |
1849 | IEEE80211_STYPE_BEACON); | 1869 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); |
1850 | memset(mgmt->da, 0xff, ETH_ALEN); | 1870 | memset(mgmt->da, 0xff, ETH_ALEN); |
1851 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 1871 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
1852 | /* BSSID is left zeroed, wildcard value */ | 1872 | /* BSSID is left zeroed, wildcard value */ |
@@ -1914,10 +1934,9 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
1914 | struct ieee80211_rts *rts) | 1934 | struct ieee80211_rts *rts) |
1915 | { | 1935 | { |
1916 | const struct ieee80211_hdr *hdr = frame; | 1936 | const struct ieee80211_hdr *hdr = frame; |
1917 | u16 fctl; | ||
1918 | 1937 | ||
1919 | fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; | 1938 | rts->frame_control = |
1920 | rts->frame_control = cpu_to_le16(fctl); | 1939 | cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); |
1921 | rts->duration = ieee80211_rts_duration(hw, vif, frame_len, | 1940 | rts->duration = ieee80211_rts_duration(hw, vif, frame_len, |
1922 | frame_txctl); | 1941 | frame_txctl); |
1923 | memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); | 1942 | memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); |
@@ -1931,10 +1950,9 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
1931 | struct ieee80211_cts *cts) | 1950 | struct ieee80211_cts *cts) |
1932 | { | 1951 | { |
1933 | const struct ieee80211_hdr *hdr = frame; | 1952 | const struct ieee80211_hdr *hdr = frame; |
1934 | u16 fctl; | ||
1935 | 1953 | ||
1936 | fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; | 1954 | cts->frame_control = |
1937 | cts->frame_control = cpu_to_le16(fctl); | 1955 | cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); |
1938 | cts->duration = ieee80211_ctstoself_duration(hw, vif, | 1956 | cts->duration = ieee80211_ctstoself_duration(hw, vif, |
1939 | frame_len, frame_txctl); | 1957 | frame_len, frame_txctl); |
1940 | memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); | 1958 | memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); |
@@ -1948,9 +1966,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1948 | struct ieee80211_local *local = hw_to_local(hw); | 1966 | struct ieee80211_local *local = hw_to_local(hw); |
1949 | struct sk_buff *skb = NULL; | 1967 | struct sk_buff *skb = NULL; |
1950 | struct sta_info *sta; | 1968 | struct sta_info *sta; |
1951 | ieee80211_tx_handler *handler; | ||
1952 | struct ieee80211_tx_data tx; | 1969 | struct ieee80211_tx_data tx; |
1953 | ieee80211_tx_result res = TX_DROP; | ||
1954 | struct net_device *bdev; | 1970 | struct net_device *bdev; |
1955 | struct ieee80211_sub_if_data *sdata; | 1971 | struct ieee80211_sub_if_data *sdata; |
1956 | struct ieee80211_if_ap *bss = NULL; | 1972 | struct ieee80211_if_ap *bss = NULL; |
@@ -2001,25 +2017,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2001 | tx.channel = local->hw.conf.channel; | 2017 | tx.channel = local->hw.conf.channel; |
2002 | info->band = tx.channel->band; | 2018 | info->band = tx.channel->band; |
2003 | 2019 | ||
2004 | for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { | 2020 | if (invoke_tx_handlers(&tx)) |
2005 | res = (*handler)(&tx); | ||
2006 | if (res == TX_DROP || res == TX_QUEUED) | ||
2007 | break; | ||
2008 | } | ||
2009 | |||
2010 | if (WARN_ON(tx.skb != skb)) | ||
2011 | res = TX_DROP; | ||
2012 | |||
2013 | if (res == TX_DROP) { | ||
2014 | I802_DEBUG_INC(local->tx_handlers_drop); | ||
2015 | dev_kfree_skb(skb); | ||
2016 | skb = NULL; | 2021 | skb = NULL; |
2017 | } else if (res == TX_QUEUED) { | 2022 | out: |
2018 | I802_DEBUG_INC(local->tx_handlers_queued); | ||
2019 | skb = NULL; | ||
2020 | } | ||
2021 | |||
2022 | out: | ||
2023 | rcu_read_unlock(); | 2023 | rcu_read_unlock(); |
2024 | 2024 | ||
2025 | return skb; | 2025 | return skb; |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index e7b6344c900a..35b664d00e23 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -84,20 +84,17 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, | |||
84 | struct sk_buff *skb, | 84 | struct sk_buff *skb, |
85 | struct ieee80211_key *key) | 85 | struct ieee80211_key *key) |
86 | { | 86 | { |
87 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 87 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
88 | u16 fc; | 88 | unsigned int hdrlen; |
89 | int hdrlen; | ||
90 | u8 *newhdr; | 89 | u8 *newhdr; |
91 | 90 | ||
92 | fc = le16_to_cpu(hdr->frame_control); | 91 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
93 | fc |= IEEE80211_FCTL_PROTECTED; | ||
94 | hdr->frame_control = cpu_to_le16(fc); | ||
95 | 92 | ||
96 | if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN || | 93 | if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN || |
97 | skb_headroom(skb) < WEP_IV_LEN)) | 94 | skb_headroom(skb) < WEP_IV_LEN)) |
98 | return NULL; | 95 | return NULL; |
99 | 96 | ||
100 | hdrlen = ieee80211_get_hdrlen(fc); | 97 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
101 | newhdr = skb_push(skb, WEP_IV_LEN); | 98 | newhdr = skb_push(skb, WEP_IV_LEN); |
102 | memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); | 99 | memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); |
103 | ieee80211_wep_get_iv(local, key, newhdr + hdrlen); | 100 | ieee80211_wep_get_iv(local, key, newhdr + hdrlen); |
@@ -109,12 +106,10 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, | |||
109 | struct sk_buff *skb, | 106 | struct sk_buff *skb, |
110 | struct ieee80211_key *key) | 107 | struct ieee80211_key *key) |
111 | { | 108 | { |
112 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 109 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
113 | u16 fc; | 110 | unsigned int hdrlen; |
114 | int hdrlen; | ||
115 | 111 | ||
116 | fc = le16_to_cpu(hdr->frame_control); | 112 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
117 | hdrlen = ieee80211_get_hdrlen(fc); | ||
118 | memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen); | 113 | memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen); |
119 | skb_pull(skb, WEP_IV_LEN); | 114 | skb_pull(skb, WEP_IV_LEN); |
120 | } | 115 | } |
@@ -224,17 +219,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, | |||
224 | u32 klen; | 219 | u32 klen; |
225 | u8 *rc4key; | 220 | u8 *rc4key; |
226 | u8 keyidx; | 221 | u8 keyidx; |
227 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 222 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
228 | u16 fc; | 223 | unsigned int hdrlen; |
229 | int hdrlen; | ||
230 | size_t len; | 224 | size_t len; |
231 | int ret = 0; | 225 | int ret = 0; |
232 | 226 | ||
233 | fc = le16_to_cpu(hdr->frame_control); | 227 | if (!ieee80211_has_protected(hdr->frame_control)) |
234 | if (!(fc & IEEE80211_FCTL_PROTECTED)) | ||
235 | return -1; | 228 | return -1; |
236 | 229 | ||
237 | hdrlen = ieee80211_get_hdrlen(fc); | 230 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
238 | 231 | ||
239 | if (skb->len < 8 + hdrlen) | 232 | if (skb->len < 8 + hdrlen) |
240 | return -1; | 233 | return -1; |
@@ -281,17 +274,15 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, | |||
281 | 274 | ||
282 | u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) | 275 | u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) |
283 | { | 276 | { |
284 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 277 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
285 | u16 fc; | 278 | unsigned int hdrlen; |
286 | int hdrlen; | ||
287 | u8 *ivpos; | 279 | u8 *ivpos; |
288 | u32 iv; | 280 | u32 iv; |
289 | 281 | ||
290 | fc = le16_to_cpu(hdr->frame_control); | 282 | if (!ieee80211_has_protected(hdr->frame_control)) |
291 | if (!(fc & IEEE80211_FCTL_PROTECTED)) | ||
292 | return NULL; | 283 | return NULL; |
293 | 284 | ||
294 | hdrlen = ieee80211_get_hdrlen(fc); | 285 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
295 | ivpos = skb->data + hdrlen; | 286 | ivpos = skb->data + hdrlen; |
296 | iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; | 287 | iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; |
297 | 288 | ||
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 5af3862e7191..df0531c28141 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -135,7 +135,39 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, | |||
135 | struct iw_request_info *info, | 135 | struct iw_request_info *info, |
136 | char *name, char *extra) | 136 | char *name, char *extra) |
137 | { | 137 | { |
138 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
139 | struct ieee80211_supported_band *sband; | ||
140 | u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0; | ||
141 | |||
142 | |||
143 | sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
144 | if (sband) { | ||
145 | is_a = 1; | ||
146 | is_ht |= sband->ht_info.ht_supported; | ||
147 | } | ||
148 | |||
149 | sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
150 | if (sband) { | ||
151 | int i; | ||
152 | /* Check for mandatory rates */ | ||
153 | for (i = 0; i < sband->n_bitrates; i++) { | ||
154 | if (sband->bitrates[i].bitrate == 10) | ||
155 | is_b = 1; | ||
156 | if (sband->bitrates[i].bitrate == 60) | ||
157 | is_g = 1; | ||
158 | } | ||
159 | is_ht |= sband->ht_info.ht_supported; | ||
160 | } | ||
161 | |||
138 | strcpy(name, "IEEE 802.11"); | 162 | strcpy(name, "IEEE 802.11"); |
163 | if (is_a) | ||
164 | strcat(name, "a"); | ||
165 | if (is_b) | ||
166 | strcat(name, "b"); | ||
167 | if (is_g) | ||
168 | strcat(name, "g"); | ||
169 | if (is_ht) | ||
170 | strcat(name, "n"); | ||
139 | 171 | ||
140 | return 0; | 172 | return 0; |
141 | } | 173 | } |
@@ -567,7 +599,7 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev, | |||
567 | if (local->sta_sw_scanning || local->sta_hw_scanning) | 599 | if (local->sta_sw_scanning || local->sta_hw_scanning) |
568 | return -EAGAIN; | 600 | return -EAGAIN; |
569 | 601 | ||
570 | res = ieee80211_sta_scan_results(dev, extra, data->length); | 602 | res = ieee80211_sta_scan_results(dev, info, extra, data->length); |
571 | if (res >= 0) { | 603 | if (res >= 0) { |
572 | data->length = res; | 604 | data->length = res; |
573 | return 0; | 605 | return 0; |
@@ -721,6 +753,9 @@ static int ieee80211_ioctl_siwrts(struct net_device *dev, | |||
721 | 753 | ||
722 | if (rts->disabled) | 754 | if (rts->disabled) |
723 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 755 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
756 | else if (!rts->fixed) | ||
757 | /* if the rts value is not fixed, then take default */ | ||
758 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | ||
724 | else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) | 759 | else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) |
725 | return -EINVAL; | 760 | return -EINVAL; |
726 | else | 761 | else |
@@ -949,6 +984,19 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, | |||
949 | erq->length = sdata->keys[idx]->conf.keylen; | 984 | erq->length = sdata->keys[idx]->conf.keylen; |
950 | erq->flags |= IW_ENCODE_ENABLED; | 985 | erq->flags |= IW_ENCODE_ENABLED; |
951 | 986 | ||
987 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | ||
988 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
989 | switch (ifsta->auth_alg) { | ||
990 | case WLAN_AUTH_OPEN: | ||
991 | case WLAN_AUTH_LEAP: | ||
992 | erq->flags |= IW_ENCODE_OPEN; | ||
993 | break; | ||
994 | case WLAN_AUTH_SHARED_KEY: | ||
995 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
996 | break; | ||
997 | } | ||
998 | } | ||
999 | |||
952 | return 0; | 1000 | return 0; |
953 | } | 1001 | } |
954 | 1002 | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 345e10e9b313..f809761fbfb5 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -49,7 +49,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, | |||
49 | ieee80211_tx_result | 49 | ieee80211_tx_result |
50 | ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | 50 | ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) |
51 | { | 51 | { |
52 | u8 *data, *sa, *da, *key, *mic, qos_tid; | 52 | u8 *data, *sa, *da, *key, *mic, qos_tid, key_offset; |
53 | size_t data_len; | 53 | size_t data_len; |
54 | u16 fc; | 54 | u16 fc; |
55 | struct sk_buff *skb = tx->skb; | 55 | struct sk_buff *skb = tx->skb; |
@@ -88,8 +88,12 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
88 | #else | 88 | #else |
89 | authenticator = 1; | 89 | authenticator = 1; |
90 | #endif | 90 | #endif |
91 | key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY : | 91 | /* At this point we know we're using ALG_TKIP. To get the MIC key |
92 | ALG_TKIP_TEMP_AUTH_RX_MIC_KEY]; | 92 | * we now will rely on the offset from the ieee80211_key_conf::key */ |
93 | key_offset = authenticator ? | ||
94 | NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY : | ||
95 | NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | ||
96 | key = &tx->key->conf.key[key_offset]; | ||
93 | mic = skb_put(skb, MICHAEL_MIC_LEN); | 97 | mic = skb_put(skb, MICHAEL_MIC_LEN); |
94 | michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); | 98 | michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); |
95 | 99 | ||
@@ -100,7 +104,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
100 | ieee80211_rx_result | 104 | ieee80211_rx_result |
101 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | 105 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) |
102 | { | 106 | { |
103 | u8 *data, *sa, *da, *key = NULL, qos_tid; | 107 | u8 *data, *sa, *da, *key = NULL, qos_tid, key_offset; |
104 | size_t data_len; | 108 | size_t data_len; |
105 | u16 fc; | 109 | u16 fc; |
106 | u8 mic[MICHAEL_MIC_LEN]; | 110 | u8 mic[MICHAEL_MIC_LEN]; |
@@ -131,8 +135,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
131 | #else | 135 | #else |
132 | authenticator = 1; | 136 | authenticator = 1; |
133 | #endif | 137 | #endif |
134 | key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY : | 138 | /* At this point we know we're using ALG_TKIP. To get the MIC key |
135 | ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; | 139 | * we now will rely on the offset from the ieee80211_key_conf::key */ |
140 | key_offset = authenticator ? | ||
141 | NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY : | ||
142 | NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | ||
143 | key = &rx->key->conf.key[key_offset]; | ||
136 | michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); | 144 | michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); |
137 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { | 145 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { |
138 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 146 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index e4b051dbed61..8aa822730145 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c | |||
@@ -30,39 +30,62 @@ struct rfkill_task { | |||
30 | spinlock_t lock; /* for accessing last and desired state */ | 30 | spinlock_t lock; /* for accessing last and desired state */ |
31 | unsigned long last; /* last schedule */ | 31 | unsigned long last; /* last schedule */ |
32 | enum rfkill_state desired_state; /* on/off */ | 32 | enum rfkill_state desired_state; /* on/off */ |
33 | enum rfkill_state current_state; /* on/off */ | ||
34 | }; | 33 | }; |
35 | 34 | ||
36 | static void rfkill_task_handler(struct work_struct *work) | 35 | static void rfkill_task_handler(struct work_struct *work) |
37 | { | 36 | { |
38 | struct rfkill_task *task = container_of(work, struct rfkill_task, work); | 37 | struct rfkill_task *task = container_of(work, struct rfkill_task, work); |
39 | enum rfkill_state state; | ||
40 | 38 | ||
41 | mutex_lock(&task->mutex); | 39 | mutex_lock(&task->mutex); |
42 | 40 | ||
43 | /* | 41 | rfkill_switch_all(task->type, task->desired_state); |
44 | * Use temp variable to fetch desired state to keep it | ||
45 | * consistent even if rfkill_schedule_toggle() runs in | ||
46 | * another thread or interrupts us. | ||
47 | */ | ||
48 | state = task->desired_state; | ||
49 | 42 | ||
50 | if (state != task->current_state) { | 43 | mutex_unlock(&task->mutex); |
51 | rfkill_switch_all(task->type, state); | 44 | } |
52 | task->current_state = state; | 45 | |
46 | static void rfkill_task_epo_handler(struct work_struct *work) | ||
47 | { | ||
48 | rfkill_epo(); | ||
49 | } | ||
50 | |||
51 | static DECLARE_WORK(epo_work, rfkill_task_epo_handler); | ||
52 | |||
53 | static void rfkill_schedule_epo(void) | ||
54 | { | ||
55 | schedule_work(&epo_work); | ||
56 | } | ||
57 | |||
58 | static void rfkill_schedule_set(struct rfkill_task *task, | ||
59 | enum rfkill_state desired_state) | ||
60 | { | ||
61 | unsigned long flags; | ||
62 | |||
63 | if (unlikely(work_pending(&epo_work))) | ||
64 | return; | ||
65 | |||
66 | spin_lock_irqsave(&task->lock, flags); | ||
67 | |||
68 | if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { | ||
69 | task->desired_state = desired_state; | ||
70 | task->last = jiffies; | ||
71 | schedule_work(&task->work); | ||
53 | } | 72 | } |
54 | 73 | ||
55 | mutex_unlock(&task->mutex); | 74 | spin_unlock_irqrestore(&task->lock, flags); |
56 | } | 75 | } |
57 | 76 | ||
58 | static void rfkill_schedule_toggle(struct rfkill_task *task) | 77 | static void rfkill_schedule_toggle(struct rfkill_task *task) |
59 | { | 78 | { |
60 | unsigned long flags; | 79 | unsigned long flags; |
61 | 80 | ||
81 | if (unlikely(work_pending(&epo_work))) | ||
82 | return; | ||
83 | |||
62 | spin_lock_irqsave(&task->lock, flags); | 84 | spin_lock_irqsave(&task->lock, flags); |
63 | 85 | ||
64 | if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { | 86 | if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { |
65 | task->desired_state = !task->desired_state; | 87 | task->desired_state = |
88 | rfkill_state_complement(task->desired_state); | ||
66 | task->last = jiffies; | 89 | task->last = jiffies; |
67 | schedule_work(&task->work); | 90 | schedule_work(&task->work); |
68 | } | 91 | } |
@@ -70,26 +93,26 @@ static void rfkill_schedule_toggle(struct rfkill_task *task) | |||
70 | spin_unlock_irqrestore(&task->lock, flags); | 93 | spin_unlock_irqrestore(&task->lock, flags); |
71 | } | 94 | } |
72 | 95 | ||
73 | #define DEFINE_RFKILL_TASK(n, t) \ | 96 | #define DEFINE_RFKILL_TASK(n, t) \ |
74 | struct rfkill_task n = { \ | 97 | struct rfkill_task n = { \ |
75 | .work = __WORK_INITIALIZER(n.work, \ | 98 | .work = __WORK_INITIALIZER(n.work, \ |
76 | rfkill_task_handler), \ | 99 | rfkill_task_handler), \ |
77 | .type = t, \ | 100 | .type = t, \ |
78 | .mutex = __MUTEX_INITIALIZER(n.mutex), \ | 101 | .mutex = __MUTEX_INITIALIZER(n.mutex), \ |
79 | .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ | 102 | .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ |
80 | .desired_state = RFKILL_STATE_ON, \ | 103 | .desired_state = RFKILL_STATE_UNBLOCKED, \ |
81 | .current_state = RFKILL_STATE_ON, \ | ||
82 | } | 104 | } |
83 | 105 | ||
84 | static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); | 106 | static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); |
85 | static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); | 107 | static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); |
86 | static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); | 108 | static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); |
87 | static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); | 109 | static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); |
110 | static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN); | ||
88 | 111 | ||
89 | static void rfkill_event(struct input_handle *handle, unsigned int type, | 112 | static void rfkill_event(struct input_handle *handle, unsigned int type, |
90 | unsigned int code, int down) | 113 | unsigned int code, int data) |
91 | { | 114 | { |
92 | if (type == EV_KEY && down == 1) { | 115 | if (type == EV_KEY && data == 1) { |
93 | switch (code) { | 116 | switch (code) { |
94 | case KEY_WLAN: | 117 | case KEY_WLAN: |
95 | rfkill_schedule_toggle(&rfkill_wlan); | 118 | rfkill_schedule_toggle(&rfkill_wlan); |
@@ -106,6 +129,28 @@ static void rfkill_event(struct input_handle *handle, unsigned int type, | |||
106 | default: | 129 | default: |
107 | break; | 130 | break; |
108 | } | 131 | } |
132 | } else if (type == EV_SW) { | ||
133 | switch (code) { | ||
134 | case SW_RFKILL_ALL: | ||
135 | /* EVERY radio type. data != 0 means radios ON */ | ||
136 | /* handle EPO (emergency power off) through shortcut */ | ||
137 | if (data) { | ||
138 | rfkill_schedule_set(&rfkill_wwan, | ||
139 | RFKILL_STATE_UNBLOCKED); | ||
140 | rfkill_schedule_set(&rfkill_wimax, | ||
141 | RFKILL_STATE_UNBLOCKED); | ||
142 | rfkill_schedule_set(&rfkill_uwb, | ||
143 | RFKILL_STATE_UNBLOCKED); | ||
144 | rfkill_schedule_set(&rfkill_bt, | ||
145 | RFKILL_STATE_UNBLOCKED); | ||
146 | rfkill_schedule_set(&rfkill_wlan, | ||
147 | RFKILL_STATE_UNBLOCKED); | ||
148 | } else | ||
149 | rfkill_schedule_epo(); | ||
150 | break; | ||
151 | default: | ||
152 | break; | ||
153 | } | ||
109 | } | 154 | } |
110 | } | 155 | } |
111 | 156 | ||
@@ -168,6 +213,11 @@ static const struct input_device_id rfkill_ids[] = { | |||
168 | .evbit = { BIT_MASK(EV_KEY) }, | 213 | .evbit = { BIT_MASK(EV_KEY) }, |
169 | .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, | 214 | .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, |
170 | }, | 215 | }, |
216 | { | ||
217 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, | ||
218 | .evbit = { BIT(EV_SW) }, | ||
219 | .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, | ||
220 | }, | ||
171 | { } | 221 | { } |
172 | }; | 222 | }; |
173 | 223 | ||
diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h index 4dae5006fc77..f63d05045685 100644 --- a/net/rfkill/rfkill-input.h +++ b/net/rfkill/rfkill-input.h | |||
@@ -12,5 +12,6 @@ | |||
12 | #define __RFKILL_INPUT_H | 12 | #define __RFKILL_INPUT_H |
13 | 13 | ||
14 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); | 14 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); |
15 | void rfkill_epo(void); | ||
15 | 16 | ||
16 | #endif /* __RFKILL_INPUT_H */ | 17 | #endif /* __RFKILL_INPUT_H */ |
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 4e10a95de832..ce0e23148cdd 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -39,8 +39,56 @@ MODULE_LICENSE("GPL"); | |||
39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | 39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ |
40 | static DEFINE_MUTEX(rfkill_mutex); | 40 | static DEFINE_MUTEX(rfkill_mutex); |
41 | 41 | ||
42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; | ||
43 | module_param_named(default_state, rfkill_default_state, uint, 0444); | ||
44 | MODULE_PARM_DESC(default_state, | ||
45 | "Default initial state for all radio types, 0 = radio off"); | ||
46 | |||
42 | static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; | 47 | static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; |
43 | 48 | ||
49 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * register_rfkill_notifier - Add notifier to rfkill notifier chain | ||
54 | * @nb: pointer to the new entry to add to the chain | ||
55 | * | ||
56 | * See blocking_notifier_chain_register() for return value and further | ||
57 | * observations. | ||
58 | * | ||
59 | * Adds a notifier to the rfkill notifier chain. The chain will be | ||
60 | * called with a pointer to the relevant rfkill structure as a parameter, | ||
61 | * refer to include/linux/rfkill.h for the possible events. | ||
62 | * | ||
63 | * Notifiers added to this chain are to always return NOTIFY_DONE. This | ||
64 | * chain is a blocking notifier chain: notifiers can sleep. | ||
65 | * | ||
66 | * Calls to this chain may have been done through a workqueue. One must | ||
67 | * assume unordered asynchronous behaviour, there is no way to know if | ||
68 | * actions related to the event that generated the notification have been | ||
69 | * carried out already. | ||
70 | */ | ||
71 | int register_rfkill_notifier(struct notifier_block *nb) | ||
72 | { | ||
73 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); | ||
76 | |||
77 | /** | ||
78 | * unregister_rfkill_notifier - remove notifier from rfkill notifier chain | ||
79 | * @nb: pointer to the entry to remove from the chain | ||
80 | * | ||
81 | * See blocking_notifier_chain_unregister() for return value and further | ||
82 | * observations. | ||
83 | * | ||
84 | * Removes a notifier from the rfkill notifier chain. | ||
85 | */ | ||
86 | int unregister_rfkill_notifier(struct notifier_block *nb) | ||
87 | { | ||
88 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); | ||
91 | |||
44 | 92 | ||
45 | static void rfkill_led_trigger(struct rfkill *rfkill, | 93 | static void rfkill_led_trigger(struct rfkill *rfkill, |
46 | enum rfkill_state state) | 94 | enum rfkill_state state) |
@@ -50,24 +98,99 @@ static void rfkill_led_trigger(struct rfkill *rfkill, | |||
50 | 98 | ||
51 | if (!led->name) | 99 | if (!led->name) |
52 | return; | 100 | return; |
53 | if (state == RFKILL_STATE_OFF) | 101 | if (state != RFKILL_STATE_UNBLOCKED) |
54 | led_trigger_event(led, LED_OFF); | 102 | led_trigger_event(led, LED_OFF); |
55 | else | 103 | else |
56 | led_trigger_event(led, LED_FULL); | 104 | led_trigger_event(led, LED_FULL); |
57 | #endif /* CONFIG_RFKILL_LEDS */ | 105 | #endif /* CONFIG_RFKILL_LEDS */ |
58 | } | 106 | } |
59 | 107 | ||
108 | static void notify_rfkill_state_change(struct rfkill *rfkill) | ||
109 | { | ||
110 | blocking_notifier_call_chain(&rfkill_notifier_list, | ||
111 | RFKILL_STATE_CHANGED, | ||
112 | rfkill); | ||
113 | } | ||
114 | |||
115 | static void update_rfkill_state(struct rfkill *rfkill) | ||
116 | { | ||
117 | enum rfkill_state newstate, oldstate; | ||
118 | |||
119 | if (rfkill->get_state) { | ||
120 | mutex_lock(&rfkill->mutex); | ||
121 | if (!rfkill->get_state(rfkill->data, &newstate)) { | ||
122 | oldstate = rfkill->state; | ||
123 | rfkill->state = newstate; | ||
124 | if (oldstate != newstate) | ||
125 | notify_rfkill_state_change(rfkill); | ||
126 | } | ||
127 | mutex_unlock(&rfkill->mutex); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * rfkill_toggle_radio - wrapper for toggle_radio hook | ||
133 | * calls toggle_radio taking into account a lot of "small" | ||
134 | * details. | ||
135 | * @rfkill: the rfkill struct to use | ||
136 | * @force: calls toggle_radio even if cache says it is not needed, | ||
137 | * and also makes sure notifications of the state will be | ||
138 | * sent even if it didn't change | ||
139 | * @state: the new state to call toggle_radio() with | ||
140 | * | ||
141 | * This wrappen protects and enforces the API for toggle_radio | ||
142 | * calls. Note that @force cannot override a (possibly cached) | ||
143 | * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of | ||
144 | * RFKILL_STATE_HARD_BLOCKED implements either get_state() or | ||
145 | * rfkill_force_state(), so the cache either is bypassed or valid. | ||
146 | * | ||
147 | * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED | ||
148 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to | ||
149 | * give the driver a hint that it should double-BLOCK the transmitter. | ||
150 | * | ||
151 | * Caller must have aquired rfkill_mutex. | ||
152 | */ | ||
60 | static int rfkill_toggle_radio(struct rfkill *rfkill, | 153 | static int rfkill_toggle_radio(struct rfkill *rfkill, |
61 | enum rfkill_state state) | 154 | enum rfkill_state state, |
155 | int force) | ||
62 | { | 156 | { |
63 | int retval = 0; | 157 | int retval = 0; |
158 | enum rfkill_state oldstate, newstate; | ||
159 | |||
160 | oldstate = rfkill->state; | ||
64 | 161 | ||
65 | if (state != rfkill->state) { | 162 | if (rfkill->get_state && !force && |
163 | !rfkill->get_state(rfkill->data, &newstate)) | ||
164 | rfkill->state = newstate; | ||
165 | |||
166 | switch (state) { | ||
167 | case RFKILL_STATE_HARD_BLOCKED: | ||
168 | /* typically happens when refreshing hardware state, | ||
169 | * such as on resume */ | ||
170 | state = RFKILL_STATE_SOFT_BLOCKED; | ||
171 | break; | ||
172 | case RFKILL_STATE_UNBLOCKED: | ||
173 | /* force can't override this, only rfkill_force_state() can */ | ||
174 | if (rfkill->state == RFKILL_STATE_HARD_BLOCKED) | ||
175 | return -EPERM; | ||
176 | break; | ||
177 | case RFKILL_STATE_SOFT_BLOCKED: | ||
178 | /* nothing to do, we want to give drivers the hint to double | ||
179 | * BLOCK even a transmitter that is already in state | ||
180 | * RFKILL_STATE_HARD_BLOCKED */ | ||
181 | break; | ||
182 | } | ||
183 | |||
184 | if (force || state != rfkill->state) { | ||
66 | retval = rfkill->toggle_radio(rfkill->data, state); | 185 | retval = rfkill->toggle_radio(rfkill->data, state); |
67 | if (!retval) { | 186 | /* never allow a HARD->SOFT downgrade! */ |
187 | if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED) | ||
68 | rfkill->state = state; | 188 | rfkill->state = state; |
69 | rfkill_led_trigger(rfkill, state); | 189 | } |
70 | } | 190 | |
191 | if (force || rfkill->state != oldstate) { | ||
192 | rfkill_led_trigger(rfkill, rfkill->state); | ||
193 | notify_rfkill_state_change(rfkill); | ||
71 | } | 194 | } |
72 | 195 | ||
73 | return retval; | 196 | return retval; |
@@ -82,7 +205,6 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
82 | * a specific switch is claimed by userspace in which case it is | 205 | * a specific switch is claimed by userspace in which case it is |
83 | * left alone. | 206 | * left alone. |
84 | */ | 207 | */ |
85 | |||
86 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | 208 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) |
87 | { | 209 | { |
88 | struct rfkill *rfkill; | 210 | struct rfkill *rfkill; |
@@ -93,13 +215,66 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |||
93 | 215 | ||
94 | list_for_each_entry(rfkill, &rfkill_list, node) { | 216 | list_for_each_entry(rfkill, &rfkill_list, node) { |
95 | if ((!rfkill->user_claim) && (rfkill->type == type)) | 217 | if ((!rfkill->user_claim) && (rfkill->type == type)) |
96 | rfkill_toggle_radio(rfkill, state); | 218 | rfkill_toggle_radio(rfkill, state, 0); |
97 | } | 219 | } |
98 | 220 | ||
99 | mutex_unlock(&rfkill_mutex); | 221 | mutex_unlock(&rfkill_mutex); |
100 | } | 222 | } |
101 | EXPORT_SYMBOL(rfkill_switch_all); | 223 | EXPORT_SYMBOL(rfkill_switch_all); |
102 | 224 | ||
225 | /** | ||
226 | * rfkill_epo - emergency power off all transmitters | ||
227 | * | ||
228 | * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring | ||
229 | * everything in its path but rfkill_mutex. | ||
230 | */ | ||
231 | void rfkill_epo(void) | ||
232 | { | ||
233 | struct rfkill *rfkill; | ||
234 | |||
235 | mutex_lock(&rfkill_mutex); | ||
236 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
237 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
238 | } | ||
239 | mutex_unlock(&rfkill_mutex); | ||
240 | } | ||
241 | EXPORT_SYMBOL_GPL(rfkill_epo); | ||
242 | |||
243 | /** | ||
244 | * rfkill_force_state - Force the internal rfkill radio state | ||
245 | * @rfkill: pointer to the rfkill class to modify. | ||
246 | * @state: the current radio state the class should be forced to. | ||
247 | * | ||
248 | * This function updates the internal state of the radio cached | ||
249 | * by the rfkill class. It should be used when the driver gets | ||
250 | * a notification by the firmware/hardware of the current *real* | ||
251 | * state of the radio rfkill switch. | ||
252 | * | ||
253 | * It may not be called from an atomic context. | ||
254 | */ | ||
255 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | ||
256 | { | ||
257 | enum rfkill_state oldstate; | ||
258 | |||
259 | if (state != RFKILL_STATE_SOFT_BLOCKED && | ||
260 | state != RFKILL_STATE_UNBLOCKED && | ||
261 | state != RFKILL_STATE_HARD_BLOCKED) | ||
262 | return -EINVAL; | ||
263 | |||
264 | mutex_lock(&rfkill->mutex); | ||
265 | |||
266 | oldstate = rfkill->state; | ||
267 | rfkill->state = state; | ||
268 | |||
269 | if (state != oldstate) | ||
270 | notify_rfkill_state_change(rfkill); | ||
271 | |||
272 | mutex_unlock(&rfkill->mutex); | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | EXPORT_SYMBOL(rfkill_force_state); | ||
277 | |||
103 | static ssize_t rfkill_name_show(struct device *dev, | 278 | static ssize_t rfkill_name_show(struct device *dev, |
104 | struct device_attribute *attr, | 279 | struct device_attribute *attr, |
105 | char *buf) | 280 | char *buf) |
@@ -109,31 +284,31 @@ static ssize_t rfkill_name_show(struct device *dev, | |||
109 | return sprintf(buf, "%s\n", rfkill->name); | 284 | return sprintf(buf, "%s\n", rfkill->name); |
110 | } | 285 | } |
111 | 286 | ||
112 | static ssize_t rfkill_type_show(struct device *dev, | 287 | static const char *rfkill_get_type_str(enum rfkill_type type) |
113 | struct device_attribute *attr, | ||
114 | char *buf) | ||
115 | { | 288 | { |
116 | struct rfkill *rfkill = to_rfkill(dev); | 289 | switch (type) { |
117 | const char *type; | ||
118 | |||
119 | switch (rfkill->type) { | ||
120 | case RFKILL_TYPE_WLAN: | 290 | case RFKILL_TYPE_WLAN: |
121 | type = "wlan"; | 291 | return "wlan"; |
122 | break; | ||
123 | case RFKILL_TYPE_BLUETOOTH: | 292 | case RFKILL_TYPE_BLUETOOTH: |
124 | type = "bluetooth"; | 293 | return "bluetooth"; |
125 | break; | ||
126 | case RFKILL_TYPE_UWB: | 294 | case RFKILL_TYPE_UWB: |
127 | type = "ultrawideband"; | 295 | return "ultrawideband"; |
128 | break; | ||
129 | case RFKILL_TYPE_WIMAX: | 296 | case RFKILL_TYPE_WIMAX: |
130 | type = "wimax"; | 297 | return "wimax"; |
131 | break; | 298 | case RFKILL_TYPE_WWAN: |
299 | return "wwan"; | ||
132 | default: | 300 | default: |
133 | BUG(); | 301 | BUG(); |
134 | } | 302 | } |
303 | } | ||
304 | |||
305 | static ssize_t rfkill_type_show(struct device *dev, | ||
306 | struct device_attribute *attr, | ||
307 | char *buf) | ||
308 | { | ||
309 | struct rfkill *rfkill = to_rfkill(dev); | ||
135 | 310 | ||
136 | return sprintf(buf, "%s\n", type); | 311 | return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); |
137 | } | 312 | } |
138 | 313 | ||
139 | static ssize_t rfkill_state_show(struct device *dev, | 314 | static ssize_t rfkill_state_show(struct device *dev, |
@@ -142,6 +317,7 @@ static ssize_t rfkill_state_show(struct device *dev, | |||
142 | { | 317 | { |
143 | struct rfkill *rfkill = to_rfkill(dev); | 318 | struct rfkill *rfkill = to_rfkill(dev); |
144 | 319 | ||
320 | update_rfkill_state(rfkill); | ||
145 | return sprintf(buf, "%d\n", rfkill->state); | 321 | return sprintf(buf, "%d\n", rfkill->state); |
146 | } | 322 | } |
147 | 323 | ||
@@ -156,10 +332,14 @@ static ssize_t rfkill_state_store(struct device *dev, | |||
156 | if (!capable(CAP_NET_ADMIN)) | 332 | if (!capable(CAP_NET_ADMIN)) |
157 | return -EPERM; | 333 | return -EPERM; |
158 | 334 | ||
335 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ | ||
336 | if (state != RFKILL_STATE_UNBLOCKED && | ||
337 | state != RFKILL_STATE_SOFT_BLOCKED) | ||
338 | return -EINVAL; | ||
339 | |||
159 | if (mutex_lock_interruptible(&rfkill->mutex)) | 340 | if (mutex_lock_interruptible(&rfkill->mutex)) |
160 | return -ERESTARTSYS; | 341 | return -ERESTARTSYS; |
161 | error = rfkill_toggle_radio(rfkill, | 342 | error = rfkill_toggle_radio(rfkill, state, 0); |
162 | state ? RFKILL_STATE_ON : RFKILL_STATE_OFF); | ||
163 | mutex_unlock(&rfkill->mutex); | 343 | mutex_unlock(&rfkill->mutex); |
164 | 344 | ||
165 | return error ? error : count; | 345 | return error ? error : count; |
@@ -200,7 +380,8 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
200 | if (rfkill->user_claim != claim) { | 380 | if (rfkill->user_claim != claim) { |
201 | if (!claim) | 381 | if (!claim) |
202 | rfkill_toggle_radio(rfkill, | 382 | rfkill_toggle_radio(rfkill, |
203 | rfkill_states[rfkill->type]); | 383 | rfkill_states[rfkill->type], |
384 | 0); | ||
204 | rfkill->user_claim = claim; | 385 | rfkill->user_claim = claim; |
205 | } | 386 | } |
206 | 387 | ||
@@ -233,12 +414,12 @@ static int rfkill_suspend(struct device *dev, pm_message_t state) | |||
233 | 414 | ||
234 | if (dev->power.power_state.event != state.event) { | 415 | if (dev->power.power_state.event != state.event) { |
235 | if (state.event & PM_EVENT_SLEEP) { | 416 | if (state.event & PM_EVENT_SLEEP) { |
236 | mutex_lock(&rfkill->mutex); | 417 | /* Stop transmitter, keep state, no notifies */ |
237 | 418 | update_rfkill_state(rfkill); | |
238 | if (rfkill->state == RFKILL_STATE_ON) | ||
239 | rfkill->toggle_radio(rfkill->data, | ||
240 | RFKILL_STATE_OFF); | ||
241 | 419 | ||
420 | mutex_lock(&rfkill->mutex); | ||
421 | rfkill->toggle_radio(rfkill->data, | ||
422 | RFKILL_STATE_SOFT_BLOCKED); | ||
242 | mutex_unlock(&rfkill->mutex); | 423 | mutex_unlock(&rfkill->mutex); |
243 | } | 424 | } |
244 | 425 | ||
@@ -255,8 +436,8 @@ static int rfkill_resume(struct device *dev) | |||
255 | if (dev->power.power_state.event != PM_EVENT_ON) { | 436 | if (dev->power.power_state.event != PM_EVENT_ON) { |
256 | mutex_lock(&rfkill->mutex); | 437 | mutex_lock(&rfkill->mutex); |
257 | 438 | ||
258 | if (rfkill->state == RFKILL_STATE_ON) | 439 | /* restore radio state AND notify everybody */ |
259 | rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON); | 440 | rfkill_toggle_radio(rfkill, rfkill->state, 1); |
260 | 441 | ||
261 | mutex_unlock(&rfkill->mutex); | 442 | mutex_unlock(&rfkill->mutex); |
262 | } | 443 | } |
@@ -269,12 +450,51 @@ static int rfkill_resume(struct device *dev) | |||
269 | #define rfkill_resume NULL | 450 | #define rfkill_resume NULL |
270 | #endif | 451 | #endif |
271 | 452 | ||
453 | static int rfkill_blocking_uevent_notifier(struct notifier_block *nb, | ||
454 | unsigned long eventid, | ||
455 | void *data) | ||
456 | { | ||
457 | struct rfkill *rfkill = (struct rfkill *)data; | ||
458 | |||
459 | switch (eventid) { | ||
460 | case RFKILL_STATE_CHANGED: | ||
461 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); | ||
462 | break; | ||
463 | default: | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | return NOTIFY_DONE; | ||
468 | } | ||
469 | |||
470 | static struct notifier_block rfkill_blocking_uevent_nb = { | ||
471 | .notifier_call = rfkill_blocking_uevent_notifier, | ||
472 | .priority = 0, | ||
473 | }; | ||
474 | |||
475 | static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
476 | { | ||
477 | struct rfkill *rfkill = to_rfkill(dev); | ||
478 | int error; | ||
479 | |||
480 | error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); | ||
481 | if (error) | ||
482 | return error; | ||
483 | error = add_uevent_var(env, "RFKILL_TYPE=%s", | ||
484 | rfkill_get_type_str(rfkill->type)); | ||
485 | if (error) | ||
486 | return error; | ||
487 | error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state); | ||
488 | return error; | ||
489 | } | ||
490 | |||
272 | static struct class rfkill_class = { | 491 | static struct class rfkill_class = { |
273 | .name = "rfkill", | 492 | .name = "rfkill", |
274 | .dev_release = rfkill_release, | 493 | .dev_release = rfkill_release, |
275 | .dev_attrs = rfkill_dev_attrs, | 494 | .dev_attrs = rfkill_dev_attrs, |
276 | .suspend = rfkill_suspend, | 495 | .suspend = rfkill_suspend, |
277 | .resume = rfkill_resume, | 496 | .resume = rfkill_resume, |
497 | .dev_uevent = rfkill_dev_uevent, | ||
278 | }; | 498 | }; |
279 | 499 | ||
280 | static int rfkill_add_switch(struct rfkill *rfkill) | 500 | static int rfkill_add_switch(struct rfkill *rfkill) |
@@ -283,7 +503,7 @@ static int rfkill_add_switch(struct rfkill *rfkill) | |||
283 | 503 | ||
284 | mutex_lock(&rfkill_mutex); | 504 | mutex_lock(&rfkill_mutex); |
285 | 505 | ||
286 | error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]); | 506 | error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0); |
287 | if (!error) | 507 | if (!error) |
288 | list_add_tail(&rfkill->node, &rfkill_list); | 508 | list_add_tail(&rfkill->node, &rfkill_list); |
289 | 509 | ||
@@ -296,7 +516,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill) | |||
296 | { | 516 | { |
297 | mutex_lock(&rfkill_mutex); | 517 | mutex_lock(&rfkill_mutex); |
298 | list_del_init(&rfkill->node); | 518 | list_del_init(&rfkill->node); |
299 | rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF); | 519 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
300 | mutex_unlock(&rfkill_mutex); | 520 | mutex_unlock(&rfkill_mutex); |
301 | } | 521 | } |
302 | 522 | ||
@@ -412,7 +632,7 @@ int rfkill_register(struct rfkill *rfkill) | |||
412 | EXPORT_SYMBOL(rfkill_register); | 632 | EXPORT_SYMBOL(rfkill_register); |
413 | 633 | ||
414 | /** | 634 | /** |
415 | * rfkill_unregister - Uegister a rfkill structure. | 635 | * rfkill_unregister - Unregister a rfkill structure. |
416 | * @rfkill: rfkill structure to be unregistered | 636 | * @rfkill: rfkill structure to be unregistered |
417 | * | 637 | * |
418 | * This function should be called by the network driver during device | 638 | * This function should be called by the network driver during device |
@@ -436,8 +656,13 @@ static int __init rfkill_init(void) | |||
436 | int error; | 656 | int error; |
437 | int i; | 657 | int i; |
438 | 658 | ||
659 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ | ||
660 | if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED && | ||
661 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) | ||
662 | return -EINVAL; | ||
663 | |||
439 | for (i = 0; i < ARRAY_SIZE(rfkill_states); i++) | 664 | for (i = 0; i < ARRAY_SIZE(rfkill_states); i++) |
440 | rfkill_states[i] = RFKILL_STATE_ON; | 665 | rfkill_states[i] = rfkill_default_state; |
441 | 666 | ||
442 | error = class_register(&rfkill_class); | 667 | error = class_register(&rfkill_class); |
443 | if (error) { | 668 | if (error) { |
@@ -445,11 +670,14 @@ static int __init rfkill_init(void) | |||
445 | return error; | 670 | return error; |
446 | } | 671 | } |
447 | 672 | ||
673 | register_rfkill_notifier(&rfkill_blocking_uevent_nb); | ||
674 | |||
448 | return 0; | 675 | return 0; |
449 | } | 676 | } |
450 | 677 | ||
451 | static void __exit rfkill_exit(void) | 678 | static void __exit rfkill_exit(void) |
452 | { | 679 | { |
680 | unregister_rfkill_notifier(&rfkill_blocking_uevent_nb); | ||
453 | class_unregister(&rfkill_class); | 681 | class_unregister(&rfkill_class); |
454 | } | 682 | } |
455 | 683 | ||
diff --git a/net/socket.c b/net/socket.c index 66c4a8cf6db9..81fe82513046 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -90,6 +90,7 @@ | |||
90 | #include <asm/unistd.h> | 90 | #include <asm/unistd.h> |
91 | 91 | ||
92 | #include <net/compat.h> | 92 | #include <net/compat.h> |
93 | #include <net/wext.h> | ||
93 | 94 | ||
94 | #include <net/sock.h> | 95 | #include <net/sock.h> |
95 | #include <linux/netfilter.h> | 96 | #include <linux/netfilter.h> |
@@ -2210,10 +2211,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd, | |||
2210 | { | 2211 | { |
2211 | struct socket *sock = file->private_data; | 2212 | struct socket *sock = file->private_data; |
2212 | int ret = -ENOIOCTLCMD; | 2213 | int ret = -ENOIOCTLCMD; |
2214 | struct sock *sk; | ||
2215 | struct net *net; | ||
2216 | |||
2217 | sk = sock->sk; | ||
2218 | net = sock_net(sk); | ||
2213 | 2219 | ||
2214 | if (sock->ops->compat_ioctl) | 2220 | if (sock->ops->compat_ioctl) |
2215 | ret = sock->ops->compat_ioctl(sock, cmd, arg); | 2221 | ret = sock->ops->compat_ioctl(sock, cmd, arg); |
2216 | 2222 | ||
2223 | if (ret == -ENOIOCTLCMD && | ||
2224 | (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) | ||
2225 | ret = compat_wext_handle_ioctl(net, cmd, arg); | ||
2226 | |||
2217 | return ret; | 2227 | return ret; |
2218 | } | 2228 | } |
2219 | #endif | 2229 | #endif |
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 947188a5b937..273a84359998 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -500,7 +500,7 @@ static int call_commit_handler(struct net_device *dev) | |||
500 | /* | 500 | /* |
501 | * Calculate size of private arguments | 501 | * Calculate size of private arguments |
502 | */ | 502 | */ |
503 | static inline int get_priv_size(__u16 args) | 503 | static int get_priv_size(__u16 args) |
504 | { | 504 | { |
505 | int num = args & IW_PRIV_SIZE_MASK; | 505 | int num = args & IW_PRIV_SIZE_MASK; |
506 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; | 506 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; |
@@ -512,10 +512,9 @@ static inline int get_priv_size(__u16 args) | |||
512 | /* | 512 | /* |
513 | * Re-calculate the size of private arguments | 513 | * Re-calculate the size of private arguments |
514 | */ | 514 | */ |
515 | static inline int adjust_priv_size(__u16 args, | 515 | static int adjust_priv_size(__u16 args, struct iw_point *iwp) |
516 | union iwreq_data * wrqu) | ||
517 | { | 516 | { |
518 | int num = wrqu->data.length; | 517 | int num = iwp->length; |
519 | int max = args & IW_PRIV_SIZE_MASK; | 518 | int max = args & IW_PRIV_SIZE_MASK; |
520 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; | 519 | int type = (args & IW_PRIV_TYPE_MASK) >> 12; |
521 | 520 | ||
@@ -695,19 +694,150 @@ void wext_proc_exit(struct net *net) | |||
695 | */ | 694 | */ |
696 | 695 | ||
697 | /* ---------------------------------------------------------------- */ | 696 | /* ---------------------------------------------------------------- */ |
697 | static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, | ||
698 | const struct iw_ioctl_description *descr, | ||
699 | iw_handler handler, struct net_device *dev, | ||
700 | struct iw_request_info *info) | ||
701 | { | ||
702 | int err, extra_size, user_length = 0, essid_compat = 0; | ||
703 | char *extra; | ||
704 | |||
705 | /* Calculate space needed by arguments. Always allocate | ||
706 | * for max space. | ||
707 | */ | ||
708 | extra_size = descr->max_tokens * descr->token_size; | ||
709 | |||
710 | /* Check need for ESSID compatibility for WE < 21 */ | ||
711 | switch (cmd) { | ||
712 | case SIOCSIWESSID: | ||
713 | case SIOCGIWESSID: | ||
714 | case SIOCSIWNICKN: | ||
715 | case SIOCGIWNICKN: | ||
716 | if (iwp->length == descr->max_tokens + 1) | ||
717 | essid_compat = 1; | ||
718 | else if (IW_IS_SET(cmd) && (iwp->length != 0)) { | ||
719 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
720 | |||
721 | err = copy_from_user(essid, iwp->pointer, | ||
722 | iwp->length * | ||
723 | descr->token_size); | ||
724 | if (err) | ||
725 | return -EFAULT; | ||
726 | |||
727 | if (essid[iwp->length - 1] == '\0') | ||
728 | essid_compat = 1; | ||
729 | } | ||
730 | break; | ||
731 | default: | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | iwp->length -= essid_compat; | ||
736 | |||
737 | /* Check what user space is giving us */ | ||
738 | if (IW_IS_SET(cmd)) { | ||
739 | /* Check NULL pointer */ | ||
740 | if (!iwp->pointer && iwp->length != 0) | ||
741 | return -EFAULT; | ||
742 | /* Check if number of token fits within bounds */ | ||
743 | if (iwp->length > descr->max_tokens) | ||
744 | return -E2BIG; | ||
745 | if (iwp->length < descr->min_tokens) | ||
746 | return -EINVAL; | ||
747 | } else { | ||
748 | /* Check NULL pointer */ | ||
749 | if (!iwp->pointer) | ||
750 | return -EFAULT; | ||
751 | /* Save user space buffer size for checking */ | ||
752 | user_length = iwp->length; | ||
753 | |||
754 | /* Don't check if user_length > max to allow forward | ||
755 | * compatibility. The test user_length < min is | ||
756 | * implied by the test at the end. | ||
757 | */ | ||
758 | |||
759 | /* Support for very large requests */ | ||
760 | if ((descr->flags & IW_DESCR_FLAG_NOMAX) && | ||
761 | (user_length > descr->max_tokens)) { | ||
762 | /* Allow userspace to GET more than max so | ||
763 | * we can support any size GET requests. | ||
764 | * There is still a limit : -ENOMEM. | ||
765 | */ | ||
766 | extra_size = user_length * descr->token_size; | ||
767 | |||
768 | /* Note : user_length is originally a __u16, | ||
769 | * and token_size is controlled by us, | ||
770 | * so extra_size won't get negative and | ||
771 | * won't overflow... | ||
772 | */ | ||
773 | } | ||
774 | } | ||
775 | |||
776 | /* kzalloc() ensures NULL-termination for essid_compat. */ | ||
777 | extra = kzalloc(extra_size, GFP_KERNEL); | ||
778 | if (!extra) | ||
779 | return -ENOMEM; | ||
780 | |||
781 | /* If it is a SET, get all the extra data in here */ | ||
782 | if (IW_IS_SET(cmd) && (iwp->length != 0)) { | ||
783 | if (copy_from_user(extra, iwp->pointer, | ||
784 | iwp->length * | ||
785 | descr->token_size)) { | ||
786 | err = -EFAULT; | ||
787 | goto out; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | err = handler(dev, info, (union iwreq_data *) iwp, extra); | ||
792 | |||
793 | iwp->length += essid_compat; | ||
794 | |||
795 | /* If we have something to return to the user */ | ||
796 | if (!err && IW_IS_GET(cmd)) { | ||
797 | /* Check if there is enough buffer up there */ | ||
798 | if (user_length < iwp->length) { | ||
799 | err = -E2BIG; | ||
800 | goto out; | ||
801 | } | ||
802 | |||
803 | if (copy_to_user(iwp->pointer, extra, | ||
804 | iwp->length * | ||
805 | descr->token_size)) { | ||
806 | err = -EFAULT; | ||
807 | goto out; | ||
808 | } | ||
809 | } | ||
810 | |||
811 | /* Generate an event to notify listeners of the change */ | ||
812 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { | ||
813 | union iwreq_data *data = (union iwreq_data *) iwp; | ||
814 | |||
815 | if (descr->flags & IW_DESCR_FLAG_RESTRICT) | ||
816 | /* If the event is restricted, don't | ||
817 | * export the payload. | ||
818 | */ | ||
819 | wireless_send_event(dev, cmd, data, NULL); | ||
820 | else | ||
821 | wireless_send_event(dev, cmd, data, extra); | ||
822 | } | ||
823 | |||
824 | out: | ||
825 | kfree(extra); | ||
826 | return err; | ||
827 | } | ||
828 | |||
698 | /* | 829 | /* |
699 | * Wrapper to call a standard Wireless Extension handler. | 830 | * Wrapper to call a standard Wireless Extension handler. |
700 | * We do various checks and also take care of moving data between | 831 | * We do various checks and also take care of moving data between |
701 | * user space and kernel space. | 832 | * user space and kernel space. |
702 | */ | 833 | */ |
703 | static int ioctl_standard_call(struct net_device * dev, | 834 | static int ioctl_standard_call(struct net_device * dev, |
704 | struct ifreq * ifr, | 835 | struct iwreq *iwr, |
705 | unsigned int cmd, | 836 | unsigned int cmd, |
837 | struct iw_request_info *info, | ||
706 | iw_handler handler) | 838 | iw_handler handler) |
707 | { | 839 | { |
708 | struct iwreq * iwr = (struct iwreq *) ifr; | ||
709 | const struct iw_ioctl_description * descr; | 840 | const struct iw_ioctl_description * descr; |
710 | struct iw_request_info info; | ||
711 | int ret = -EINVAL; | 841 | int ret = -EINVAL; |
712 | 842 | ||
713 | /* Get the description of the IOCTL */ | 843 | /* Get the description of the IOCTL */ |
@@ -715,145 +845,19 @@ static int ioctl_standard_call(struct net_device * dev, | |||
715 | return -EOPNOTSUPP; | 845 | return -EOPNOTSUPP; |
716 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | 846 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); |
717 | 847 | ||
718 | /* Prepare the call */ | ||
719 | info.cmd = cmd; | ||
720 | info.flags = 0; | ||
721 | |||
722 | /* Check if we have a pointer to user space data or not */ | 848 | /* Check if we have a pointer to user space data or not */ |
723 | if (descr->header_type != IW_HEADER_TYPE_POINT) { | 849 | if (descr->header_type != IW_HEADER_TYPE_POINT) { |
724 | 850 | ||
725 | /* No extra arguments. Trivial to handle */ | 851 | /* No extra arguments. Trivial to handle */ |
726 | ret = handler(dev, &info, &(iwr->u), NULL); | 852 | ret = handler(dev, info, &(iwr->u), NULL); |
727 | 853 | ||
728 | /* Generate an event to notify listeners of the change */ | 854 | /* Generate an event to notify listeners of the change */ |
729 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && | 855 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && |
730 | ((ret == 0) || (ret == -EIWCOMMIT))) | 856 | ((ret == 0) || (ret == -EIWCOMMIT))) |
731 | wireless_send_event(dev, cmd, &(iwr->u), NULL); | 857 | wireless_send_event(dev, cmd, &(iwr->u), NULL); |
732 | } else { | 858 | } else { |
733 | char * extra; | 859 | ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, |
734 | int extra_size; | 860 | handler, dev, info); |
735 | int user_length = 0; | ||
736 | int err; | ||
737 | int essid_compat = 0; | ||
738 | |||
739 | /* Calculate space needed by arguments. Always allocate | ||
740 | * for max space. Easier, and won't last long... */ | ||
741 | extra_size = descr->max_tokens * descr->token_size; | ||
742 | |||
743 | /* Check need for ESSID compatibility for WE < 21 */ | ||
744 | switch (cmd) { | ||
745 | case SIOCSIWESSID: | ||
746 | case SIOCGIWESSID: | ||
747 | case SIOCSIWNICKN: | ||
748 | case SIOCGIWNICKN: | ||
749 | if (iwr->u.data.length == descr->max_tokens + 1) | ||
750 | essid_compat = 1; | ||
751 | else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { | ||
752 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
753 | |||
754 | err = copy_from_user(essid, iwr->u.data.pointer, | ||
755 | iwr->u.data.length * | ||
756 | descr->token_size); | ||
757 | if (err) | ||
758 | return -EFAULT; | ||
759 | |||
760 | if (essid[iwr->u.data.length - 1] == '\0') | ||
761 | essid_compat = 1; | ||
762 | } | ||
763 | break; | ||
764 | default: | ||
765 | break; | ||
766 | } | ||
767 | |||
768 | iwr->u.data.length -= essid_compat; | ||
769 | |||
770 | /* Check what user space is giving us */ | ||
771 | if (IW_IS_SET(cmd)) { | ||
772 | /* Check NULL pointer */ | ||
773 | if ((iwr->u.data.pointer == NULL) && | ||
774 | (iwr->u.data.length != 0)) | ||
775 | return -EFAULT; | ||
776 | /* Check if number of token fits within bounds */ | ||
777 | if (iwr->u.data.length > descr->max_tokens) | ||
778 | return -E2BIG; | ||
779 | if (iwr->u.data.length < descr->min_tokens) | ||
780 | return -EINVAL; | ||
781 | } else { | ||
782 | /* Check NULL pointer */ | ||
783 | if (iwr->u.data.pointer == NULL) | ||
784 | return -EFAULT; | ||
785 | /* Save user space buffer size for checking */ | ||
786 | user_length = iwr->u.data.length; | ||
787 | |||
788 | /* Don't check if user_length > max to allow forward | ||
789 | * compatibility. The test user_length < min is | ||
790 | * implied by the test at the end. */ | ||
791 | |||
792 | /* Support for very large requests */ | ||
793 | if ((descr->flags & IW_DESCR_FLAG_NOMAX) && | ||
794 | (user_length > descr->max_tokens)) { | ||
795 | /* Allow userspace to GET more than max so | ||
796 | * we can support any size GET requests. | ||
797 | * There is still a limit : -ENOMEM. */ | ||
798 | extra_size = user_length * descr->token_size; | ||
799 | /* Note : user_length is originally a __u16, | ||
800 | * and token_size is controlled by us, | ||
801 | * so extra_size won't get negative and | ||
802 | * won't overflow... */ | ||
803 | } | ||
804 | } | ||
805 | |||
806 | /* Create the kernel buffer */ | ||
807 | /* kzalloc ensures NULL-termination for essid_compat */ | ||
808 | extra = kzalloc(extra_size, GFP_KERNEL); | ||
809 | if (extra == NULL) | ||
810 | return -ENOMEM; | ||
811 | |||
812 | /* If it is a SET, get all the extra data in here */ | ||
813 | if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { | ||
814 | err = copy_from_user(extra, iwr->u.data.pointer, | ||
815 | iwr->u.data.length * | ||
816 | descr->token_size); | ||
817 | if (err) { | ||
818 | kfree(extra); | ||
819 | return -EFAULT; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | /* Call the handler */ | ||
824 | ret = handler(dev, &info, &(iwr->u), extra); | ||
825 | |||
826 | iwr->u.data.length += essid_compat; | ||
827 | |||
828 | /* If we have something to return to the user */ | ||
829 | if (!ret && IW_IS_GET(cmd)) { | ||
830 | /* Check if there is enough buffer up there */ | ||
831 | if (user_length < iwr->u.data.length) { | ||
832 | kfree(extra); | ||
833 | return -E2BIG; | ||
834 | } | ||
835 | |||
836 | err = copy_to_user(iwr->u.data.pointer, extra, | ||
837 | iwr->u.data.length * | ||
838 | descr->token_size); | ||
839 | if (err) | ||
840 | ret = -EFAULT; | ||
841 | } | ||
842 | |||
843 | /* Generate an event to notify listeners of the change */ | ||
844 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && | ||
845 | ((ret == 0) || (ret == -EIWCOMMIT))) { | ||
846 | if (descr->flags & IW_DESCR_FLAG_RESTRICT) | ||
847 | /* If the event is restricted, don't | ||
848 | * export the payload */ | ||
849 | wireless_send_event(dev, cmd, &(iwr->u), NULL); | ||
850 | else | ||
851 | wireless_send_event(dev, cmd, &(iwr->u), | ||
852 | extra); | ||
853 | } | ||
854 | |||
855 | /* Cleanup - I told you it wasn't that long ;-) */ | ||
856 | kfree(extra); | ||
857 | } | 861 | } |
858 | 862 | ||
859 | /* Call commit handler if needed and defined */ | 863 | /* Call commit handler if needed and defined */ |
@@ -881,25 +885,22 @@ static int ioctl_standard_call(struct net_device * dev, | |||
881 | * a iw_handler but process it in your ioctl handler (i.e. use the | 885 | * a iw_handler but process it in your ioctl handler (i.e. use the |
882 | * old driver API). | 886 | * old driver API). |
883 | */ | 887 | */ |
884 | static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, | 888 | static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, |
885 | unsigned int cmd, iw_handler handler) | 889 | const struct iw_priv_args **descrp) |
886 | { | 890 | { |
887 | struct iwreq * iwr = (struct iwreq *) ifr; | 891 | const struct iw_priv_args *descr; |
888 | const struct iw_priv_args * descr = NULL; | 892 | int i, extra_size; |
889 | struct iw_request_info info; | ||
890 | int extra_size = 0; | ||
891 | int i; | ||
892 | int ret = -EINVAL; | ||
893 | 893 | ||
894 | /* Get the description of the IOCTL */ | 894 | descr = NULL; |
895 | for (i = 0; i < dev->wireless_handlers->num_private_args; i++) | 895 | for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { |
896 | if (cmd == dev->wireless_handlers->private_args[i].cmd) { | 896 | if (cmd == dev->wireless_handlers->private_args[i].cmd) { |
897 | descr = &(dev->wireless_handlers->private_args[i]); | 897 | descr = &dev->wireless_handlers->private_args[i]; |
898 | break; | 898 | break; |
899 | } | 899 | } |
900 | } | ||
900 | 901 | ||
901 | /* Compute the size of the set/get arguments */ | 902 | extra_size = 0; |
902 | if (descr != NULL) { | 903 | if (descr) { |
903 | if (IW_IS_SET(cmd)) { | 904 | if (IW_IS_SET(cmd)) { |
904 | int offset = 0; /* For sub-ioctls */ | 905 | int offset = 0; /* For sub-ioctls */ |
905 | /* Check for sub-ioctl handler */ | 906 | /* Check for sub-ioctl handler */ |
@@ -924,72 +925,77 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, | |||
924 | extra_size = 0; | 925 | extra_size = 0; |
925 | } | 926 | } |
926 | } | 927 | } |
928 | *descrp = descr; | ||
929 | return extra_size; | ||
930 | } | ||
927 | 931 | ||
928 | /* Prepare the call */ | 932 | static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, |
929 | info.cmd = cmd; | 933 | const struct iw_priv_args *descr, |
930 | info.flags = 0; | 934 | iw_handler handler, struct net_device *dev, |
935 | struct iw_request_info *info, int extra_size) | ||
936 | { | ||
937 | char *extra; | ||
938 | int err; | ||
931 | 939 | ||
932 | /* Check if we have a pointer to user space data or not. */ | 940 | /* Check what user space is giving us */ |
933 | if (extra_size == 0) { | 941 | if (IW_IS_SET(cmd)) { |
934 | /* No extra arguments. Trivial to handle */ | 942 | if (!iwp->pointer && iwp->length != 0) |
935 | ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); | 943 | return -EFAULT; |
936 | } else { | ||
937 | char * extra; | ||
938 | int err; | ||
939 | 944 | ||
940 | /* Check what user space is giving us */ | 945 | if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) |
941 | if (IW_IS_SET(cmd)) { | 946 | return -E2BIG; |
942 | /* Check NULL pointer */ | 947 | } else if (!iwp->pointer) |
943 | if ((iwr->u.data.pointer == NULL) && | 948 | return -EFAULT; |
944 | (iwr->u.data.length != 0)) | ||
945 | return -EFAULT; | ||
946 | 949 | ||
947 | /* Does it fits within bounds ? */ | 950 | extra = kmalloc(extra_size, GFP_KERNEL); |
948 | if (iwr->u.data.length > (descr->set_args & | 951 | if (!extra) |
949 | IW_PRIV_SIZE_MASK)) | 952 | return -ENOMEM; |
950 | return -E2BIG; | ||
951 | } else if (iwr->u.data.pointer == NULL) | ||
952 | return -EFAULT; | ||
953 | 953 | ||
954 | /* Always allocate for max space. Easier, and won't last | 954 | /* If it is a SET, get all the extra data in here */ |
955 | * long... */ | 955 | if (IW_IS_SET(cmd) && (iwp->length != 0)) { |
956 | extra = kmalloc(extra_size, GFP_KERNEL); | 956 | if (copy_from_user(extra, iwp->pointer, extra_size)) { |
957 | if (extra == NULL) | 957 | err = -EFAULT; |
958 | return -ENOMEM; | 958 | goto out; |
959 | |||
960 | /* If it is a SET, get all the extra data in here */ | ||
961 | if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { | ||
962 | err = copy_from_user(extra, iwr->u.data.pointer, | ||
963 | extra_size); | ||
964 | if (err) { | ||
965 | kfree(extra); | ||
966 | return -EFAULT; | ||
967 | } | ||
968 | } | 959 | } |
960 | } | ||
969 | 961 | ||
970 | /* Call the handler */ | 962 | /* Call the handler */ |
971 | ret = handler(dev, &info, &(iwr->u), extra); | 963 | err = handler(dev, info, (union iwreq_data *) iwp, extra); |
972 | 964 | ||
973 | /* If we have something to return to the user */ | 965 | /* If we have something to return to the user */ |
974 | if (!ret && IW_IS_GET(cmd)) { | 966 | if (!err && IW_IS_GET(cmd)) { |
967 | /* Adjust for the actual length if it's variable, | ||
968 | * avoid leaking kernel bits outside. | ||
969 | */ | ||
970 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) | ||
971 | extra_size = adjust_priv_size(descr->get_args, iwp); | ||
975 | 972 | ||
976 | /* Adjust for the actual length if it's variable, | 973 | if (copy_to_user(iwp->pointer, extra, extra_size)) |
977 | * avoid leaking kernel bits outside. */ | 974 | err = -EFAULT; |
978 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { | 975 | } |
979 | extra_size = adjust_priv_size(descr->get_args, | ||
980 | &(iwr->u)); | ||
981 | } | ||
982 | 976 | ||
983 | err = copy_to_user(iwr->u.data.pointer, extra, | 977 | out: |
984 | extra_size); | 978 | kfree(extra); |
985 | if (err) | 979 | return err; |
986 | ret = -EFAULT; | 980 | } |
987 | } | ||
988 | 981 | ||
989 | /* Cleanup - I told you it wasn't that long ;-) */ | 982 | static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, |
990 | kfree(extra); | 983 | unsigned int cmd, struct iw_request_info *info, |
991 | } | 984 | iw_handler handler) |
985 | { | ||
986 | int extra_size = 0, ret = -EINVAL; | ||
987 | const struct iw_priv_args *descr; | ||
992 | 988 | ||
989 | extra_size = get_priv_descr_and_size(dev, cmd, &descr); | ||
990 | |||
991 | /* Check if we have a pointer to user space data or not. */ | ||
992 | if (extra_size == 0) { | ||
993 | /* No extra arguments. Trivial to handle */ | ||
994 | ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); | ||
995 | } else { | ||
996 | ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, | ||
997 | handler, dev, info, extra_size); | ||
998 | } | ||
993 | 999 | ||
994 | /* Call commit handler if needed and defined */ | 1000 | /* Call commit handler if needed and defined */ |
995 | if (ret == -EIWCOMMIT) | 1001 | if (ret == -EIWCOMMIT) |
@@ -999,12 +1005,21 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, | |||
999 | } | 1005 | } |
1000 | 1006 | ||
1001 | /* ---------------------------------------------------------------- */ | 1007 | /* ---------------------------------------------------------------- */ |
1008 | typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, | ||
1009 | unsigned int, struct iw_request_info *, | ||
1010 | iw_handler); | ||
1011 | |||
1002 | /* | 1012 | /* |
1003 | * Main IOCTl dispatcher. | 1013 | * Main IOCTl dispatcher. |
1004 | * Check the type of IOCTL and call the appropriate wrapper... | 1014 | * Check the type of IOCTL and call the appropriate wrapper... |
1005 | */ | 1015 | */ |
1006 | static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) | 1016 | static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, |
1017 | unsigned int cmd, | ||
1018 | struct iw_request_info *info, | ||
1019 | wext_ioctl_func standard, | ||
1020 | wext_ioctl_func private) | ||
1007 | { | 1021 | { |
1022 | struct iwreq *iwr = (struct iwreq *) ifr; | ||
1008 | struct net_device *dev; | 1023 | struct net_device *dev; |
1009 | iw_handler handler; | 1024 | iw_handler handler; |
1010 | 1025 | ||
@@ -1019,12 +1034,12 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i | |||
1019 | * Note that 'cmd' is already filtered in dev_ioctl() with | 1034 | * Note that 'cmd' is already filtered in dev_ioctl() with |
1020 | * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ | 1035 | * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ |
1021 | if (cmd == SIOCGIWSTATS) | 1036 | if (cmd == SIOCGIWSTATS) |
1022 | return ioctl_standard_call(dev, ifr, cmd, | 1037 | return standard(dev, iwr, cmd, info, |
1023 | &iw_handler_get_iwstats); | 1038 | &iw_handler_get_iwstats); |
1024 | 1039 | ||
1025 | if (cmd == SIOCGIWPRIV && dev->wireless_handlers) | 1040 | if (cmd == SIOCGIWPRIV && dev->wireless_handlers) |
1026 | return ioctl_standard_call(dev, ifr, cmd, | 1041 | return standard(dev, iwr, cmd, info, |
1027 | &iw_handler_get_private); | 1042 | &iw_handler_get_private); |
1028 | 1043 | ||
1029 | /* Basic check */ | 1044 | /* Basic check */ |
1030 | if (!netif_device_present(dev)) | 1045 | if (!netif_device_present(dev)) |
@@ -1035,9 +1050,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i | |||
1035 | if (handler) { | 1050 | if (handler) { |
1036 | /* Standard and private are not the same */ | 1051 | /* Standard and private are not the same */ |
1037 | if (cmd < SIOCIWFIRSTPRIV) | 1052 | if (cmd < SIOCIWFIRSTPRIV) |
1038 | return ioctl_standard_call(dev, ifr, cmd, handler); | 1053 | return standard(dev, iwr, cmd, info, handler); |
1039 | else | 1054 | else |
1040 | return ioctl_private_call(dev, ifr, cmd, handler); | 1055 | return private(dev, iwr, cmd, info, handler); |
1041 | } | 1056 | } |
1042 | /* Old driver API : call driver ioctl handler */ | 1057 | /* Old driver API : call driver ioctl handler */ |
1043 | if (dev->do_ioctl) | 1058 | if (dev->do_ioctl) |
@@ -1045,27 +1060,154 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned i | |||
1045 | return -EOPNOTSUPP; | 1060 | return -EOPNOTSUPP; |
1046 | } | 1061 | } |
1047 | 1062 | ||
1048 | /* entry point from dev ioctl */ | 1063 | /* If command is `set a parameter', or `get the encoding parameters', |
1049 | int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, | 1064 | * check if the user has the right to do it. |
1050 | void __user *arg) | 1065 | */ |
1066 | static int wext_permission_check(unsigned int cmd) | ||
1051 | { | 1067 | { |
1052 | int ret; | ||
1053 | |||
1054 | /* If command is `set a parameter', or | ||
1055 | * `get the encoding parameters', check if | ||
1056 | * the user has the right to do it */ | ||
1057 | if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) | 1068 | if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) |
1058 | && !capable(CAP_NET_ADMIN)) | 1069 | && !capable(CAP_NET_ADMIN)) |
1059 | return -EPERM; | 1070 | return -EPERM; |
1060 | 1071 | ||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | /* entry point from dev ioctl */ | ||
1076 | static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, | ||
1077 | unsigned int cmd, struct iw_request_info *info, | ||
1078 | wext_ioctl_func standard, | ||
1079 | wext_ioctl_func private) | ||
1080 | { | ||
1081 | int ret = wext_permission_check(cmd); | ||
1082 | |||
1083 | if (ret) | ||
1084 | return ret; | ||
1085 | |||
1061 | dev_load(net, ifr->ifr_name); | 1086 | dev_load(net, ifr->ifr_name); |
1062 | rtnl_lock(); | 1087 | rtnl_lock(); |
1063 | ret = wireless_process_ioctl(net, ifr, cmd); | 1088 | ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); |
1064 | rtnl_unlock(); | 1089 | rtnl_unlock(); |
1065 | if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq))) | 1090 | |
1091 | return ret; | ||
1092 | } | ||
1093 | |||
1094 | int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, | ||
1095 | void __user *arg) | ||
1096 | { | ||
1097 | struct iw_request_info info = { .cmd = cmd, .flags = 0 }; | ||
1098 | int ret; | ||
1099 | |||
1100 | ret = wext_ioctl_dispatch(net, ifr, cmd, &info, | ||
1101 | ioctl_standard_call, | ||
1102 | ioctl_private_call); | ||
1103 | if (ret >= 0 && | ||
1104 | IW_IS_GET(cmd) && | ||
1105 | copy_to_user(arg, ifr, sizeof(struct iwreq))) | ||
1106 | return -EFAULT; | ||
1107 | |||
1108 | return ret; | ||
1109 | } | ||
1110 | |||
1111 | #ifdef CONFIG_COMPAT | ||
1112 | static int compat_standard_call(struct net_device *dev, | ||
1113 | struct iwreq *iwr, | ||
1114 | unsigned int cmd, | ||
1115 | struct iw_request_info *info, | ||
1116 | iw_handler handler) | ||
1117 | { | ||
1118 | const struct iw_ioctl_description *descr; | ||
1119 | struct compat_iw_point *iwp_compat; | ||
1120 | struct iw_point iwp; | ||
1121 | int err; | ||
1122 | |||
1123 | descr = standard_ioctl + (cmd - SIOCIWFIRST); | ||
1124 | |||
1125 | if (descr->header_type != IW_HEADER_TYPE_POINT) | ||
1126 | return ioctl_standard_call(dev, iwr, cmd, info, handler); | ||
1127 | |||
1128 | iwp_compat = (struct compat_iw_point *) &iwr->u.data; | ||
1129 | iwp.pointer = compat_ptr(iwp_compat->pointer); | ||
1130 | iwp.length = iwp_compat->length; | ||
1131 | iwp.flags = iwp_compat->flags; | ||
1132 | |||
1133 | err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); | ||
1134 | |||
1135 | iwp_compat->pointer = ptr_to_compat(iwp.pointer); | ||
1136 | iwp_compat->length = iwp.length; | ||
1137 | iwp_compat->flags = iwp.flags; | ||
1138 | |||
1139 | return err; | ||
1140 | } | ||
1141 | |||
1142 | static int compat_private_call(struct net_device *dev, struct iwreq *iwr, | ||
1143 | unsigned int cmd, struct iw_request_info *info, | ||
1144 | iw_handler handler) | ||
1145 | { | ||
1146 | const struct iw_priv_args *descr; | ||
1147 | int ret, extra_size; | ||
1148 | |||
1149 | extra_size = get_priv_descr_and_size(dev, cmd, &descr); | ||
1150 | |||
1151 | /* Check if we have a pointer to user space data or not. */ | ||
1152 | if (extra_size == 0) { | ||
1153 | /* No extra arguments. Trivial to handle */ | ||
1154 | ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); | ||
1155 | } else { | ||
1156 | struct compat_iw_point *iwp_compat; | ||
1157 | struct iw_point iwp; | ||
1158 | |||
1159 | iwp_compat = (struct compat_iw_point *) &iwr->u.data; | ||
1160 | iwp.pointer = compat_ptr(iwp_compat->pointer); | ||
1161 | iwp.length = iwp_compat->length; | ||
1162 | iwp.flags = iwp_compat->flags; | ||
1163 | |||
1164 | ret = ioctl_private_iw_point(&iwp, cmd, descr, | ||
1165 | handler, dev, info, extra_size); | ||
1166 | |||
1167 | iwp_compat->pointer = ptr_to_compat(iwp.pointer); | ||
1168 | iwp_compat->length = iwp.length; | ||
1169 | iwp_compat->flags = iwp.flags; | ||
1170 | } | ||
1171 | |||
1172 | /* Call commit handler if needed and defined */ | ||
1173 | if (ret == -EIWCOMMIT) | ||
1174 | ret = call_commit_handler(dev); | ||
1175 | |||
1176 | return ret; | ||
1177 | } | ||
1178 | |||
1179 | int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, | ||
1180 | unsigned long arg) | ||
1181 | { | ||
1182 | void __user *argp = (void __user *)arg; | ||
1183 | struct iw_request_info info; | ||
1184 | struct iwreq iwr; | ||
1185 | char *colon; | ||
1186 | int ret; | ||
1187 | |||
1188 | if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) | ||
1189 | return -EFAULT; | ||
1190 | |||
1191 | iwr.ifr_name[IFNAMSIZ-1] = 0; | ||
1192 | colon = strchr(iwr.ifr_name, ':'); | ||
1193 | if (colon) | ||
1194 | *colon = 0; | ||
1195 | |||
1196 | info.cmd = cmd; | ||
1197 | info.flags = IW_REQUEST_FLAG_COMPAT; | ||
1198 | |||
1199 | ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, | ||
1200 | compat_standard_call, | ||
1201 | compat_private_call); | ||
1202 | |||
1203 | if (ret >= 0 && | ||
1204 | IW_IS_GET(cmd) && | ||
1205 | copy_to_user(argp, &iwr, sizeof(struct iwreq))) | ||
1066 | return -EFAULT; | 1206 | return -EFAULT; |
1207 | |||
1067 | return ret; | 1208 | return ret; |
1068 | } | 1209 | } |
1210 | #endif | ||
1069 | 1211 | ||
1070 | /************************* EVENT PROCESSING *************************/ | 1212 | /************************* EVENT PROCESSING *************************/ |
1071 | /* | 1213 | /* |