Commit 254416aae70ab2e6b57fd79782c8a67196234d02
1 parent
a252e749f1
Exists in
master
and in
7 other branches
wireless: report reasonable bitrate for MCS rates through wext
Previously, cfg80211 had reported "0" for MCS (i.e. 802.11n) bitrates through the wireless extensions interface. However, nl80211 was converting MCS rates into a reasonable bitrate number. This patch moves the nl80211 code to cfg80211 where it is now shared between both the nl80211 interface and the wireless extensions interface. Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 4 changed files with 38 additions and 39 deletions Inline Diff
net/wireless/core.h
1 | /* | 1 | /* |
2 | * Wireless configuration interface internals. | 2 | * Wireless configuration interface internals. |
3 | * | 3 | * |
4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | #ifndef __NET_WIRELESS_CORE_H | 6 | #ifndef __NET_WIRELESS_CORE_H |
7 | #define __NET_WIRELESS_CORE_H | 7 | #define __NET_WIRELESS_CORE_H |
8 | #include <linux/mutex.h> | 8 | #include <linux/mutex.h> |
9 | #include <linux/list.h> | 9 | #include <linux/list.h> |
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/kref.h> | 11 | #include <linux/kref.h> |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | 14 | #include <linux/rfkill.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <net/genetlink.h> | 16 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
18 | #include "reg.h" | 18 | #include "reg.h" |
19 | 19 | ||
20 | struct cfg80211_registered_device { | 20 | struct cfg80211_registered_device { |
21 | const struct cfg80211_ops *ops; | 21 | const struct cfg80211_ops *ops; |
22 | struct list_head list; | 22 | struct list_head list; |
23 | /* we hold this mutex during any call so that | 23 | /* we hold this mutex during any call so that |
24 | * we cannot do multiple calls at once, and also | 24 | * we cannot do multiple calls at once, and also |
25 | * to avoid the deregister call to proceed while | 25 | * to avoid the deregister call to proceed while |
26 | * any call is in progress */ | 26 | * any call is in progress */ |
27 | struct mutex mtx; | 27 | struct mutex mtx; |
28 | 28 | ||
29 | /* rfkill support */ | 29 | /* rfkill support */ |
30 | struct rfkill_ops rfkill_ops; | 30 | struct rfkill_ops rfkill_ops; |
31 | struct rfkill *rfkill; | 31 | struct rfkill *rfkill; |
32 | struct work_struct rfkill_sync; | 32 | struct work_struct rfkill_sync; |
33 | 33 | ||
34 | /* ISO / IEC 3166 alpha2 for which this device is receiving | 34 | /* ISO / IEC 3166 alpha2 for which this device is receiving |
35 | * country IEs on, this can help disregard country IEs from APs | 35 | * country IEs on, this can help disregard country IEs from APs |
36 | * on the same alpha2 quickly. The alpha2 may differ from | 36 | * on the same alpha2 quickly. The alpha2 may differ from |
37 | * cfg80211_regdomain's alpha2 when an intersection has occurred. | 37 | * cfg80211_regdomain's alpha2 when an intersection has occurred. |
38 | * If the AP is reconfigured this can also be used to tell us if | 38 | * If the AP is reconfigured this can also be used to tell us if |
39 | * the country on the country IE changed. */ | 39 | * the country on the country IE changed. */ |
40 | char country_ie_alpha2[2]; | 40 | char country_ie_alpha2[2]; |
41 | 41 | ||
42 | /* If a Country IE has been received this tells us the environment | 42 | /* If a Country IE has been received this tells us the environment |
43 | * which its telling us its in. This defaults to ENVIRON_ANY */ | 43 | * which its telling us its in. This defaults to ENVIRON_ANY */ |
44 | enum environment_cap env; | 44 | enum environment_cap env; |
45 | 45 | ||
46 | /* wiphy index, internal only */ | 46 | /* wiphy index, internal only */ |
47 | int wiphy_idx; | 47 | int wiphy_idx; |
48 | 48 | ||
49 | /* associate netdev list */ | 49 | /* associate netdev list */ |
50 | struct mutex devlist_mtx; | 50 | struct mutex devlist_mtx; |
51 | struct list_head netdev_list; | 51 | struct list_head netdev_list; |
52 | int devlist_generation; | 52 | int devlist_generation; |
53 | int opencount; /* also protected by devlist_mtx */ | 53 | int opencount; /* also protected by devlist_mtx */ |
54 | wait_queue_head_t dev_wait; | 54 | wait_queue_head_t dev_wait; |
55 | 55 | ||
56 | /* BSSes/scanning */ | 56 | /* BSSes/scanning */ |
57 | spinlock_t bss_lock; | 57 | spinlock_t bss_lock; |
58 | struct list_head bss_list; | 58 | struct list_head bss_list; |
59 | struct rb_root bss_tree; | 59 | struct rb_root bss_tree; |
60 | u32 bss_generation; | 60 | u32 bss_generation; |
61 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 61 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
62 | unsigned long suspend_at; | 62 | unsigned long suspend_at; |
63 | struct work_struct scan_done_wk; | 63 | struct work_struct scan_done_wk; |
64 | 64 | ||
65 | #ifdef CONFIG_NL80211_TESTMODE | 65 | #ifdef CONFIG_NL80211_TESTMODE |
66 | struct genl_info *testmode_info; | 66 | struct genl_info *testmode_info; |
67 | #endif | 67 | #endif |
68 | 68 | ||
69 | struct work_struct conn_work; | 69 | struct work_struct conn_work; |
70 | struct work_struct event_work; | 70 | struct work_struct event_work; |
71 | 71 | ||
72 | /* current channel */ | 72 | /* current channel */ |
73 | struct ieee80211_channel *channel; | 73 | struct ieee80211_channel *channel; |
74 | 74 | ||
75 | /* must be last because of the way we do wiphy_priv(), | 75 | /* must be last because of the way we do wiphy_priv(), |
76 | * and it should at least be aligned to NETDEV_ALIGN */ | 76 | * and it should at least be aligned to NETDEV_ALIGN */ |
77 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); | 77 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static inline | 80 | static inline |
81 | struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) | 81 | struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) |
82 | { | 82 | { |
83 | BUG_ON(!wiphy); | 83 | BUG_ON(!wiphy); |
84 | return container_of(wiphy, struct cfg80211_registered_device, wiphy); | 84 | return container_of(wiphy, struct cfg80211_registered_device, wiphy); |
85 | } | 85 | } |
86 | 86 | ||
87 | /* Note 0 is valid, hence phy0 */ | 87 | /* Note 0 is valid, hence phy0 */ |
88 | static inline | 88 | static inline |
89 | bool wiphy_idx_valid(int wiphy_idx) | 89 | bool wiphy_idx_valid(int wiphy_idx) |
90 | { | 90 | { |
91 | return (wiphy_idx >= 0); | 91 | return (wiphy_idx >= 0); |
92 | } | 92 | } |
93 | 93 | ||
94 | 94 | ||
95 | extern struct workqueue_struct *cfg80211_wq; | 95 | extern struct workqueue_struct *cfg80211_wq; |
96 | extern struct mutex cfg80211_mutex; | 96 | extern struct mutex cfg80211_mutex; |
97 | extern struct list_head cfg80211_rdev_list; | 97 | extern struct list_head cfg80211_rdev_list; |
98 | extern int cfg80211_rdev_list_generation; | 98 | extern int cfg80211_rdev_list_generation; |
99 | 99 | ||
100 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 100 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * You can use this to mark a wiphy_idx as not having an associated wiphy. | 103 | * You can use this to mark a wiphy_idx as not having an associated wiphy. |
104 | * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL | 104 | * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL |
105 | */ | 105 | */ |
106 | #define WIPHY_IDX_STALE -1 | 106 | #define WIPHY_IDX_STALE -1 |
107 | 107 | ||
108 | struct cfg80211_internal_bss { | 108 | struct cfg80211_internal_bss { |
109 | struct list_head list; | 109 | struct list_head list; |
110 | struct rb_node rbn; | 110 | struct rb_node rbn; |
111 | unsigned long ts; | 111 | unsigned long ts; |
112 | struct kref ref; | 112 | struct kref ref; |
113 | atomic_t hold; | 113 | atomic_t hold; |
114 | bool ies_allocated; | 114 | bool ies_allocated; |
115 | 115 | ||
116 | /* must be last because of priv member */ | 116 | /* must be last because of priv member */ |
117 | struct cfg80211_bss pub; | 117 | struct cfg80211_bss pub; |
118 | }; | 118 | }; |
119 | 119 | ||
120 | static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) | 120 | static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) |
121 | { | 121 | { |
122 | return container_of(pub, struct cfg80211_internal_bss, pub); | 122 | return container_of(pub, struct cfg80211_internal_bss, pub); |
123 | } | 123 | } |
124 | 124 | ||
125 | static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) | 125 | static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) |
126 | { | 126 | { |
127 | kref_get(&bss->ref); | 127 | kref_get(&bss->ref); |
128 | } | 128 | } |
129 | 129 | ||
130 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) | 130 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) |
131 | { | 131 | { |
132 | atomic_inc(&bss->hold); | 132 | atomic_inc(&bss->hold); |
133 | } | 133 | } |
134 | 134 | ||
135 | static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) | 135 | static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) |
136 | { | 136 | { |
137 | int r = atomic_dec_return(&bss->hold); | 137 | int r = atomic_dec_return(&bss->hold); |
138 | WARN_ON(r < 0); | 138 | WARN_ON(r < 0); |
139 | } | 139 | } |
140 | 140 | ||
141 | 141 | ||
142 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); | 142 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); |
143 | int get_wiphy_idx(struct wiphy *wiphy); | 143 | int get_wiphy_idx(struct wiphy *wiphy); |
144 | 144 | ||
145 | struct cfg80211_registered_device * | 145 | struct cfg80211_registered_device * |
146 | __cfg80211_rdev_from_info(struct genl_info *info); | 146 | __cfg80211_rdev_from_info(struct genl_info *info); |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * This function returns a pointer to the driver | 149 | * This function returns a pointer to the driver |
150 | * that the genl_info item that is passed refers to. | 150 | * that the genl_info item that is passed refers to. |
151 | * If successful, it returns non-NULL and also locks | 151 | * If successful, it returns non-NULL and also locks |
152 | * the driver's mutex! | 152 | * the driver's mutex! |
153 | * | 153 | * |
154 | * This means that you need to call cfg80211_unlock_rdev() | 154 | * This means that you need to call cfg80211_unlock_rdev() |
155 | * before being allowed to acquire &cfg80211_mutex! | 155 | * before being allowed to acquire &cfg80211_mutex! |
156 | * | 156 | * |
157 | * This is necessary because we need to lock the global | 157 | * This is necessary because we need to lock the global |
158 | * mutex to get an item off the list safely, and then | 158 | * mutex to get an item off the list safely, and then |
159 | * we lock the rdev mutex so it doesn't go away under us. | 159 | * we lock the rdev mutex so it doesn't go away under us. |
160 | * | 160 | * |
161 | * We don't want to keep cfg80211_mutex locked | 161 | * We don't want to keep cfg80211_mutex locked |
162 | * for all the time in order to allow requests on | 162 | * for all the time in order to allow requests on |
163 | * other interfaces to go through at the same time. | 163 | * other interfaces to go through at the same time. |
164 | * | 164 | * |
165 | * The result of this can be a PTR_ERR and hence must | 165 | * The result of this can be a PTR_ERR and hence must |
166 | * be checked with IS_ERR() for errors. | 166 | * be checked with IS_ERR() for errors. |
167 | */ | 167 | */ |
168 | extern struct cfg80211_registered_device * | 168 | extern struct cfg80211_registered_device * |
169 | cfg80211_get_dev_from_info(struct genl_info *info); | 169 | cfg80211_get_dev_from_info(struct genl_info *info); |
170 | 170 | ||
171 | /* requires cfg80211_rdev_mutex to be held! */ | 171 | /* requires cfg80211_rdev_mutex to be held! */ |
172 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | 172 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); |
173 | 173 | ||
174 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ | 174 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ |
175 | extern struct cfg80211_registered_device * | 175 | extern struct cfg80211_registered_device * |
176 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); | 176 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); |
177 | 177 | ||
178 | int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | 178 | int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, |
179 | struct net *net); | 179 | struct net *net); |
180 | 180 | ||
181 | static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) | 181 | static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) |
182 | { | 182 | { |
183 | mutex_lock(&rdev->mtx); | 183 | mutex_lock(&rdev->mtx); |
184 | } | 184 | } |
185 | 185 | ||
186 | static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev) | 186 | static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev) |
187 | { | 187 | { |
188 | BUG_ON(IS_ERR(rdev) || !rdev); | 188 | BUG_ON(IS_ERR(rdev) || !rdev); |
189 | mutex_unlock(&rdev->mtx); | 189 | mutex_unlock(&rdev->mtx); |
190 | } | 190 | } |
191 | 191 | ||
192 | static inline void wdev_lock(struct wireless_dev *wdev) | 192 | static inline void wdev_lock(struct wireless_dev *wdev) |
193 | __acquires(wdev) | 193 | __acquires(wdev) |
194 | { | 194 | { |
195 | mutex_lock(&wdev->mtx); | 195 | mutex_lock(&wdev->mtx); |
196 | __acquire(wdev->mtx); | 196 | __acquire(wdev->mtx); |
197 | } | 197 | } |
198 | 198 | ||
199 | static inline void wdev_unlock(struct wireless_dev *wdev) | 199 | static inline void wdev_unlock(struct wireless_dev *wdev) |
200 | __releases(wdev) | 200 | __releases(wdev) |
201 | { | 201 | { |
202 | __release(wdev->mtx); | 202 | __release(wdev->mtx); |
203 | mutex_unlock(&wdev->mtx); | 203 | mutex_unlock(&wdev->mtx); |
204 | } | 204 | } |
205 | 205 | ||
206 | #define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); | 206 | #define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); |
207 | #define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); | 207 | #define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); |
208 | 208 | ||
209 | enum cfg80211_event_type { | 209 | enum cfg80211_event_type { |
210 | EVENT_CONNECT_RESULT, | 210 | EVENT_CONNECT_RESULT, |
211 | EVENT_ROAMED, | 211 | EVENT_ROAMED, |
212 | EVENT_DISCONNECTED, | 212 | EVENT_DISCONNECTED, |
213 | EVENT_IBSS_JOINED, | 213 | EVENT_IBSS_JOINED, |
214 | }; | 214 | }; |
215 | 215 | ||
216 | struct cfg80211_event { | 216 | struct cfg80211_event { |
217 | struct list_head list; | 217 | struct list_head list; |
218 | enum cfg80211_event_type type; | 218 | enum cfg80211_event_type type; |
219 | 219 | ||
220 | union { | 220 | union { |
221 | struct { | 221 | struct { |
222 | u8 bssid[ETH_ALEN]; | 222 | u8 bssid[ETH_ALEN]; |
223 | const u8 *req_ie; | 223 | const u8 *req_ie; |
224 | const u8 *resp_ie; | 224 | const u8 *resp_ie; |
225 | size_t req_ie_len; | 225 | size_t req_ie_len; |
226 | size_t resp_ie_len; | 226 | size_t resp_ie_len; |
227 | u16 status; | 227 | u16 status; |
228 | } cr; | 228 | } cr; |
229 | struct { | 229 | struct { |
230 | u8 bssid[ETH_ALEN]; | 230 | u8 bssid[ETH_ALEN]; |
231 | const u8 *req_ie; | 231 | const u8 *req_ie; |
232 | const u8 *resp_ie; | 232 | const u8 *resp_ie; |
233 | size_t req_ie_len; | 233 | size_t req_ie_len; |
234 | size_t resp_ie_len; | 234 | size_t resp_ie_len; |
235 | } rm; | 235 | } rm; |
236 | struct { | 236 | struct { |
237 | const u8 *ie; | 237 | const u8 *ie; |
238 | size_t ie_len; | 238 | size_t ie_len; |
239 | u16 reason; | 239 | u16 reason; |
240 | } dc; | 240 | } dc; |
241 | struct { | 241 | struct { |
242 | u8 bssid[ETH_ALEN]; | 242 | u8 bssid[ETH_ALEN]; |
243 | } ij; | 243 | } ij; |
244 | }; | 244 | }; |
245 | }; | 245 | }; |
246 | 246 | ||
247 | struct cfg80211_cached_keys { | 247 | struct cfg80211_cached_keys { |
248 | struct key_params params[6]; | 248 | struct key_params params[6]; |
249 | u8 data[6][WLAN_MAX_KEY_LEN]; | 249 | u8 data[6][WLAN_MAX_KEY_LEN]; |
250 | int def, defmgmt; | 250 | int def, defmgmt; |
251 | }; | 251 | }; |
252 | 252 | ||
253 | 253 | ||
254 | /* free object */ | 254 | /* free object */ |
255 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 255 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
256 | 256 | ||
257 | extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 257 | extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, |
258 | char *newname); | 258 | char *newname); |
259 | 259 | ||
260 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy); | 260 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy); |
261 | void wiphy_update_regulatory(struct wiphy *wiphy, | 261 | void wiphy_update_regulatory(struct wiphy *wiphy, |
262 | enum nl80211_reg_initiator setby); | 262 | enum nl80211_reg_initiator setby); |
263 | 263 | ||
264 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); | 264 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); |
265 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | 265 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, |
266 | unsigned long age_secs); | 266 | unsigned long age_secs); |
267 | 267 | ||
268 | /* IBSS */ | 268 | /* IBSS */ |
269 | int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 269 | int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, |
270 | struct net_device *dev, | 270 | struct net_device *dev, |
271 | struct cfg80211_ibss_params *params, | 271 | struct cfg80211_ibss_params *params, |
272 | struct cfg80211_cached_keys *connkeys); | 272 | struct cfg80211_cached_keys *connkeys); |
273 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 273 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, |
274 | struct net_device *dev, | 274 | struct net_device *dev, |
275 | struct cfg80211_ibss_params *params, | 275 | struct cfg80211_ibss_params *params, |
276 | struct cfg80211_cached_keys *connkeys); | 276 | struct cfg80211_cached_keys *connkeys); |
277 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | 277 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext); |
278 | int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 278 | int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
279 | struct net_device *dev, bool nowext); | 279 | struct net_device *dev, bool nowext); |
280 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 280 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
281 | struct net_device *dev, bool nowext); | 281 | struct net_device *dev, bool nowext); |
282 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | 282 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); |
283 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 283 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
284 | struct wireless_dev *wdev); | 284 | struct wireless_dev *wdev); |
285 | 285 | ||
286 | /* MLME */ | 286 | /* MLME */ |
287 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 287 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
288 | struct net_device *dev, | 288 | struct net_device *dev, |
289 | struct ieee80211_channel *chan, | 289 | struct ieee80211_channel *chan, |
290 | enum nl80211_auth_type auth_type, | 290 | enum nl80211_auth_type auth_type, |
291 | const u8 *bssid, | 291 | const u8 *bssid, |
292 | const u8 *ssid, int ssid_len, | 292 | const u8 *ssid, int ssid_len, |
293 | const u8 *ie, int ie_len, | 293 | const u8 *ie, int ie_len, |
294 | const u8 *key, int key_len, int key_idx); | 294 | const u8 *key, int key_len, int key_idx); |
295 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 295 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
296 | struct net_device *dev, struct ieee80211_channel *chan, | 296 | struct net_device *dev, struct ieee80211_channel *chan, |
297 | enum nl80211_auth_type auth_type, const u8 *bssid, | 297 | enum nl80211_auth_type auth_type, const u8 *bssid, |
298 | const u8 *ssid, int ssid_len, | 298 | const u8 *ssid, int ssid_len, |
299 | const u8 *ie, int ie_len, | 299 | const u8 *ie, int ie_len, |
300 | const u8 *key, int key_len, int key_idx); | 300 | const u8 *key, int key_len, int key_idx); |
301 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 301 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
302 | struct net_device *dev, | 302 | struct net_device *dev, |
303 | struct ieee80211_channel *chan, | 303 | struct ieee80211_channel *chan, |
304 | const u8 *bssid, const u8 *prev_bssid, | 304 | const u8 *bssid, const u8 *prev_bssid, |
305 | const u8 *ssid, int ssid_len, | 305 | const u8 *ssid, int ssid_len, |
306 | const u8 *ie, int ie_len, bool use_mfp, | 306 | const u8 *ie, int ie_len, bool use_mfp, |
307 | struct cfg80211_crypto_settings *crypt); | 307 | struct cfg80211_crypto_settings *crypt); |
308 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 308 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
309 | struct net_device *dev, struct ieee80211_channel *chan, | 309 | struct net_device *dev, struct ieee80211_channel *chan, |
310 | const u8 *bssid, const u8 *prev_bssid, | 310 | const u8 *bssid, const u8 *prev_bssid, |
311 | const u8 *ssid, int ssid_len, | 311 | const u8 *ssid, int ssid_len, |
312 | const u8 *ie, int ie_len, bool use_mfp, | 312 | const u8 *ie, int ie_len, bool use_mfp, |
313 | struct cfg80211_crypto_settings *crypt); | 313 | struct cfg80211_crypto_settings *crypt); |
314 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 314 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
315 | struct net_device *dev, const u8 *bssid, | 315 | struct net_device *dev, const u8 *bssid, |
316 | const u8 *ie, int ie_len, u16 reason); | 316 | const u8 *ie, int ie_len, u16 reason); |
317 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 317 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
318 | struct net_device *dev, const u8 *bssid, | 318 | struct net_device *dev, const u8 *bssid, |
319 | const u8 *ie, int ie_len, u16 reason); | 319 | const u8 *ie, int ie_len, u16 reason); |
320 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | 320 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, |
321 | struct net_device *dev, const u8 *bssid, | 321 | struct net_device *dev, const u8 *bssid, |
322 | const u8 *ie, int ie_len, u16 reason); | 322 | const u8 *ie, int ie_len, u16 reason); |
323 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 323 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
324 | struct net_device *dev); | 324 | struct net_device *dev); |
325 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 325 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
326 | const u8 *req_ie, size_t req_ie_len, | 326 | const u8 *req_ie, size_t req_ie_len, |
327 | const u8 *resp_ie, size_t resp_ie_len, | 327 | const u8 *resp_ie, size_t resp_ie_len, |
328 | u16 status, bool wextev, | 328 | u16 status, bool wextev, |
329 | struct cfg80211_bss *bss); | 329 | struct cfg80211_bss *bss); |
330 | 330 | ||
331 | /* SME */ | 331 | /* SME */ |
332 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 332 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
333 | struct net_device *dev, | 333 | struct net_device *dev, |
334 | struct cfg80211_connect_params *connect, | 334 | struct cfg80211_connect_params *connect, |
335 | struct cfg80211_cached_keys *connkeys, | 335 | struct cfg80211_cached_keys *connkeys, |
336 | const u8 *prev_bssid); | 336 | const u8 *prev_bssid); |
337 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 337 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
338 | struct net_device *dev, | 338 | struct net_device *dev, |
339 | struct cfg80211_connect_params *connect, | 339 | struct cfg80211_connect_params *connect, |
340 | struct cfg80211_cached_keys *connkeys); | 340 | struct cfg80211_cached_keys *connkeys); |
341 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 341 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
342 | struct net_device *dev, u16 reason, | 342 | struct net_device *dev, u16 reason, |
343 | bool wextev); | 343 | bool wextev); |
344 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 344 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
345 | struct net_device *dev, u16 reason, | 345 | struct net_device *dev, u16 reason, |
346 | bool wextev); | 346 | bool wextev); |
347 | void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | 347 | void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, |
348 | const u8 *req_ie, size_t req_ie_len, | 348 | const u8 *req_ie, size_t req_ie_len, |
349 | const u8 *resp_ie, size_t resp_ie_len); | 349 | const u8 *resp_ie, size_t resp_ie_len); |
350 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | 350 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, |
351 | struct wireless_dev *wdev); | 351 | struct wireless_dev *wdev); |
352 | 352 | ||
353 | void cfg80211_conn_work(struct work_struct *work); | 353 | void cfg80211_conn_work(struct work_struct *work); |
354 | void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); | 354 | void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); |
355 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | 355 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); |
356 | 356 | ||
357 | /* internal helpers */ | 357 | /* internal helpers */ |
358 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 358 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
359 | struct key_params *params, int key_idx, | 359 | struct key_params *params, int key_idx, |
360 | const u8 *mac_addr); | 360 | const u8 *mac_addr); |
361 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | 361 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
362 | size_t ie_len, u16 reason, bool from_ap); | 362 | size_t ie_len, u16 reason, bool from_ap); |
363 | void cfg80211_sme_scan_done(struct net_device *dev); | 363 | void cfg80211_sme_scan_done(struct net_device *dev); |
364 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 364 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
365 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 365 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
366 | void __cfg80211_scan_done(struct work_struct *wk); | 366 | void __cfg80211_scan_done(struct work_struct *wk); |
367 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); | 367 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); |
368 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 368 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
369 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | 369 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, |
370 | struct net_device *dev, enum nl80211_iftype ntype, | 370 | struct net_device *dev, enum nl80211_iftype ntype, |
371 | u32 *flags, struct vif_params *params); | 371 | u32 *flags, struct vif_params *params); |
372 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 372 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
373 | 373 | ||
374 | struct ieee80211_channel * | 374 | struct ieee80211_channel * |
375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | 375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, |
376 | struct wireless_dev *for_wdev); | 376 | struct wireless_dev *for_wdev); |
377 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | 377 | int rdev_set_freq(struct cfg80211_registered_device *rdev, |
378 | struct wireless_dev *for_wdev, | 378 | struct wireless_dev *for_wdev, |
379 | int freq, enum nl80211_channel_type channel_type); | 379 | int freq, enum nl80211_channel_type channel_type); |
380 | 380 | ||
381 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); | ||
382 | |||
381 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 383 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
382 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 384 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
383 | #else | 385 | #else |
384 | /* | 386 | /* |
385 | * Trick to enable using it as a condition, | 387 | * Trick to enable using it as a condition, |
386 | * and also not give a warning when it's | 388 | * and also not give a warning when it's |
387 | * not used that way. | 389 | * not used that way. |
388 | */ | 390 | */ |
389 | #define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; }) | 391 | #define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; }) |
390 | #endif | 392 | #endif |
391 | 393 | ||
392 | #endif /* __NET_WIRELESS_CORE_H */ | 394 | #endif /* __NET_WIRELESS_CORE_H */ |
393 | 395 |
net/wireless/nl80211.c
1 | /* | 1 | /* |
2 | * This is the new netlink-based wireless configuration interface. | 2 | * This is the new netlink-based wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
11 | #include <linux/if_ether.h> | 11 | #include <linux/if_ether.h> |
12 | #include <linux/ieee80211.h> | 12 | #include <linux/ieee80211.h> |
13 | #include <linux/nl80211.h> | 13 | #include <linux/nl80211.h> |
14 | #include <linux/rtnetlink.h> | 14 | #include <linux/rtnetlink.h> |
15 | #include <linux/netlink.h> | 15 | #include <linux/netlink.h> |
16 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
17 | #include <net/net_namespace.h> | 17 | #include <net/net_namespace.h> |
18 | #include <net/genetlink.h> | 18 | #include <net/genetlink.h> |
19 | #include <net/cfg80211.h> | 19 | #include <net/cfg80211.h> |
20 | #include <net/sock.h> | 20 | #include <net/sock.h> |
21 | #include "core.h" | 21 | #include "core.h" |
22 | #include "nl80211.h" | 22 | #include "nl80211.h" |
23 | #include "reg.h" | 23 | #include "reg.h" |
24 | 24 | ||
25 | /* the netlink family */ | 25 | /* the netlink family */ |
26 | static struct genl_family nl80211_fam = { | 26 | static struct genl_family nl80211_fam = { |
27 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ | 27 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ |
28 | .name = "nl80211", /* have users key off the name instead */ | 28 | .name = "nl80211", /* have users key off the name instead */ |
29 | .hdrsize = 0, /* no private header */ | 29 | .hdrsize = 0, /* no private header */ |
30 | .version = 1, /* no particular meaning now */ | 30 | .version = 1, /* no particular meaning now */ |
31 | .maxattr = NL80211_ATTR_MAX, | 31 | .maxattr = NL80211_ATTR_MAX, |
32 | .netnsok = true, | 32 | .netnsok = true, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* internal helper: get rdev and dev */ | 35 | /* internal helper: get rdev and dev */ |
36 | static int get_rdev_dev_by_info_ifindex(struct genl_info *info, | 36 | static int get_rdev_dev_by_info_ifindex(struct genl_info *info, |
37 | struct cfg80211_registered_device **rdev, | 37 | struct cfg80211_registered_device **rdev, |
38 | struct net_device **dev) | 38 | struct net_device **dev) |
39 | { | 39 | { |
40 | struct nlattr **attrs = info->attrs; | 40 | struct nlattr **attrs = info->attrs; |
41 | int ifindex; | 41 | int ifindex; |
42 | 42 | ||
43 | if (!attrs[NL80211_ATTR_IFINDEX]) | 43 | if (!attrs[NL80211_ATTR_IFINDEX]) |
44 | return -EINVAL; | 44 | return -EINVAL; |
45 | 45 | ||
46 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 46 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
47 | *dev = dev_get_by_index(genl_info_net(info), ifindex); | 47 | *dev = dev_get_by_index(genl_info_net(info), ifindex); |
48 | if (!*dev) | 48 | if (!*dev) |
49 | return -ENODEV; | 49 | return -ENODEV; |
50 | 50 | ||
51 | *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); | 51 | *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); |
52 | if (IS_ERR(*rdev)) { | 52 | if (IS_ERR(*rdev)) { |
53 | dev_put(*dev); | 53 | dev_put(*dev); |
54 | return PTR_ERR(*rdev); | 54 | return PTR_ERR(*rdev); |
55 | } | 55 | } |
56 | 56 | ||
57 | return 0; | 57 | return 0; |
58 | } | 58 | } |
59 | 59 | ||
60 | /* policy for the attributes */ | 60 | /* policy for the attributes */ |
61 | static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | 61 | static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { |
62 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 62 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
63 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 63 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
64 | .len = 20-1 }, | 64 | .len = 20-1 }, |
65 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | 65 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
66 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | 66 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, |
67 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, | 67 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, |
68 | [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, | 68 | [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, |
69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, | 69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, |
70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, | 70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, |
71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, | 71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, |
72 | 72 | ||
73 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 73 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
74 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 74 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
75 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 75 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
76 | 76 | ||
77 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 77 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, |
78 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 78 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, |
79 | 79 | ||
80 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | 80 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, |
81 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 81 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |
82 | .len = WLAN_MAX_KEY_LEN }, | 82 | .len = WLAN_MAX_KEY_LEN }, |
83 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 83 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
84 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 84 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
85 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 85 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
86 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 86 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
87 | 87 | ||
88 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 88 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
89 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 89 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
90 | [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, | 90 | [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, |
91 | .len = IEEE80211_MAX_DATA_LEN }, | 91 | .len = IEEE80211_MAX_DATA_LEN }, |
92 | [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, | 92 | [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, |
93 | .len = IEEE80211_MAX_DATA_LEN }, | 93 | .len = IEEE80211_MAX_DATA_LEN }, |
94 | [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, | 94 | [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, |
95 | [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, | 95 | [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, |
96 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, | 96 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, |
97 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, | 97 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, |
98 | .len = NL80211_MAX_SUPP_RATES }, | 98 | .len = NL80211_MAX_SUPP_RATES }, |
99 | [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, | 99 | [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, |
100 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 100 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
101 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, | 101 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, |
102 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | 102 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, |
103 | .len = IEEE80211_MAX_MESH_ID_LEN }, | 103 | .len = IEEE80211_MAX_MESH_ID_LEN }, |
104 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | 104 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, |
105 | 105 | ||
106 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, | 106 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, |
107 | [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, | 107 | [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, |
108 | 108 | ||
109 | [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, | 109 | [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, |
110 | [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, | 110 | [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, |
111 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, | 111 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, |
112 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, | 112 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, |
113 | .len = NL80211_MAX_SUPP_RATES }, | 113 | .len = NL80211_MAX_SUPP_RATES }, |
114 | 114 | ||
115 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, | 115 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, |
116 | 116 | ||
117 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 117 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
118 | .len = NL80211_HT_CAPABILITY_LEN }, | 118 | .len = NL80211_HT_CAPABILITY_LEN }, |
119 | 119 | ||
120 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | 120 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, |
121 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | 121 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, |
122 | .len = IEEE80211_MAX_DATA_LEN }, | 122 | .len = IEEE80211_MAX_DATA_LEN }, |
123 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, | 123 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, |
124 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, | 124 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, |
125 | 125 | ||
126 | [NL80211_ATTR_SSID] = { .type = NLA_BINARY, | 126 | [NL80211_ATTR_SSID] = { .type = NLA_BINARY, |
127 | .len = IEEE80211_MAX_SSID_LEN }, | 127 | .len = IEEE80211_MAX_SSID_LEN }, |
128 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, | 128 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, |
129 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, | 129 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, |
130 | [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, | 130 | [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, |
131 | [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, | 131 | [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, |
132 | [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, | 132 | [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, |
133 | [NL80211_ATTR_STA_FLAGS2] = { | 133 | [NL80211_ATTR_STA_FLAGS2] = { |
134 | .len = sizeof(struct nl80211_sta_flag_update), | 134 | .len = sizeof(struct nl80211_sta_flag_update), |
135 | }, | 135 | }, |
136 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, | 136 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, |
137 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, | 137 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, |
138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, | 140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, |
141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, | 141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, |
142 | [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, | 142 | [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, |
143 | .len = WLAN_PMKID_LEN }, | 143 | .len = WLAN_PMKID_LEN }, |
144 | }; | 144 | }; |
145 | 145 | ||
146 | /* policy for the attributes */ | 146 | /* policy for the attributes */ |
147 | static struct nla_policy | 147 | static struct nla_policy |
148 | nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { | 148 | nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { |
149 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, | 149 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, |
150 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | 150 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, |
151 | [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, | 151 | [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, |
152 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 152 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
153 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 153 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
154 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 154 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
155 | }; | 155 | }; |
156 | 156 | ||
157 | /* ifidx get helper */ | 157 | /* ifidx get helper */ |
158 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 158 | static int nl80211_get_ifidx(struct netlink_callback *cb) |
159 | { | 159 | { |
160 | int res; | 160 | int res; |
161 | 161 | ||
162 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 162 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
163 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 163 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
164 | nl80211_policy); | 164 | nl80211_policy); |
165 | if (res) | 165 | if (res) |
166 | return res; | 166 | return res; |
167 | 167 | ||
168 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | 168 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) |
169 | return -EINVAL; | 169 | return -EINVAL; |
170 | 170 | ||
171 | res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | 171 | res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); |
172 | if (!res) | 172 | if (!res) |
173 | return -EINVAL; | 173 | return -EINVAL; |
174 | return res; | 174 | return res; |
175 | } | 175 | } |
176 | 176 | ||
177 | /* IE validation */ | 177 | /* IE validation */ |
178 | static bool is_valid_ie_attr(const struct nlattr *attr) | 178 | static bool is_valid_ie_attr(const struct nlattr *attr) |
179 | { | 179 | { |
180 | const u8 *pos; | 180 | const u8 *pos; |
181 | int len; | 181 | int len; |
182 | 182 | ||
183 | if (!attr) | 183 | if (!attr) |
184 | return true; | 184 | return true; |
185 | 185 | ||
186 | pos = nla_data(attr); | 186 | pos = nla_data(attr); |
187 | len = nla_len(attr); | 187 | len = nla_len(attr); |
188 | 188 | ||
189 | while (len) { | 189 | while (len) { |
190 | u8 elemlen; | 190 | u8 elemlen; |
191 | 191 | ||
192 | if (len < 2) | 192 | if (len < 2) |
193 | return false; | 193 | return false; |
194 | len -= 2; | 194 | len -= 2; |
195 | 195 | ||
196 | elemlen = pos[1]; | 196 | elemlen = pos[1]; |
197 | if (elemlen > len) | 197 | if (elemlen > len) |
198 | return false; | 198 | return false; |
199 | 199 | ||
200 | len -= elemlen; | 200 | len -= elemlen; |
201 | pos += 2 + elemlen; | 201 | pos += 2 + elemlen; |
202 | } | 202 | } |
203 | 203 | ||
204 | return true; | 204 | return true; |
205 | } | 205 | } |
206 | 206 | ||
207 | /* message building helper */ | 207 | /* message building helper */ |
208 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, | 208 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, |
209 | int flags, u8 cmd) | 209 | int flags, u8 cmd) |
210 | { | 210 | { |
211 | /* since there is no private header just add the generic one */ | 211 | /* since there is no private header just add the generic one */ |
212 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); | 212 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); |
213 | } | 213 | } |
214 | 214 | ||
215 | static int nl80211_msg_put_channel(struct sk_buff *msg, | 215 | static int nl80211_msg_put_channel(struct sk_buff *msg, |
216 | struct ieee80211_channel *chan) | 216 | struct ieee80211_channel *chan) |
217 | { | 217 | { |
218 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, | 218 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, |
219 | chan->center_freq); | 219 | chan->center_freq); |
220 | 220 | ||
221 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 221 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
222 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); | 222 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); |
223 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 223 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
224 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); | 224 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); |
225 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | 225 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) |
226 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); | 226 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); |
227 | if (chan->flags & IEEE80211_CHAN_RADAR) | 227 | if (chan->flags & IEEE80211_CHAN_RADAR) |
228 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); | 228 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); |
229 | 229 | ||
230 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 230 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
231 | DBM_TO_MBM(chan->max_power)); | 231 | DBM_TO_MBM(chan->max_power)); |
232 | 232 | ||
233 | return 0; | 233 | return 0; |
234 | 234 | ||
235 | nla_put_failure: | 235 | nla_put_failure: |
236 | return -ENOBUFS; | 236 | return -ENOBUFS; |
237 | } | 237 | } |
238 | 238 | ||
239 | /* netlink command implementations */ | 239 | /* netlink command implementations */ |
240 | 240 | ||
241 | struct key_parse { | 241 | struct key_parse { |
242 | struct key_params p; | 242 | struct key_params p; |
243 | int idx; | 243 | int idx; |
244 | bool def, defmgmt; | 244 | bool def, defmgmt; |
245 | }; | 245 | }; |
246 | 246 | ||
247 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | 247 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) |
248 | { | 248 | { |
249 | struct nlattr *tb[NL80211_KEY_MAX + 1]; | 249 | struct nlattr *tb[NL80211_KEY_MAX + 1]; |
250 | int err = nla_parse_nested(tb, NL80211_KEY_MAX, key, | 250 | int err = nla_parse_nested(tb, NL80211_KEY_MAX, key, |
251 | nl80211_key_policy); | 251 | nl80211_key_policy); |
252 | if (err) | 252 | if (err) |
253 | return err; | 253 | return err; |
254 | 254 | ||
255 | k->def = !!tb[NL80211_KEY_DEFAULT]; | 255 | k->def = !!tb[NL80211_KEY_DEFAULT]; |
256 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; | 256 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; |
257 | 257 | ||
258 | if (tb[NL80211_KEY_IDX]) | 258 | if (tb[NL80211_KEY_IDX]) |
259 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); | 259 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); |
260 | 260 | ||
261 | if (tb[NL80211_KEY_DATA]) { | 261 | if (tb[NL80211_KEY_DATA]) { |
262 | k->p.key = nla_data(tb[NL80211_KEY_DATA]); | 262 | k->p.key = nla_data(tb[NL80211_KEY_DATA]); |
263 | k->p.key_len = nla_len(tb[NL80211_KEY_DATA]); | 263 | k->p.key_len = nla_len(tb[NL80211_KEY_DATA]); |
264 | } | 264 | } |
265 | 265 | ||
266 | if (tb[NL80211_KEY_SEQ]) { | 266 | if (tb[NL80211_KEY_SEQ]) { |
267 | k->p.seq = nla_data(tb[NL80211_KEY_SEQ]); | 267 | k->p.seq = nla_data(tb[NL80211_KEY_SEQ]); |
268 | k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]); | 268 | k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]); |
269 | } | 269 | } |
270 | 270 | ||
271 | if (tb[NL80211_KEY_CIPHER]) | 271 | if (tb[NL80211_KEY_CIPHER]) |
272 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); | 272 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); |
273 | 273 | ||
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | 277 | static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) |
278 | { | 278 | { |
279 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { | 279 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { |
280 | k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); | 280 | k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); |
281 | k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); | 281 | k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); |
282 | } | 282 | } |
283 | 283 | ||
284 | if (info->attrs[NL80211_ATTR_KEY_SEQ]) { | 284 | if (info->attrs[NL80211_ATTR_KEY_SEQ]) { |
285 | k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); | 285 | k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); |
286 | k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); | 286 | k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); |
287 | } | 287 | } |
288 | 288 | ||
289 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 289 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
290 | k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 290 | k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
291 | 291 | ||
292 | if (info->attrs[NL80211_ATTR_KEY_CIPHER]) | 292 | if (info->attrs[NL80211_ATTR_KEY_CIPHER]) |
293 | k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); | 293 | k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); |
294 | 294 | ||
295 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 295 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
296 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 296 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
297 | 297 | ||
298 | return 0; | 298 | return 0; |
299 | } | 299 | } |
300 | 300 | ||
301 | static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | 301 | static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) |
302 | { | 302 | { |
303 | int err; | 303 | int err; |
304 | 304 | ||
305 | memset(k, 0, sizeof(*k)); | 305 | memset(k, 0, sizeof(*k)); |
306 | k->idx = -1; | 306 | k->idx = -1; |
307 | 307 | ||
308 | if (info->attrs[NL80211_ATTR_KEY]) | 308 | if (info->attrs[NL80211_ATTR_KEY]) |
309 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); | 309 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); |
310 | else | 310 | else |
311 | err = nl80211_parse_key_old(info, k); | 311 | err = nl80211_parse_key_old(info, k); |
312 | 312 | ||
313 | if (err) | 313 | if (err) |
314 | return err; | 314 | return err; |
315 | 315 | ||
316 | if (k->def && k->defmgmt) | 316 | if (k->def && k->defmgmt) |
317 | return -EINVAL; | 317 | return -EINVAL; |
318 | 318 | ||
319 | if (k->idx != -1) { | 319 | if (k->idx != -1) { |
320 | if (k->defmgmt) { | 320 | if (k->defmgmt) { |
321 | if (k->idx < 4 || k->idx > 5) | 321 | if (k->idx < 4 || k->idx > 5) |
322 | return -EINVAL; | 322 | return -EINVAL; |
323 | } else if (k->def) { | 323 | } else if (k->def) { |
324 | if (k->idx < 0 || k->idx > 3) | 324 | if (k->idx < 0 || k->idx > 3) |
325 | return -EINVAL; | 325 | return -EINVAL; |
326 | } else { | 326 | } else { |
327 | if (k->idx < 0 || k->idx > 5) | 327 | if (k->idx < 0 || k->idx > 5) |
328 | return -EINVAL; | 328 | return -EINVAL; |
329 | } | 329 | } |
330 | } | 330 | } |
331 | 331 | ||
332 | return 0; | 332 | return 0; |
333 | } | 333 | } |
334 | 334 | ||
335 | static struct cfg80211_cached_keys * | 335 | static struct cfg80211_cached_keys * |
336 | nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | 336 | nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, |
337 | struct nlattr *keys) | 337 | struct nlattr *keys) |
338 | { | 338 | { |
339 | struct key_parse parse; | 339 | struct key_parse parse; |
340 | struct nlattr *key; | 340 | struct nlattr *key; |
341 | struct cfg80211_cached_keys *result; | 341 | struct cfg80211_cached_keys *result; |
342 | int rem, err, def = 0; | 342 | int rem, err, def = 0; |
343 | 343 | ||
344 | result = kzalloc(sizeof(*result), GFP_KERNEL); | 344 | result = kzalloc(sizeof(*result), GFP_KERNEL); |
345 | if (!result) | 345 | if (!result) |
346 | return ERR_PTR(-ENOMEM); | 346 | return ERR_PTR(-ENOMEM); |
347 | 347 | ||
348 | result->def = -1; | 348 | result->def = -1; |
349 | result->defmgmt = -1; | 349 | result->defmgmt = -1; |
350 | 350 | ||
351 | nla_for_each_nested(key, keys, rem) { | 351 | nla_for_each_nested(key, keys, rem) { |
352 | memset(&parse, 0, sizeof(parse)); | 352 | memset(&parse, 0, sizeof(parse)); |
353 | parse.idx = -1; | 353 | parse.idx = -1; |
354 | 354 | ||
355 | err = nl80211_parse_key_new(key, &parse); | 355 | err = nl80211_parse_key_new(key, &parse); |
356 | if (err) | 356 | if (err) |
357 | goto error; | 357 | goto error; |
358 | err = -EINVAL; | 358 | err = -EINVAL; |
359 | if (!parse.p.key) | 359 | if (!parse.p.key) |
360 | goto error; | 360 | goto error; |
361 | if (parse.idx < 0 || parse.idx > 4) | 361 | if (parse.idx < 0 || parse.idx > 4) |
362 | goto error; | 362 | goto error; |
363 | if (parse.def) { | 363 | if (parse.def) { |
364 | if (def) | 364 | if (def) |
365 | goto error; | 365 | goto error; |
366 | def = 1; | 366 | def = 1; |
367 | result->def = parse.idx; | 367 | result->def = parse.idx; |
368 | } else if (parse.defmgmt) | 368 | } else if (parse.defmgmt) |
369 | goto error; | 369 | goto error; |
370 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 370 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
371 | parse.idx, NULL); | 371 | parse.idx, NULL); |
372 | if (err) | 372 | if (err) |
373 | goto error; | 373 | goto error; |
374 | result->params[parse.idx].cipher = parse.p.cipher; | 374 | result->params[parse.idx].cipher = parse.p.cipher; |
375 | result->params[parse.idx].key_len = parse.p.key_len; | 375 | result->params[parse.idx].key_len = parse.p.key_len; |
376 | result->params[parse.idx].key = result->data[parse.idx]; | 376 | result->params[parse.idx].key = result->data[parse.idx]; |
377 | memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); | 377 | memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); |
378 | } | 378 | } |
379 | 379 | ||
380 | return result; | 380 | return result; |
381 | error: | 381 | error: |
382 | kfree(result); | 382 | kfree(result); |
383 | return ERR_PTR(err); | 383 | return ERR_PTR(err); |
384 | } | 384 | } |
385 | 385 | ||
386 | static int nl80211_key_allowed(struct wireless_dev *wdev) | 386 | static int nl80211_key_allowed(struct wireless_dev *wdev) |
387 | { | 387 | { |
388 | ASSERT_WDEV_LOCK(wdev); | 388 | ASSERT_WDEV_LOCK(wdev); |
389 | 389 | ||
390 | if (!netif_running(wdev->netdev)) | 390 | if (!netif_running(wdev->netdev)) |
391 | return -ENETDOWN; | 391 | return -ENETDOWN; |
392 | 392 | ||
393 | switch (wdev->iftype) { | 393 | switch (wdev->iftype) { |
394 | case NL80211_IFTYPE_AP: | 394 | case NL80211_IFTYPE_AP: |
395 | case NL80211_IFTYPE_AP_VLAN: | 395 | case NL80211_IFTYPE_AP_VLAN: |
396 | break; | 396 | break; |
397 | case NL80211_IFTYPE_ADHOC: | 397 | case NL80211_IFTYPE_ADHOC: |
398 | if (!wdev->current_bss) | 398 | if (!wdev->current_bss) |
399 | return -ENOLINK; | 399 | return -ENOLINK; |
400 | break; | 400 | break; |
401 | case NL80211_IFTYPE_STATION: | 401 | case NL80211_IFTYPE_STATION: |
402 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 402 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
403 | return -ENOLINK; | 403 | return -ENOLINK; |
404 | break; | 404 | break; |
405 | default: | 405 | default: |
406 | return -EINVAL; | 406 | return -EINVAL; |
407 | } | 407 | } |
408 | 408 | ||
409 | return 0; | 409 | return 0; |
410 | } | 410 | } |
411 | 411 | ||
412 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 412 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
413 | struct cfg80211_registered_device *dev) | 413 | struct cfg80211_registered_device *dev) |
414 | { | 414 | { |
415 | void *hdr; | 415 | void *hdr; |
416 | struct nlattr *nl_bands, *nl_band; | 416 | struct nlattr *nl_bands, *nl_band; |
417 | struct nlattr *nl_freqs, *nl_freq; | 417 | struct nlattr *nl_freqs, *nl_freq; |
418 | struct nlattr *nl_rates, *nl_rate; | 418 | struct nlattr *nl_rates, *nl_rate; |
419 | struct nlattr *nl_modes; | 419 | struct nlattr *nl_modes; |
420 | struct nlattr *nl_cmds; | 420 | struct nlattr *nl_cmds; |
421 | enum ieee80211_band band; | 421 | enum ieee80211_band band; |
422 | struct ieee80211_channel *chan; | 422 | struct ieee80211_channel *chan; |
423 | struct ieee80211_rate *rate; | 423 | struct ieee80211_rate *rate; |
424 | int i; | 424 | int i; |
425 | u16 ifmodes = dev->wiphy.interface_modes; | 425 | u16 ifmodes = dev->wiphy.interface_modes; |
426 | 426 | ||
427 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); | 427 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); |
428 | if (!hdr) | 428 | if (!hdr) |
429 | return -1; | 429 | return -1; |
430 | 430 | ||
431 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 431 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
432 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 432 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
433 | 433 | ||
434 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | 434 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, |
435 | cfg80211_rdev_list_generation); | 435 | cfg80211_rdev_list_generation); |
436 | 436 | ||
437 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 437 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
438 | dev->wiphy.retry_short); | 438 | dev->wiphy.retry_short); |
439 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | 439 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, |
440 | dev->wiphy.retry_long); | 440 | dev->wiphy.retry_long); |
441 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | 441 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, |
442 | dev->wiphy.frag_threshold); | 442 | dev->wiphy.frag_threshold); |
443 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | 443 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, |
444 | dev->wiphy.rts_threshold); | 444 | dev->wiphy.rts_threshold); |
445 | 445 | ||
446 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 446 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
447 | dev->wiphy.max_scan_ssids); | 447 | dev->wiphy.max_scan_ssids); |
448 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 448 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
449 | dev->wiphy.max_scan_ie_len); | 449 | dev->wiphy.max_scan_ie_len); |
450 | 450 | ||
451 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 451 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
452 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 452 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
453 | dev->wiphy.cipher_suites); | 453 | dev->wiphy.cipher_suites); |
454 | 454 | ||
455 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | 455 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, |
456 | dev->wiphy.max_num_pmkids); | 456 | dev->wiphy.max_num_pmkids); |
457 | 457 | ||
458 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 458 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
459 | if (!nl_modes) | 459 | if (!nl_modes) |
460 | goto nla_put_failure; | 460 | goto nla_put_failure; |
461 | 461 | ||
462 | i = 0; | 462 | i = 0; |
463 | while (ifmodes) { | 463 | while (ifmodes) { |
464 | if (ifmodes & 1) | 464 | if (ifmodes & 1) |
465 | NLA_PUT_FLAG(msg, i); | 465 | NLA_PUT_FLAG(msg, i); |
466 | ifmodes >>= 1; | 466 | ifmodes >>= 1; |
467 | i++; | 467 | i++; |
468 | } | 468 | } |
469 | 469 | ||
470 | nla_nest_end(msg, nl_modes); | 470 | nla_nest_end(msg, nl_modes); |
471 | 471 | ||
472 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 472 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
473 | if (!nl_bands) | 473 | if (!nl_bands) |
474 | goto nla_put_failure; | 474 | goto nla_put_failure; |
475 | 475 | ||
476 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 476 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
477 | if (!dev->wiphy.bands[band]) | 477 | if (!dev->wiphy.bands[band]) |
478 | continue; | 478 | continue; |
479 | 479 | ||
480 | nl_band = nla_nest_start(msg, band); | 480 | nl_band = nla_nest_start(msg, band); |
481 | if (!nl_band) | 481 | if (!nl_band) |
482 | goto nla_put_failure; | 482 | goto nla_put_failure; |
483 | 483 | ||
484 | /* add HT info */ | 484 | /* add HT info */ |
485 | if (dev->wiphy.bands[band]->ht_cap.ht_supported) { | 485 | if (dev->wiphy.bands[band]->ht_cap.ht_supported) { |
486 | NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET, | 486 | NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET, |
487 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), | 487 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), |
488 | &dev->wiphy.bands[band]->ht_cap.mcs); | 488 | &dev->wiphy.bands[band]->ht_cap.mcs); |
489 | NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA, | 489 | NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA, |
490 | dev->wiphy.bands[band]->ht_cap.cap); | 490 | dev->wiphy.bands[band]->ht_cap.cap); |
491 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 491 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, |
492 | dev->wiphy.bands[band]->ht_cap.ampdu_factor); | 492 | dev->wiphy.bands[band]->ht_cap.ampdu_factor); |
493 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | 493 | NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, |
494 | dev->wiphy.bands[band]->ht_cap.ampdu_density); | 494 | dev->wiphy.bands[band]->ht_cap.ampdu_density); |
495 | } | 495 | } |
496 | 496 | ||
497 | /* add frequencies */ | 497 | /* add frequencies */ |
498 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 498 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
499 | if (!nl_freqs) | 499 | if (!nl_freqs) |
500 | goto nla_put_failure; | 500 | goto nla_put_failure; |
501 | 501 | ||
502 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { | 502 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { |
503 | nl_freq = nla_nest_start(msg, i); | 503 | nl_freq = nla_nest_start(msg, i); |
504 | if (!nl_freq) | 504 | if (!nl_freq) |
505 | goto nla_put_failure; | 505 | goto nla_put_failure; |
506 | 506 | ||
507 | chan = &dev->wiphy.bands[band]->channels[i]; | 507 | chan = &dev->wiphy.bands[band]->channels[i]; |
508 | 508 | ||
509 | if (nl80211_msg_put_channel(msg, chan)) | 509 | if (nl80211_msg_put_channel(msg, chan)) |
510 | goto nla_put_failure; | 510 | goto nla_put_failure; |
511 | 511 | ||
512 | nla_nest_end(msg, nl_freq); | 512 | nla_nest_end(msg, nl_freq); |
513 | } | 513 | } |
514 | 514 | ||
515 | nla_nest_end(msg, nl_freqs); | 515 | nla_nest_end(msg, nl_freqs); |
516 | 516 | ||
517 | /* add bitrates */ | 517 | /* add bitrates */ |
518 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); | 518 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); |
519 | if (!nl_rates) | 519 | if (!nl_rates) |
520 | goto nla_put_failure; | 520 | goto nla_put_failure; |
521 | 521 | ||
522 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { | 522 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { |
523 | nl_rate = nla_nest_start(msg, i); | 523 | nl_rate = nla_nest_start(msg, i); |
524 | if (!nl_rate) | 524 | if (!nl_rate) |
525 | goto nla_put_failure; | 525 | goto nla_put_failure; |
526 | 526 | ||
527 | rate = &dev->wiphy.bands[band]->bitrates[i]; | 527 | rate = &dev->wiphy.bands[band]->bitrates[i]; |
528 | NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, | 528 | NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, |
529 | rate->bitrate); | 529 | rate->bitrate); |
530 | if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) | 530 | if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) |
531 | NLA_PUT_FLAG(msg, | 531 | NLA_PUT_FLAG(msg, |
532 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); | 532 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); |
533 | 533 | ||
534 | nla_nest_end(msg, nl_rate); | 534 | nla_nest_end(msg, nl_rate); |
535 | } | 535 | } |
536 | 536 | ||
537 | nla_nest_end(msg, nl_rates); | 537 | nla_nest_end(msg, nl_rates); |
538 | 538 | ||
539 | nla_nest_end(msg, nl_band); | 539 | nla_nest_end(msg, nl_band); |
540 | } | 540 | } |
541 | nla_nest_end(msg, nl_bands); | 541 | nla_nest_end(msg, nl_bands); |
542 | 542 | ||
543 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 543 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); |
544 | if (!nl_cmds) | 544 | if (!nl_cmds) |
545 | goto nla_put_failure; | 545 | goto nla_put_failure; |
546 | 546 | ||
547 | i = 0; | 547 | i = 0; |
548 | #define CMD(op, n) \ | 548 | #define CMD(op, n) \ |
549 | do { \ | 549 | do { \ |
550 | if (dev->ops->op) { \ | 550 | if (dev->ops->op) { \ |
551 | i++; \ | 551 | i++; \ |
552 | NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \ | 552 | NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \ |
553 | } \ | 553 | } \ |
554 | } while (0) | 554 | } while (0) |
555 | 555 | ||
556 | CMD(add_virtual_intf, NEW_INTERFACE); | 556 | CMD(add_virtual_intf, NEW_INTERFACE); |
557 | CMD(change_virtual_intf, SET_INTERFACE); | 557 | CMD(change_virtual_intf, SET_INTERFACE); |
558 | CMD(add_key, NEW_KEY); | 558 | CMD(add_key, NEW_KEY); |
559 | CMD(add_beacon, NEW_BEACON); | 559 | CMD(add_beacon, NEW_BEACON); |
560 | CMD(add_station, NEW_STATION); | 560 | CMD(add_station, NEW_STATION); |
561 | CMD(add_mpath, NEW_MPATH); | 561 | CMD(add_mpath, NEW_MPATH); |
562 | CMD(set_mesh_params, SET_MESH_PARAMS); | 562 | CMD(set_mesh_params, SET_MESH_PARAMS); |
563 | CMD(change_bss, SET_BSS); | 563 | CMD(change_bss, SET_BSS); |
564 | CMD(auth, AUTHENTICATE); | 564 | CMD(auth, AUTHENTICATE); |
565 | CMD(assoc, ASSOCIATE); | 565 | CMD(assoc, ASSOCIATE); |
566 | CMD(deauth, DEAUTHENTICATE); | 566 | CMD(deauth, DEAUTHENTICATE); |
567 | CMD(disassoc, DISASSOCIATE); | 567 | CMD(disassoc, DISASSOCIATE); |
568 | CMD(join_ibss, JOIN_IBSS); | 568 | CMD(join_ibss, JOIN_IBSS); |
569 | CMD(set_pmksa, SET_PMKSA); | 569 | CMD(set_pmksa, SET_PMKSA); |
570 | CMD(del_pmksa, DEL_PMKSA); | 570 | CMD(del_pmksa, DEL_PMKSA); |
571 | CMD(flush_pmksa, FLUSH_PMKSA); | 571 | CMD(flush_pmksa, FLUSH_PMKSA); |
572 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 572 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
573 | i++; | 573 | i++; |
574 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 574 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
575 | } | 575 | } |
576 | 576 | ||
577 | #undef CMD | 577 | #undef CMD |
578 | 578 | ||
579 | if (dev->ops->connect || dev->ops->auth) { | 579 | if (dev->ops->connect || dev->ops->auth) { |
580 | i++; | 580 | i++; |
581 | NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); | 581 | NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); |
582 | } | 582 | } |
583 | 583 | ||
584 | if (dev->ops->disconnect || dev->ops->deauth) { | 584 | if (dev->ops->disconnect || dev->ops->deauth) { |
585 | i++; | 585 | i++; |
586 | NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); | 586 | NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); |
587 | } | 587 | } |
588 | 588 | ||
589 | nla_nest_end(msg, nl_cmds); | 589 | nla_nest_end(msg, nl_cmds); |
590 | 590 | ||
591 | return genlmsg_end(msg, hdr); | 591 | return genlmsg_end(msg, hdr); |
592 | 592 | ||
593 | nla_put_failure: | 593 | nla_put_failure: |
594 | genlmsg_cancel(msg, hdr); | 594 | genlmsg_cancel(msg, hdr); |
595 | return -EMSGSIZE; | 595 | return -EMSGSIZE; |
596 | } | 596 | } |
597 | 597 | ||
598 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | 598 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) |
599 | { | 599 | { |
600 | int idx = 0; | 600 | int idx = 0; |
601 | int start = cb->args[0]; | 601 | int start = cb->args[0]; |
602 | struct cfg80211_registered_device *dev; | 602 | struct cfg80211_registered_device *dev; |
603 | 603 | ||
604 | mutex_lock(&cfg80211_mutex); | 604 | mutex_lock(&cfg80211_mutex); |
605 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 605 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
606 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 606 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
607 | continue; | 607 | continue; |
608 | if (++idx <= start) | 608 | if (++idx <= start) |
609 | continue; | 609 | continue; |
610 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, | 610 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, |
611 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 611 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
612 | dev) < 0) { | 612 | dev) < 0) { |
613 | idx--; | 613 | idx--; |
614 | break; | 614 | break; |
615 | } | 615 | } |
616 | } | 616 | } |
617 | mutex_unlock(&cfg80211_mutex); | 617 | mutex_unlock(&cfg80211_mutex); |
618 | 618 | ||
619 | cb->args[0] = idx; | 619 | cb->args[0] = idx; |
620 | 620 | ||
621 | return skb->len; | 621 | return skb->len; |
622 | } | 622 | } |
623 | 623 | ||
624 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 624 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
625 | { | 625 | { |
626 | struct sk_buff *msg; | 626 | struct sk_buff *msg; |
627 | struct cfg80211_registered_device *dev; | 627 | struct cfg80211_registered_device *dev; |
628 | 628 | ||
629 | dev = cfg80211_get_dev_from_info(info); | 629 | dev = cfg80211_get_dev_from_info(info); |
630 | if (IS_ERR(dev)) | 630 | if (IS_ERR(dev)) |
631 | return PTR_ERR(dev); | 631 | return PTR_ERR(dev); |
632 | 632 | ||
633 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 633 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
634 | if (!msg) | 634 | if (!msg) |
635 | goto out_err; | 635 | goto out_err; |
636 | 636 | ||
637 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) | 637 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) |
638 | goto out_free; | 638 | goto out_free; |
639 | 639 | ||
640 | cfg80211_unlock_rdev(dev); | 640 | cfg80211_unlock_rdev(dev); |
641 | 641 | ||
642 | return genlmsg_reply(msg, info); | 642 | return genlmsg_reply(msg, info); |
643 | 643 | ||
644 | out_free: | 644 | out_free: |
645 | nlmsg_free(msg); | 645 | nlmsg_free(msg); |
646 | out_err: | 646 | out_err: |
647 | cfg80211_unlock_rdev(dev); | 647 | cfg80211_unlock_rdev(dev); |
648 | return -ENOBUFS; | 648 | return -ENOBUFS; |
649 | } | 649 | } |
650 | 650 | ||
651 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | 651 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { |
652 | [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, | 652 | [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, |
653 | [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, | 653 | [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, |
654 | [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, | 654 | [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, |
655 | [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, | 655 | [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, |
656 | [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, | 656 | [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, |
657 | }; | 657 | }; |
658 | 658 | ||
659 | static int parse_txq_params(struct nlattr *tb[], | 659 | static int parse_txq_params(struct nlattr *tb[], |
660 | struct ieee80211_txq_params *txq_params) | 660 | struct ieee80211_txq_params *txq_params) |
661 | { | 661 | { |
662 | if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || | 662 | if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || |
663 | !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || | 663 | !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || |
664 | !tb[NL80211_TXQ_ATTR_AIFS]) | 664 | !tb[NL80211_TXQ_ATTR_AIFS]) |
665 | return -EINVAL; | 665 | return -EINVAL; |
666 | 666 | ||
667 | txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); | 667 | txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); |
668 | txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); | 668 | txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); |
669 | txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); | 669 | txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); |
670 | txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); | 670 | txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); |
671 | txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); | 671 | txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); |
672 | 672 | ||
673 | return 0; | 673 | return 0; |
674 | } | 674 | } |
675 | 675 | ||
676 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 676 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
677 | { | 677 | { |
678 | struct cfg80211_registered_device *rdev; | 678 | struct cfg80211_registered_device *rdev; |
679 | int result = 0, rem_txq_params = 0; | 679 | int result = 0, rem_txq_params = 0; |
680 | struct nlattr *nl_txq_params; | 680 | struct nlattr *nl_txq_params; |
681 | u32 changed; | 681 | u32 changed; |
682 | u8 retry_short = 0, retry_long = 0; | 682 | u8 retry_short = 0, retry_long = 0; |
683 | u32 frag_threshold = 0, rts_threshold = 0; | 683 | u32 frag_threshold = 0, rts_threshold = 0; |
684 | 684 | ||
685 | rtnl_lock(); | 685 | rtnl_lock(); |
686 | 686 | ||
687 | mutex_lock(&cfg80211_mutex); | 687 | mutex_lock(&cfg80211_mutex); |
688 | 688 | ||
689 | rdev = __cfg80211_rdev_from_info(info); | 689 | rdev = __cfg80211_rdev_from_info(info); |
690 | if (IS_ERR(rdev)) { | 690 | if (IS_ERR(rdev)) { |
691 | mutex_unlock(&cfg80211_mutex); | 691 | mutex_unlock(&cfg80211_mutex); |
692 | result = PTR_ERR(rdev); | 692 | result = PTR_ERR(rdev); |
693 | goto unlock; | 693 | goto unlock; |
694 | } | 694 | } |
695 | 695 | ||
696 | mutex_lock(&rdev->mtx); | 696 | mutex_lock(&rdev->mtx); |
697 | 697 | ||
698 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) | 698 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) |
699 | result = cfg80211_dev_rename( | 699 | result = cfg80211_dev_rename( |
700 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 700 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
701 | 701 | ||
702 | mutex_unlock(&cfg80211_mutex); | 702 | mutex_unlock(&cfg80211_mutex); |
703 | 703 | ||
704 | if (result) | 704 | if (result) |
705 | goto bad_res; | 705 | goto bad_res; |
706 | 706 | ||
707 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | 707 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { |
708 | struct ieee80211_txq_params txq_params; | 708 | struct ieee80211_txq_params txq_params; |
709 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; | 709 | struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; |
710 | 710 | ||
711 | if (!rdev->ops->set_txq_params) { | 711 | if (!rdev->ops->set_txq_params) { |
712 | result = -EOPNOTSUPP; | 712 | result = -EOPNOTSUPP; |
713 | goto bad_res; | 713 | goto bad_res; |
714 | } | 714 | } |
715 | 715 | ||
716 | nla_for_each_nested(nl_txq_params, | 716 | nla_for_each_nested(nl_txq_params, |
717 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 717 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
718 | rem_txq_params) { | 718 | rem_txq_params) { |
719 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, | 719 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, |
720 | nla_data(nl_txq_params), | 720 | nla_data(nl_txq_params), |
721 | nla_len(nl_txq_params), | 721 | nla_len(nl_txq_params), |
722 | txq_params_policy); | 722 | txq_params_policy); |
723 | result = parse_txq_params(tb, &txq_params); | 723 | result = parse_txq_params(tb, &txq_params); |
724 | if (result) | 724 | if (result) |
725 | goto bad_res; | 725 | goto bad_res; |
726 | 726 | ||
727 | result = rdev->ops->set_txq_params(&rdev->wiphy, | 727 | result = rdev->ops->set_txq_params(&rdev->wiphy, |
728 | &txq_params); | 728 | &txq_params); |
729 | if (result) | 729 | if (result) |
730 | goto bad_res; | 730 | goto bad_res; |
731 | } | 731 | } |
732 | } | 732 | } |
733 | 733 | ||
734 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 734 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
735 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 735 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
736 | u32 freq; | 736 | u32 freq; |
737 | 737 | ||
738 | result = -EINVAL; | 738 | result = -EINVAL; |
739 | 739 | ||
740 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 740 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
741 | channel_type = nla_get_u32(info->attrs[ | 741 | channel_type = nla_get_u32(info->attrs[ |
742 | NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | 742 | NL80211_ATTR_WIPHY_CHANNEL_TYPE]); |
743 | if (channel_type != NL80211_CHAN_NO_HT && | 743 | if (channel_type != NL80211_CHAN_NO_HT && |
744 | channel_type != NL80211_CHAN_HT20 && | 744 | channel_type != NL80211_CHAN_HT20 && |
745 | channel_type != NL80211_CHAN_HT40PLUS && | 745 | channel_type != NL80211_CHAN_HT40PLUS && |
746 | channel_type != NL80211_CHAN_HT40MINUS) | 746 | channel_type != NL80211_CHAN_HT40MINUS) |
747 | goto bad_res; | 747 | goto bad_res; |
748 | } | 748 | } |
749 | 749 | ||
750 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 750 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
751 | 751 | ||
752 | mutex_lock(&rdev->devlist_mtx); | 752 | mutex_lock(&rdev->devlist_mtx); |
753 | result = rdev_set_freq(rdev, NULL, freq, channel_type); | 753 | result = rdev_set_freq(rdev, NULL, freq, channel_type); |
754 | mutex_unlock(&rdev->devlist_mtx); | 754 | mutex_unlock(&rdev->devlist_mtx); |
755 | if (result) | 755 | if (result) |
756 | goto bad_res; | 756 | goto bad_res; |
757 | } | 757 | } |
758 | 758 | ||
759 | changed = 0; | 759 | changed = 0; |
760 | 760 | ||
761 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | 761 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { |
762 | retry_short = nla_get_u8( | 762 | retry_short = nla_get_u8( |
763 | info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); | 763 | info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); |
764 | if (retry_short == 0) { | 764 | if (retry_short == 0) { |
765 | result = -EINVAL; | 765 | result = -EINVAL; |
766 | goto bad_res; | 766 | goto bad_res; |
767 | } | 767 | } |
768 | changed |= WIPHY_PARAM_RETRY_SHORT; | 768 | changed |= WIPHY_PARAM_RETRY_SHORT; |
769 | } | 769 | } |
770 | 770 | ||
771 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { | 771 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { |
772 | retry_long = nla_get_u8( | 772 | retry_long = nla_get_u8( |
773 | info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); | 773 | info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); |
774 | if (retry_long == 0) { | 774 | if (retry_long == 0) { |
775 | result = -EINVAL; | 775 | result = -EINVAL; |
776 | goto bad_res; | 776 | goto bad_res; |
777 | } | 777 | } |
778 | changed |= WIPHY_PARAM_RETRY_LONG; | 778 | changed |= WIPHY_PARAM_RETRY_LONG; |
779 | } | 779 | } |
780 | 780 | ||
781 | if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { | 781 | if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { |
782 | frag_threshold = nla_get_u32( | 782 | frag_threshold = nla_get_u32( |
783 | info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); | 783 | info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); |
784 | if (frag_threshold < 256) { | 784 | if (frag_threshold < 256) { |
785 | result = -EINVAL; | 785 | result = -EINVAL; |
786 | goto bad_res; | 786 | goto bad_res; |
787 | } | 787 | } |
788 | if (frag_threshold != (u32) -1) { | 788 | if (frag_threshold != (u32) -1) { |
789 | /* | 789 | /* |
790 | * Fragments (apart from the last one) are required to | 790 | * Fragments (apart from the last one) are required to |
791 | * have even length. Make the fragmentation code | 791 | * have even length. Make the fragmentation code |
792 | * simpler by stripping LSB should someone try to use | 792 | * simpler by stripping LSB should someone try to use |
793 | * odd threshold value. | 793 | * odd threshold value. |
794 | */ | 794 | */ |
795 | frag_threshold &= ~0x1; | 795 | frag_threshold &= ~0x1; |
796 | } | 796 | } |
797 | changed |= WIPHY_PARAM_FRAG_THRESHOLD; | 797 | changed |= WIPHY_PARAM_FRAG_THRESHOLD; |
798 | } | 798 | } |
799 | 799 | ||
800 | if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { | 800 | if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { |
801 | rts_threshold = nla_get_u32( | 801 | rts_threshold = nla_get_u32( |
802 | info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); | 802 | info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); |
803 | changed |= WIPHY_PARAM_RTS_THRESHOLD; | 803 | changed |= WIPHY_PARAM_RTS_THRESHOLD; |
804 | } | 804 | } |
805 | 805 | ||
806 | if (changed) { | 806 | if (changed) { |
807 | u8 old_retry_short, old_retry_long; | 807 | u8 old_retry_short, old_retry_long; |
808 | u32 old_frag_threshold, old_rts_threshold; | 808 | u32 old_frag_threshold, old_rts_threshold; |
809 | 809 | ||
810 | if (!rdev->ops->set_wiphy_params) { | 810 | if (!rdev->ops->set_wiphy_params) { |
811 | result = -EOPNOTSUPP; | 811 | result = -EOPNOTSUPP; |
812 | goto bad_res; | 812 | goto bad_res; |
813 | } | 813 | } |
814 | 814 | ||
815 | old_retry_short = rdev->wiphy.retry_short; | 815 | old_retry_short = rdev->wiphy.retry_short; |
816 | old_retry_long = rdev->wiphy.retry_long; | 816 | old_retry_long = rdev->wiphy.retry_long; |
817 | old_frag_threshold = rdev->wiphy.frag_threshold; | 817 | old_frag_threshold = rdev->wiphy.frag_threshold; |
818 | old_rts_threshold = rdev->wiphy.rts_threshold; | 818 | old_rts_threshold = rdev->wiphy.rts_threshold; |
819 | 819 | ||
820 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 820 | if (changed & WIPHY_PARAM_RETRY_SHORT) |
821 | rdev->wiphy.retry_short = retry_short; | 821 | rdev->wiphy.retry_short = retry_short; |
822 | if (changed & WIPHY_PARAM_RETRY_LONG) | 822 | if (changed & WIPHY_PARAM_RETRY_LONG) |
823 | rdev->wiphy.retry_long = retry_long; | 823 | rdev->wiphy.retry_long = retry_long; |
824 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) | 824 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) |
825 | rdev->wiphy.frag_threshold = frag_threshold; | 825 | rdev->wiphy.frag_threshold = frag_threshold; |
826 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | 826 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) |
827 | rdev->wiphy.rts_threshold = rts_threshold; | 827 | rdev->wiphy.rts_threshold = rts_threshold; |
828 | 828 | ||
829 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); | 829 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); |
830 | if (result) { | 830 | if (result) { |
831 | rdev->wiphy.retry_short = old_retry_short; | 831 | rdev->wiphy.retry_short = old_retry_short; |
832 | rdev->wiphy.retry_long = old_retry_long; | 832 | rdev->wiphy.retry_long = old_retry_long; |
833 | rdev->wiphy.frag_threshold = old_frag_threshold; | 833 | rdev->wiphy.frag_threshold = old_frag_threshold; |
834 | rdev->wiphy.rts_threshold = old_rts_threshold; | 834 | rdev->wiphy.rts_threshold = old_rts_threshold; |
835 | } | 835 | } |
836 | } | 836 | } |
837 | 837 | ||
838 | bad_res: | 838 | bad_res: |
839 | mutex_unlock(&rdev->mtx); | 839 | mutex_unlock(&rdev->mtx); |
840 | unlock: | 840 | unlock: |
841 | rtnl_unlock(); | 841 | rtnl_unlock(); |
842 | return result; | 842 | return result; |
843 | } | 843 | } |
844 | 844 | ||
845 | 845 | ||
846 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 846 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
847 | struct cfg80211_registered_device *rdev, | 847 | struct cfg80211_registered_device *rdev, |
848 | struct net_device *dev) | 848 | struct net_device *dev) |
849 | { | 849 | { |
850 | void *hdr; | 850 | void *hdr; |
851 | 851 | ||
852 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 852 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
853 | if (!hdr) | 853 | if (!hdr) |
854 | return -1; | 854 | return -1; |
855 | 855 | ||
856 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 856 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
857 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 857 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
858 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 858 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
859 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 859 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
860 | 860 | ||
861 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | 861 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, |
862 | rdev->devlist_generation ^ | 862 | rdev->devlist_generation ^ |
863 | (cfg80211_rdev_list_generation << 2)); | 863 | (cfg80211_rdev_list_generation << 2)); |
864 | 864 | ||
865 | return genlmsg_end(msg, hdr); | 865 | return genlmsg_end(msg, hdr); |
866 | 866 | ||
867 | nla_put_failure: | 867 | nla_put_failure: |
868 | genlmsg_cancel(msg, hdr); | 868 | genlmsg_cancel(msg, hdr); |
869 | return -EMSGSIZE; | 869 | return -EMSGSIZE; |
870 | } | 870 | } |
871 | 871 | ||
872 | static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) | 872 | static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) |
873 | { | 873 | { |
874 | int wp_idx = 0; | 874 | int wp_idx = 0; |
875 | int if_idx = 0; | 875 | int if_idx = 0; |
876 | int wp_start = cb->args[0]; | 876 | int wp_start = cb->args[0]; |
877 | int if_start = cb->args[1]; | 877 | int if_start = cb->args[1]; |
878 | struct cfg80211_registered_device *rdev; | 878 | struct cfg80211_registered_device *rdev; |
879 | struct wireless_dev *wdev; | 879 | struct wireless_dev *wdev; |
880 | 880 | ||
881 | mutex_lock(&cfg80211_mutex); | 881 | mutex_lock(&cfg80211_mutex); |
882 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 882 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
883 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) | 883 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
884 | continue; | 884 | continue; |
885 | if (wp_idx < wp_start) { | 885 | if (wp_idx < wp_start) { |
886 | wp_idx++; | 886 | wp_idx++; |
887 | continue; | 887 | continue; |
888 | } | 888 | } |
889 | if_idx = 0; | 889 | if_idx = 0; |
890 | 890 | ||
891 | mutex_lock(&rdev->devlist_mtx); | 891 | mutex_lock(&rdev->devlist_mtx); |
892 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 892 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
893 | if (if_idx < if_start) { | 893 | if (if_idx < if_start) { |
894 | if_idx++; | 894 | if_idx++; |
895 | continue; | 895 | continue; |
896 | } | 896 | } |
897 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 897 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
898 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 898 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
899 | rdev, wdev->netdev) < 0) { | 899 | rdev, wdev->netdev) < 0) { |
900 | mutex_unlock(&rdev->devlist_mtx); | 900 | mutex_unlock(&rdev->devlist_mtx); |
901 | goto out; | 901 | goto out; |
902 | } | 902 | } |
903 | if_idx++; | 903 | if_idx++; |
904 | } | 904 | } |
905 | mutex_unlock(&rdev->devlist_mtx); | 905 | mutex_unlock(&rdev->devlist_mtx); |
906 | 906 | ||
907 | wp_idx++; | 907 | wp_idx++; |
908 | } | 908 | } |
909 | out: | 909 | out: |
910 | mutex_unlock(&cfg80211_mutex); | 910 | mutex_unlock(&cfg80211_mutex); |
911 | 911 | ||
912 | cb->args[0] = wp_idx; | 912 | cb->args[0] = wp_idx; |
913 | cb->args[1] = if_idx; | 913 | cb->args[1] = if_idx; |
914 | 914 | ||
915 | return skb->len; | 915 | return skb->len; |
916 | } | 916 | } |
917 | 917 | ||
918 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | 918 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) |
919 | { | 919 | { |
920 | struct sk_buff *msg; | 920 | struct sk_buff *msg; |
921 | struct cfg80211_registered_device *dev; | 921 | struct cfg80211_registered_device *dev; |
922 | struct net_device *netdev; | 922 | struct net_device *netdev; |
923 | int err; | 923 | int err; |
924 | 924 | ||
925 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); | 925 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); |
926 | if (err) | 926 | if (err) |
927 | return err; | 927 | return err; |
928 | 928 | ||
929 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 929 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
930 | if (!msg) | 930 | if (!msg) |
931 | goto out_err; | 931 | goto out_err; |
932 | 932 | ||
933 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 933 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
934 | dev, netdev) < 0) | 934 | dev, netdev) < 0) |
935 | goto out_free; | 935 | goto out_free; |
936 | 936 | ||
937 | dev_put(netdev); | 937 | dev_put(netdev); |
938 | cfg80211_unlock_rdev(dev); | 938 | cfg80211_unlock_rdev(dev); |
939 | 939 | ||
940 | return genlmsg_reply(msg, info); | 940 | return genlmsg_reply(msg, info); |
941 | 941 | ||
942 | out_free: | 942 | out_free: |
943 | nlmsg_free(msg); | 943 | nlmsg_free(msg); |
944 | out_err: | 944 | out_err: |
945 | dev_put(netdev); | 945 | dev_put(netdev); |
946 | cfg80211_unlock_rdev(dev); | 946 | cfg80211_unlock_rdev(dev); |
947 | return -ENOBUFS; | 947 | return -ENOBUFS; |
948 | } | 948 | } |
949 | 949 | ||
950 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | 950 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { |
951 | [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, | 951 | [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, |
952 | [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, | 952 | [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, |
953 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, | 953 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, |
954 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, | 954 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, |
955 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, | 955 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, |
956 | }; | 956 | }; |
957 | 957 | ||
958 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) | 958 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) |
959 | { | 959 | { |
960 | struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; | 960 | struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; |
961 | int flag; | 961 | int flag; |
962 | 962 | ||
963 | *mntrflags = 0; | 963 | *mntrflags = 0; |
964 | 964 | ||
965 | if (!nla) | 965 | if (!nla) |
966 | return -EINVAL; | 966 | return -EINVAL; |
967 | 967 | ||
968 | if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, | 968 | if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, |
969 | nla, mntr_flags_policy)) | 969 | nla, mntr_flags_policy)) |
970 | return -EINVAL; | 970 | return -EINVAL; |
971 | 971 | ||
972 | for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) | 972 | for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) |
973 | if (flags[flag]) | 973 | if (flags[flag]) |
974 | *mntrflags |= (1<<flag); | 974 | *mntrflags |= (1<<flag); |
975 | 975 | ||
976 | return 0; | 976 | return 0; |
977 | } | 977 | } |
978 | 978 | ||
979 | static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | 979 | static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, |
980 | struct net_device *netdev, u8 use_4addr, | 980 | struct net_device *netdev, u8 use_4addr, |
981 | enum nl80211_iftype iftype) | 981 | enum nl80211_iftype iftype) |
982 | { | 982 | { |
983 | if (!use_4addr) { | 983 | if (!use_4addr) { |
984 | if (netdev && netdev->br_port) | 984 | if (netdev && netdev->br_port) |
985 | return -EBUSY; | 985 | return -EBUSY; |
986 | return 0; | 986 | return 0; |
987 | } | 987 | } |
988 | 988 | ||
989 | switch (iftype) { | 989 | switch (iftype) { |
990 | case NL80211_IFTYPE_AP_VLAN: | 990 | case NL80211_IFTYPE_AP_VLAN: |
991 | if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP) | 991 | if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP) |
992 | return 0; | 992 | return 0; |
993 | break; | 993 | break; |
994 | case NL80211_IFTYPE_STATION: | 994 | case NL80211_IFTYPE_STATION: |
995 | if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION) | 995 | if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION) |
996 | return 0; | 996 | return 0; |
997 | break; | 997 | break; |
998 | default: | 998 | default: |
999 | break; | 999 | break; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | return -EOPNOTSUPP; | 1002 | return -EOPNOTSUPP; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 1005 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
1006 | { | 1006 | { |
1007 | struct cfg80211_registered_device *rdev; | 1007 | struct cfg80211_registered_device *rdev; |
1008 | struct vif_params params; | 1008 | struct vif_params params; |
1009 | int err; | 1009 | int err; |
1010 | enum nl80211_iftype otype, ntype; | 1010 | enum nl80211_iftype otype, ntype; |
1011 | struct net_device *dev; | 1011 | struct net_device *dev; |
1012 | u32 _flags, *flags = NULL; | 1012 | u32 _flags, *flags = NULL; |
1013 | bool change = false; | 1013 | bool change = false; |
1014 | 1014 | ||
1015 | memset(¶ms, 0, sizeof(params)); | 1015 | memset(¶ms, 0, sizeof(params)); |
1016 | 1016 | ||
1017 | rtnl_lock(); | 1017 | rtnl_lock(); |
1018 | 1018 | ||
1019 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1019 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1020 | if (err) | 1020 | if (err) |
1021 | goto unlock_rtnl; | 1021 | goto unlock_rtnl; |
1022 | 1022 | ||
1023 | otype = ntype = dev->ieee80211_ptr->iftype; | 1023 | otype = ntype = dev->ieee80211_ptr->iftype; |
1024 | 1024 | ||
1025 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 1025 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
1026 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 1026 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
1027 | if (otype != ntype) | 1027 | if (otype != ntype) |
1028 | change = true; | 1028 | change = true; |
1029 | if (ntype > NL80211_IFTYPE_MAX) { | 1029 | if (ntype > NL80211_IFTYPE_MAX) { |
1030 | err = -EINVAL; | 1030 | err = -EINVAL; |
1031 | goto unlock; | 1031 | goto unlock; |
1032 | } | 1032 | } |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1035 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1036 | if (ntype != NL80211_IFTYPE_MESH_POINT) { | 1036 | if (ntype != NL80211_IFTYPE_MESH_POINT) { |
1037 | err = -EINVAL; | 1037 | err = -EINVAL; |
1038 | goto unlock; | 1038 | goto unlock; |
1039 | } | 1039 | } |
1040 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1040 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
1041 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1041 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1042 | change = true; | 1042 | change = true; |
1043 | } | 1043 | } |
1044 | 1044 | ||
1045 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1045 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
1046 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1046 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1047 | change = true; | 1047 | change = true; |
1048 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); | 1048 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); |
1049 | if (err) | 1049 | if (err) |
1050 | goto unlock; | 1050 | goto unlock; |
1051 | } else { | 1051 | } else { |
1052 | params.use_4addr = -1; | 1052 | params.use_4addr = -1; |
1053 | } | 1053 | } |
1054 | 1054 | ||
1055 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1055 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
1056 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1056 | if (ntype != NL80211_IFTYPE_MONITOR) { |
1057 | err = -EINVAL; | 1057 | err = -EINVAL; |
1058 | goto unlock; | 1058 | goto unlock; |
1059 | } | 1059 | } |
1060 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 1060 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
1061 | &_flags); | 1061 | &_flags); |
1062 | if (err) | 1062 | if (err) |
1063 | goto unlock; | 1063 | goto unlock; |
1064 | 1064 | ||
1065 | flags = &_flags; | 1065 | flags = &_flags; |
1066 | change = true; | 1066 | change = true; |
1067 | } | 1067 | } |
1068 | 1068 | ||
1069 | if (change) | 1069 | if (change) |
1070 | err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); | 1070 | err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); |
1071 | else | 1071 | else |
1072 | err = 0; | 1072 | err = 0; |
1073 | 1073 | ||
1074 | if (!err && params.use_4addr != -1) | 1074 | if (!err && params.use_4addr != -1) |
1075 | dev->ieee80211_ptr->use_4addr = params.use_4addr; | 1075 | dev->ieee80211_ptr->use_4addr = params.use_4addr; |
1076 | 1076 | ||
1077 | unlock: | 1077 | unlock: |
1078 | dev_put(dev); | 1078 | dev_put(dev); |
1079 | cfg80211_unlock_rdev(rdev); | 1079 | cfg80211_unlock_rdev(rdev); |
1080 | unlock_rtnl: | 1080 | unlock_rtnl: |
1081 | rtnl_unlock(); | 1081 | rtnl_unlock(); |
1082 | return err; | 1082 | return err; |
1083 | } | 1083 | } |
1084 | 1084 | ||
1085 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 1085 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
1086 | { | 1086 | { |
1087 | struct cfg80211_registered_device *rdev; | 1087 | struct cfg80211_registered_device *rdev; |
1088 | struct vif_params params; | 1088 | struct vif_params params; |
1089 | int err; | 1089 | int err; |
1090 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1090 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1091 | u32 flags; | 1091 | u32 flags; |
1092 | 1092 | ||
1093 | memset(¶ms, 0, sizeof(params)); | 1093 | memset(¶ms, 0, sizeof(params)); |
1094 | 1094 | ||
1095 | if (!info->attrs[NL80211_ATTR_IFNAME]) | 1095 | if (!info->attrs[NL80211_ATTR_IFNAME]) |
1096 | return -EINVAL; | 1096 | return -EINVAL; |
1097 | 1097 | ||
1098 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 1098 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
1099 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 1099 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
1100 | if (type > NL80211_IFTYPE_MAX) | 1100 | if (type > NL80211_IFTYPE_MAX) |
1101 | return -EINVAL; | 1101 | return -EINVAL; |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | rtnl_lock(); | 1104 | rtnl_lock(); |
1105 | 1105 | ||
1106 | rdev = cfg80211_get_dev_from_info(info); | 1106 | rdev = cfg80211_get_dev_from_info(info); |
1107 | if (IS_ERR(rdev)) { | 1107 | if (IS_ERR(rdev)) { |
1108 | err = PTR_ERR(rdev); | 1108 | err = PTR_ERR(rdev); |
1109 | goto unlock_rtnl; | 1109 | goto unlock_rtnl; |
1110 | } | 1110 | } |
1111 | 1111 | ||
1112 | if (!rdev->ops->add_virtual_intf || | 1112 | if (!rdev->ops->add_virtual_intf || |
1113 | !(rdev->wiphy.interface_modes & (1 << type))) { | 1113 | !(rdev->wiphy.interface_modes & (1 << type))) { |
1114 | err = -EOPNOTSUPP; | 1114 | err = -EOPNOTSUPP; |
1115 | goto unlock; | 1115 | goto unlock; |
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | if (type == NL80211_IFTYPE_MESH_POINT && | 1118 | if (type == NL80211_IFTYPE_MESH_POINT && |
1119 | info->attrs[NL80211_ATTR_MESH_ID]) { | 1119 | info->attrs[NL80211_ATTR_MESH_ID]) { |
1120 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1120 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
1121 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1121 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1124 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
1125 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1125 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1126 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1126 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
1127 | if (err) | 1127 | if (err) |
1128 | goto unlock; | 1128 | goto unlock; |
1129 | } | 1129 | } |
1130 | 1130 | ||
1131 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1131 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1132 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 1132 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1133 | &flags); | 1133 | &flags); |
1134 | err = rdev->ops->add_virtual_intf(&rdev->wiphy, | 1134 | err = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1135 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1135 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1136 | type, err ? NULL : &flags, ¶ms); | 1136 | type, err ? NULL : &flags, ¶ms); |
1137 | 1137 | ||
1138 | unlock: | 1138 | unlock: |
1139 | cfg80211_unlock_rdev(rdev); | 1139 | cfg80211_unlock_rdev(rdev); |
1140 | unlock_rtnl: | 1140 | unlock_rtnl: |
1141 | rtnl_unlock(); | 1141 | rtnl_unlock(); |
1142 | return err; | 1142 | return err; |
1143 | } | 1143 | } |
1144 | 1144 | ||
1145 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1145 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1146 | { | 1146 | { |
1147 | struct cfg80211_registered_device *rdev; | 1147 | struct cfg80211_registered_device *rdev; |
1148 | int err; | 1148 | int err; |
1149 | struct net_device *dev; | 1149 | struct net_device *dev; |
1150 | 1150 | ||
1151 | rtnl_lock(); | 1151 | rtnl_lock(); |
1152 | 1152 | ||
1153 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1153 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1154 | if (err) | 1154 | if (err) |
1155 | goto unlock_rtnl; | 1155 | goto unlock_rtnl; |
1156 | 1156 | ||
1157 | if (!rdev->ops->del_virtual_intf) { | 1157 | if (!rdev->ops->del_virtual_intf) { |
1158 | err = -EOPNOTSUPP; | 1158 | err = -EOPNOTSUPP; |
1159 | goto out; | 1159 | goto out; |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | 1162 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1163 | 1163 | ||
1164 | out: | 1164 | out: |
1165 | cfg80211_unlock_rdev(rdev); | 1165 | cfg80211_unlock_rdev(rdev); |
1166 | dev_put(dev); | 1166 | dev_put(dev); |
1167 | unlock_rtnl: | 1167 | unlock_rtnl: |
1168 | rtnl_unlock(); | 1168 | rtnl_unlock(); |
1169 | return err; | 1169 | return err; |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | struct get_key_cookie { | 1172 | struct get_key_cookie { |
1173 | struct sk_buff *msg; | 1173 | struct sk_buff *msg; |
1174 | int error; | 1174 | int error; |
1175 | int idx; | 1175 | int idx; |
1176 | }; | 1176 | }; |
1177 | 1177 | ||
1178 | static void get_key_callback(void *c, struct key_params *params) | 1178 | static void get_key_callback(void *c, struct key_params *params) |
1179 | { | 1179 | { |
1180 | struct nlattr *key; | 1180 | struct nlattr *key; |
1181 | struct get_key_cookie *cookie = c; | 1181 | struct get_key_cookie *cookie = c; |
1182 | 1182 | ||
1183 | if (params->key) | 1183 | if (params->key) |
1184 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, | 1184 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, |
1185 | params->key_len, params->key); | 1185 | params->key_len, params->key); |
1186 | 1186 | ||
1187 | if (params->seq) | 1187 | if (params->seq) |
1188 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, | 1188 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, |
1189 | params->seq_len, params->seq); | 1189 | params->seq_len, params->seq); |
1190 | 1190 | ||
1191 | if (params->cipher) | 1191 | if (params->cipher) |
1192 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, | 1192 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, |
1193 | params->cipher); | 1193 | params->cipher); |
1194 | 1194 | ||
1195 | key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY); | 1195 | key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY); |
1196 | if (!key) | 1196 | if (!key) |
1197 | goto nla_put_failure; | 1197 | goto nla_put_failure; |
1198 | 1198 | ||
1199 | if (params->key) | 1199 | if (params->key) |
1200 | NLA_PUT(cookie->msg, NL80211_KEY_DATA, | 1200 | NLA_PUT(cookie->msg, NL80211_KEY_DATA, |
1201 | params->key_len, params->key); | 1201 | params->key_len, params->key); |
1202 | 1202 | ||
1203 | if (params->seq) | 1203 | if (params->seq) |
1204 | NLA_PUT(cookie->msg, NL80211_KEY_SEQ, | 1204 | NLA_PUT(cookie->msg, NL80211_KEY_SEQ, |
1205 | params->seq_len, params->seq); | 1205 | params->seq_len, params->seq); |
1206 | 1206 | ||
1207 | if (params->cipher) | 1207 | if (params->cipher) |
1208 | NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER, | 1208 | NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER, |
1209 | params->cipher); | 1209 | params->cipher); |
1210 | 1210 | ||
1211 | NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx); | 1211 | NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx); |
1212 | 1212 | ||
1213 | nla_nest_end(cookie->msg, key); | 1213 | nla_nest_end(cookie->msg, key); |
1214 | 1214 | ||
1215 | return; | 1215 | return; |
1216 | nla_put_failure: | 1216 | nla_put_failure: |
1217 | cookie->error = 1; | 1217 | cookie->error = 1; |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | 1220 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) |
1221 | { | 1221 | { |
1222 | struct cfg80211_registered_device *rdev; | 1222 | struct cfg80211_registered_device *rdev; |
1223 | int err; | 1223 | int err; |
1224 | struct net_device *dev; | 1224 | struct net_device *dev; |
1225 | u8 key_idx = 0; | 1225 | u8 key_idx = 0; |
1226 | u8 *mac_addr = NULL; | 1226 | u8 *mac_addr = NULL; |
1227 | struct get_key_cookie cookie = { | 1227 | struct get_key_cookie cookie = { |
1228 | .error = 0, | 1228 | .error = 0, |
1229 | }; | 1229 | }; |
1230 | void *hdr; | 1230 | void *hdr; |
1231 | struct sk_buff *msg; | 1231 | struct sk_buff *msg; |
1232 | 1232 | ||
1233 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 1233 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
1234 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 1234 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
1235 | 1235 | ||
1236 | if (key_idx > 5) | 1236 | if (key_idx > 5) |
1237 | return -EINVAL; | 1237 | return -EINVAL; |
1238 | 1238 | ||
1239 | if (info->attrs[NL80211_ATTR_MAC]) | 1239 | if (info->attrs[NL80211_ATTR_MAC]) |
1240 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1240 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1241 | 1241 | ||
1242 | rtnl_lock(); | 1242 | rtnl_lock(); |
1243 | 1243 | ||
1244 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1244 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1245 | if (err) | 1245 | if (err) |
1246 | goto unlock_rtnl; | 1246 | goto unlock_rtnl; |
1247 | 1247 | ||
1248 | if (!rdev->ops->get_key) { | 1248 | if (!rdev->ops->get_key) { |
1249 | err = -EOPNOTSUPP; | 1249 | err = -EOPNOTSUPP; |
1250 | goto out; | 1250 | goto out; |
1251 | } | 1251 | } |
1252 | 1252 | ||
1253 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1253 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1254 | if (!msg) { | 1254 | if (!msg) { |
1255 | err = -ENOMEM; | 1255 | err = -ENOMEM; |
1256 | goto out; | 1256 | goto out; |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 1259 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
1260 | NL80211_CMD_NEW_KEY); | 1260 | NL80211_CMD_NEW_KEY); |
1261 | 1261 | ||
1262 | if (IS_ERR(hdr)) { | 1262 | if (IS_ERR(hdr)) { |
1263 | err = PTR_ERR(hdr); | 1263 | err = PTR_ERR(hdr); |
1264 | goto free_msg; | 1264 | goto free_msg; |
1265 | } | 1265 | } |
1266 | 1266 | ||
1267 | cookie.msg = msg; | 1267 | cookie.msg = msg; |
1268 | cookie.idx = key_idx; | 1268 | cookie.idx = key_idx; |
1269 | 1269 | ||
1270 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1270 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1271 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); | 1271 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); |
1272 | if (mac_addr) | 1272 | if (mac_addr) |
1273 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1273 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1274 | 1274 | ||
1275 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, | 1275 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, |
1276 | &cookie, get_key_callback); | 1276 | &cookie, get_key_callback); |
1277 | 1277 | ||
1278 | if (err) | 1278 | if (err) |
1279 | goto free_msg; | 1279 | goto free_msg; |
1280 | 1280 | ||
1281 | if (cookie.error) | 1281 | if (cookie.error) |
1282 | goto nla_put_failure; | 1282 | goto nla_put_failure; |
1283 | 1283 | ||
1284 | genlmsg_end(msg, hdr); | 1284 | genlmsg_end(msg, hdr); |
1285 | err = genlmsg_reply(msg, info); | 1285 | err = genlmsg_reply(msg, info); |
1286 | goto out; | 1286 | goto out; |
1287 | 1287 | ||
1288 | nla_put_failure: | 1288 | nla_put_failure: |
1289 | err = -ENOBUFS; | 1289 | err = -ENOBUFS; |
1290 | free_msg: | 1290 | free_msg: |
1291 | nlmsg_free(msg); | 1291 | nlmsg_free(msg); |
1292 | out: | 1292 | out: |
1293 | cfg80211_unlock_rdev(rdev); | 1293 | cfg80211_unlock_rdev(rdev); |
1294 | dev_put(dev); | 1294 | dev_put(dev); |
1295 | unlock_rtnl: | 1295 | unlock_rtnl: |
1296 | rtnl_unlock(); | 1296 | rtnl_unlock(); |
1297 | 1297 | ||
1298 | return err; | 1298 | return err; |
1299 | } | 1299 | } |
1300 | 1300 | ||
1301 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 1301 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
1302 | { | 1302 | { |
1303 | struct cfg80211_registered_device *rdev; | 1303 | struct cfg80211_registered_device *rdev; |
1304 | struct key_parse key; | 1304 | struct key_parse key; |
1305 | int err; | 1305 | int err; |
1306 | struct net_device *dev; | 1306 | struct net_device *dev; |
1307 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | 1307 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, |
1308 | u8 key_index); | 1308 | u8 key_index); |
1309 | 1309 | ||
1310 | err = nl80211_parse_key(info, &key); | 1310 | err = nl80211_parse_key(info, &key); |
1311 | if (err) | 1311 | if (err) |
1312 | return err; | 1312 | return err; |
1313 | 1313 | ||
1314 | if (key.idx < 0) | 1314 | if (key.idx < 0) |
1315 | return -EINVAL; | 1315 | return -EINVAL; |
1316 | 1316 | ||
1317 | /* only support setting default key */ | 1317 | /* only support setting default key */ |
1318 | if (!key.def && !key.defmgmt) | 1318 | if (!key.def && !key.defmgmt) |
1319 | return -EINVAL; | 1319 | return -EINVAL; |
1320 | 1320 | ||
1321 | rtnl_lock(); | 1321 | rtnl_lock(); |
1322 | 1322 | ||
1323 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1323 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1324 | if (err) | 1324 | if (err) |
1325 | goto unlock_rtnl; | 1325 | goto unlock_rtnl; |
1326 | 1326 | ||
1327 | if (key.def) | 1327 | if (key.def) |
1328 | func = rdev->ops->set_default_key; | 1328 | func = rdev->ops->set_default_key; |
1329 | else | 1329 | else |
1330 | func = rdev->ops->set_default_mgmt_key; | 1330 | func = rdev->ops->set_default_mgmt_key; |
1331 | 1331 | ||
1332 | if (!func) { | 1332 | if (!func) { |
1333 | err = -EOPNOTSUPP; | 1333 | err = -EOPNOTSUPP; |
1334 | goto out; | 1334 | goto out; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | wdev_lock(dev->ieee80211_ptr); | 1337 | wdev_lock(dev->ieee80211_ptr); |
1338 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1338 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1339 | if (!err) | 1339 | if (!err) |
1340 | err = func(&rdev->wiphy, dev, key.idx); | 1340 | err = func(&rdev->wiphy, dev, key.idx); |
1341 | 1341 | ||
1342 | #ifdef CONFIG_CFG80211_WEXT | 1342 | #ifdef CONFIG_CFG80211_WEXT |
1343 | if (!err) { | 1343 | if (!err) { |
1344 | if (func == rdev->ops->set_default_key) | 1344 | if (func == rdev->ops->set_default_key) |
1345 | dev->ieee80211_ptr->wext.default_key = key.idx; | 1345 | dev->ieee80211_ptr->wext.default_key = key.idx; |
1346 | else | 1346 | else |
1347 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | 1347 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; |
1348 | } | 1348 | } |
1349 | #endif | 1349 | #endif |
1350 | wdev_unlock(dev->ieee80211_ptr); | 1350 | wdev_unlock(dev->ieee80211_ptr); |
1351 | 1351 | ||
1352 | out: | 1352 | out: |
1353 | cfg80211_unlock_rdev(rdev); | 1353 | cfg80211_unlock_rdev(rdev); |
1354 | dev_put(dev); | 1354 | dev_put(dev); |
1355 | 1355 | ||
1356 | unlock_rtnl: | 1356 | unlock_rtnl: |
1357 | rtnl_unlock(); | 1357 | rtnl_unlock(); |
1358 | 1358 | ||
1359 | return err; | 1359 | return err; |
1360 | } | 1360 | } |
1361 | 1361 | ||
1362 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1362 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
1363 | { | 1363 | { |
1364 | struct cfg80211_registered_device *rdev; | 1364 | struct cfg80211_registered_device *rdev; |
1365 | int err; | 1365 | int err; |
1366 | struct net_device *dev; | 1366 | struct net_device *dev; |
1367 | struct key_parse key; | 1367 | struct key_parse key; |
1368 | u8 *mac_addr = NULL; | 1368 | u8 *mac_addr = NULL; |
1369 | 1369 | ||
1370 | err = nl80211_parse_key(info, &key); | 1370 | err = nl80211_parse_key(info, &key); |
1371 | if (err) | 1371 | if (err) |
1372 | return err; | 1372 | return err; |
1373 | 1373 | ||
1374 | if (!key.p.key) | 1374 | if (!key.p.key) |
1375 | return -EINVAL; | 1375 | return -EINVAL; |
1376 | 1376 | ||
1377 | if (info->attrs[NL80211_ATTR_MAC]) | 1377 | if (info->attrs[NL80211_ATTR_MAC]) |
1378 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1378 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1379 | 1379 | ||
1380 | rtnl_lock(); | 1380 | rtnl_lock(); |
1381 | 1381 | ||
1382 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1382 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1383 | if (err) | 1383 | if (err) |
1384 | goto unlock_rtnl; | 1384 | goto unlock_rtnl; |
1385 | 1385 | ||
1386 | if (!rdev->ops->add_key) { | 1386 | if (!rdev->ops->add_key) { |
1387 | err = -EOPNOTSUPP; | 1387 | err = -EOPNOTSUPP; |
1388 | goto out; | 1388 | goto out; |
1389 | } | 1389 | } |
1390 | 1390 | ||
1391 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { | 1391 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { |
1392 | err = -EINVAL; | 1392 | err = -EINVAL; |
1393 | goto out; | 1393 | goto out; |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | wdev_lock(dev->ieee80211_ptr); | 1396 | wdev_lock(dev->ieee80211_ptr); |
1397 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1397 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1398 | if (!err) | 1398 | if (!err) |
1399 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, | 1399 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, |
1400 | mac_addr, &key.p); | 1400 | mac_addr, &key.p); |
1401 | wdev_unlock(dev->ieee80211_ptr); | 1401 | wdev_unlock(dev->ieee80211_ptr); |
1402 | 1402 | ||
1403 | out: | 1403 | out: |
1404 | cfg80211_unlock_rdev(rdev); | 1404 | cfg80211_unlock_rdev(rdev); |
1405 | dev_put(dev); | 1405 | dev_put(dev); |
1406 | unlock_rtnl: | 1406 | unlock_rtnl: |
1407 | rtnl_unlock(); | 1407 | rtnl_unlock(); |
1408 | 1408 | ||
1409 | return err; | 1409 | return err; |
1410 | } | 1410 | } |
1411 | 1411 | ||
1412 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | 1412 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) |
1413 | { | 1413 | { |
1414 | struct cfg80211_registered_device *rdev; | 1414 | struct cfg80211_registered_device *rdev; |
1415 | int err; | 1415 | int err; |
1416 | struct net_device *dev; | 1416 | struct net_device *dev; |
1417 | u8 *mac_addr = NULL; | 1417 | u8 *mac_addr = NULL; |
1418 | struct key_parse key; | 1418 | struct key_parse key; |
1419 | 1419 | ||
1420 | err = nl80211_parse_key(info, &key); | 1420 | err = nl80211_parse_key(info, &key); |
1421 | if (err) | 1421 | if (err) |
1422 | return err; | 1422 | return err; |
1423 | 1423 | ||
1424 | if (info->attrs[NL80211_ATTR_MAC]) | 1424 | if (info->attrs[NL80211_ATTR_MAC]) |
1425 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1425 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1426 | 1426 | ||
1427 | rtnl_lock(); | 1427 | rtnl_lock(); |
1428 | 1428 | ||
1429 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1429 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1430 | if (err) | 1430 | if (err) |
1431 | goto unlock_rtnl; | 1431 | goto unlock_rtnl; |
1432 | 1432 | ||
1433 | if (!rdev->ops->del_key) { | 1433 | if (!rdev->ops->del_key) { |
1434 | err = -EOPNOTSUPP; | 1434 | err = -EOPNOTSUPP; |
1435 | goto out; | 1435 | goto out; |
1436 | } | 1436 | } |
1437 | 1437 | ||
1438 | wdev_lock(dev->ieee80211_ptr); | 1438 | wdev_lock(dev->ieee80211_ptr); |
1439 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1439 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1440 | if (!err) | 1440 | if (!err) |
1441 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); | 1441 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); |
1442 | 1442 | ||
1443 | #ifdef CONFIG_CFG80211_WEXT | 1443 | #ifdef CONFIG_CFG80211_WEXT |
1444 | if (!err) { | 1444 | if (!err) { |
1445 | if (key.idx == dev->ieee80211_ptr->wext.default_key) | 1445 | if (key.idx == dev->ieee80211_ptr->wext.default_key) |
1446 | dev->ieee80211_ptr->wext.default_key = -1; | 1446 | dev->ieee80211_ptr->wext.default_key = -1; |
1447 | else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key) | 1447 | else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key) |
1448 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | 1448 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; |
1449 | } | 1449 | } |
1450 | #endif | 1450 | #endif |
1451 | wdev_unlock(dev->ieee80211_ptr); | 1451 | wdev_unlock(dev->ieee80211_ptr); |
1452 | 1452 | ||
1453 | out: | 1453 | out: |
1454 | cfg80211_unlock_rdev(rdev); | 1454 | cfg80211_unlock_rdev(rdev); |
1455 | dev_put(dev); | 1455 | dev_put(dev); |
1456 | 1456 | ||
1457 | unlock_rtnl: | 1457 | unlock_rtnl: |
1458 | rtnl_unlock(); | 1458 | rtnl_unlock(); |
1459 | 1459 | ||
1460 | return err; | 1460 | return err; |
1461 | } | 1461 | } |
1462 | 1462 | ||
1463 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | 1463 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) |
1464 | { | 1464 | { |
1465 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | 1465 | int (*call)(struct wiphy *wiphy, struct net_device *dev, |
1466 | struct beacon_parameters *info); | 1466 | struct beacon_parameters *info); |
1467 | struct cfg80211_registered_device *rdev; | 1467 | struct cfg80211_registered_device *rdev; |
1468 | int err; | 1468 | int err; |
1469 | struct net_device *dev; | 1469 | struct net_device *dev; |
1470 | struct beacon_parameters params; | 1470 | struct beacon_parameters params; |
1471 | int haveinfo = 0; | 1471 | int haveinfo = 0; |
1472 | 1472 | ||
1473 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1473 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1474 | return -EINVAL; | 1474 | return -EINVAL; |
1475 | 1475 | ||
1476 | rtnl_lock(); | 1476 | rtnl_lock(); |
1477 | 1477 | ||
1478 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1478 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1479 | if (err) | 1479 | if (err) |
1480 | goto unlock_rtnl; | 1480 | goto unlock_rtnl; |
1481 | 1481 | ||
1482 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | 1482 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
1483 | err = -EOPNOTSUPP; | 1483 | err = -EOPNOTSUPP; |
1484 | goto out; | 1484 | goto out; |
1485 | } | 1485 | } |
1486 | 1486 | ||
1487 | switch (info->genlhdr->cmd) { | 1487 | switch (info->genlhdr->cmd) { |
1488 | case NL80211_CMD_NEW_BEACON: | 1488 | case NL80211_CMD_NEW_BEACON: |
1489 | /* these are required for NEW_BEACON */ | 1489 | /* these are required for NEW_BEACON */ |
1490 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | 1490 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
1491 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | 1491 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
1492 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1492 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { |
1493 | err = -EINVAL; | 1493 | err = -EINVAL; |
1494 | goto out; | 1494 | goto out; |
1495 | } | 1495 | } |
1496 | 1496 | ||
1497 | call = rdev->ops->add_beacon; | 1497 | call = rdev->ops->add_beacon; |
1498 | break; | 1498 | break; |
1499 | case NL80211_CMD_SET_BEACON: | 1499 | case NL80211_CMD_SET_BEACON: |
1500 | call = rdev->ops->set_beacon; | 1500 | call = rdev->ops->set_beacon; |
1501 | break; | 1501 | break; |
1502 | default: | 1502 | default: |
1503 | WARN_ON(1); | 1503 | WARN_ON(1); |
1504 | err = -EOPNOTSUPP; | 1504 | err = -EOPNOTSUPP; |
1505 | goto out; | 1505 | goto out; |
1506 | } | 1506 | } |
1507 | 1507 | ||
1508 | if (!call) { | 1508 | if (!call) { |
1509 | err = -EOPNOTSUPP; | 1509 | err = -EOPNOTSUPP; |
1510 | goto out; | 1510 | goto out; |
1511 | } | 1511 | } |
1512 | 1512 | ||
1513 | memset(¶ms, 0, sizeof(params)); | 1513 | memset(¶ms, 0, sizeof(params)); |
1514 | 1514 | ||
1515 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | 1515 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { |
1516 | params.interval = | 1516 | params.interval = |
1517 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | 1517 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); |
1518 | haveinfo = 1; | 1518 | haveinfo = 1; |
1519 | } | 1519 | } |
1520 | 1520 | ||
1521 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { | 1521 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { |
1522 | params.dtim_period = | 1522 | params.dtim_period = |
1523 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | 1523 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); |
1524 | haveinfo = 1; | 1524 | haveinfo = 1; |
1525 | } | 1525 | } |
1526 | 1526 | ||
1527 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1527 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { |
1528 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 1528 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); |
1529 | params.head_len = | 1529 | params.head_len = |
1530 | nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 1530 | nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); |
1531 | haveinfo = 1; | 1531 | haveinfo = 1; |
1532 | } | 1532 | } |
1533 | 1533 | ||
1534 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { | 1534 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { |
1535 | params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); | 1535 | params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); |
1536 | params.tail_len = | 1536 | params.tail_len = |
1537 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); | 1537 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); |
1538 | haveinfo = 1; | 1538 | haveinfo = 1; |
1539 | } | 1539 | } |
1540 | 1540 | ||
1541 | if (!haveinfo) { | 1541 | if (!haveinfo) { |
1542 | err = -EINVAL; | 1542 | err = -EINVAL; |
1543 | goto out; | 1543 | goto out; |
1544 | } | 1544 | } |
1545 | 1545 | ||
1546 | err = call(&rdev->wiphy, dev, ¶ms); | 1546 | err = call(&rdev->wiphy, dev, ¶ms); |
1547 | 1547 | ||
1548 | out: | 1548 | out: |
1549 | cfg80211_unlock_rdev(rdev); | 1549 | cfg80211_unlock_rdev(rdev); |
1550 | dev_put(dev); | 1550 | dev_put(dev); |
1551 | unlock_rtnl: | 1551 | unlock_rtnl: |
1552 | rtnl_unlock(); | 1552 | rtnl_unlock(); |
1553 | 1553 | ||
1554 | return err; | 1554 | return err; |
1555 | } | 1555 | } |
1556 | 1556 | ||
1557 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 1557 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1558 | { | 1558 | { |
1559 | struct cfg80211_registered_device *rdev; | 1559 | struct cfg80211_registered_device *rdev; |
1560 | int err; | 1560 | int err; |
1561 | struct net_device *dev; | 1561 | struct net_device *dev; |
1562 | 1562 | ||
1563 | rtnl_lock(); | 1563 | rtnl_lock(); |
1564 | 1564 | ||
1565 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1565 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1566 | if (err) | 1566 | if (err) |
1567 | goto unlock_rtnl; | 1567 | goto unlock_rtnl; |
1568 | 1568 | ||
1569 | if (!rdev->ops->del_beacon) { | 1569 | if (!rdev->ops->del_beacon) { |
1570 | err = -EOPNOTSUPP; | 1570 | err = -EOPNOTSUPP; |
1571 | goto out; | 1571 | goto out; |
1572 | } | 1572 | } |
1573 | 1573 | ||
1574 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | 1574 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
1575 | err = -EOPNOTSUPP; | 1575 | err = -EOPNOTSUPP; |
1576 | goto out; | 1576 | goto out; |
1577 | } | 1577 | } |
1578 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); | 1578 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); |
1579 | 1579 | ||
1580 | out: | 1580 | out: |
1581 | cfg80211_unlock_rdev(rdev); | 1581 | cfg80211_unlock_rdev(rdev); |
1582 | dev_put(dev); | 1582 | dev_put(dev); |
1583 | unlock_rtnl: | 1583 | unlock_rtnl: |
1584 | rtnl_unlock(); | 1584 | rtnl_unlock(); |
1585 | 1585 | ||
1586 | return err; | 1586 | return err; |
1587 | } | 1587 | } |
1588 | 1588 | ||
1589 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 1589 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
1590 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, | 1590 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, |
1591 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, | 1591 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, |
1592 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, | 1592 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, |
1593 | [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, | 1593 | [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, |
1594 | }; | 1594 | }; |
1595 | 1595 | ||
1596 | static int parse_station_flags(struct genl_info *info, | 1596 | static int parse_station_flags(struct genl_info *info, |
1597 | struct station_parameters *params) | 1597 | struct station_parameters *params) |
1598 | { | 1598 | { |
1599 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; | 1599 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; |
1600 | struct nlattr *nla; | 1600 | struct nlattr *nla; |
1601 | int flag; | 1601 | int flag; |
1602 | 1602 | ||
1603 | /* | 1603 | /* |
1604 | * Try parsing the new attribute first so userspace | 1604 | * Try parsing the new attribute first so userspace |
1605 | * can specify both for older kernels. | 1605 | * can specify both for older kernels. |
1606 | */ | 1606 | */ |
1607 | nla = info->attrs[NL80211_ATTR_STA_FLAGS2]; | 1607 | nla = info->attrs[NL80211_ATTR_STA_FLAGS2]; |
1608 | if (nla) { | 1608 | if (nla) { |
1609 | struct nl80211_sta_flag_update *sta_flags; | 1609 | struct nl80211_sta_flag_update *sta_flags; |
1610 | 1610 | ||
1611 | sta_flags = nla_data(nla); | 1611 | sta_flags = nla_data(nla); |
1612 | params->sta_flags_mask = sta_flags->mask; | 1612 | params->sta_flags_mask = sta_flags->mask; |
1613 | params->sta_flags_set = sta_flags->set; | 1613 | params->sta_flags_set = sta_flags->set; |
1614 | if ((params->sta_flags_mask | | 1614 | if ((params->sta_flags_mask | |
1615 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) | 1615 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) |
1616 | return -EINVAL; | 1616 | return -EINVAL; |
1617 | return 0; | 1617 | return 0; |
1618 | } | 1618 | } |
1619 | 1619 | ||
1620 | /* if present, parse the old attribute */ | 1620 | /* if present, parse the old attribute */ |
1621 | 1621 | ||
1622 | nla = info->attrs[NL80211_ATTR_STA_FLAGS]; | 1622 | nla = info->attrs[NL80211_ATTR_STA_FLAGS]; |
1623 | if (!nla) | 1623 | if (!nla) |
1624 | return 0; | 1624 | return 0; |
1625 | 1625 | ||
1626 | if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, | 1626 | if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, |
1627 | nla, sta_flags_policy)) | 1627 | nla, sta_flags_policy)) |
1628 | return -EINVAL; | 1628 | return -EINVAL; |
1629 | 1629 | ||
1630 | params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1; | 1630 | params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1; |
1631 | params->sta_flags_mask &= ~1; | 1631 | params->sta_flags_mask &= ~1; |
1632 | 1632 | ||
1633 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) | 1633 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) |
1634 | if (flags[flag]) | 1634 | if (flags[flag]) |
1635 | params->sta_flags_set |= (1<<flag); | 1635 | params->sta_flags_set |= (1<<flag); |
1636 | 1636 | ||
1637 | return 0; | 1637 | return 0; |
1638 | } | 1638 | } |
1639 | 1639 | ||
1640 | static u16 nl80211_calculate_bitrate(struct rate_info *rate) | ||
1641 | { | ||
1642 | int modulation, streams, bitrate; | ||
1643 | |||
1644 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | ||
1645 | return rate->legacy; | ||
1646 | |||
1647 | /* the formula below does only work for MCS values smaller than 32 */ | ||
1648 | if (rate->mcs >= 32) | ||
1649 | return 0; | ||
1650 | |||
1651 | modulation = rate->mcs & 7; | ||
1652 | streams = (rate->mcs >> 3) + 1; | ||
1653 | |||
1654 | bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? | ||
1655 | 13500000 : 6500000; | ||
1656 | |||
1657 | if (modulation < 4) | ||
1658 | bitrate *= (modulation + 1); | ||
1659 | else if (modulation == 4) | ||
1660 | bitrate *= (modulation + 2); | ||
1661 | else | ||
1662 | bitrate *= (modulation + 3); | ||
1663 | |||
1664 | bitrate *= streams; | ||
1665 | |||
1666 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | ||
1667 | bitrate = (bitrate / 9) * 10; | ||
1668 | |||
1669 | /* do NOT round down here */ | ||
1670 | return (bitrate + 50000) / 100000; | ||
1671 | } | ||
1672 | |||
1673 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | 1640 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, |
1674 | int flags, struct net_device *dev, | 1641 | int flags, struct net_device *dev, |
1675 | u8 *mac_addr, struct station_info *sinfo) | 1642 | u8 *mac_addr, struct station_info *sinfo) |
1676 | { | 1643 | { |
1677 | void *hdr; | 1644 | void *hdr; |
1678 | struct nlattr *sinfoattr, *txrate; | 1645 | struct nlattr *sinfoattr, *txrate; |
1679 | u16 bitrate; | 1646 | u16 bitrate; |
1680 | 1647 | ||
1681 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 1648 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
1682 | if (!hdr) | 1649 | if (!hdr) |
1683 | return -1; | 1650 | return -1; |
1684 | 1651 | ||
1685 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1652 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1686 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1653 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1687 | 1654 | ||
1688 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); | 1655 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); |
1689 | 1656 | ||
1690 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 1657 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
1691 | if (!sinfoattr) | 1658 | if (!sinfoattr) |
1692 | goto nla_put_failure; | 1659 | goto nla_put_failure; |
1693 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) | 1660 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) |
1694 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 1661 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, |
1695 | sinfo->inactive_time); | 1662 | sinfo->inactive_time); |
1696 | if (sinfo->filled & STATION_INFO_RX_BYTES) | 1663 | if (sinfo->filled & STATION_INFO_RX_BYTES) |
1697 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, | 1664 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, |
1698 | sinfo->rx_bytes); | 1665 | sinfo->rx_bytes); |
1699 | if (sinfo->filled & STATION_INFO_TX_BYTES) | 1666 | if (sinfo->filled & STATION_INFO_TX_BYTES) |
1700 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, | 1667 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, |
1701 | sinfo->tx_bytes); | 1668 | sinfo->tx_bytes); |
1702 | if (sinfo->filled & STATION_INFO_LLID) | 1669 | if (sinfo->filled & STATION_INFO_LLID) |
1703 | NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, | 1670 | NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, |
1704 | sinfo->llid); | 1671 | sinfo->llid); |
1705 | if (sinfo->filled & STATION_INFO_PLID) | 1672 | if (sinfo->filled & STATION_INFO_PLID) |
1706 | NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, | 1673 | NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, |
1707 | sinfo->plid); | 1674 | sinfo->plid); |
1708 | if (sinfo->filled & STATION_INFO_PLINK_STATE) | 1675 | if (sinfo->filled & STATION_INFO_PLINK_STATE) |
1709 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, | 1676 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, |
1710 | sinfo->plink_state); | 1677 | sinfo->plink_state); |
1711 | if (sinfo->filled & STATION_INFO_SIGNAL) | 1678 | if (sinfo->filled & STATION_INFO_SIGNAL) |
1712 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, | 1679 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, |
1713 | sinfo->signal); | 1680 | sinfo->signal); |
1714 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 1681 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { |
1715 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); | 1682 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); |
1716 | if (!txrate) | 1683 | if (!txrate) |
1717 | goto nla_put_failure; | 1684 | goto nla_put_failure; |
1718 | 1685 | ||
1719 | /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ | 1686 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
1720 | bitrate = nl80211_calculate_bitrate(&sinfo->txrate); | 1687 | bitrate = cfg80211_calculate_bitrate(&sinfo->txrate); |
1721 | if (bitrate > 0) | 1688 | if (bitrate > 0) |
1722 | NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); | 1689 | NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); |
1723 | 1690 | ||
1724 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) | 1691 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) |
1725 | NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, | 1692 | NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, |
1726 | sinfo->txrate.mcs); | 1693 | sinfo->txrate.mcs); |
1727 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) | 1694 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) |
1728 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); | 1695 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); |
1729 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) | 1696 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) |
1730 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); | 1697 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); |
1731 | 1698 | ||
1732 | nla_nest_end(msg, txrate); | 1699 | nla_nest_end(msg, txrate); |
1733 | } | 1700 | } |
1734 | if (sinfo->filled & STATION_INFO_RX_PACKETS) | 1701 | if (sinfo->filled & STATION_INFO_RX_PACKETS) |
1735 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS, | 1702 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS, |
1736 | sinfo->rx_packets); | 1703 | sinfo->rx_packets); |
1737 | if (sinfo->filled & STATION_INFO_TX_PACKETS) | 1704 | if (sinfo->filled & STATION_INFO_TX_PACKETS) |
1738 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, | 1705 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, |
1739 | sinfo->tx_packets); | 1706 | sinfo->tx_packets); |
1740 | nla_nest_end(msg, sinfoattr); | 1707 | nla_nest_end(msg, sinfoattr); |
1741 | 1708 | ||
1742 | return genlmsg_end(msg, hdr); | 1709 | return genlmsg_end(msg, hdr); |
1743 | 1710 | ||
1744 | nla_put_failure: | 1711 | nla_put_failure: |
1745 | genlmsg_cancel(msg, hdr); | 1712 | genlmsg_cancel(msg, hdr); |
1746 | return -EMSGSIZE; | 1713 | return -EMSGSIZE; |
1747 | } | 1714 | } |
1748 | 1715 | ||
1749 | static int nl80211_dump_station(struct sk_buff *skb, | 1716 | static int nl80211_dump_station(struct sk_buff *skb, |
1750 | struct netlink_callback *cb) | 1717 | struct netlink_callback *cb) |
1751 | { | 1718 | { |
1752 | struct station_info sinfo; | 1719 | struct station_info sinfo; |
1753 | struct cfg80211_registered_device *dev; | 1720 | struct cfg80211_registered_device *dev; |
1754 | struct net_device *netdev; | 1721 | struct net_device *netdev; |
1755 | u8 mac_addr[ETH_ALEN]; | 1722 | u8 mac_addr[ETH_ALEN]; |
1756 | int ifidx = cb->args[0]; | 1723 | int ifidx = cb->args[0]; |
1757 | int sta_idx = cb->args[1]; | 1724 | int sta_idx = cb->args[1]; |
1758 | int err; | 1725 | int err; |
1759 | 1726 | ||
1760 | if (!ifidx) | 1727 | if (!ifidx) |
1761 | ifidx = nl80211_get_ifidx(cb); | 1728 | ifidx = nl80211_get_ifidx(cb); |
1762 | if (ifidx < 0) | 1729 | if (ifidx < 0) |
1763 | return ifidx; | 1730 | return ifidx; |
1764 | 1731 | ||
1765 | rtnl_lock(); | 1732 | rtnl_lock(); |
1766 | 1733 | ||
1767 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | 1734 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
1768 | if (!netdev) { | 1735 | if (!netdev) { |
1769 | err = -ENODEV; | 1736 | err = -ENODEV; |
1770 | goto out_rtnl; | 1737 | goto out_rtnl; |
1771 | } | 1738 | } |
1772 | 1739 | ||
1773 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | 1740 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
1774 | if (IS_ERR(dev)) { | 1741 | if (IS_ERR(dev)) { |
1775 | err = PTR_ERR(dev); | 1742 | err = PTR_ERR(dev); |
1776 | goto out_rtnl; | 1743 | goto out_rtnl; |
1777 | } | 1744 | } |
1778 | 1745 | ||
1779 | if (!dev->ops->dump_station) { | 1746 | if (!dev->ops->dump_station) { |
1780 | err = -EOPNOTSUPP; | 1747 | err = -EOPNOTSUPP; |
1781 | goto out_err; | 1748 | goto out_err; |
1782 | } | 1749 | } |
1783 | 1750 | ||
1784 | while (1) { | 1751 | while (1) { |
1785 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, | 1752 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, |
1786 | mac_addr, &sinfo); | 1753 | mac_addr, &sinfo); |
1787 | if (err == -ENOENT) | 1754 | if (err == -ENOENT) |
1788 | break; | 1755 | break; |
1789 | if (err) | 1756 | if (err) |
1790 | goto out_err; | 1757 | goto out_err; |
1791 | 1758 | ||
1792 | if (nl80211_send_station(skb, | 1759 | if (nl80211_send_station(skb, |
1793 | NETLINK_CB(cb->skb).pid, | 1760 | NETLINK_CB(cb->skb).pid, |
1794 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1761 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1795 | netdev, mac_addr, | 1762 | netdev, mac_addr, |
1796 | &sinfo) < 0) | 1763 | &sinfo) < 0) |
1797 | goto out; | 1764 | goto out; |
1798 | 1765 | ||
1799 | sta_idx++; | 1766 | sta_idx++; |
1800 | } | 1767 | } |
1801 | 1768 | ||
1802 | 1769 | ||
1803 | out: | 1770 | out: |
1804 | cb->args[1] = sta_idx; | 1771 | cb->args[1] = sta_idx; |
1805 | err = skb->len; | 1772 | err = skb->len; |
1806 | out_err: | 1773 | out_err: |
1807 | cfg80211_unlock_rdev(dev); | 1774 | cfg80211_unlock_rdev(dev); |
1808 | out_rtnl: | 1775 | out_rtnl: |
1809 | rtnl_unlock(); | 1776 | rtnl_unlock(); |
1810 | 1777 | ||
1811 | return err; | 1778 | return err; |
1812 | } | 1779 | } |
1813 | 1780 | ||
1814 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1781 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
1815 | { | 1782 | { |
1816 | struct cfg80211_registered_device *rdev; | 1783 | struct cfg80211_registered_device *rdev; |
1817 | int err; | 1784 | int err; |
1818 | struct net_device *dev; | 1785 | struct net_device *dev; |
1819 | struct station_info sinfo; | 1786 | struct station_info sinfo; |
1820 | struct sk_buff *msg; | 1787 | struct sk_buff *msg; |
1821 | u8 *mac_addr = NULL; | 1788 | u8 *mac_addr = NULL; |
1822 | 1789 | ||
1823 | memset(&sinfo, 0, sizeof(sinfo)); | 1790 | memset(&sinfo, 0, sizeof(sinfo)); |
1824 | 1791 | ||
1825 | if (!info->attrs[NL80211_ATTR_MAC]) | 1792 | if (!info->attrs[NL80211_ATTR_MAC]) |
1826 | return -EINVAL; | 1793 | return -EINVAL; |
1827 | 1794 | ||
1828 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1795 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1829 | 1796 | ||
1830 | rtnl_lock(); | 1797 | rtnl_lock(); |
1831 | 1798 | ||
1832 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1799 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1833 | if (err) | 1800 | if (err) |
1834 | goto out_rtnl; | 1801 | goto out_rtnl; |
1835 | 1802 | ||
1836 | if (!rdev->ops->get_station) { | 1803 | if (!rdev->ops->get_station) { |
1837 | err = -EOPNOTSUPP; | 1804 | err = -EOPNOTSUPP; |
1838 | goto out; | 1805 | goto out; |
1839 | } | 1806 | } |
1840 | 1807 | ||
1841 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); | 1808 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); |
1842 | if (err) | 1809 | if (err) |
1843 | goto out; | 1810 | goto out; |
1844 | 1811 | ||
1845 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1812 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1846 | if (!msg) | 1813 | if (!msg) |
1847 | goto out; | 1814 | goto out; |
1848 | 1815 | ||
1849 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1816 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
1850 | dev, mac_addr, &sinfo) < 0) | 1817 | dev, mac_addr, &sinfo) < 0) |
1851 | goto out_free; | 1818 | goto out_free; |
1852 | 1819 | ||
1853 | err = genlmsg_reply(msg, info); | 1820 | err = genlmsg_reply(msg, info); |
1854 | goto out; | 1821 | goto out; |
1855 | 1822 | ||
1856 | out_free: | 1823 | out_free: |
1857 | nlmsg_free(msg); | 1824 | nlmsg_free(msg); |
1858 | out: | 1825 | out: |
1859 | cfg80211_unlock_rdev(rdev); | 1826 | cfg80211_unlock_rdev(rdev); |
1860 | dev_put(dev); | 1827 | dev_put(dev); |
1861 | out_rtnl: | 1828 | out_rtnl: |
1862 | rtnl_unlock(); | 1829 | rtnl_unlock(); |
1863 | 1830 | ||
1864 | return err; | 1831 | return err; |
1865 | } | 1832 | } |
1866 | 1833 | ||
1867 | /* | 1834 | /* |
1868 | * Get vlan interface making sure it is running and on the right wiphy. | 1835 | * Get vlan interface making sure it is running and on the right wiphy. |
1869 | */ | 1836 | */ |
1870 | static int get_vlan(struct genl_info *info, | 1837 | static int get_vlan(struct genl_info *info, |
1871 | struct cfg80211_registered_device *rdev, | 1838 | struct cfg80211_registered_device *rdev, |
1872 | struct net_device **vlan) | 1839 | struct net_device **vlan) |
1873 | { | 1840 | { |
1874 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; | 1841 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; |
1875 | *vlan = NULL; | 1842 | *vlan = NULL; |
1876 | 1843 | ||
1877 | if (vlanattr) { | 1844 | if (vlanattr) { |
1878 | *vlan = dev_get_by_index(genl_info_net(info), | 1845 | *vlan = dev_get_by_index(genl_info_net(info), |
1879 | nla_get_u32(vlanattr)); | 1846 | nla_get_u32(vlanattr)); |
1880 | if (!*vlan) | 1847 | if (!*vlan) |
1881 | return -ENODEV; | 1848 | return -ENODEV; |
1882 | if (!(*vlan)->ieee80211_ptr) | 1849 | if (!(*vlan)->ieee80211_ptr) |
1883 | return -EINVAL; | 1850 | return -EINVAL; |
1884 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | 1851 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) |
1885 | return -EINVAL; | 1852 | return -EINVAL; |
1886 | if (!netif_running(*vlan)) | 1853 | if (!netif_running(*vlan)) |
1887 | return -ENETDOWN; | 1854 | return -ENETDOWN; |
1888 | } | 1855 | } |
1889 | return 0; | 1856 | return 0; |
1890 | } | 1857 | } |
1891 | 1858 | ||
1892 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 1859 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
1893 | { | 1860 | { |
1894 | struct cfg80211_registered_device *rdev; | 1861 | struct cfg80211_registered_device *rdev; |
1895 | int err; | 1862 | int err; |
1896 | struct net_device *dev; | 1863 | struct net_device *dev; |
1897 | struct station_parameters params; | 1864 | struct station_parameters params; |
1898 | u8 *mac_addr = NULL; | 1865 | u8 *mac_addr = NULL; |
1899 | 1866 | ||
1900 | memset(¶ms, 0, sizeof(params)); | 1867 | memset(¶ms, 0, sizeof(params)); |
1901 | 1868 | ||
1902 | params.listen_interval = -1; | 1869 | params.listen_interval = -1; |
1903 | 1870 | ||
1904 | if (info->attrs[NL80211_ATTR_STA_AID]) | 1871 | if (info->attrs[NL80211_ATTR_STA_AID]) |
1905 | return -EINVAL; | 1872 | return -EINVAL; |
1906 | 1873 | ||
1907 | if (!info->attrs[NL80211_ATTR_MAC]) | 1874 | if (!info->attrs[NL80211_ATTR_MAC]) |
1908 | return -EINVAL; | 1875 | return -EINVAL; |
1909 | 1876 | ||
1910 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1877 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1911 | 1878 | ||
1912 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { | 1879 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { |
1913 | params.supported_rates = | 1880 | params.supported_rates = |
1914 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1881 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1915 | params.supported_rates_len = | 1882 | params.supported_rates_len = |
1916 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1883 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1917 | } | 1884 | } |
1918 | 1885 | ||
1919 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 1886 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
1920 | params.listen_interval = | 1887 | params.listen_interval = |
1921 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1888 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
1922 | 1889 | ||
1923 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1890 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
1924 | params.ht_capa = | 1891 | params.ht_capa = |
1925 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1892 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
1926 | 1893 | ||
1927 | if (parse_station_flags(info, ¶ms)) | 1894 | if (parse_station_flags(info, ¶ms)) |
1928 | return -EINVAL; | 1895 | return -EINVAL; |
1929 | 1896 | ||
1930 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 1897 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) |
1931 | params.plink_action = | 1898 | params.plink_action = |
1932 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 1899 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
1933 | 1900 | ||
1934 | rtnl_lock(); | 1901 | rtnl_lock(); |
1935 | 1902 | ||
1936 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1903 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1937 | if (err) | 1904 | if (err) |
1938 | goto out_rtnl; | 1905 | goto out_rtnl; |
1939 | 1906 | ||
1940 | err = get_vlan(info, rdev, ¶ms.vlan); | 1907 | err = get_vlan(info, rdev, ¶ms.vlan); |
1941 | if (err) | 1908 | if (err) |
1942 | goto out; | 1909 | goto out; |
1943 | 1910 | ||
1944 | /* validate settings */ | 1911 | /* validate settings */ |
1945 | err = 0; | 1912 | err = 0; |
1946 | 1913 | ||
1947 | switch (dev->ieee80211_ptr->iftype) { | 1914 | switch (dev->ieee80211_ptr->iftype) { |
1948 | case NL80211_IFTYPE_AP: | 1915 | case NL80211_IFTYPE_AP: |
1949 | case NL80211_IFTYPE_AP_VLAN: | 1916 | case NL80211_IFTYPE_AP_VLAN: |
1950 | /* disallow mesh-specific things */ | 1917 | /* disallow mesh-specific things */ |
1951 | if (params.plink_action) | 1918 | if (params.plink_action) |
1952 | err = -EINVAL; | 1919 | err = -EINVAL; |
1953 | break; | 1920 | break; |
1954 | case NL80211_IFTYPE_STATION: | 1921 | case NL80211_IFTYPE_STATION: |
1955 | /* disallow everything but AUTHORIZED flag */ | 1922 | /* disallow everything but AUTHORIZED flag */ |
1956 | if (params.plink_action) | 1923 | if (params.plink_action) |
1957 | err = -EINVAL; | 1924 | err = -EINVAL; |
1958 | if (params.vlan) | 1925 | if (params.vlan) |
1959 | err = -EINVAL; | 1926 | err = -EINVAL; |
1960 | if (params.supported_rates) | 1927 | if (params.supported_rates) |
1961 | err = -EINVAL; | 1928 | err = -EINVAL; |
1962 | if (params.ht_capa) | 1929 | if (params.ht_capa) |
1963 | err = -EINVAL; | 1930 | err = -EINVAL; |
1964 | if (params.listen_interval >= 0) | 1931 | if (params.listen_interval >= 0) |
1965 | err = -EINVAL; | 1932 | err = -EINVAL; |
1966 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 1933 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) |
1967 | err = -EINVAL; | 1934 | err = -EINVAL; |
1968 | break; | 1935 | break; |
1969 | case NL80211_IFTYPE_MESH_POINT: | 1936 | case NL80211_IFTYPE_MESH_POINT: |
1970 | /* disallow things mesh doesn't support */ | 1937 | /* disallow things mesh doesn't support */ |
1971 | if (params.vlan) | 1938 | if (params.vlan) |
1972 | err = -EINVAL; | 1939 | err = -EINVAL; |
1973 | if (params.ht_capa) | 1940 | if (params.ht_capa) |
1974 | err = -EINVAL; | 1941 | err = -EINVAL; |
1975 | if (params.listen_interval >= 0) | 1942 | if (params.listen_interval >= 0) |
1976 | err = -EINVAL; | 1943 | err = -EINVAL; |
1977 | if (params.supported_rates) | 1944 | if (params.supported_rates) |
1978 | err = -EINVAL; | 1945 | err = -EINVAL; |
1979 | if (params.sta_flags_mask) | 1946 | if (params.sta_flags_mask) |
1980 | err = -EINVAL; | 1947 | err = -EINVAL; |
1981 | break; | 1948 | break; |
1982 | default: | 1949 | default: |
1983 | err = -EINVAL; | 1950 | err = -EINVAL; |
1984 | } | 1951 | } |
1985 | 1952 | ||
1986 | if (err) | 1953 | if (err) |
1987 | goto out; | 1954 | goto out; |
1988 | 1955 | ||
1989 | if (!rdev->ops->change_station) { | 1956 | if (!rdev->ops->change_station) { |
1990 | err = -EOPNOTSUPP; | 1957 | err = -EOPNOTSUPP; |
1991 | goto out; | 1958 | goto out; |
1992 | } | 1959 | } |
1993 | 1960 | ||
1994 | err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 1961 | err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
1995 | 1962 | ||
1996 | out: | 1963 | out: |
1997 | if (params.vlan) | 1964 | if (params.vlan) |
1998 | dev_put(params.vlan); | 1965 | dev_put(params.vlan); |
1999 | cfg80211_unlock_rdev(rdev); | 1966 | cfg80211_unlock_rdev(rdev); |
2000 | dev_put(dev); | 1967 | dev_put(dev); |
2001 | out_rtnl: | 1968 | out_rtnl: |
2002 | rtnl_unlock(); | 1969 | rtnl_unlock(); |
2003 | 1970 | ||
2004 | return err; | 1971 | return err; |
2005 | } | 1972 | } |
2006 | 1973 | ||
2007 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 1974 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
2008 | { | 1975 | { |
2009 | struct cfg80211_registered_device *rdev; | 1976 | struct cfg80211_registered_device *rdev; |
2010 | int err; | 1977 | int err; |
2011 | struct net_device *dev; | 1978 | struct net_device *dev; |
2012 | struct station_parameters params; | 1979 | struct station_parameters params; |
2013 | u8 *mac_addr = NULL; | 1980 | u8 *mac_addr = NULL; |
2014 | 1981 | ||
2015 | memset(¶ms, 0, sizeof(params)); | 1982 | memset(¶ms, 0, sizeof(params)); |
2016 | 1983 | ||
2017 | if (!info->attrs[NL80211_ATTR_MAC]) | 1984 | if (!info->attrs[NL80211_ATTR_MAC]) |
2018 | return -EINVAL; | 1985 | return -EINVAL; |
2019 | 1986 | ||
2020 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 1987 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
2021 | return -EINVAL; | 1988 | return -EINVAL; |
2022 | 1989 | ||
2023 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | 1990 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) |
2024 | return -EINVAL; | 1991 | return -EINVAL; |
2025 | 1992 | ||
2026 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1993 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2027 | params.supported_rates = | 1994 | params.supported_rates = |
2028 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1995 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
2029 | params.supported_rates_len = | 1996 | params.supported_rates_len = |
2030 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1997 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
2031 | params.listen_interval = | 1998 | params.listen_interval = |
2032 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1999 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
2033 | 2000 | ||
2034 | if (info->attrs[NL80211_ATTR_STA_AID]) { | 2001 | if (info->attrs[NL80211_ATTR_STA_AID]) { |
2035 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 2002 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
2036 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 2003 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
2037 | return -EINVAL; | 2004 | return -EINVAL; |
2038 | } | 2005 | } |
2039 | 2006 | ||
2040 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 2007 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
2041 | params.ht_capa = | 2008 | params.ht_capa = |
2042 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 2009 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
2043 | 2010 | ||
2044 | if (parse_station_flags(info, ¶ms)) | 2011 | if (parse_station_flags(info, ¶ms)) |
2045 | return -EINVAL; | 2012 | return -EINVAL; |
2046 | 2013 | ||
2047 | rtnl_lock(); | 2014 | rtnl_lock(); |
2048 | 2015 | ||
2049 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2016 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2050 | if (err) | 2017 | if (err) |
2051 | goto out_rtnl; | 2018 | goto out_rtnl; |
2052 | 2019 | ||
2053 | err = get_vlan(info, rdev, ¶ms.vlan); | 2020 | err = get_vlan(info, rdev, ¶ms.vlan); |
2054 | if (err) | 2021 | if (err) |
2055 | goto out; | 2022 | goto out; |
2056 | 2023 | ||
2057 | /* validate settings */ | 2024 | /* validate settings */ |
2058 | err = 0; | 2025 | err = 0; |
2059 | 2026 | ||
2060 | switch (dev->ieee80211_ptr->iftype) { | 2027 | switch (dev->ieee80211_ptr->iftype) { |
2061 | case NL80211_IFTYPE_AP: | 2028 | case NL80211_IFTYPE_AP: |
2062 | case NL80211_IFTYPE_AP_VLAN: | 2029 | case NL80211_IFTYPE_AP_VLAN: |
2063 | /* all ok but must have AID */ | 2030 | /* all ok but must have AID */ |
2064 | if (!params.aid) | 2031 | if (!params.aid) |
2065 | err = -EINVAL; | 2032 | err = -EINVAL; |
2066 | break; | 2033 | break; |
2067 | case NL80211_IFTYPE_MESH_POINT: | 2034 | case NL80211_IFTYPE_MESH_POINT: |
2068 | /* disallow things mesh doesn't support */ | 2035 | /* disallow things mesh doesn't support */ |
2069 | if (params.vlan) | 2036 | if (params.vlan) |
2070 | err = -EINVAL; | 2037 | err = -EINVAL; |
2071 | if (params.aid) | 2038 | if (params.aid) |
2072 | err = -EINVAL; | 2039 | err = -EINVAL; |
2073 | if (params.ht_capa) | 2040 | if (params.ht_capa) |
2074 | err = -EINVAL; | 2041 | err = -EINVAL; |
2075 | if (params.listen_interval >= 0) | 2042 | if (params.listen_interval >= 0) |
2076 | err = -EINVAL; | 2043 | err = -EINVAL; |
2077 | if (params.supported_rates) | 2044 | if (params.supported_rates) |
2078 | err = -EINVAL; | 2045 | err = -EINVAL; |
2079 | if (params.sta_flags_mask) | 2046 | if (params.sta_flags_mask) |
2080 | err = -EINVAL; | 2047 | err = -EINVAL; |
2081 | break; | 2048 | break; |
2082 | default: | 2049 | default: |
2083 | err = -EINVAL; | 2050 | err = -EINVAL; |
2084 | } | 2051 | } |
2085 | 2052 | ||
2086 | if (err) | 2053 | if (err) |
2087 | goto out; | 2054 | goto out; |
2088 | 2055 | ||
2089 | if (!rdev->ops->add_station) { | 2056 | if (!rdev->ops->add_station) { |
2090 | err = -EOPNOTSUPP; | 2057 | err = -EOPNOTSUPP; |
2091 | goto out; | 2058 | goto out; |
2092 | } | 2059 | } |
2093 | 2060 | ||
2094 | if (!netif_running(dev)) { | 2061 | if (!netif_running(dev)) { |
2095 | err = -ENETDOWN; | 2062 | err = -ENETDOWN; |
2096 | goto out; | 2063 | goto out; |
2097 | } | 2064 | } |
2098 | 2065 | ||
2099 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2066 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2100 | 2067 | ||
2101 | out: | 2068 | out: |
2102 | if (params.vlan) | 2069 | if (params.vlan) |
2103 | dev_put(params.vlan); | 2070 | dev_put(params.vlan); |
2104 | cfg80211_unlock_rdev(rdev); | 2071 | cfg80211_unlock_rdev(rdev); |
2105 | dev_put(dev); | 2072 | dev_put(dev); |
2106 | out_rtnl: | 2073 | out_rtnl: |
2107 | rtnl_unlock(); | 2074 | rtnl_unlock(); |
2108 | 2075 | ||
2109 | return err; | 2076 | return err; |
2110 | } | 2077 | } |
2111 | 2078 | ||
2112 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | 2079 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) |
2113 | { | 2080 | { |
2114 | struct cfg80211_registered_device *rdev; | 2081 | struct cfg80211_registered_device *rdev; |
2115 | int err; | 2082 | int err; |
2116 | struct net_device *dev; | 2083 | struct net_device *dev; |
2117 | u8 *mac_addr = NULL; | 2084 | u8 *mac_addr = NULL; |
2118 | 2085 | ||
2119 | if (info->attrs[NL80211_ATTR_MAC]) | 2086 | if (info->attrs[NL80211_ATTR_MAC]) |
2120 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2087 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2121 | 2088 | ||
2122 | rtnl_lock(); | 2089 | rtnl_lock(); |
2123 | 2090 | ||
2124 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2091 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2125 | if (err) | 2092 | if (err) |
2126 | goto out_rtnl; | 2093 | goto out_rtnl; |
2127 | 2094 | ||
2128 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2095 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2129 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2096 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2130 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2097 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
2131 | err = -EINVAL; | 2098 | err = -EINVAL; |
2132 | goto out; | 2099 | goto out; |
2133 | } | 2100 | } |
2134 | 2101 | ||
2135 | if (!rdev->ops->del_station) { | 2102 | if (!rdev->ops->del_station) { |
2136 | err = -EOPNOTSUPP; | 2103 | err = -EOPNOTSUPP; |
2137 | goto out; | 2104 | goto out; |
2138 | } | 2105 | } |
2139 | 2106 | ||
2140 | err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); | 2107 | err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); |
2141 | 2108 | ||
2142 | out: | 2109 | out: |
2143 | cfg80211_unlock_rdev(rdev); | 2110 | cfg80211_unlock_rdev(rdev); |
2144 | dev_put(dev); | 2111 | dev_put(dev); |
2145 | out_rtnl: | 2112 | out_rtnl: |
2146 | rtnl_unlock(); | 2113 | rtnl_unlock(); |
2147 | 2114 | ||
2148 | return err; | 2115 | return err; |
2149 | } | 2116 | } |
2150 | 2117 | ||
2151 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | 2118 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, |
2152 | int flags, struct net_device *dev, | 2119 | int flags, struct net_device *dev, |
2153 | u8 *dst, u8 *next_hop, | 2120 | u8 *dst, u8 *next_hop, |
2154 | struct mpath_info *pinfo) | 2121 | struct mpath_info *pinfo) |
2155 | { | 2122 | { |
2156 | void *hdr; | 2123 | void *hdr; |
2157 | struct nlattr *pinfoattr; | 2124 | struct nlattr *pinfoattr; |
2158 | 2125 | ||
2159 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 2126 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
2160 | if (!hdr) | 2127 | if (!hdr) |
2161 | return -1; | 2128 | return -1; |
2162 | 2129 | ||
2163 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 2130 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
2164 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | 2131 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); |
2165 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | 2132 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); |
2166 | 2133 | ||
2167 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); | 2134 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); |
2168 | 2135 | ||
2169 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | 2136 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); |
2170 | if (!pinfoattr) | 2137 | if (!pinfoattr) |
2171 | goto nla_put_failure; | 2138 | goto nla_put_failure; |
2172 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) | 2139 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) |
2173 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, | 2140 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, |
2174 | pinfo->frame_qlen); | 2141 | pinfo->frame_qlen); |
2175 | if (pinfo->filled & MPATH_INFO_SN) | 2142 | if (pinfo->filled & MPATH_INFO_SN) |
2176 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN, | 2143 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN, |
2177 | pinfo->sn); | 2144 | pinfo->sn); |
2178 | if (pinfo->filled & MPATH_INFO_METRIC) | 2145 | if (pinfo->filled & MPATH_INFO_METRIC) |
2179 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, | 2146 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, |
2180 | pinfo->metric); | 2147 | pinfo->metric); |
2181 | if (pinfo->filled & MPATH_INFO_EXPTIME) | 2148 | if (pinfo->filled & MPATH_INFO_EXPTIME) |
2182 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, | 2149 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, |
2183 | pinfo->exptime); | 2150 | pinfo->exptime); |
2184 | if (pinfo->filled & MPATH_INFO_FLAGS) | 2151 | if (pinfo->filled & MPATH_INFO_FLAGS) |
2185 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, | 2152 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, |
2186 | pinfo->flags); | 2153 | pinfo->flags); |
2187 | if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) | 2154 | if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) |
2188 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | 2155 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, |
2189 | pinfo->discovery_timeout); | 2156 | pinfo->discovery_timeout); |
2190 | if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) | 2157 | if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) |
2191 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, | 2158 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, |
2192 | pinfo->discovery_retries); | 2159 | pinfo->discovery_retries); |
2193 | 2160 | ||
2194 | nla_nest_end(msg, pinfoattr); | 2161 | nla_nest_end(msg, pinfoattr); |
2195 | 2162 | ||
2196 | return genlmsg_end(msg, hdr); | 2163 | return genlmsg_end(msg, hdr); |
2197 | 2164 | ||
2198 | nla_put_failure: | 2165 | nla_put_failure: |
2199 | genlmsg_cancel(msg, hdr); | 2166 | genlmsg_cancel(msg, hdr); |
2200 | return -EMSGSIZE; | 2167 | return -EMSGSIZE; |
2201 | } | 2168 | } |
2202 | 2169 | ||
2203 | static int nl80211_dump_mpath(struct sk_buff *skb, | 2170 | static int nl80211_dump_mpath(struct sk_buff *skb, |
2204 | struct netlink_callback *cb) | 2171 | struct netlink_callback *cb) |
2205 | { | 2172 | { |
2206 | struct mpath_info pinfo; | 2173 | struct mpath_info pinfo; |
2207 | struct cfg80211_registered_device *dev; | 2174 | struct cfg80211_registered_device *dev; |
2208 | struct net_device *netdev; | 2175 | struct net_device *netdev; |
2209 | u8 dst[ETH_ALEN]; | 2176 | u8 dst[ETH_ALEN]; |
2210 | u8 next_hop[ETH_ALEN]; | 2177 | u8 next_hop[ETH_ALEN]; |
2211 | int ifidx = cb->args[0]; | 2178 | int ifidx = cb->args[0]; |
2212 | int path_idx = cb->args[1]; | 2179 | int path_idx = cb->args[1]; |
2213 | int err; | 2180 | int err; |
2214 | 2181 | ||
2215 | if (!ifidx) | 2182 | if (!ifidx) |
2216 | ifidx = nl80211_get_ifidx(cb); | 2183 | ifidx = nl80211_get_ifidx(cb); |
2217 | if (ifidx < 0) | 2184 | if (ifidx < 0) |
2218 | return ifidx; | 2185 | return ifidx; |
2219 | 2186 | ||
2220 | rtnl_lock(); | 2187 | rtnl_lock(); |
2221 | 2188 | ||
2222 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | 2189 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
2223 | if (!netdev) { | 2190 | if (!netdev) { |
2224 | err = -ENODEV; | 2191 | err = -ENODEV; |
2225 | goto out_rtnl; | 2192 | goto out_rtnl; |
2226 | } | 2193 | } |
2227 | 2194 | ||
2228 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | 2195 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
2229 | if (IS_ERR(dev)) { | 2196 | if (IS_ERR(dev)) { |
2230 | err = PTR_ERR(dev); | 2197 | err = PTR_ERR(dev); |
2231 | goto out_rtnl; | 2198 | goto out_rtnl; |
2232 | } | 2199 | } |
2233 | 2200 | ||
2234 | if (!dev->ops->dump_mpath) { | 2201 | if (!dev->ops->dump_mpath) { |
2235 | err = -EOPNOTSUPP; | 2202 | err = -EOPNOTSUPP; |
2236 | goto out_err; | 2203 | goto out_err; |
2237 | } | 2204 | } |
2238 | 2205 | ||
2239 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2206 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
2240 | err = -EOPNOTSUPP; | 2207 | err = -EOPNOTSUPP; |
2241 | goto out_err; | 2208 | goto out_err; |
2242 | } | 2209 | } |
2243 | 2210 | ||
2244 | while (1) { | 2211 | while (1) { |
2245 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, | 2212 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, |
2246 | dst, next_hop, &pinfo); | 2213 | dst, next_hop, &pinfo); |
2247 | if (err == -ENOENT) | 2214 | if (err == -ENOENT) |
2248 | break; | 2215 | break; |
2249 | if (err) | 2216 | if (err) |
2250 | goto out_err; | 2217 | goto out_err; |
2251 | 2218 | ||
2252 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, | 2219 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, |
2253 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 2220 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
2254 | netdev, dst, next_hop, | 2221 | netdev, dst, next_hop, |
2255 | &pinfo) < 0) | 2222 | &pinfo) < 0) |
2256 | goto out; | 2223 | goto out; |
2257 | 2224 | ||
2258 | path_idx++; | 2225 | path_idx++; |
2259 | } | 2226 | } |
2260 | 2227 | ||
2261 | 2228 | ||
2262 | out: | 2229 | out: |
2263 | cb->args[1] = path_idx; | 2230 | cb->args[1] = path_idx; |
2264 | err = skb->len; | 2231 | err = skb->len; |
2265 | out_err: | 2232 | out_err: |
2266 | cfg80211_unlock_rdev(dev); | 2233 | cfg80211_unlock_rdev(dev); |
2267 | out_rtnl: | 2234 | out_rtnl: |
2268 | rtnl_unlock(); | 2235 | rtnl_unlock(); |
2269 | 2236 | ||
2270 | return err; | 2237 | return err; |
2271 | } | 2238 | } |
2272 | 2239 | ||
2273 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 2240 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
2274 | { | 2241 | { |
2275 | struct cfg80211_registered_device *rdev; | 2242 | struct cfg80211_registered_device *rdev; |
2276 | int err; | 2243 | int err; |
2277 | struct net_device *dev; | 2244 | struct net_device *dev; |
2278 | struct mpath_info pinfo; | 2245 | struct mpath_info pinfo; |
2279 | struct sk_buff *msg; | 2246 | struct sk_buff *msg; |
2280 | u8 *dst = NULL; | 2247 | u8 *dst = NULL; |
2281 | u8 next_hop[ETH_ALEN]; | 2248 | u8 next_hop[ETH_ALEN]; |
2282 | 2249 | ||
2283 | memset(&pinfo, 0, sizeof(pinfo)); | 2250 | memset(&pinfo, 0, sizeof(pinfo)); |
2284 | 2251 | ||
2285 | if (!info->attrs[NL80211_ATTR_MAC]) | 2252 | if (!info->attrs[NL80211_ATTR_MAC]) |
2286 | return -EINVAL; | 2253 | return -EINVAL; |
2287 | 2254 | ||
2288 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2255 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2289 | 2256 | ||
2290 | rtnl_lock(); | 2257 | rtnl_lock(); |
2291 | 2258 | ||
2292 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2259 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2293 | if (err) | 2260 | if (err) |
2294 | goto out_rtnl; | 2261 | goto out_rtnl; |
2295 | 2262 | ||
2296 | if (!rdev->ops->get_mpath) { | 2263 | if (!rdev->ops->get_mpath) { |
2297 | err = -EOPNOTSUPP; | 2264 | err = -EOPNOTSUPP; |
2298 | goto out; | 2265 | goto out; |
2299 | } | 2266 | } |
2300 | 2267 | ||
2301 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2268 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
2302 | err = -EOPNOTSUPP; | 2269 | err = -EOPNOTSUPP; |
2303 | goto out; | 2270 | goto out; |
2304 | } | 2271 | } |
2305 | 2272 | ||
2306 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); | 2273 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); |
2307 | if (err) | 2274 | if (err) |
2308 | goto out; | 2275 | goto out; |
2309 | 2276 | ||
2310 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2277 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2311 | if (!msg) | 2278 | if (!msg) |
2312 | goto out; | 2279 | goto out; |
2313 | 2280 | ||
2314 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | 2281 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, |
2315 | dev, dst, next_hop, &pinfo) < 0) | 2282 | dev, dst, next_hop, &pinfo) < 0) |
2316 | goto out_free; | 2283 | goto out_free; |
2317 | 2284 | ||
2318 | err = genlmsg_reply(msg, info); | 2285 | err = genlmsg_reply(msg, info); |
2319 | goto out; | 2286 | goto out; |
2320 | 2287 | ||
2321 | out_free: | 2288 | out_free: |
2322 | nlmsg_free(msg); | 2289 | nlmsg_free(msg); |
2323 | out: | 2290 | out: |
2324 | cfg80211_unlock_rdev(rdev); | 2291 | cfg80211_unlock_rdev(rdev); |
2325 | dev_put(dev); | 2292 | dev_put(dev); |
2326 | out_rtnl: | 2293 | out_rtnl: |
2327 | rtnl_unlock(); | 2294 | rtnl_unlock(); |
2328 | 2295 | ||
2329 | return err; | 2296 | return err; |
2330 | } | 2297 | } |
2331 | 2298 | ||
2332 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | 2299 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) |
2333 | { | 2300 | { |
2334 | struct cfg80211_registered_device *rdev; | 2301 | struct cfg80211_registered_device *rdev; |
2335 | int err; | 2302 | int err; |
2336 | struct net_device *dev; | 2303 | struct net_device *dev; |
2337 | u8 *dst = NULL; | 2304 | u8 *dst = NULL; |
2338 | u8 *next_hop = NULL; | 2305 | u8 *next_hop = NULL; |
2339 | 2306 | ||
2340 | if (!info->attrs[NL80211_ATTR_MAC]) | 2307 | if (!info->attrs[NL80211_ATTR_MAC]) |
2341 | return -EINVAL; | 2308 | return -EINVAL; |
2342 | 2309 | ||
2343 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | 2310 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) |
2344 | return -EINVAL; | 2311 | return -EINVAL; |
2345 | 2312 | ||
2346 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2313 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2347 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2314 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2348 | 2315 | ||
2349 | rtnl_lock(); | 2316 | rtnl_lock(); |
2350 | 2317 | ||
2351 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2318 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2352 | if (err) | 2319 | if (err) |
2353 | goto out_rtnl; | 2320 | goto out_rtnl; |
2354 | 2321 | ||
2355 | if (!rdev->ops->change_mpath) { | 2322 | if (!rdev->ops->change_mpath) { |
2356 | err = -EOPNOTSUPP; | 2323 | err = -EOPNOTSUPP; |
2357 | goto out; | 2324 | goto out; |
2358 | } | 2325 | } |
2359 | 2326 | ||
2360 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2327 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
2361 | err = -EOPNOTSUPP; | 2328 | err = -EOPNOTSUPP; |
2362 | goto out; | 2329 | goto out; |
2363 | } | 2330 | } |
2364 | 2331 | ||
2365 | if (!netif_running(dev)) { | 2332 | if (!netif_running(dev)) { |
2366 | err = -ENETDOWN; | 2333 | err = -ENETDOWN; |
2367 | goto out; | 2334 | goto out; |
2368 | } | 2335 | } |
2369 | 2336 | ||
2370 | err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); | 2337 | err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); |
2371 | 2338 | ||
2372 | out: | 2339 | out: |
2373 | cfg80211_unlock_rdev(rdev); | 2340 | cfg80211_unlock_rdev(rdev); |
2374 | dev_put(dev); | 2341 | dev_put(dev); |
2375 | out_rtnl: | 2342 | out_rtnl: |
2376 | rtnl_unlock(); | 2343 | rtnl_unlock(); |
2377 | 2344 | ||
2378 | return err; | 2345 | return err; |
2379 | } | 2346 | } |
2380 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 2347 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
2381 | { | 2348 | { |
2382 | struct cfg80211_registered_device *rdev; | 2349 | struct cfg80211_registered_device *rdev; |
2383 | int err; | 2350 | int err; |
2384 | struct net_device *dev; | 2351 | struct net_device *dev; |
2385 | u8 *dst = NULL; | 2352 | u8 *dst = NULL; |
2386 | u8 *next_hop = NULL; | 2353 | u8 *next_hop = NULL; |
2387 | 2354 | ||
2388 | if (!info->attrs[NL80211_ATTR_MAC]) | 2355 | if (!info->attrs[NL80211_ATTR_MAC]) |
2389 | return -EINVAL; | 2356 | return -EINVAL; |
2390 | 2357 | ||
2391 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | 2358 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) |
2392 | return -EINVAL; | 2359 | return -EINVAL; |
2393 | 2360 | ||
2394 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2361 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2395 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2362 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2396 | 2363 | ||
2397 | rtnl_lock(); | 2364 | rtnl_lock(); |
2398 | 2365 | ||
2399 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2366 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2400 | if (err) | 2367 | if (err) |
2401 | goto out_rtnl; | 2368 | goto out_rtnl; |
2402 | 2369 | ||
2403 | if (!rdev->ops->add_mpath) { | 2370 | if (!rdev->ops->add_mpath) { |
2404 | err = -EOPNOTSUPP; | 2371 | err = -EOPNOTSUPP; |
2405 | goto out; | 2372 | goto out; |
2406 | } | 2373 | } |
2407 | 2374 | ||
2408 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2375 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
2409 | err = -EOPNOTSUPP; | 2376 | err = -EOPNOTSUPP; |
2410 | goto out; | 2377 | goto out; |
2411 | } | 2378 | } |
2412 | 2379 | ||
2413 | if (!netif_running(dev)) { | 2380 | if (!netif_running(dev)) { |
2414 | err = -ENETDOWN; | 2381 | err = -ENETDOWN; |
2415 | goto out; | 2382 | goto out; |
2416 | } | 2383 | } |
2417 | 2384 | ||
2418 | err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); | 2385 | err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); |
2419 | 2386 | ||
2420 | out: | 2387 | out: |
2421 | cfg80211_unlock_rdev(rdev); | 2388 | cfg80211_unlock_rdev(rdev); |
2422 | dev_put(dev); | 2389 | dev_put(dev); |
2423 | out_rtnl: | 2390 | out_rtnl: |
2424 | rtnl_unlock(); | 2391 | rtnl_unlock(); |
2425 | 2392 | ||
2426 | return err; | 2393 | return err; |
2427 | } | 2394 | } |
2428 | 2395 | ||
2429 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | 2396 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) |
2430 | { | 2397 | { |
2431 | struct cfg80211_registered_device *rdev; | 2398 | struct cfg80211_registered_device *rdev; |
2432 | int err; | 2399 | int err; |
2433 | struct net_device *dev; | 2400 | struct net_device *dev; |
2434 | u8 *dst = NULL; | 2401 | u8 *dst = NULL; |
2435 | 2402 | ||
2436 | if (info->attrs[NL80211_ATTR_MAC]) | 2403 | if (info->attrs[NL80211_ATTR_MAC]) |
2437 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2404 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2438 | 2405 | ||
2439 | rtnl_lock(); | 2406 | rtnl_lock(); |
2440 | 2407 | ||
2441 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2408 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2442 | if (err) | 2409 | if (err) |
2443 | goto out_rtnl; | 2410 | goto out_rtnl; |
2444 | 2411 | ||
2445 | if (!rdev->ops->del_mpath) { | 2412 | if (!rdev->ops->del_mpath) { |
2446 | err = -EOPNOTSUPP; | 2413 | err = -EOPNOTSUPP; |
2447 | goto out; | 2414 | goto out; |
2448 | } | 2415 | } |
2449 | 2416 | ||
2450 | err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); | 2417 | err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); |
2451 | 2418 | ||
2452 | out: | 2419 | out: |
2453 | cfg80211_unlock_rdev(rdev); | 2420 | cfg80211_unlock_rdev(rdev); |
2454 | dev_put(dev); | 2421 | dev_put(dev); |
2455 | out_rtnl: | 2422 | out_rtnl: |
2456 | rtnl_unlock(); | 2423 | rtnl_unlock(); |
2457 | 2424 | ||
2458 | return err; | 2425 | return err; |
2459 | } | 2426 | } |
2460 | 2427 | ||
2461 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 2428 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
2462 | { | 2429 | { |
2463 | struct cfg80211_registered_device *rdev; | 2430 | struct cfg80211_registered_device *rdev; |
2464 | int err; | 2431 | int err; |
2465 | struct net_device *dev; | 2432 | struct net_device *dev; |
2466 | struct bss_parameters params; | 2433 | struct bss_parameters params; |
2467 | 2434 | ||
2468 | memset(¶ms, 0, sizeof(params)); | 2435 | memset(¶ms, 0, sizeof(params)); |
2469 | /* default to not changing parameters */ | 2436 | /* default to not changing parameters */ |
2470 | params.use_cts_prot = -1; | 2437 | params.use_cts_prot = -1; |
2471 | params.use_short_preamble = -1; | 2438 | params.use_short_preamble = -1; |
2472 | params.use_short_slot_time = -1; | 2439 | params.use_short_slot_time = -1; |
2473 | 2440 | ||
2474 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) | 2441 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) |
2475 | params.use_cts_prot = | 2442 | params.use_cts_prot = |
2476 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]); | 2443 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]); |
2477 | if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]) | 2444 | if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]) |
2478 | params.use_short_preamble = | 2445 | params.use_short_preamble = |
2479 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]); | 2446 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]); |
2480 | if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) | 2447 | if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) |
2481 | params.use_short_slot_time = | 2448 | params.use_short_slot_time = |
2482 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); | 2449 | nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); |
2483 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | 2450 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { |
2484 | params.basic_rates = | 2451 | params.basic_rates = |
2485 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 2452 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
2486 | params.basic_rates_len = | 2453 | params.basic_rates_len = |
2487 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 2454 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
2488 | } | 2455 | } |
2489 | 2456 | ||
2490 | rtnl_lock(); | 2457 | rtnl_lock(); |
2491 | 2458 | ||
2492 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2459 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2493 | if (err) | 2460 | if (err) |
2494 | goto out_rtnl; | 2461 | goto out_rtnl; |
2495 | 2462 | ||
2496 | if (!rdev->ops->change_bss) { | 2463 | if (!rdev->ops->change_bss) { |
2497 | err = -EOPNOTSUPP; | 2464 | err = -EOPNOTSUPP; |
2498 | goto out; | 2465 | goto out; |
2499 | } | 2466 | } |
2500 | 2467 | ||
2501 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | 2468 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
2502 | err = -EOPNOTSUPP; | 2469 | err = -EOPNOTSUPP; |
2503 | goto out; | 2470 | goto out; |
2504 | } | 2471 | } |
2505 | 2472 | ||
2506 | err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); | 2473 | err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); |
2507 | 2474 | ||
2508 | out: | 2475 | out: |
2509 | cfg80211_unlock_rdev(rdev); | 2476 | cfg80211_unlock_rdev(rdev); |
2510 | dev_put(dev); | 2477 | dev_put(dev); |
2511 | out_rtnl: | 2478 | out_rtnl: |
2512 | rtnl_unlock(); | 2479 | rtnl_unlock(); |
2513 | 2480 | ||
2514 | return err; | 2481 | return err; |
2515 | } | 2482 | } |
2516 | 2483 | ||
2517 | static const struct nla_policy | 2484 | static const struct nla_policy |
2518 | reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 2485 | reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
2519 | [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, | 2486 | [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, |
2520 | [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, | 2487 | [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, |
2521 | [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, | 2488 | [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, |
2522 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, | 2489 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, |
2523 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, | 2490 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, |
2524 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, | 2491 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, |
2525 | }; | 2492 | }; |
2526 | 2493 | ||
2527 | static int parse_reg_rule(struct nlattr *tb[], | 2494 | static int parse_reg_rule(struct nlattr *tb[], |
2528 | struct ieee80211_reg_rule *reg_rule) | 2495 | struct ieee80211_reg_rule *reg_rule) |
2529 | { | 2496 | { |
2530 | struct ieee80211_freq_range *freq_range = ®_rule->freq_range; | 2497 | struct ieee80211_freq_range *freq_range = ®_rule->freq_range; |
2531 | struct ieee80211_power_rule *power_rule = ®_rule->power_rule; | 2498 | struct ieee80211_power_rule *power_rule = ®_rule->power_rule; |
2532 | 2499 | ||
2533 | if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) | 2500 | if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) |
2534 | return -EINVAL; | 2501 | return -EINVAL; |
2535 | if (!tb[NL80211_ATTR_FREQ_RANGE_START]) | 2502 | if (!tb[NL80211_ATTR_FREQ_RANGE_START]) |
2536 | return -EINVAL; | 2503 | return -EINVAL; |
2537 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | 2504 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) |
2538 | return -EINVAL; | 2505 | return -EINVAL; |
2539 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | 2506 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) |
2540 | return -EINVAL; | 2507 | return -EINVAL; |
2541 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | 2508 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) |
2542 | return -EINVAL; | 2509 | return -EINVAL; |
2543 | 2510 | ||
2544 | reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); | 2511 | reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); |
2545 | 2512 | ||
2546 | freq_range->start_freq_khz = | 2513 | freq_range->start_freq_khz = |
2547 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | 2514 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); |
2548 | freq_range->end_freq_khz = | 2515 | freq_range->end_freq_khz = |
2549 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | 2516 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); |
2550 | freq_range->max_bandwidth_khz = | 2517 | freq_range->max_bandwidth_khz = |
2551 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | 2518 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); |
2552 | 2519 | ||
2553 | power_rule->max_eirp = | 2520 | power_rule->max_eirp = |
2554 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | 2521 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); |
2555 | 2522 | ||
2556 | if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) | 2523 | if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) |
2557 | power_rule->max_antenna_gain = | 2524 | power_rule->max_antenna_gain = |
2558 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); | 2525 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); |
2559 | 2526 | ||
2560 | return 0; | 2527 | return 0; |
2561 | } | 2528 | } |
2562 | 2529 | ||
2563 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | 2530 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) |
2564 | { | 2531 | { |
2565 | int r; | 2532 | int r; |
2566 | char *data = NULL; | 2533 | char *data = NULL; |
2567 | 2534 | ||
2568 | /* | 2535 | /* |
2569 | * You should only get this when cfg80211 hasn't yet initialized | 2536 | * You should only get this when cfg80211 hasn't yet initialized |
2570 | * completely when built-in to the kernel right between the time | 2537 | * completely when built-in to the kernel right between the time |
2571 | * window between nl80211_init() and regulatory_init(), if that is | 2538 | * window between nl80211_init() and regulatory_init(), if that is |
2572 | * even possible. | 2539 | * even possible. |
2573 | */ | 2540 | */ |
2574 | mutex_lock(&cfg80211_mutex); | 2541 | mutex_lock(&cfg80211_mutex); |
2575 | if (unlikely(!cfg80211_regdomain)) { | 2542 | if (unlikely(!cfg80211_regdomain)) { |
2576 | mutex_unlock(&cfg80211_mutex); | 2543 | mutex_unlock(&cfg80211_mutex); |
2577 | return -EINPROGRESS; | 2544 | return -EINPROGRESS; |
2578 | } | 2545 | } |
2579 | mutex_unlock(&cfg80211_mutex); | 2546 | mutex_unlock(&cfg80211_mutex); |
2580 | 2547 | ||
2581 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 2548 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
2582 | return -EINVAL; | 2549 | return -EINVAL; |
2583 | 2550 | ||
2584 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 2551 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
2585 | 2552 | ||
2586 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 2553 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
2587 | /* We ignore world regdom requests with the old regdom setup */ | 2554 | /* We ignore world regdom requests with the old regdom setup */ |
2588 | if (is_world_regdom(data)) | 2555 | if (is_world_regdom(data)) |
2589 | return -EINVAL; | 2556 | return -EINVAL; |
2590 | #endif | 2557 | #endif |
2591 | 2558 | ||
2592 | r = regulatory_hint_user(data); | 2559 | r = regulatory_hint_user(data); |
2593 | 2560 | ||
2594 | return r; | 2561 | return r; |
2595 | } | 2562 | } |
2596 | 2563 | ||
2597 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2564 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2598 | struct genl_info *info) | 2565 | struct genl_info *info) |
2599 | { | 2566 | { |
2600 | struct cfg80211_registered_device *rdev; | 2567 | struct cfg80211_registered_device *rdev; |
2601 | struct mesh_config cur_params; | 2568 | struct mesh_config cur_params; |
2602 | int err; | 2569 | int err; |
2603 | struct net_device *dev; | 2570 | struct net_device *dev; |
2604 | void *hdr; | 2571 | void *hdr; |
2605 | struct nlattr *pinfoattr; | 2572 | struct nlattr *pinfoattr; |
2606 | struct sk_buff *msg; | 2573 | struct sk_buff *msg; |
2607 | 2574 | ||
2608 | rtnl_lock(); | 2575 | rtnl_lock(); |
2609 | 2576 | ||
2610 | /* Look up our device */ | 2577 | /* Look up our device */ |
2611 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2578 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2612 | if (err) | 2579 | if (err) |
2613 | goto out_rtnl; | 2580 | goto out_rtnl; |
2614 | 2581 | ||
2615 | if (!rdev->ops->get_mesh_params) { | 2582 | if (!rdev->ops->get_mesh_params) { |
2616 | err = -EOPNOTSUPP; | 2583 | err = -EOPNOTSUPP; |
2617 | goto out; | 2584 | goto out; |
2618 | } | 2585 | } |
2619 | 2586 | ||
2620 | /* Get the mesh params */ | 2587 | /* Get the mesh params */ |
2621 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2588 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); |
2622 | if (err) | 2589 | if (err) |
2623 | goto out; | 2590 | goto out; |
2624 | 2591 | ||
2625 | /* Draw up a netlink message to send back */ | 2592 | /* Draw up a netlink message to send back */ |
2626 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2593 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2627 | if (!msg) { | 2594 | if (!msg) { |
2628 | err = -ENOBUFS; | 2595 | err = -ENOBUFS; |
2629 | goto out; | 2596 | goto out; |
2630 | } | 2597 | } |
2631 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2598 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2632 | NL80211_CMD_GET_MESH_PARAMS); | 2599 | NL80211_CMD_GET_MESH_PARAMS); |
2633 | if (!hdr) | 2600 | if (!hdr) |
2634 | goto nla_put_failure; | 2601 | goto nla_put_failure; |
2635 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); | 2602 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); |
2636 | if (!pinfoattr) | 2603 | if (!pinfoattr) |
2637 | goto nla_put_failure; | 2604 | goto nla_put_failure; |
2638 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 2605 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
2639 | NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT, | 2606 | NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT, |
2640 | cur_params.dot11MeshRetryTimeout); | 2607 | cur_params.dot11MeshRetryTimeout); |
2641 | NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT, | 2608 | NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT, |
2642 | cur_params.dot11MeshConfirmTimeout); | 2609 | cur_params.dot11MeshConfirmTimeout); |
2643 | NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT, | 2610 | NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT, |
2644 | cur_params.dot11MeshHoldingTimeout); | 2611 | cur_params.dot11MeshHoldingTimeout); |
2645 | NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, | 2612 | NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, |
2646 | cur_params.dot11MeshMaxPeerLinks); | 2613 | cur_params.dot11MeshMaxPeerLinks); |
2647 | NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES, | 2614 | NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES, |
2648 | cur_params.dot11MeshMaxRetries); | 2615 | cur_params.dot11MeshMaxRetries); |
2649 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, | 2616 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, |
2650 | cur_params.dot11MeshTTL); | 2617 | cur_params.dot11MeshTTL); |
2651 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, | 2618 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
2652 | cur_params.auto_open_plinks); | 2619 | cur_params.auto_open_plinks); |
2653 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 2620 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
2654 | cur_params.dot11MeshHWMPmaxPREQretries); | 2621 | cur_params.dot11MeshHWMPmaxPREQretries); |
2655 | NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME, | 2622 | NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME, |
2656 | cur_params.path_refresh_time); | 2623 | cur_params.path_refresh_time); |
2657 | NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 2624 | NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
2658 | cur_params.min_discovery_timeout); | 2625 | cur_params.min_discovery_timeout); |
2659 | NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 2626 | NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
2660 | cur_params.dot11MeshHWMPactivePathTimeout); | 2627 | cur_params.dot11MeshHWMPactivePathTimeout); |
2661 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 2628 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
2662 | cur_params.dot11MeshHWMPpreqMinInterval); | 2629 | cur_params.dot11MeshHWMPpreqMinInterval); |
2663 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2630 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2664 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); | 2631 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); |
2665 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, | 2632 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, |
2666 | cur_params.dot11MeshHWMPRootMode); | 2633 | cur_params.dot11MeshHWMPRootMode); |
2667 | nla_nest_end(msg, pinfoattr); | 2634 | nla_nest_end(msg, pinfoattr); |
2668 | genlmsg_end(msg, hdr); | 2635 | genlmsg_end(msg, hdr); |
2669 | err = genlmsg_reply(msg, info); | 2636 | err = genlmsg_reply(msg, info); |
2670 | goto out; | 2637 | goto out; |
2671 | 2638 | ||
2672 | nla_put_failure: | 2639 | nla_put_failure: |
2673 | genlmsg_cancel(msg, hdr); | 2640 | genlmsg_cancel(msg, hdr); |
2674 | err = -EMSGSIZE; | 2641 | err = -EMSGSIZE; |
2675 | out: | 2642 | out: |
2676 | /* Cleanup */ | 2643 | /* Cleanup */ |
2677 | cfg80211_unlock_rdev(rdev); | 2644 | cfg80211_unlock_rdev(rdev); |
2678 | dev_put(dev); | 2645 | dev_put(dev); |
2679 | out_rtnl: | 2646 | out_rtnl: |
2680 | rtnl_unlock(); | 2647 | rtnl_unlock(); |
2681 | 2648 | ||
2682 | return err; | 2649 | return err; |
2683 | } | 2650 | } |
2684 | 2651 | ||
2685 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | 2652 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
2686 | do {\ | 2653 | do {\ |
2687 | if (table[attr_num]) {\ | 2654 | if (table[attr_num]) {\ |
2688 | cfg.param = nla_fn(table[attr_num]); \ | 2655 | cfg.param = nla_fn(table[attr_num]); \ |
2689 | mask |= (1 << (attr_num - 1)); \ | 2656 | mask |= (1 << (attr_num - 1)); \ |
2690 | } \ | 2657 | } \ |
2691 | } while (0);\ | 2658 | } while (0);\ |
2692 | 2659 | ||
2693 | static struct nla_policy | 2660 | static struct nla_policy |
2694 | nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = { | 2661 | nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = { |
2695 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, | 2662 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, |
2696 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, | 2663 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, |
2697 | [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, | 2664 | [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, |
2698 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, | 2665 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, |
2699 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, | 2666 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, |
2700 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, | 2667 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, |
2701 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 2668 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
2702 | 2669 | ||
2703 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 2670 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
2704 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, | 2671 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, |
2705 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, | 2672 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, |
2706 | [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, | 2673 | [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, |
2707 | [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, | 2674 | [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, |
2708 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, | 2675 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, |
2709 | }; | 2676 | }; |
2710 | 2677 | ||
2711 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2678 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) |
2712 | { | 2679 | { |
2713 | int err; | 2680 | int err; |
2714 | u32 mask; | 2681 | u32 mask; |
2715 | struct cfg80211_registered_device *rdev; | 2682 | struct cfg80211_registered_device *rdev; |
2716 | struct net_device *dev; | 2683 | struct net_device *dev; |
2717 | struct mesh_config cfg; | 2684 | struct mesh_config cfg; |
2718 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2685 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2719 | struct nlattr *parent_attr; | 2686 | struct nlattr *parent_attr; |
2720 | 2687 | ||
2721 | parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; | 2688 | parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; |
2722 | if (!parent_attr) | 2689 | if (!parent_attr) |
2723 | return -EINVAL; | 2690 | return -EINVAL; |
2724 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, | 2691 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, |
2725 | parent_attr, nl80211_meshconf_params_policy)) | 2692 | parent_attr, nl80211_meshconf_params_policy)) |
2726 | return -EINVAL; | 2693 | return -EINVAL; |
2727 | 2694 | ||
2728 | rtnl_lock(); | 2695 | rtnl_lock(); |
2729 | 2696 | ||
2730 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2697 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2731 | if (err) | 2698 | if (err) |
2732 | goto out_rtnl; | 2699 | goto out_rtnl; |
2733 | 2700 | ||
2734 | if (!rdev->ops->set_mesh_params) { | 2701 | if (!rdev->ops->set_mesh_params) { |
2735 | err = -EOPNOTSUPP; | 2702 | err = -EOPNOTSUPP; |
2736 | goto out; | 2703 | goto out; |
2737 | } | 2704 | } |
2738 | 2705 | ||
2739 | /* This makes sure that there aren't more than 32 mesh config | 2706 | /* This makes sure that there aren't more than 32 mesh config |
2740 | * parameters (otherwise our bitfield scheme would not work.) */ | 2707 | * parameters (otherwise our bitfield scheme would not work.) */ |
2741 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); | 2708 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); |
2742 | 2709 | ||
2743 | /* Fill in the params struct */ | 2710 | /* Fill in the params struct */ |
2744 | mask = 0; | 2711 | mask = 0; |
2745 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 2712 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
2746 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 2713 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); |
2747 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 2714 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
2748 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); | 2715 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); |
2749 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, | 2716 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, |
2750 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); | 2717 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); |
2751 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, | 2718 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, |
2752 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); | 2719 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); |
2753 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, | 2720 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, |
2754 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 2721 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); |
2755 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 2722 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
2756 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 2723 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
2757 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 2724 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
2758 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 2725 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); |
2759 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 2726 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
2760 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 2727 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
2761 | nla_get_u8); | 2728 | nla_get_u8); |
2762 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, | 2729 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, |
2763 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); | 2730 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); |
2764 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, | 2731 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, |
2765 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 2732 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
2766 | nla_get_u16); | 2733 | nla_get_u16); |
2767 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, | 2734 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, |
2768 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 2735 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
2769 | nla_get_u32); | 2736 | nla_get_u32); |
2770 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, | 2737 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, |
2771 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 2738 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
2772 | nla_get_u16); | 2739 | nla_get_u16); |
2773 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 2740 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
2774 | dot11MeshHWMPnetDiameterTraversalTime, | 2741 | dot11MeshHWMPnetDiameterTraversalTime, |
2775 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2742 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2776 | nla_get_u16); | 2743 | nla_get_u16); |
2777 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 2744 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
2778 | dot11MeshHWMPRootMode, mask, | 2745 | dot11MeshHWMPRootMode, mask, |
2779 | NL80211_MESHCONF_HWMP_ROOTMODE, | 2746 | NL80211_MESHCONF_HWMP_ROOTMODE, |
2780 | nla_get_u8); | 2747 | nla_get_u8); |
2781 | 2748 | ||
2782 | /* Apply changes */ | 2749 | /* Apply changes */ |
2783 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2750 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
2784 | 2751 | ||
2785 | out: | 2752 | out: |
2786 | /* cleanup */ | 2753 | /* cleanup */ |
2787 | cfg80211_unlock_rdev(rdev); | 2754 | cfg80211_unlock_rdev(rdev); |
2788 | dev_put(dev); | 2755 | dev_put(dev); |
2789 | out_rtnl: | 2756 | out_rtnl: |
2790 | rtnl_unlock(); | 2757 | rtnl_unlock(); |
2791 | 2758 | ||
2792 | return err; | 2759 | return err; |
2793 | } | 2760 | } |
2794 | 2761 | ||
2795 | #undef FILL_IN_MESH_PARAM_IF_SET | 2762 | #undef FILL_IN_MESH_PARAM_IF_SET |
2796 | 2763 | ||
2797 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 2764 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) |
2798 | { | 2765 | { |
2799 | struct sk_buff *msg; | 2766 | struct sk_buff *msg; |
2800 | void *hdr = NULL; | 2767 | void *hdr = NULL; |
2801 | struct nlattr *nl_reg_rules; | 2768 | struct nlattr *nl_reg_rules; |
2802 | unsigned int i; | 2769 | unsigned int i; |
2803 | int err = -EINVAL; | 2770 | int err = -EINVAL; |
2804 | 2771 | ||
2805 | mutex_lock(&cfg80211_mutex); | 2772 | mutex_lock(&cfg80211_mutex); |
2806 | 2773 | ||
2807 | if (!cfg80211_regdomain) | 2774 | if (!cfg80211_regdomain) |
2808 | goto out; | 2775 | goto out; |
2809 | 2776 | ||
2810 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2777 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2811 | if (!msg) { | 2778 | if (!msg) { |
2812 | err = -ENOBUFS; | 2779 | err = -ENOBUFS; |
2813 | goto out; | 2780 | goto out; |
2814 | } | 2781 | } |
2815 | 2782 | ||
2816 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2783 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2817 | NL80211_CMD_GET_REG); | 2784 | NL80211_CMD_GET_REG); |
2818 | if (!hdr) | 2785 | if (!hdr) |
2819 | goto nla_put_failure; | 2786 | goto nla_put_failure; |
2820 | 2787 | ||
2821 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, | 2788 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, |
2822 | cfg80211_regdomain->alpha2); | 2789 | cfg80211_regdomain->alpha2); |
2823 | 2790 | ||
2824 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 2791 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
2825 | if (!nl_reg_rules) | 2792 | if (!nl_reg_rules) |
2826 | goto nla_put_failure; | 2793 | goto nla_put_failure; |
2827 | 2794 | ||
2828 | for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { | 2795 | for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { |
2829 | struct nlattr *nl_reg_rule; | 2796 | struct nlattr *nl_reg_rule; |
2830 | const struct ieee80211_reg_rule *reg_rule; | 2797 | const struct ieee80211_reg_rule *reg_rule; |
2831 | const struct ieee80211_freq_range *freq_range; | 2798 | const struct ieee80211_freq_range *freq_range; |
2832 | const struct ieee80211_power_rule *power_rule; | 2799 | const struct ieee80211_power_rule *power_rule; |
2833 | 2800 | ||
2834 | reg_rule = &cfg80211_regdomain->reg_rules[i]; | 2801 | reg_rule = &cfg80211_regdomain->reg_rules[i]; |
2835 | freq_range = ®_rule->freq_range; | 2802 | freq_range = ®_rule->freq_range; |
2836 | power_rule = ®_rule->power_rule; | 2803 | power_rule = ®_rule->power_rule; |
2837 | 2804 | ||
2838 | nl_reg_rule = nla_nest_start(msg, i); | 2805 | nl_reg_rule = nla_nest_start(msg, i); |
2839 | if (!nl_reg_rule) | 2806 | if (!nl_reg_rule) |
2840 | goto nla_put_failure; | 2807 | goto nla_put_failure; |
2841 | 2808 | ||
2842 | NLA_PUT_U32(msg, NL80211_ATTR_REG_RULE_FLAGS, | 2809 | NLA_PUT_U32(msg, NL80211_ATTR_REG_RULE_FLAGS, |
2843 | reg_rule->flags); | 2810 | reg_rule->flags); |
2844 | NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_START, | 2811 | NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_START, |
2845 | freq_range->start_freq_khz); | 2812 | freq_range->start_freq_khz); |
2846 | NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_END, | 2813 | NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_END, |
2847 | freq_range->end_freq_khz); | 2814 | freq_range->end_freq_khz); |
2848 | NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, | 2815 | NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, |
2849 | freq_range->max_bandwidth_khz); | 2816 | freq_range->max_bandwidth_khz); |
2850 | NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, | 2817 | NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, |
2851 | power_rule->max_antenna_gain); | 2818 | power_rule->max_antenna_gain); |
2852 | NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, | 2819 | NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, |
2853 | power_rule->max_eirp); | 2820 | power_rule->max_eirp); |
2854 | 2821 | ||
2855 | nla_nest_end(msg, nl_reg_rule); | 2822 | nla_nest_end(msg, nl_reg_rule); |
2856 | } | 2823 | } |
2857 | 2824 | ||
2858 | nla_nest_end(msg, nl_reg_rules); | 2825 | nla_nest_end(msg, nl_reg_rules); |
2859 | 2826 | ||
2860 | genlmsg_end(msg, hdr); | 2827 | genlmsg_end(msg, hdr); |
2861 | err = genlmsg_reply(msg, info); | 2828 | err = genlmsg_reply(msg, info); |
2862 | goto out; | 2829 | goto out; |
2863 | 2830 | ||
2864 | nla_put_failure: | 2831 | nla_put_failure: |
2865 | genlmsg_cancel(msg, hdr); | 2832 | genlmsg_cancel(msg, hdr); |
2866 | err = -EMSGSIZE; | 2833 | err = -EMSGSIZE; |
2867 | out: | 2834 | out: |
2868 | mutex_unlock(&cfg80211_mutex); | 2835 | mutex_unlock(&cfg80211_mutex); |
2869 | return err; | 2836 | return err; |
2870 | } | 2837 | } |
2871 | 2838 | ||
2872 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 2839 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
2873 | { | 2840 | { |
2874 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 2841 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
2875 | struct nlattr *nl_reg_rule; | 2842 | struct nlattr *nl_reg_rule; |
2876 | char *alpha2 = NULL; | 2843 | char *alpha2 = NULL; |
2877 | int rem_reg_rules = 0, r = 0; | 2844 | int rem_reg_rules = 0, r = 0; |
2878 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 2845 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
2879 | struct ieee80211_regdomain *rd = NULL; | 2846 | struct ieee80211_regdomain *rd = NULL; |
2880 | 2847 | ||
2881 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 2848 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
2882 | return -EINVAL; | 2849 | return -EINVAL; |
2883 | 2850 | ||
2884 | if (!info->attrs[NL80211_ATTR_REG_RULES]) | 2851 | if (!info->attrs[NL80211_ATTR_REG_RULES]) |
2885 | return -EINVAL; | 2852 | return -EINVAL; |
2886 | 2853 | ||
2887 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 2854 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
2888 | 2855 | ||
2889 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 2856 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
2890 | rem_reg_rules) { | 2857 | rem_reg_rules) { |
2891 | num_rules++; | 2858 | num_rules++; |
2892 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 2859 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
2893 | return -EINVAL; | 2860 | return -EINVAL; |
2894 | } | 2861 | } |
2895 | 2862 | ||
2896 | mutex_lock(&cfg80211_mutex); | 2863 | mutex_lock(&cfg80211_mutex); |
2897 | 2864 | ||
2898 | if (!reg_is_valid_request(alpha2)) { | 2865 | if (!reg_is_valid_request(alpha2)) { |
2899 | r = -EINVAL; | 2866 | r = -EINVAL; |
2900 | goto bad_reg; | 2867 | goto bad_reg; |
2901 | } | 2868 | } |
2902 | 2869 | ||
2903 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 2870 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
2904 | (num_rules * sizeof(struct ieee80211_reg_rule)); | 2871 | (num_rules * sizeof(struct ieee80211_reg_rule)); |
2905 | 2872 | ||
2906 | rd = kzalloc(size_of_regd, GFP_KERNEL); | 2873 | rd = kzalloc(size_of_regd, GFP_KERNEL); |
2907 | if (!rd) { | 2874 | if (!rd) { |
2908 | r = -ENOMEM; | 2875 | r = -ENOMEM; |
2909 | goto bad_reg; | 2876 | goto bad_reg; |
2910 | } | 2877 | } |
2911 | 2878 | ||
2912 | rd->n_reg_rules = num_rules; | 2879 | rd->n_reg_rules = num_rules; |
2913 | rd->alpha2[0] = alpha2[0]; | 2880 | rd->alpha2[0] = alpha2[0]; |
2914 | rd->alpha2[1] = alpha2[1]; | 2881 | rd->alpha2[1] = alpha2[1]; |
2915 | 2882 | ||
2916 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 2883 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
2917 | rem_reg_rules) { | 2884 | rem_reg_rules) { |
2918 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 2885 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
2919 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), | 2886 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), |
2920 | reg_rule_policy); | 2887 | reg_rule_policy); |
2921 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); | 2888 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); |
2922 | if (r) | 2889 | if (r) |
2923 | goto bad_reg; | 2890 | goto bad_reg; |
2924 | 2891 | ||
2925 | rule_idx++; | 2892 | rule_idx++; |
2926 | 2893 | ||
2927 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { | 2894 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { |
2928 | r = -EINVAL; | 2895 | r = -EINVAL; |
2929 | goto bad_reg; | 2896 | goto bad_reg; |
2930 | } | 2897 | } |
2931 | } | 2898 | } |
2932 | 2899 | ||
2933 | BUG_ON(rule_idx != num_rules); | 2900 | BUG_ON(rule_idx != num_rules); |
2934 | 2901 | ||
2935 | r = set_regdom(rd); | 2902 | r = set_regdom(rd); |
2936 | 2903 | ||
2937 | mutex_unlock(&cfg80211_mutex); | 2904 | mutex_unlock(&cfg80211_mutex); |
2938 | 2905 | ||
2939 | return r; | 2906 | return r; |
2940 | 2907 | ||
2941 | bad_reg: | 2908 | bad_reg: |
2942 | mutex_unlock(&cfg80211_mutex); | 2909 | mutex_unlock(&cfg80211_mutex); |
2943 | kfree(rd); | 2910 | kfree(rd); |
2944 | return r; | 2911 | return r; |
2945 | } | 2912 | } |
2946 | 2913 | ||
2947 | static int validate_scan_freqs(struct nlattr *freqs) | 2914 | static int validate_scan_freqs(struct nlattr *freqs) |
2948 | { | 2915 | { |
2949 | struct nlattr *attr1, *attr2; | 2916 | struct nlattr *attr1, *attr2; |
2950 | int n_channels = 0, tmp1, tmp2; | 2917 | int n_channels = 0, tmp1, tmp2; |
2951 | 2918 | ||
2952 | nla_for_each_nested(attr1, freqs, tmp1) { | 2919 | nla_for_each_nested(attr1, freqs, tmp1) { |
2953 | n_channels++; | 2920 | n_channels++; |
2954 | /* | 2921 | /* |
2955 | * Some hardware has a limited channel list for | 2922 | * Some hardware has a limited channel list for |
2956 | * scanning, and it is pretty much nonsensical | 2923 | * scanning, and it is pretty much nonsensical |
2957 | * to scan for a channel twice, so disallow that | 2924 | * to scan for a channel twice, so disallow that |
2958 | * and don't require drivers to check that the | 2925 | * and don't require drivers to check that the |
2959 | * channel list they get isn't longer than what | 2926 | * channel list they get isn't longer than what |
2960 | * they can scan, as long as they can scan all | 2927 | * they can scan, as long as they can scan all |
2961 | * the channels they registered at once. | 2928 | * the channels they registered at once. |
2962 | */ | 2929 | */ |
2963 | nla_for_each_nested(attr2, freqs, tmp2) | 2930 | nla_for_each_nested(attr2, freqs, tmp2) |
2964 | if (attr1 != attr2 && | 2931 | if (attr1 != attr2 && |
2965 | nla_get_u32(attr1) == nla_get_u32(attr2)) | 2932 | nla_get_u32(attr1) == nla_get_u32(attr2)) |
2966 | return 0; | 2933 | return 0; |
2967 | } | 2934 | } |
2968 | 2935 | ||
2969 | return n_channels; | 2936 | return n_channels; |
2970 | } | 2937 | } |
2971 | 2938 | ||
2972 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2939 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
2973 | { | 2940 | { |
2974 | struct cfg80211_registered_device *rdev; | 2941 | struct cfg80211_registered_device *rdev; |
2975 | struct net_device *dev; | 2942 | struct net_device *dev; |
2976 | struct cfg80211_scan_request *request; | 2943 | struct cfg80211_scan_request *request; |
2977 | struct cfg80211_ssid *ssid; | 2944 | struct cfg80211_ssid *ssid; |
2978 | struct ieee80211_channel *channel; | 2945 | struct ieee80211_channel *channel; |
2979 | struct nlattr *attr; | 2946 | struct nlattr *attr; |
2980 | struct wiphy *wiphy; | 2947 | struct wiphy *wiphy; |
2981 | int err, tmp, n_ssids = 0, n_channels, i; | 2948 | int err, tmp, n_ssids = 0, n_channels, i; |
2982 | enum ieee80211_band band; | 2949 | enum ieee80211_band band; |
2983 | size_t ie_len; | 2950 | size_t ie_len; |
2984 | 2951 | ||
2985 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 2952 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
2986 | return -EINVAL; | 2953 | return -EINVAL; |
2987 | 2954 | ||
2988 | rtnl_lock(); | 2955 | rtnl_lock(); |
2989 | 2956 | ||
2990 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 2957 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2991 | if (err) | 2958 | if (err) |
2992 | goto out_rtnl; | 2959 | goto out_rtnl; |
2993 | 2960 | ||
2994 | wiphy = &rdev->wiphy; | 2961 | wiphy = &rdev->wiphy; |
2995 | 2962 | ||
2996 | if (!rdev->ops->scan) { | 2963 | if (!rdev->ops->scan) { |
2997 | err = -EOPNOTSUPP; | 2964 | err = -EOPNOTSUPP; |
2998 | goto out; | 2965 | goto out; |
2999 | } | 2966 | } |
3000 | 2967 | ||
3001 | if (!netif_running(dev)) { | 2968 | if (!netif_running(dev)) { |
3002 | err = -ENETDOWN; | 2969 | err = -ENETDOWN; |
3003 | goto out; | 2970 | goto out; |
3004 | } | 2971 | } |
3005 | 2972 | ||
3006 | if (rdev->scan_req) { | 2973 | if (rdev->scan_req) { |
3007 | err = -EBUSY; | 2974 | err = -EBUSY; |
3008 | goto out; | 2975 | goto out; |
3009 | } | 2976 | } |
3010 | 2977 | ||
3011 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2978 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
3012 | n_channels = validate_scan_freqs( | 2979 | n_channels = validate_scan_freqs( |
3013 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 2980 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
3014 | if (!n_channels) { | 2981 | if (!n_channels) { |
3015 | err = -EINVAL; | 2982 | err = -EINVAL; |
3016 | goto out; | 2983 | goto out; |
3017 | } | 2984 | } |
3018 | } else { | 2985 | } else { |
3019 | n_channels = 0; | 2986 | n_channels = 0; |
3020 | 2987 | ||
3021 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 2988 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
3022 | if (wiphy->bands[band]) | 2989 | if (wiphy->bands[band]) |
3023 | n_channels += wiphy->bands[band]->n_channels; | 2990 | n_channels += wiphy->bands[band]->n_channels; |
3024 | } | 2991 | } |
3025 | 2992 | ||
3026 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | 2993 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) |
3027 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | 2994 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) |
3028 | n_ssids++; | 2995 | n_ssids++; |
3029 | 2996 | ||
3030 | if (n_ssids > wiphy->max_scan_ssids) { | 2997 | if (n_ssids > wiphy->max_scan_ssids) { |
3031 | err = -EINVAL; | 2998 | err = -EINVAL; |
3032 | goto out; | 2999 | goto out; |
3033 | } | 3000 | } |
3034 | 3001 | ||
3035 | if (info->attrs[NL80211_ATTR_IE]) | 3002 | if (info->attrs[NL80211_ATTR_IE]) |
3036 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3003 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3037 | else | 3004 | else |
3038 | ie_len = 0; | 3005 | ie_len = 0; |
3039 | 3006 | ||
3040 | if (ie_len > wiphy->max_scan_ie_len) { | 3007 | if (ie_len > wiphy->max_scan_ie_len) { |
3041 | err = -EINVAL; | 3008 | err = -EINVAL; |
3042 | goto out; | 3009 | goto out; |
3043 | } | 3010 | } |
3044 | 3011 | ||
3045 | request = kzalloc(sizeof(*request) | 3012 | request = kzalloc(sizeof(*request) |
3046 | + sizeof(*ssid) * n_ssids | 3013 | + sizeof(*ssid) * n_ssids |
3047 | + sizeof(channel) * n_channels | 3014 | + sizeof(channel) * n_channels |
3048 | + ie_len, GFP_KERNEL); | 3015 | + ie_len, GFP_KERNEL); |
3049 | if (!request) { | 3016 | if (!request) { |
3050 | err = -ENOMEM; | 3017 | err = -ENOMEM; |
3051 | goto out; | 3018 | goto out; |
3052 | } | 3019 | } |
3053 | 3020 | ||
3054 | if (n_ssids) | 3021 | if (n_ssids) |
3055 | request->ssids = (void *)&request->channels[n_channels]; | 3022 | request->ssids = (void *)&request->channels[n_channels]; |
3056 | request->n_ssids = n_ssids; | 3023 | request->n_ssids = n_ssids; |
3057 | if (ie_len) { | 3024 | if (ie_len) { |
3058 | if (request->ssids) | 3025 | if (request->ssids) |
3059 | request->ie = (void *)(request->ssids + n_ssids); | 3026 | request->ie = (void *)(request->ssids + n_ssids); |
3060 | else | 3027 | else |
3061 | request->ie = (void *)(request->channels + n_channels); | 3028 | request->ie = (void *)(request->channels + n_channels); |
3062 | } | 3029 | } |
3063 | 3030 | ||
3064 | i = 0; | 3031 | i = 0; |
3065 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 3032 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
3066 | /* user specified, bail out if channel not found */ | 3033 | /* user specified, bail out if channel not found */ |
3067 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { | 3034 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { |
3068 | struct ieee80211_channel *chan; | 3035 | struct ieee80211_channel *chan; |
3069 | 3036 | ||
3070 | chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); | 3037 | chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); |
3071 | 3038 | ||
3072 | if (!chan) { | 3039 | if (!chan) { |
3073 | err = -EINVAL; | 3040 | err = -EINVAL; |
3074 | goto out_free; | 3041 | goto out_free; |
3075 | } | 3042 | } |
3076 | 3043 | ||
3077 | /* ignore disabled channels */ | 3044 | /* ignore disabled channels */ |
3078 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 3045 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
3079 | continue; | 3046 | continue; |
3080 | 3047 | ||
3081 | request->channels[i] = chan; | 3048 | request->channels[i] = chan; |
3082 | i++; | 3049 | i++; |
3083 | } | 3050 | } |
3084 | } else { | 3051 | } else { |
3085 | /* all channels */ | 3052 | /* all channels */ |
3086 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 3053 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
3087 | int j; | 3054 | int j; |
3088 | if (!wiphy->bands[band]) | 3055 | if (!wiphy->bands[band]) |
3089 | continue; | 3056 | continue; |
3090 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { | 3057 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { |
3091 | struct ieee80211_channel *chan; | 3058 | struct ieee80211_channel *chan; |
3092 | 3059 | ||
3093 | chan = &wiphy->bands[band]->channels[j]; | 3060 | chan = &wiphy->bands[band]->channels[j]; |
3094 | 3061 | ||
3095 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 3062 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
3096 | continue; | 3063 | continue; |
3097 | 3064 | ||
3098 | request->channels[i] = chan; | 3065 | request->channels[i] = chan; |
3099 | i++; | 3066 | i++; |
3100 | } | 3067 | } |
3101 | } | 3068 | } |
3102 | } | 3069 | } |
3103 | 3070 | ||
3104 | if (!i) { | 3071 | if (!i) { |
3105 | err = -EINVAL; | 3072 | err = -EINVAL; |
3106 | goto out_free; | 3073 | goto out_free; |
3107 | } | 3074 | } |
3108 | 3075 | ||
3109 | request->n_channels = i; | 3076 | request->n_channels = i; |
3110 | 3077 | ||
3111 | i = 0; | 3078 | i = 0; |
3112 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { | 3079 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { |
3113 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { | 3080 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { |
3114 | if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) { | 3081 | if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) { |
3115 | err = -EINVAL; | 3082 | err = -EINVAL; |
3116 | goto out_free; | 3083 | goto out_free; |
3117 | } | 3084 | } |
3118 | memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); | 3085 | memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); |
3119 | request->ssids[i].ssid_len = nla_len(attr); | 3086 | request->ssids[i].ssid_len = nla_len(attr); |
3120 | i++; | 3087 | i++; |
3121 | } | 3088 | } |
3122 | } | 3089 | } |
3123 | 3090 | ||
3124 | if (info->attrs[NL80211_ATTR_IE]) { | 3091 | if (info->attrs[NL80211_ATTR_IE]) { |
3125 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3092 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3126 | memcpy((void *)request->ie, | 3093 | memcpy((void *)request->ie, |
3127 | nla_data(info->attrs[NL80211_ATTR_IE]), | 3094 | nla_data(info->attrs[NL80211_ATTR_IE]), |
3128 | request->ie_len); | 3095 | request->ie_len); |
3129 | } | 3096 | } |
3130 | 3097 | ||
3131 | request->dev = dev; | 3098 | request->dev = dev; |
3132 | request->wiphy = &rdev->wiphy; | 3099 | request->wiphy = &rdev->wiphy; |
3133 | 3100 | ||
3134 | rdev->scan_req = request; | 3101 | rdev->scan_req = request; |
3135 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 3102 | err = rdev->ops->scan(&rdev->wiphy, dev, request); |
3136 | 3103 | ||
3137 | if (!err) { | 3104 | if (!err) { |
3138 | nl80211_send_scan_start(rdev, dev); | 3105 | nl80211_send_scan_start(rdev, dev); |
3139 | dev_hold(dev); | 3106 | dev_hold(dev); |
3140 | } | 3107 | } |
3141 | 3108 | ||
3142 | out_free: | 3109 | out_free: |
3143 | if (err) { | 3110 | if (err) { |
3144 | rdev->scan_req = NULL; | 3111 | rdev->scan_req = NULL; |
3145 | kfree(request); | 3112 | kfree(request); |
3146 | } | 3113 | } |
3147 | out: | 3114 | out: |
3148 | cfg80211_unlock_rdev(rdev); | 3115 | cfg80211_unlock_rdev(rdev); |
3149 | dev_put(dev); | 3116 | dev_put(dev); |
3150 | out_rtnl: | 3117 | out_rtnl: |
3151 | rtnl_unlock(); | 3118 | rtnl_unlock(); |
3152 | 3119 | ||
3153 | return err; | 3120 | return err; |
3154 | } | 3121 | } |
3155 | 3122 | ||
3156 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 3123 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
3157 | struct cfg80211_registered_device *rdev, | 3124 | struct cfg80211_registered_device *rdev, |
3158 | struct wireless_dev *wdev, | 3125 | struct wireless_dev *wdev, |
3159 | struct cfg80211_internal_bss *intbss) | 3126 | struct cfg80211_internal_bss *intbss) |
3160 | { | 3127 | { |
3161 | struct cfg80211_bss *res = &intbss->pub; | 3128 | struct cfg80211_bss *res = &intbss->pub; |
3162 | void *hdr; | 3129 | void *hdr; |
3163 | struct nlattr *bss; | 3130 | struct nlattr *bss; |
3164 | int i; | 3131 | int i; |
3165 | 3132 | ||
3166 | ASSERT_WDEV_LOCK(wdev); | 3133 | ASSERT_WDEV_LOCK(wdev); |
3167 | 3134 | ||
3168 | hdr = nl80211hdr_put(msg, pid, seq, flags, | 3135 | hdr = nl80211hdr_put(msg, pid, seq, flags, |
3169 | NL80211_CMD_NEW_SCAN_RESULTS); | 3136 | NL80211_CMD_NEW_SCAN_RESULTS); |
3170 | if (!hdr) | 3137 | if (!hdr) |
3171 | return -1; | 3138 | return -1; |
3172 | 3139 | ||
3173 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); | 3140 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3174 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3141 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3175 | 3142 | ||
3176 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 3143 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
3177 | if (!bss) | 3144 | if (!bss) |
3178 | goto nla_put_failure; | 3145 | goto nla_put_failure; |
3179 | if (!is_zero_ether_addr(res->bssid)) | 3146 | if (!is_zero_ether_addr(res->bssid)) |
3180 | NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid); | 3147 | NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid); |
3181 | if (res->information_elements && res->len_information_elements) | 3148 | if (res->information_elements && res->len_information_elements) |
3182 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, | 3149 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, |
3183 | res->len_information_elements, | 3150 | res->len_information_elements, |
3184 | res->information_elements); | 3151 | res->information_elements); |
3185 | if (res->tsf) | 3152 | if (res->tsf) |
3186 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); | 3153 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); |
3187 | if (res->beacon_interval) | 3154 | if (res->beacon_interval) |
3188 | NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval); | 3155 | NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval); |
3189 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); | 3156 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); |
3190 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); | 3157 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); |
3191 | NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO, | 3158 | NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO, |
3192 | jiffies_to_msecs(jiffies - intbss->ts)); | 3159 | jiffies_to_msecs(jiffies - intbss->ts)); |
3193 | 3160 | ||
3194 | switch (rdev->wiphy.signal_type) { | 3161 | switch (rdev->wiphy.signal_type) { |
3195 | case CFG80211_SIGNAL_TYPE_MBM: | 3162 | case CFG80211_SIGNAL_TYPE_MBM: |
3196 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); | 3163 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); |
3197 | break; | 3164 | break; |
3198 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 3165 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
3199 | NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal); | 3166 | NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal); |
3200 | break; | 3167 | break; |
3201 | default: | 3168 | default: |
3202 | break; | 3169 | break; |
3203 | } | 3170 | } |
3204 | 3171 | ||
3205 | switch (wdev->iftype) { | 3172 | switch (wdev->iftype) { |
3206 | case NL80211_IFTYPE_STATION: | 3173 | case NL80211_IFTYPE_STATION: |
3207 | if (intbss == wdev->current_bss) | 3174 | if (intbss == wdev->current_bss) |
3208 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, | 3175 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, |
3209 | NL80211_BSS_STATUS_ASSOCIATED); | 3176 | NL80211_BSS_STATUS_ASSOCIATED); |
3210 | else for (i = 0; i < MAX_AUTH_BSSES; i++) { | 3177 | else for (i = 0; i < MAX_AUTH_BSSES; i++) { |
3211 | if (intbss != wdev->auth_bsses[i]) | 3178 | if (intbss != wdev->auth_bsses[i]) |
3212 | continue; | 3179 | continue; |
3213 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, | 3180 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, |
3214 | NL80211_BSS_STATUS_AUTHENTICATED); | 3181 | NL80211_BSS_STATUS_AUTHENTICATED); |
3215 | break; | 3182 | break; |
3216 | } | 3183 | } |
3217 | break; | 3184 | break; |
3218 | case NL80211_IFTYPE_ADHOC: | 3185 | case NL80211_IFTYPE_ADHOC: |
3219 | if (intbss == wdev->current_bss) | 3186 | if (intbss == wdev->current_bss) |
3220 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, | 3187 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, |
3221 | NL80211_BSS_STATUS_IBSS_JOINED); | 3188 | NL80211_BSS_STATUS_IBSS_JOINED); |
3222 | break; | 3189 | break; |
3223 | default: | 3190 | default: |
3224 | break; | 3191 | break; |
3225 | } | 3192 | } |
3226 | 3193 | ||
3227 | nla_nest_end(msg, bss); | 3194 | nla_nest_end(msg, bss); |
3228 | 3195 | ||
3229 | return genlmsg_end(msg, hdr); | 3196 | return genlmsg_end(msg, hdr); |
3230 | 3197 | ||
3231 | nla_put_failure: | 3198 | nla_put_failure: |
3232 | genlmsg_cancel(msg, hdr); | 3199 | genlmsg_cancel(msg, hdr); |
3233 | return -EMSGSIZE; | 3200 | return -EMSGSIZE; |
3234 | } | 3201 | } |
3235 | 3202 | ||
3236 | static int nl80211_dump_scan(struct sk_buff *skb, | 3203 | static int nl80211_dump_scan(struct sk_buff *skb, |
3237 | struct netlink_callback *cb) | 3204 | struct netlink_callback *cb) |
3238 | { | 3205 | { |
3239 | struct cfg80211_registered_device *rdev; | 3206 | struct cfg80211_registered_device *rdev; |
3240 | struct net_device *dev; | 3207 | struct net_device *dev; |
3241 | struct cfg80211_internal_bss *scan; | 3208 | struct cfg80211_internal_bss *scan; |
3242 | struct wireless_dev *wdev; | 3209 | struct wireless_dev *wdev; |
3243 | int ifidx = cb->args[0]; | 3210 | int ifidx = cb->args[0]; |
3244 | int start = cb->args[1], idx = 0; | 3211 | int start = cb->args[1], idx = 0; |
3245 | int err; | 3212 | int err; |
3246 | 3213 | ||
3247 | if (!ifidx) | 3214 | if (!ifidx) |
3248 | ifidx = nl80211_get_ifidx(cb); | 3215 | ifidx = nl80211_get_ifidx(cb); |
3249 | if (ifidx < 0) | 3216 | if (ifidx < 0) |
3250 | return ifidx; | 3217 | return ifidx; |
3251 | cb->args[0] = ifidx; | 3218 | cb->args[0] = ifidx; |
3252 | 3219 | ||
3253 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | 3220 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); |
3254 | if (!dev) | 3221 | if (!dev) |
3255 | return -ENODEV; | 3222 | return -ENODEV; |
3256 | 3223 | ||
3257 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | 3224 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
3258 | if (IS_ERR(rdev)) { | 3225 | if (IS_ERR(rdev)) { |
3259 | err = PTR_ERR(rdev); | 3226 | err = PTR_ERR(rdev); |
3260 | goto out_put_netdev; | 3227 | goto out_put_netdev; |
3261 | } | 3228 | } |
3262 | 3229 | ||
3263 | wdev = dev->ieee80211_ptr; | 3230 | wdev = dev->ieee80211_ptr; |
3264 | 3231 | ||
3265 | wdev_lock(wdev); | 3232 | wdev_lock(wdev); |
3266 | spin_lock_bh(&rdev->bss_lock); | 3233 | spin_lock_bh(&rdev->bss_lock); |
3267 | cfg80211_bss_expire(rdev); | 3234 | cfg80211_bss_expire(rdev); |
3268 | 3235 | ||
3269 | list_for_each_entry(scan, &rdev->bss_list, list) { | 3236 | list_for_each_entry(scan, &rdev->bss_list, list) { |
3270 | if (++idx <= start) | 3237 | if (++idx <= start) |
3271 | continue; | 3238 | continue; |
3272 | if (nl80211_send_bss(skb, | 3239 | if (nl80211_send_bss(skb, |
3273 | NETLINK_CB(cb->skb).pid, | 3240 | NETLINK_CB(cb->skb).pid, |
3274 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3241 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3275 | rdev, wdev, scan) < 0) { | 3242 | rdev, wdev, scan) < 0) { |
3276 | idx--; | 3243 | idx--; |
3277 | goto out; | 3244 | goto out; |
3278 | } | 3245 | } |
3279 | } | 3246 | } |
3280 | 3247 | ||
3281 | out: | 3248 | out: |
3282 | spin_unlock_bh(&rdev->bss_lock); | 3249 | spin_unlock_bh(&rdev->bss_lock); |
3283 | wdev_unlock(wdev); | 3250 | wdev_unlock(wdev); |
3284 | 3251 | ||
3285 | cb->args[1] = idx; | 3252 | cb->args[1] = idx; |
3286 | err = skb->len; | 3253 | err = skb->len; |
3287 | cfg80211_unlock_rdev(rdev); | 3254 | cfg80211_unlock_rdev(rdev); |
3288 | out_put_netdev: | 3255 | out_put_netdev: |
3289 | dev_put(dev); | 3256 | dev_put(dev); |
3290 | 3257 | ||
3291 | return err; | 3258 | return err; |
3292 | } | 3259 | } |
3293 | 3260 | ||
3294 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | 3261 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, |
3295 | int flags, struct net_device *dev, | 3262 | int flags, struct net_device *dev, |
3296 | struct survey_info *survey) | 3263 | struct survey_info *survey) |
3297 | { | 3264 | { |
3298 | void *hdr; | 3265 | void *hdr; |
3299 | struct nlattr *infoattr; | 3266 | struct nlattr *infoattr; |
3300 | 3267 | ||
3301 | /* Survey without a channel doesn't make sense */ | 3268 | /* Survey without a channel doesn't make sense */ |
3302 | if (!survey->channel) | 3269 | if (!survey->channel) |
3303 | return -EINVAL; | 3270 | return -EINVAL; |
3304 | 3271 | ||
3305 | hdr = nl80211hdr_put(msg, pid, seq, flags, | 3272 | hdr = nl80211hdr_put(msg, pid, seq, flags, |
3306 | NL80211_CMD_NEW_SURVEY_RESULTS); | 3273 | NL80211_CMD_NEW_SURVEY_RESULTS); |
3307 | if (!hdr) | 3274 | if (!hdr) |
3308 | return -ENOMEM; | 3275 | return -ENOMEM; |
3309 | 3276 | ||
3310 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 3277 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
3311 | 3278 | ||
3312 | infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); | 3279 | infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); |
3313 | if (!infoattr) | 3280 | if (!infoattr) |
3314 | goto nla_put_failure; | 3281 | goto nla_put_failure; |
3315 | 3282 | ||
3316 | NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, | 3283 | NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, |
3317 | survey->channel->center_freq); | 3284 | survey->channel->center_freq); |
3318 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | 3285 | if (survey->filled & SURVEY_INFO_NOISE_DBM) |
3319 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | 3286 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, |
3320 | survey->noise); | 3287 | survey->noise); |
3321 | 3288 | ||
3322 | nla_nest_end(msg, infoattr); | 3289 | nla_nest_end(msg, infoattr); |
3323 | 3290 | ||
3324 | return genlmsg_end(msg, hdr); | 3291 | return genlmsg_end(msg, hdr); |
3325 | 3292 | ||
3326 | nla_put_failure: | 3293 | nla_put_failure: |
3327 | genlmsg_cancel(msg, hdr); | 3294 | genlmsg_cancel(msg, hdr); |
3328 | return -EMSGSIZE; | 3295 | return -EMSGSIZE; |
3329 | } | 3296 | } |
3330 | 3297 | ||
3331 | static int nl80211_dump_survey(struct sk_buff *skb, | 3298 | static int nl80211_dump_survey(struct sk_buff *skb, |
3332 | struct netlink_callback *cb) | 3299 | struct netlink_callback *cb) |
3333 | { | 3300 | { |
3334 | struct survey_info survey; | 3301 | struct survey_info survey; |
3335 | struct cfg80211_registered_device *dev; | 3302 | struct cfg80211_registered_device *dev; |
3336 | struct net_device *netdev; | 3303 | struct net_device *netdev; |
3337 | int ifidx = cb->args[0]; | 3304 | int ifidx = cb->args[0]; |
3338 | int survey_idx = cb->args[1]; | 3305 | int survey_idx = cb->args[1]; |
3339 | int res; | 3306 | int res; |
3340 | 3307 | ||
3341 | if (!ifidx) | 3308 | if (!ifidx) |
3342 | ifidx = nl80211_get_ifidx(cb); | 3309 | ifidx = nl80211_get_ifidx(cb); |
3343 | if (ifidx < 0) | 3310 | if (ifidx < 0) |
3344 | return ifidx; | 3311 | return ifidx; |
3345 | cb->args[0] = ifidx; | 3312 | cb->args[0] = ifidx; |
3346 | 3313 | ||
3347 | rtnl_lock(); | 3314 | rtnl_lock(); |
3348 | 3315 | ||
3349 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | 3316 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
3350 | if (!netdev) { | 3317 | if (!netdev) { |
3351 | res = -ENODEV; | 3318 | res = -ENODEV; |
3352 | goto out_rtnl; | 3319 | goto out_rtnl; |
3353 | } | 3320 | } |
3354 | 3321 | ||
3355 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | 3322 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
3356 | if (IS_ERR(dev)) { | 3323 | if (IS_ERR(dev)) { |
3357 | res = PTR_ERR(dev); | 3324 | res = PTR_ERR(dev); |
3358 | goto out_rtnl; | 3325 | goto out_rtnl; |
3359 | } | 3326 | } |
3360 | 3327 | ||
3361 | if (!dev->ops->dump_survey) { | 3328 | if (!dev->ops->dump_survey) { |
3362 | res = -EOPNOTSUPP; | 3329 | res = -EOPNOTSUPP; |
3363 | goto out_err; | 3330 | goto out_err; |
3364 | } | 3331 | } |
3365 | 3332 | ||
3366 | while (1) { | 3333 | while (1) { |
3367 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, | 3334 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, |
3368 | &survey); | 3335 | &survey); |
3369 | if (res == -ENOENT) | 3336 | if (res == -ENOENT) |
3370 | break; | 3337 | break; |
3371 | if (res) | 3338 | if (res) |
3372 | goto out_err; | 3339 | goto out_err; |
3373 | 3340 | ||
3374 | if (nl80211_send_survey(skb, | 3341 | if (nl80211_send_survey(skb, |
3375 | NETLINK_CB(cb->skb).pid, | 3342 | NETLINK_CB(cb->skb).pid, |
3376 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3343 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3377 | netdev, | 3344 | netdev, |
3378 | &survey) < 0) | 3345 | &survey) < 0) |
3379 | goto out; | 3346 | goto out; |
3380 | survey_idx++; | 3347 | survey_idx++; |
3381 | } | 3348 | } |
3382 | 3349 | ||
3383 | out: | 3350 | out: |
3384 | cb->args[1] = survey_idx; | 3351 | cb->args[1] = survey_idx; |
3385 | res = skb->len; | 3352 | res = skb->len; |
3386 | out_err: | 3353 | out_err: |
3387 | cfg80211_unlock_rdev(dev); | 3354 | cfg80211_unlock_rdev(dev); |
3388 | out_rtnl: | 3355 | out_rtnl: |
3389 | rtnl_unlock(); | 3356 | rtnl_unlock(); |
3390 | 3357 | ||
3391 | return res; | 3358 | return res; |
3392 | } | 3359 | } |
3393 | 3360 | ||
3394 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | 3361 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) |
3395 | { | 3362 | { |
3396 | return auth_type <= NL80211_AUTHTYPE_MAX; | 3363 | return auth_type <= NL80211_AUTHTYPE_MAX; |
3397 | } | 3364 | } |
3398 | 3365 | ||
3399 | static bool nl80211_valid_wpa_versions(u32 wpa_versions) | 3366 | static bool nl80211_valid_wpa_versions(u32 wpa_versions) |
3400 | { | 3367 | { |
3401 | return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | | 3368 | return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | |
3402 | NL80211_WPA_VERSION_2)); | 3369 | NL80211_WPA_VERSION_2)); |
3403 | } | 3370 | } |
3404 | 3371 | ||
3405 | static bool nl80211_valid_akm_suite(u32 akm) | 3372 | static bool nl80211_valid_akm_suite(u32 akm) |
3406 | { | 3373 | { |
3407 | return akm == WLAN_AKM_SUITE_8021X || | 3374 | return akm == WLAN_AKM_SUITE_8021X || |
3408 | akm == WLAN_AKM_SUITE_PSK; | 3375 | akm == WLAN_AKM_SUITE_PSK; |
3409 | } | 3376 | } |
3410 | 3377 | ||
3411 | static bool nl80211_valid_cipher_suite(u32 cipher) | 3378 | static bool nl80211_valid_cipher_suite(u32 cipher) |
3412 | { | 3379 | { |
3413 | return cipher == WLAN_CIPHER_SUITE_WEP40 || | 3380 | return cipher == WLAN_CIPHER_SUITE_WEP40 || |
3414 | cipher == WLAN_CIPHER_SUITE_WEP104 || | 3381 | cipher == WLAN_CIPHER_SUITE_WEP104 || |
3415 | cipher == WLAN_CIPHER_SUITE_TKIP || | 3382 | cipher == WLAN_CIPHER_SUITE_TKIP || |
3416 | cipher == WLAN_CIPHER_SUITE_CCMP || | 3383 | cipher == WLAN_CIPHER_SUITE_CCMP || |
3417 | cipher == WLAN_CIPHER_SUITE_AES_CMAC; | 3384 | cipher == WLAN_CIPHER_SUITE_AES_CMAC; |
3418 | } | 3385 | } |
3419 | 3386 | ||
3420 | 3387 | ||
3421 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | 3388 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) |
3422 | { | 3389 | { |
3423 | struct cfg80211_registered_device *rdev; | 3390 | struct cfg80211_registered_device *rdev; |
3424 | struct net_device *dev; | 3391 | struct net_device *dev; |
3425 | struct ieee80211_channel *chan; | 3392 | struct ieee80211_channel *chan; |
3426 | const u8 *bssid, *ssid, *ie = NULL; | 3393 | const u8 *bssid, *ssid, *ie = NULL; |
3427 | int err, ssid_len, ie_len = 0; | 3394 | int err, ssid_len, ie_len = 0; |
3428 | enum nl80211_auth_type auth_type; | 3395 | enum nl80211_auth_type auth_type; |
3429 | struct key_parse key; | 3396 | struct key_parse key; |
3430 | 3397 | ||
3431 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3398 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3432 | return -EINVAL; | 3399 | return -EINVAL; |
3433 | 3400 | ||
3434 | if (!info->attrs[NL80211_ATTR_MAC]) | 3401 | if (!info->attrs[NL80211_ATTR_MAC]) |
3435 | return -EINVAL; | 3402 | return -EINVAL; |
3436 | 3403 | ||
3437 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) | 3404 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) |
3438 | return -EINVAL; | 3405 | return -EINVAL; |
3439 | 3406 | ||
3440 | if (!info->attrs[NL80211_ATTR_SSID]) | 3407 | if (!info->attrs[NL80211_ATTR_SSID]) |
3441 | return -EINVAL; | 3408 | return -EINVAL; |
3442 | 3409 | ||
3443 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 3410 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
3444 | return -EINVAL; | 3411 | return -EINVAL; |
3445 | 3412 | ||
3446 | err = nl80211_parse_key(info, &key); | 3413 | err = nl80211_parse_key(info, &key); |
3447 | if (err) | 3414 | if (err) |
3448 | return err; | 3415 | return err; |
3449 | 3416 | ||
3450 | if (key.idx >= 0) { | 3417 | if (key.idx >= 0) { |
3451 | if (!key.p.key || !key.p.key_len) | 3418 | if (!key.p.key || !key.p.key_len) |
3452 | return -EINVAL; | 3419 | return -EINVAL; |
3453 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || | 3420 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || |
3454 | key.p.key_len != WLAN_KEY_LEN_WEP40) && | 3421 | key.p.key_len != WLAN_KEY_LEN_WEP40) && |
3455 | (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 || | 3422 | (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 || |
3456 | key.p.key_len != WLAN_KEY_LEN_WEP104)) | 3423 | key.p.key_len != WLAN_KEY_LEN_WEP104)) |
3457 | return -EINVAL; | 3424 | return -EINVAL; |
3458 | if (key.idx > 4) | 3425 | if (key.idx > 4) |
3459 | return -EINVAL; | 3426 | return -EINVAL; |
3460 | } else { | 3427 | } else { |
3461 | key.p.key_len = 0; | 3428 | key.p.key_len = 0; |
3462 | key.p.key = NULL; | 3429 | key.p.key = NULL; |
3463 | } | 3430 | } |
3464 | 3431 | ||
3465 | rtnl_lock(); | 3432 | rtnl_lock(); |
3466 | 3433 | ||
3467 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3434 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3468 | if (err) | 3435 | if (err) |
3469 | goto unlock_rtnl; | 3436 | goto unlock_rtnl; |
3470 | 3437 | ||
3471 | if (!rdev->ops->auth) { | 3438 | if (!rdev->ops->auth) { |
3472 | err = -EOPNOTSUPP; | 3439 | err = -EOPNOTSUPP; |
3473 | goto out; | 3440 | goto out; |
3474 | } | 3441 | } |
3475 | 3442 | ||
3476 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3443 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
3477 | err = -EOPNOTSUPP; | 3444 | err = -EOPNOTSUPP; |
3478 | goto out; | 3445 | goto out; |
3479 | } | 3446 | } |
3480 | 3447 | ||
3481 | if (!netif_running(dev)) { | 3448 | if (!netif_running(dev)) { |
3482 | err = -ENETDOWN; | 3449 | err = -ENETDOWN; |
3483 | goto out; | 3450 | goto out; |
3484 | } | 3451 | } |
3485 | 3452 | ||
3486 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3453 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3487 | chan = ieee80211_get_channel(&rdev->wiphy, | 3454 | chan = ieee80211_get_channel(&rdev->wiphy, |
3488 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3455 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3489 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3456 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { |
3490 | err = -EINVAL; | 3457 | err = -EINVAL; |
3491 | goto out; | 3458 | goto out; |
3492 | } | 3459 | } |
3493 | 3460 | ||
3494 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3461 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3495 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3462 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3496 | 3463 | ||
3497 | if (info->attrs[NL80211_ATTR_IE]) { | 3464 | if (info->attrs[NL80211_ATTR_IE]) { |
3498 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3465 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3499 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3466 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3500 | } | 3467 | } |
3501 | 3468 | ||
3502 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3469 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
3503 | if (!nl80211_valid_auth_type(auth_type)) { | 3470 | if (!nl80211_valid_auth_type(auth_type)) { |
3504 | err = -EINVAL; | 3471 | err = -EINVAL; |
3505 | goto out; | 3472 | goto out; |
3506 | } | 3473 | } |
3507 | 3474 | ||
3508 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 3475 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
3509 | ssid, ssid_len, ie, ie_len, | 3476 | ssid, ssid_len, ie, ie_len, |
3510 | key.p.key, key.p.key_len, key.idx); | 3477 | key.p.key, key.p.key_len, key.idx); |
3511 | 3478 | ||
3512 | out: | 3479 | out: |
3513 | cfg80211_unlock_rdev(rdev); | 3480 | cfg80211_unlock_rdev(rdev); |
3514 | dev_put(dev); | 3481 | dev_put(dev); |
3515 | unlock_rtnl: | 3482 | unlock_rtnl: |
3516 | rtnl_unlock(); | 3483 | rtnl_unlock(); |
3517 | return err; | 3484 | return err; |
3518 | } | 3485 | } |
3519 | 3486 | ||
3520 | static int nl80211_crypto_settings(struct genl_info *info, | 3487 | static int nl80211_crypto_settings(struct genl_info *info, |
3521 | struct cfg80211_crypto_settings *settings, | 3488 | struct cfg80211_crypto_settings *settings, |
3522 | int cipher_limit) | 3489 | int cipher_limit) |
3523 | { | 3490 | { |
3524 | memset(settings, 0, sizeof(*settings)); | 3491 | memset(settings, 0, sizeof(*settings)); |
3525 | 3492 | ||
3526 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | 3493 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; |
3527 | 3494 | ||
3528 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { | 3495 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { |
3529 | void *data; | 3496 | void *data; |
3530 | int len, i; | 3497 | int len, i; |
3531 | 3498 | ||
3532 | data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); | 3499 | data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); |
3533 | len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); | 3500 | len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); |
3534 | settings->n_ciphers_pairwise = len / sizeof(u32); | 3501 | settings->n_ciphers_pairwise = len / sizeof(u32); |
3535 | 3502 | ||
3536 | if (len % sizeof(u32)) | 3503 | if (len % sizeof(u32)) |
3537 | return -EINVAL; | 3504 | return -EINVAL; |
3538 | 3505 | ||
3539 | if (settings->n_ciphers_pairwise > cipher_limit) | 3506 | if (settings->n_ciphers_pairwise > cipher_limit) |
3540 | return -EINVAL; | 3507 | return -EINVAL; |
3541 | 3508 | ||
3542 | memcpy(settings->ciphers_pairwise, data, len); | 3509 | memcpy(settings->ciphers_pairwise, data, len); |
3543 | 3510 | ||
3544 | for (i = 0; i < settings->n_ciphers_pairwise; i++) | 3511 | for (i = 0; i < settings->n_ciphers_pairwise; i++) |
3545 | if (!nl80211_valid_cipher_suite( | 3512 | if (!nl80211_valid_cipher_suite( |
3546 | settings->ciphers_pairwise[i])) | 3513 | settings->ciphers_pairwise[i])) |
3547 | return -EINVAL; | 3514 | return -EINVAL; |
3548 | } | 3515 | } |
3549 | 3516 | ||
3550 | if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) { | 3517 | if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) { |
3551 | settings->cipher_group = | 3518 | settings->cipher_group = |
3552 | nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]); | 3519 | nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]); |
3553 | if (!nl80211_valid_cipher_suite(settings->cipher_group)) | 3520 | if (!nl80211_valid_cipher_suite(settings->cipher_group)) |
3554 | return -EINVAL; | 3521 | return -EINVAL; |
3555 | } | 3522 | } |
3556 | 3523 | ||
3557 | if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) { | 3524 | if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) { |
3558 | settings->wpa_versions = | 3525 | settings->wpa_versions = |
3559 | nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]); | 3526 | nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]); |
3560 | if (!nl80211_valid_wpa_versions(settings->wpa_versions)) | 3527 | if (!nl80211_valid_wpa_versions(settings->wpa_versions)) |
3561 | return -EINVAL; | 3528 | return -EINVAL; |
3562 | } | 3529 | } |
3563 | 3530 | ||
3564 | if (info->attrs[NL80211_ATTR_AKM_SUITES]) { | 3531 | if (info->attrs[NL80211_ATTR_AKM_SUITES]) { |
3565 | void *data; | 3532 | void *data; |
3566 | int len, i; | 3533 | int len, i; |
3567 | 3534 | ||
3568 | data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]); | 3535 | data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]); |
3569 | len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]); | 3536 | len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]); |
3570 | settings->n_akm_suites = len / sizeof(u32); | 3537 | settings->n_akm_suites = len / sizeof(u32); |
3571 | 3538 | ||
3572 | if (len % sizeof(u32)) | 3539 | if (len % sizeof(u32)) |
3573 | return -EINVAL; | 3540 | return -EINVAL; |
3574 | 3541 | ||
3575 | memcpy(settings->akm_suites, data, len); | 3542 | memcpy(settings->akm_suites, data, len); |
3576 | 3543 | ||
3577 | for (i = 0; i < settings->n_ciphers_pairwise; i++) | 3544 | for (i = 0; i < settings->n_ciphers_pairwise; i++) |
3578 | if (!nl80211_valid_akm_suite(settings->akm_suites[i])) | 3545 | if (!nl80211_valid_akm_suite(settings->akm_suites[i])) |
3579 | return -EINVAL; | 3546 | return -EINVAL; |
3580 | } | 3547 | } |
3581 | 3548 | ||
3582 | return 0; | 3549 | return 0; |
3583 | } | 3550 | } |
3584 | 3551 | ||
3585 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3552 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3586 | { | 3553 | { |
3587 | struct cfg80211_registered_device *rdev; | 3554 | struct cfg80211_registered_device *rdev; |
3588 | struct net_device *dev; | 3555 | struct net_device *dev; |
3589 | struct cfg80211_crypto_settings crypto; | 3556 | struct cfg80211_crypto_settings crypto; |
3590 | struct ieee80211_channel *chan, *fixedchan; | 3557 | struct ieee80211_channel *chan, *fixedchan; |
3591 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3558 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
3592 | int err, ssid_len, ie_len = 0; | 3559 | int err, ssid_len, ie_len = 0; |
3593 | bool use_mfp = false; | 3560 | bool use_mfp = false; |
3594 | 3561 | ||
3595 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3562 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3596 | return -EINVAL; | 3563 | return -EINVAL; |
3597 | 3564 | ||
3598 | if (!info->attrs[NL80211_ATTR_MAC] || | 3565 | if (!info->attrs[NL80211_ATTR_MAC] || |
3599 | !info->attrs[NL80211_ATTR_SSID] || | 3566 | !info->attrs[NL80211_ATTR_SSID] || |
3600 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 3567 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
3601 | return -EINVAL; | 3568 | return -EINVAL; |
3602 | 3569 | ||
3603 | rtnl_lock(); | 3570 | rtnl_lock(); |
3604 | 3571 | ||
3605 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3572 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3606 | if (err) | 3573 | if (err) |
3607 | goto unlock_rtnl; | 3574 | goto unlock_rtnl; |
3608 | 3575 | ||
3609 | if (!rdev->ops->assoc) { | 3576 | if (!rdev->ops->assoc) { |
3610 | err = -EOPNOTSUPP; | 3577 | err = -EOPNOTSUPP; |
3611 | goto out; | 3578 | goto out; |
3612 | } | 3579 | } |
3613 | 3580 | ||
3614 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3581 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
3615 | err = -EOPNOTSUPP; | 3582 | err = -EOPNOTSUPP; |
3616 | goto out; | 3583 | goto out; |
3617 | } | 3584 | } |
3618 | 3585 | ||
3619 | if (!netif_running(dev)) { | 3586 | if (!netif_running(dev)) { |
3620 | err = -ENETDOWN; | 3587 | err = -ENETDOWN; |
3621 | goto out; | 3588 | goto out; |
3622 | } | 3589 | } |
3623 | 3590 | ||
3624 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3591 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3625 | 3592 | ||
3626 | chan = ieee80211_get_channel(&rdev->wiphy, | 3593 | chan = ieee80211_get_channel(&rdev->wiphy, |
3627 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3594 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3628 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3595 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { |
3629 | err = -EINVAL; | 3596 | err = -EINVAL; |
3630 | goto out; | 3597 | goto out; |
3631 | } | 3598 | } |
3632 | 3599 | ||
3633 | mutex_lock(&rdev->devlist_mtx); | 3600 | mutex_lock(&rdev->devlist_mtx); |
3634 | fixedchan = rdev_fixed_channel(rdev, NULL); | 3601 | fixedchan = rdev_fixed_channel(rdev, NULL); |
3635 | if (fixedchan && chan != fixedchan) { | 3602 | if (fixedchan && chan != fixedchan) { |
3636 | err = -EBUSY; | 3603 | err = -EBUSY; |
3637 | mutex_unlock(&rdev->devlist_mtx); | 3604 | mutex_unlock(&rdev->devlist_mtx); |
3638 | goto out; | 3605 | goto out; |
3639 | } | 3606 | } |
3640 | mutex_unlock(&rdev->devlist_mtx); | 3607 | mutex_unlock(&rdev->devlist_mtx); |
3641 | 3608 | ||
3642 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3609 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3643 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3610 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3644 | 3611 | ||
3645 | if (info->attrs[NL80211_ATTR_IE]) { | 3612 | if (info->attrs[NL80211_ATTR_IE]) { |
3646 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3613 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3647 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3614 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3648 | } | 3615 | } |
3649 | 3616 | ||
3650 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | 3617 | if (info->attrs[NL80211_ATTR_USE_MFP]) { |
3651 | enum nl80211_mfp mfp = | 3618 | enum nl80211_mfp mfp = |
3652 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 3619 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
3653 | if (mfp == NL80211_MFP_REQUIRED) | 3620 | if (mfp == NL80211_MFP_REQUIRED) |
3654 | use_mfp = true; | 3621 | use_mfp = true; |
3655 | else if (mfp != NL80211_MFP_NO) { | 3622 | else if (mfp != NL80211_MFP_NO) { |
3656 | err = -EINVAL; | 3623 | err = -EINVAL; |
3657 | goto out; | 3624 | goto out; |
3658 | } | 3625 | } |
3659 | } | 3626 | } |
3660 | 3627 | ||
3661 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 3628 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
3662 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 3629 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
3663 | 3630 | ||
3664 | err = nl80211_crypto_settings(info, &crypto, 1); | 3631 | err = nl80211_crypto_settings(info, &crypto, 1); |
3665 | if (!err) | 3632 | if (!err) |
3666 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 3633 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
3667 | ssid, ssid_len, ie, ie_len, use_mfp, | 3634 | ssid, ssid_len, ie, ie_len, use_mfp, |
3668 | &crypto); | 3635 | &crypto); |
3669 | 3636 | ||
3670 | out: | 3637 | out: |
3671 | cfg80211_unlock_rdev(rdev); | 3638 | cfg80211_unlock_rdev(rdev); |
3672 | dev_put(dev); | 3639 | dev_put(dev); |
3673 | unlock_rtnl: | 3640 | unlock_rtnl: |
3674 | rtnl_unlock(); | 3641 | rtnl_unlock(); |
3675 | return err; | 3642 | return err; |
3676 | } | 3643 | } |
3677 | 3644 | ||
3678 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | 3645 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) |
3679 | { | 3646 | { |
3680 | struct cfg80211_registered_device *rdev; | 3647 | struct cfg80211_registered_device *rdev; |
3681 | struct net_device *dev; | 3648 | struct net_device *dev; |
3682 | const u8 *ie = NULL, *bssid; | 3649 | const u8 *ie = NULL, *bssid; |
3683 | int err, ie_len = 0; | 3650 | int err, ie_len = 0; |
3684 | u16 reason_code; | 3651 | u16 reason_code; |
3685 | 3652 | ||
3686 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3653 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3687 | return -EINVAL; | 3654 | return -EINVAL; |
3688 | 3655 | ||
3689 | if (!info->attrs[NL80211_ATTR_MAC]) | 3656 | if (!info->attrs[NL80211_ATTR_MAC]) |
3690 | return -EINVAL; | 3657 | return -EINVAL; |
3691 | 3658 | ||
3692 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3659 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3693 | return -EINVAL; | 3660 | return -EINVAL; |
3694 | 3661 | ||
3695 | rtnl_lock(); | 3662 | rtnl_lock(); |
3696 | 3663 | ||
3697 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3664 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3698 | if (err) | 3665 | if (err) |
3699 | goto unlock_rtnl; | 3666 | goto unlock_rtnl; |
3700 | 3667 | ||
3701 | if (!rdev->ops->deauth) { | 3668 | if (!rdev->ops->deauth) { |
3702 | err = -EOPNOTSUPP; | 3669 | err = -EOPNOTSUPP; |
3703 | goto out; | 3670 | goto out; |
3704 | } | 3671 | } |
3705 | 3672 | ||
3706 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3673 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
3707 | err = -EOPNOTSUPP; | 3674 | err = -EOPNOTSUPP; |
3708 | goto out; | 3675 | goto out; |
3709 | } | 3676 | } |
3710 | 3677 | ||
3711 | if (!netif_running(dev)) { | 3678 | if (!netif_running(dev)) { |
3712 | err = -ENETDOWN; | 3679 | err = -ENETDOWN; |
3713 | goto out; | 3680 | goto out; |
3714 | } | 3681 | } |
3715 | 3682 | ||
3716 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3683 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3717 | 3684 | ||
3718 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3685 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3719 | if (reason_code == 0) { | 3686 | if (reason_code == 0) { |
3720 | /* Reason Code 0 is reserved */ | 3687 | /* Reason Code 0 is reserved */ |
3721 | err = -EINVAL; | 3688 | err = -EINVAL; |
3722 | goto out; | 3689 | goto out; |
3723 | } | 3690 | } |
3724 | 3691 | ||
3725 | if (info->attrs[NL80211_ATTR_IE]) { | 3692 | if (info->attrs[NL80211_ATTR_IE]) { |
3726 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3693 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3727 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3694 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3728 | } | 3695 | } |
3729 | 3696 | ||
3730 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); | 3697 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); |
3731 | 3698 | ||
3732 | out: | 3699 | out: |
3733 | cfg80211_unlock_rdev(rdev); | 3700 | cfg80211_unlock_rdev(rdev); |
3734 | dev_put(dev); | 3701 | dev_put(dev); |
3735 | unlock_rtnl: | 3702 | unlock_rtnl: |
3736 | rtnl_unlock(); | 3703 | rtnl_unlock(); |
3737 | return err; | 3704 | return err; |
3738 | } | 3705 | } |
3739 | 3706 | ||
3740 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | 3707 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) |
3741 | { | 3708 | { |
3742 | struct cfg80211_registered_device *rdev; | 3709 | struct cfg80211_registered_device *rdev; |
3743 | struct net_device *dev; | 3710 | struct net_device *dev; |
3744 | const u8 *ie = NULL, *bssid; | 3711 | const u8 *ie = NULL, *bssid; |
3745 | int err, ie_len = 0; | 3712 | int err, ie_len = 0; |
3746 | u16 reason_code; | 3713 | u16 reason_code; |
3747 | 3714 | ||
3748 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3715 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3749 | return -EINVAL; | 3716 | return -EINVAL; |
3750 | 3717 | ||
3751 | if (!info->attrs[NL80211_ATTR_MAC]) | 3718 | if (!info->attrs[NL80211_ATTR_MAC]) |
3752 | return -EINVAL; | 3719 | return -EINVAL; |
3753 | 3720 | ||
3754 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3721 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3755 | return -EINVAL; | 3722 | return -EINVAL; |
3756 | 3723 | ||
3757 | rtnl_lock(); | 3724 | rtnl_lock(); |
3758 | 3725 | ||
3759 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3726 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3760 | if (err) | 3727 | if (err) |
3761 | goto unlock_rtnl; | 3728 | goto unlock_rtnl; |
3762 | 3729 | ||
3763 | if (!rdev->ops->disassoc) { | 3730 | if (!rdev->ops->disassoc) { |
3764 | err = -EOPNOTSUPP; | 3731 | err = -EOPNOTSUPP; |
3765 | goto out; | 3732 | goto out; |
3766 | } | 3733 | } |
3767 | 3734 | ||
3768 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3735 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
3769 | err = -EOPNOTSUPP; | 3736 | err = -EOPNOTSUPP; |
3770 | goto out; | 3737 | goto out; |
3771 | } | 3738 | } |
3772 | 3739 | ||
3773 | if (!netif_running(dev)) { | 3740 | if (!netif_running(dev)) { |
3774 | err = -ENETDOWN; | 3741 | err = -ENETDOWN; |
3775 | goto out; | 3742 | goto out; |
3776 | } | 3743 | } |
3777 | 3744 | ||
3778 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3745 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3779 | 3746 | ||
3780 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3747 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3781 | if (reason_code == 0) { | 3748 | if (reason_code == 0) { |
3782 | /* Reason Code 0 is reserved */ | 3749 | /* Reason Code 0 is reserved */ |
3783 | err = -EINVAL; | 3750 | err = -EINVAL; |
3784 | goto out; | 3751 | goto out; |
3785 | } | 3752 | } |
3786 | 3753 | ||
3787 | if (info->attrs[NL80211_ATTR_IE]) { | 3754 | if (info->attrs[NL80211_ATTR_IE]) { |
3788 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3755 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3789 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3756 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3790 | } | 3757 | } |
3791 | 3758 | ||
3792 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); | 3759 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); |
3793 | 3760 | ||
3794 | out: | 3761 | out: |
3795 | cfg80211_unlock_rdev(rdev); | 3762 | cfg80211_unlock_rdev(rdev); |
3796 | dev_put(dev); | 3763 | dev_put(dev); |
3797 | unlock_rtnl: | 3764 | unlock_rtnl: |
3798 | rtnl_unlock(); | 3765 | rtnl_unlock(); |
3799 | return err; | 3766 | return err; |
3800 | } | 3767 | } |
3801 | 3768 | ||
3802 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | 3769 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) |
3803 | { | 3770 | { |
3804 | struct cfg80211_registered_device *rdev; | 3771 | struct cfg80211_registered_device *rdev; |
3805 | struct net_device *dev; | 3772 | struct net_device *dev; |
3806 | struct cfg80211_ibss_params ibss; | 3773 | struct cfg80211_ibss_params ibss; |
3807 | struct wiphy *wiphy; | 3774 | struct wiphy *wiphy; |
3808 | struct cfg80211_cached_keys *connkeys = NULL; | 3775 | struct cfg80211_cached_keys *connkeys = NULL; |
3809 | int err; | 3776 | int err; |
3810 | 3777 | ||
3811 | memset(&ibss, 0, sizeof(ibss)); | 3778 | memset(&ibss, 0, sizeof(ibss)); |
3812 | 3779 | ||
3813 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3780 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3814 | return -EINVAL; | 3781 | return -EINVAL; |
3815 | 3782 | ||
3816 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | 3783 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || |
3817 | !info->attrs[NL80211_ATTR_SSID] || | 3784 | !info->attrs[NL80211_ATTR_SSID] || |
3818 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | 3785 | !nla_len(info->attrs[NL80211_ATTR_SSID])) |
3819 | return -EINVAL; | 3786 | return -EINVAL; |
3820 | 3787 | ||
3821 | ibss.beacon_interval = 100; | 3788 | ibss.beacon_interval = 100; |
3822 | 3789 | ||
3823 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | 3790 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { |
3824 | ibss.beacon_interval = | 3791 | ibss.beacon_interval = |
3825 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | 3792 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); |
3826 | if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) | 3793 | if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) |
3827 | return -EINVAL; | 3794 | return -EINVAL; |
3828 | } | 3795 | } |
3829 | 3796 | ||
3830 | rtnl_lock(); | 3797 | rtnl_lock(); |
3831 | 3798 | ||
3832 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3799 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3833 | if (err) | 3800 | if (err) |
3834 | goto unlock_rtnl; | 3801 | goto unlock_rtnl; |
3835 | 3802 | ||
3836 | if (!rdev->ops->join_ibss) { | 3803 | if (!rdev->ops->join_ibss) { |
3837 | err = -EOPNOTSUPP; | 3804 | err = -EOPNOTSUPP; |
3838 | goto out; | 3805 | goto out; |
3839 | } | 3806 | } |
3840 | 3807 | ||
3841 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 3808 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { |
3842 | err = -EOPNOTSUPP; | 3809 | err = -EOPNOTSUPP; |
3843 | goto out; | 3810 | goto out; |
3844 | } | 3811 | } |
3845 | 3812 | ||
3846 | if (!netif_running(dev)) { | 3813 | if (!netif_running(dev)) { |
3847 | err = -ENETDOWN; | 3814 | err = -ENETDOWN; |
3848 | goto out; | 3815 | goto out; |
3849 | } | 3816 | } |
3850 | 3817 | ||
3851 | wiphy = &rdev->wiphy; | 3818 | wiphy = &rdev->wiphy; |
3852 | 3819 | ||
3853 | if (info->attrs[NL80211_ATTR_MAC]) | 3820 | if (info->attrs[NL80211_ATTR_MAC]) |
3854 | ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3821 | ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3855 | ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3822 | ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3856 | ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3823 | ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3857 | 3824 | ||
3858 | if (info->attrs[NL80211_ATTR_IE]) { | 3825 | if (info->attrs[NL80211_ATTR_IE]) { |
3859 | ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3826 | ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3860 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3827 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3861 | } | 3828 | } |
3862 | 3829 | ||
3863 | ibss.channel = ieee80211_get_channel(wiphy, | 3830 | ibss.channel = ieee80211_get_channel(wiphy, |
3864 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3831 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3865 | if (!ibss.channel || | 3832 | if (!ibss.channel || |
3866 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | 3833 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || |
3867 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | 3834 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { |
3868 | err = -EINVAL; | 3835 | err = -EINVAL; |
3869 | goto out; | 3836 | goto out; |
3870 | } | 3837 | } |
3871 | 3838 | ||
3872 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 3839 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
3873 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 3840 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
3874 | 3841 | ||
3875 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 3842 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
3876 | connkeys = nl80211_parse_connkeys(rdev, | 3843 | connkeys = nl80211_parse_connkeys(rdev, |
3877 | info->attrs[NL80211_ATTR_KEYS]); | 3844 | info->attrs[NL80211_ATTR_KEYS]); |
3878 | if (IS_ERR(connkeys)) { | 3845 | if (IS_ERR(connkeys)) { |
3879 | err = PTR_ERR(connkeys); | 3846 | err = PTR_ERR(connkeys); |
3880 | connkeys = NULL; | 3847 | connkeys = NULL; |
3881 | goto out; | 3848 | goto out; |
3882 | } | 3849 | } |
3883 | } | 3850 | } |
3884 | 3851 | ||
3885 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 3852 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
3886 | 3853 | ||
3887 | out: | 3854 | out: |
3888 | cfg80211_unlock_rdev(rdev); | 3855 | cfg80211_unlock_rdev(rdev); |
3889 | dev_put(dev); | 3856 | dev_put(dev); |
3890 | unlock_rtnl: | 3857 | unlock_rtnl: |
3891 | if (err) | 3858 | if (err) |
3892 | kfree(connkeys); | 3859 | kfree(connkeys); |
3893 | rtnl_unlock(); | 3860 | rtnl_unlock(); |
3894 | return err; | 3861 | return err; |
3895 | } | 3862 | } |
3896 | 3863 | ||
3897 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | 3864 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) |
3898 | { | 3865 | { |
3899 | struct cfg80211_registered_device *rdev; | 3866 | struct cfg80211_registered_device *rdev; |
3900 | struct net_device *dev; | 3867 | struct net_device *dev; |
3901 | int err; | 3868 | int err; |
3902 | 3869 | ||
3903 | rtnl_lock(); | 3870 | rtnl_lock(); |
3904 | 3871 | ||
3905 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3872 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3906 | if (err) | 3873 | if (err) |
3907 | goto unlock_rtnl; | 3874 | goto unlock_rtnl; |
3908 | 3875 | ||
3909 | if (!rdev->ops->leave_ibss) { | 3876 | if (!rdev->ops->leave_ibss) { |
3910 | err = -EOPNOTSUPP; | 3877 | err = -EOPNOTSUPP; |
3911 | goto out; | 3878 | goto out; |
3912 | } | 3879 | } |
3913 | 3880 | ||
3914 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 3881 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { |
3915 | err = -EOPNOTSUPP; | 3882 | err = -EOPNOTSUPP; |
3916 | goto out; | 3883 | goto out; |
3917 | } | 3884 | } |
3918 | 3885 | ||
3919 | if (!netif_running(dev)) { | 3886 | if (!netif_running(dev)) { |
3920 | err = -ENETDOWN; | 3887 | err = -ENETDOWN; |
3921 | goto out; | 3888 | goto out; |
3922 | } | 3889 | } |
3923 | 3890 | ||
3924 | err = cfg80211_leave_ibss(rdev, dev, false); | 3891 | err = cfg80211_leave_ibss(rdev, dev, false); |
3925 | 3892 | ||
3926 | out: | 3893 | out: |
3927 | cfg80211_unlock_rdev(rdev); | 3894 | cfg80211_unlock_rdev(rdev); |
3928 | dev_put(dev); | 3895 | dev_put(dev); |
3929 | unlock_rtnl: | 3896 | unlock_rtnl: |
3930 | rtnl_unlock(); | 3897 | rtnl_unlock(); |
3931 | return err; | 3898 | return err; |
3932 | } | 3899 | } |
3933 | 3900 | ||
3934 | #ifdef CONFIG_NL80211_TESTMODE | 3901 | #ifdef CONFIG_NL80211_TESTMODE |
3935 | static struct genl_multicast_group nl80211_testmode_mcgrp = { | 3902 | static struct genl_multicast_group nl80211_testmode_mcgrp = { |
3936 | .name = "testmode", | 3903 | .name = "testmode", |
3937 | }; | 3904 | }; |
3938 | 3905 | ||
3939 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | 3906 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) |
3940 | { | 3907 | { |
3941 | struct cfg80211_registered_device *rdev; | 3908 | struct cfg80211_registered_device *rdev; |
3942 | int err; | 3909 | int err; |
3943 | 3910 | ||
3944 | if (!info->attrs[NL80211_ATTR_TESTDATA]) | 3911 | if (!info->attrs[NL80211_ATTR_TESTDATA]) |
3945 | return -EINVAL; | 3912 | return -EINVAL; |
3946 | 3913 | ||
3947 | rtnl_lock(); | 3914 | rtnl_lock(); |
3948 | 3915 | ||
3949 | rdev = cfg80211_get_dev_from_info(info); | 3916 | rdev = cfg80211_get_dev_from_info(info); |
3950 | if (IS_ERR(rdev)) { | 3917 | if (IS_ERR(rdev)) { |
3951 | err = PTR_ERR(rdev); | 3918 | err = PTR_ERR(rdev); |
3952 | goto unlock_rtnl; | 3919 | goto unlock_rtnl; |
3953 | } | 3920 | } |
3954 | 3921 | ||
3955 | err = -EOPNOTSUPP; | 3922 | err = -EOPNOTSUPP; |
3956 | if (rdev->ops->testmode_cmd) { | 3923 | if (rdev->ops->testmode_cmd) { |
3957 | rdev->testmode_info = info; | 3924 | rdev->testmode_info = info; |
3958 | err = rdev->ops->testmode_cmd(&rdev->wiphy, | 3925 | err = rdev->ops->testmode_cmd(&rdev->wiphy, |
3959 | nla_data(info->attrs[NL80211_ATTR_TESTDATA]), | 3926 | nla_data(info->attrs[NL80211_ATTR_TESTDATA]), |
3960 | nla_len(info->attrs[NL80211_ATTR_TESTDATA])); | 3927 | nla_len(info->attrs[NL80211_ATTR_TESTDATA])); |
3961 | rdev->testmode_info = NULL; | 3928 | rdev->testmode_info = NULL; |
3962 | } | 3929 | } |
3963 | 3930 | ||
3964 | cfg80211_unlock_rdev(rdev); | 3931 | cfg80211_unlock_rdev(rdev); |
3965 | 3932 | ||
3966 | unlock_rtnl: | 3933 | unlock_rtnl: |
3967 | rtnl_unlock(); | 3934 | rtnl_unlock(); |
3968 | return err; | 3935 | return err; |
3969 | } | 3936 | } |
3970 | 3937 | ||
3971 | static struct sk_buff * | 3938 | static struct sk_buff * |
3972 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, | 3939 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, |
3973 | int approxlen, u32 pid, u32 seq, gfp_t gfp) | 3940 | int approxlen, u32 pid, u32 seq, gfp_t gfp) |
3974 | { | 3941 | { |
3975 | struct sk_buff *skb; | 3942 | struct sk_buff *skb; |
3976 | void *hdr; | 3943 | void *hdr; |
3977 | struct nlattr *data; | 3944 | struct nlattr *data; |
3978 | 3945 | ||
3979 | skb = nlmsg_new(approxlen + 100, gfp); | 3946 | skb = nlmsg_new(approxlen + 100, gfp); |
3980 | if (!skb) | 3947 | if (!skb) |
3981 | return NULL; | 3948 | return NULL; |
3982 | 3949 | ||
3983 | hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE); | 3950 | hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE); |
3984 | if (!hdr) { | 3951 | if (!hdr) { |
3985 | kfree_skb(skb); | 3952 | kfree_skb(skb); |
3986 | return NULL; | 3953 | return NULL; |
3987 | } | 3954 | } |
3988 | 3955 | ||
3989 | NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 3956 | NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
3990 | data = nla_nest_start(skb, NL80211_ATTR_TESTDATA); | 3957 | data = nla_nest_start(skb, NL80211_ATTR_TESTDATA); |
3991 | 3958 | ||
3992 | ((void **)skb->cb)[0] = rdev; | 3959 | ((void **)skb->cb)[0] = rdev; |
3993 | ((void **)skb->cb)[1] = hdr; | 3960 | ((void **)skb->cb)[1] = hdr; |
3994 | ((void **)skb->cb)[2] = data; | 3961 | ((void **)skb->cb)[2] = data; |
3995 | 3962 | ||
3996 | return skb; | 3963 | return skb; |
3997 | 3964 | ||
3998 | nla_put_failure: | 3965 | nla_put_failure: |
3999 | kfree_skb(skb); | 3966 | kfree_skb(skb); |
4000 | return NULL; | 3967 | return NULL; |
4001 | } | 3968 | } |
4002 | 3969 | ||
4003 | struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, | 3970 | struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, |
4004 | int approxlen) | 3971 | int approxlen) |
4005 | { | 3972 | { |
4006 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 3973 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
4007 | 3974 | ||
4008 | if (WARN_ON(!rdev->testmode_info)) | 3975 | if (WARN_ON(!rdev->testmode_info)) |
4009 | return NULL; | 3976 | return NULL; |
4010 | 3977 | ||
4011 | return __cfg80211_testmode_alloc_skb(rdev, approxlen, | 3978 | return __cfg80211_testmode_alloc_skb(rdev, approxlen, |
4012 | rdev->testmode_info->snd_pid, | 3979 | rdev->testmode_info->snd_pid, |
4013 | rdev->testmode_info->snd_seq, | 3980 | rdev->testmode_info->snd_seq, |
4014 | GFP_KERNEL); | 3981 | GFP_KERNEL); |
4015 | } | 3982 | } |
4016 | EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb); | 3983 | EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb); |
4017 | 3984 | ||
4018 | int cfg80211_testmode_reply(struct sk_buff *skb) | 3985 | int cfg80211_testmode_reply(struct sk_buff *skb) |
4019 | { | 3986 | { |
4020 | struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; | 3987 | struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; |
4021 | void *hdr = ((void **)skb->cb)[1]; | 3988 | void *hdr = ((void **)skb->cb)[1]; |
4022 | struct nlattr *data = ((void **)skb->cb)[2]; | 3989 | struct nlattr *data = ((void **)skb->cb)[2]; |
4023 | 3990 | ||
4024 | if (WARN_ON(!rdev->testmode_info)) { | 3991 | if (WARN_ON(!rdev->testmode_info)) { |
4025 | kfree_skb(skb); | 3992 | kfree_skb(skb); |
4026 | return -EINVAL; | 3993 | return -EINVAL; |
4027 | } | 3994 | } |
4028 | 3995 | ||
4029 | nla_nest_end(skb, data); | 3996 | nla_nest_end(skb, data); |
4030 | genlmsg_end(skb, hdr); | 3997 | genlmsg_end(skb, hdr); |
4031 | return genlmsg_reply(skb, rdev->testmode_info); | 3998 | return genlmsg_reply(skb, rdev->testmode_info); |
4032 | } | 3999 | } |
4033 | EXPORT_SYMBOL(cfg80211_testmode_reply); | 4000 | EXPORT_SYMBOL(cfg80211_testmode_reply); |
4034 | 4001 | ||
4035 | struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, | 4002 | struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, |
4036 | int approxlen, gfp_t gfp) | 4003 | int approxlen, gfp_t gfp) |
4037 | { | 4004 | { |
4038 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 4005 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
4039 | 4006 | ||
4040 | return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp); | 4007 | return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp); |
4041 | } | 4008 | } |
4042 | EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); | 4009 | EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); |
4043 | 4010 | ||
4044 | void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) | 4011 | void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) |
4045 | { | 4012 | { |
4046 | void *hdr = ((void **)skb->cb)[1]; | 4013 | void *hdr = ((void **)skb->cb)[1]; |
4047 | struct nlattr *data = ((void **)skb->cb)[2]; | 4014 | struct nlattr *data = ((void **)skb->cb)[2]; |
4048 | 4015 | ||
4049 | nla_nest_end(skb, data); | 4016 | nla_nest_end(skb, data); |
4050 | genlmsg_end(skb, hdr); | 4017 | genlmsg_end(skb, hdr); |
4051 | genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp); | 4018 | genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp); |
4052 | } | 4019 | } |
4053 | EXPORT_SYMBOL(cfg80211_testmode_event); | 4020 | EXPORT_SYMBOL(cfg80211_testmode_event); |
4054 | #endif | 4021 | #endif |
4055 | 4022 | ||
4056 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | 4023 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) |
4057 | { | 4024 | { |
4058 | struct cfg80211_registered_device *rdev; | 4025 | struct cfg80211_registered_device *rdev; |
4059 | struct net_device *dev; | 4026 | struct net_device *dev; |
4060 | struct cfg80211_connect_params connect; | 4027 | struct cfg80211_connect_params connect; |
4061 | struct wiphy *wiphy; | 4028 | struct wiphy *wiphy; |
4062 | struct cfg80211_cached_keys *connkeys = NULL; | 4029 | struct cfg80211_cached_keys *connkeys = NULL; |
4063 | int err; | 4030 | int err; |
4064 | 4031 | ||
4065 | memset(&connect, 0, sizeof(connect)); | 4032 | memset(&connect, 0, sizeof(connect)); |
4066 | 4033 | ||
4067 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 4034 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
4068 | return -EINVAL; | 4035 | return -EINVAL; |
4069 | 4036 | ||
4070 | if (!info->attrs[NL80211_ATTR_SSID] || | 4037 | if (!info->attrs[NL80211_ATTR_SSID] || |
4071 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | 4038 | !nla_len(info->attrs[NL80211_ATTR_SSID])) |
4072 | return -EINVAL; | 4039 | return -EINVAL; |
4073 | 4040 | ||
4074 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | 4041 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { |
4075 | connect.auth_type = | 4042 | connect.auth_type = |
4076 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 4043 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
4077 | if (!nl80211_valid_auth_type(connect.auth_type)) | 4044 | if (!nl80211_valid_auth_type(connect.auth_type)) |
4078 | return -EINVAL; | 4045 | return -EINVAL; |
4079 | } else | 4046 | } else |
4080 | connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 4047 | connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
4081 | 4048 | ||
4082 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; | 4049 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; |
4083 | 4050 | ||
4084 | err = nl80211_crypto_settings(info, &connect.crypto, | 4051 | err = nl80211_crypto_settings(info, &connect.crypto, |
4085 | NL80211_MAX_NR_CIPHER_SUITES); | 4052 | NL80211_MAX_NR_CIPHER_SUITES); |
4086 | if (err) | 4053 | if (err) |
4087 | return err; | 4054 | return err; |
4088 | rtnl_lock(); | 4055 | rtnl_lock(); |
4089 | 4056 | ||
4090 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 4057 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4091 | if (err) | 4058 | if (err) |
4092 | goto unlock_rtnl; | 4059 | goto unlock_rtnl; |
4093 | 4060 | ||
4094 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4061 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
4095 | err = -EOPNOTSUPP; | 4062 | err = -EOPNOTSUPP; |
4096 | goto out; | 4063 | goto out; |
4097 | } | 4064 | } |
4098 | 4065 | ||
4099 | if (!netif_running(dev)) { | 4066 | if (!netif_running(dev)) { |
4100 | err = -ENETDOWN; | 4067 | err = -ENETDOWN; |
4101 | goto out; | 4068 | goto out; |
4102 | } | 4069 | } |
4103 | 4070 | ||
4104 | wiphy = &rdev->wiphy; | 4071 | wiphy = &rdev->wiphy; |
4105 | 4072 | ||
4106 | if (info->attrs[NL80211_ATTR_MAC]) | 4073 | if (info->attrs[NL80211_ATTR_MAC]) |
4107 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 4074 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4108 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 4075 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
4109 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 4076 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
4110 | 4077 | ||
4111 | if (info->attrs[NL80211_ATTR_IE]) { | 4078 | if (info->attrs[NL80211_ATTR_IE]) { |
4112 | connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 4079 | connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
4113 | connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 4080 | connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
4114 | } | 4081 | } |
4115 | 4082 | ||
4116 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 4083 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
4117 | connect.channel = | 4084 | connect.channel = |
4118 | ieee80211_get_channel(wiphy, | 4085 | ieee80211_get_channel(wiphy, |
4119 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 4086 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4120 | if (!connect.channel || | 4087 | if (!connect.channel || |
4121 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { | 4088 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { |
4122 | err = -EINVAL; | 4089 | err = -EINVAL; |
4123 | goto out; | 4090 | goto out; |
4124 | } | 4091 | } |
4125 | } | 4092 | } |
4126 | 4093 | ||
4127 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 4094 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
4128 | connkeys = nl80211_parse_connkeys(rdev, | 4095 | connkeys = nl80211_parse_connkeys(rdev, |
4129 | info->attrs[NL80211_ATTR_KEYS]); | 4096 | info->attrs[NL80211_ATTR_KEYS]); |
4130 | if (IS_ERR(connkeys)) { | 4097 | if (IS_ERR(connkeys)) { |
4131 | err = PTR_ERR(connkeys); | 4098 | err = PTR_ERR(connkeys); |
4132 | connkeys = NULL; | 4099 | connkeys = NULL; |
4133 | goto out; | 4100 | goto out; |
4134 | } | 4101 | } |
4135 | } | 4102 | } |
4136 | 4103 | ||
4137 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 4104 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4138 | 4105 | ||
4139 | out: | 4106 | out: |
4140 | cfg80211_unlock_rdev(rdev); | 4107 | cfg80211_unlock_rdev(rdev); |
4141 | dev_put(dev); | 4108 | dev_put(dev); |
4142 | unlock_rtnl: | 4109 | unlock_rtnl: |
4143 | if (err) | 4110 | if (err) |
4144 | kfree(connkeys); | 4111 | kfree(connkeys); |
4145 | rtnl_unlock(); | 4112 | rtnl_unlock(); |
4146 | return err; | 4113 | return err; |
4147 | } | 4114 | } |
4148 | 4115 | ||
4149 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | 4116 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) |
4150 | { | 4117 | { |
4151 | struct cfg80211_registered_device *rdev; | 4118 | struct cfg80211_registered_device *rdev; |
4152 | struct net_device *dev; | 4119 | struct net_device *dev; |
4153 | int err; | 4120 | int err; |
4154 | u16 reason; | 4121 | u16 reason; |
4155 | 4122 | ||
4156 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 4123 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
4157 | reason = WLAN_REASON_DEAUTH_LEAVING; | 4124 | reason = WLAN_REASON_DEAUTH_LEAVING; |
4158 | else | 4125 | else |
4159 | reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 4126 | reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
4160 | 4127 | ||
4161 | if (reason == 0) | 4128 | if (reason == 0) |
4162 | return -EINVAL; | 4129 | return -EINVAL; |
4163 | 4130 | ||
4164 | rtnl_lock(); | 4131 | rtnl_lock(); |
4165 | 4132 | ||
4166 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 4133 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4167 | if (err) | 4134 | if (err) |
4168 | goto unlock_rtnl; | 4135 | goto unlock_rtnl; |
4169 | 4136 | ||
4170 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4137 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
4171 | err = -EOPNOTSUPP; | 4138 | err = -EOPNOTSUPP; |
4172 | goto out; | 4139 | goto out; |
4173 | } | 4140 | } |
4174 | 4141 | ||
4175 | if (!netif_running(dev)) { | 4142 | if (!netif_running(dev)) { |
4176 | err = -ENETDOWN; | 4143 | err = -ENETDOWN; |
4177 | goto out; | 4144 | goto out; |
4178 | } | 4145 | } |
4179 | 4146 | ||
4180 | err = cfg80211_disconnect(rdev, dev, reason, true); | 4147 | err = cfg80211_disconnect(rdev, dev, reason, true); |
4181 | 4148 | ||
4182 | out: | 4149 | out: |
4183 | cfg80211_unlock_rdev(rdev); | 4150 | cfg80211_unlock_rdev(rdev); |
4184 | dev_put(dev); | 4151 | dev_put(dev); |
4185 | unlock_rtnl: | 4152 | unlock_rtnl: |
4186 | rtnl_unlock(); | 4153 | rtnl_unlock(); |
4187 | return err; | 4154 | return err; |
4188 | } | 4155 | } |
4189 | 4156 | ||
4190 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | 4157 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) |
4191 | { | 4158 | { |
4192 | struct cfg80211_registered_device *rdev; | 4159 | struct cfg80211_registered_device *rdev; |
4193 | struct net *net; | 4160 | struct net *net; |
4194 | int err; | 4161 | int err; |
4195 | u32 pid; | 4162 | u32 pid; |
4196 | 4163 | ||
4197 | if (!info->attrs[NL80211_ATTR_PID]) | 4164 | if (!info->attrs[NL80211_ATTR_PID]) |
4198 | return -EINVAL; | 4165 | return -EINVAL; |
4199 | 4166 | ||
4200 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | 4167 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); |
4201 | 4168 | ||
4202 | rtnl_lock(); | 4169 | rtnl_lock(); |
4203 | 4170 | ||
4204 | rdev = cfg80211_get_dev_from_info(info); | 4171 | rdev = cfg80211_get_dev_from_info(info); |
4205 | if (IS_ERR(rdev)) { | 4172 | if (IS_ERR(rdev)) { |
4206 | err = PTR_ERR(rdev); | 4173 | err = PTR_ERR(rdev); |
4207 | goto out_rtnl; | 4174 | goto out_rtnl; |
4208 | } | 4175 | } |
4209 | 4176 | ||
4210 | net = get_net_ns_by_pid(pid); | 4177 | net = get_net_ns_by_pid(pid); |
4211 | if (IS_ERR(net)) { | 4178 | if (IS_ERR(net)) { |
4212 | err = PTR_ERR(net); | 4179 | err = PTR_ERR(net); |
4213 | goto out; | 4180 | goto out; |
4214 | } | 4181 | } |
4215 | 4182 | ||
4216 | err = 0; | 4183 | err = 0; |
4217 | 4184 | ||
4218 | /* check if anything to do */ | 4185 | /* check if anything to do */ |
4219 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 4186 | if (net_eq(wiphy_net(&rdev->wiphy), net)) |
4220 | goto out_put_net; | 4187 | goto out_put_net; |
4221 | 4188 | ||
4222 | err = cfg80211_switch_netns(rdev, net); | 4189 | err = cfg80211_switch_netns(rdev, net); |
4223 | out_put_net: | 4190 | out_put_net: |
4224 | put_net(net); | 4191 | put_net(net); |
4225 | out: | 4192 | out: |
4226 | cfg80211_unlock_rdev(rdev); | 4193 | cfg80211_unlock_rdev(rdev); |
4227 | out_rtnl: | 4194 | out_rtnl: |
4228 | rtnl_unlock(); | 4195 | rtnl_unlock(); |
4229 | return err; | 4196 | return err; |
4230 | } | 4197 | } |
4231 | 4198 | ||
4232 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | 4199 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) |
4233 | { | 4200 | { |
4234 | struct cfg80211_registered_device *rdev; | 4201 | struct cfg80211_registered_device *rdev; |
4235 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, | 4202 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, |
4236 | struct cfg80211_pmksa *pmksa) = NULL; | 4203 | struct cfg80211_pmksa *pmksa) = NULL; |
4237 | int err; | 4204 | int err; |
4238 | struct net_device *dev; | 4205 | struct net_device *dev; |
4239 | struct cfg80211_pmksa pmksa; | 4206 | struct cfg80211_pmksa pmksa; |
4240 | 4207 | ||
4241 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | 4208 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); |
4242 | 4209 | ||
4243 | if (!info->attrs[NL80211_ATTR_MAC]) | 4210 | if (!info->attrs[NL80211_ATTR_MAC]) |
4244 | return -EINVAL; | 4211 | return -EINVAL; |
4245 | 4212 | ||
4246 | if (!info->attrs[NL80211_ATTR_PMKID]) | 4213 | if (!info->attrs[NL80211_ATTR_PMKID]) |
4247 | return -EINVAL; | 4214 | return -EINVAL; |
4248 | 4215 | ||
4249 | rtnl_lock(); | 4216 | rtnl_lock(); |
4250 | 4217 | ||
4251 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 4218 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4252 | if (err) | 4219 | if (err) |
4253 | goto out_rtnl; | 4220 | goto out_rtnl; |
4254 | 4221 | ||
4255 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); | 4222 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); |
4256 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 4223 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4257 | 4224 | ||
4258 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4225 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
4259 | err = -EOPNOTSUPP; | 4226 | err = -EOPNOTSUPP; |
4260 | goto out; | 4227 | goto out; |
4261 | } | 4228 | } |
4262 | 4229 | ||
4263 | switch (info->genlhdr->cmd) { | 4230 | switch (info->genlhdr->cmd) { |
4264 | case NL80211_CMD_SET_PMKSA: | 4231 | case NL80211_CMD_SET_PMKSA: |
4265 | rdev_ops = rdev->ops->set_pmksa; | 4232 | rdev_ops = rdev->ops->set_pmksa; |
4266 | break; | 4233 | break; |
4267 | case NL80211_CMD_DEL_PMKSA: | 4234 | case NL80211_CMD_DEL_PMKSA: |
4268 | rdev_ops = rdev->ops->del_pmksa; | 4235 | rdev_ops = rdev->ops->del_pmksa; |
4269 | break; | 4236 | break; |
4270 | default: | 4237 | default: |
4271 | WARN_ON(1); | 4238 | WARN_ON(1); |
4272 | break; | 4239 | break; |
4273 | } | 4240 | } |
4274 | 4241 | ||
4275 | if (!rdev_ops) { | 4242 | if (!rdev_ops) { |
4276 | err = -EOPNOTSUPP; | 4243 | err = -EOPNOTSUPP; |
4277 | goto out; | 4244 | goto out; |
4278 | } | 4245 | } |
4279 | 4246 | ||
4280 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); | 4247 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); |
4281 | 4248 | ||
4282 | out: | 4249 | out: |
4283 | cfg80211_unlock_rdev(rdev); | 4250 | cfg80211_unlock_rdev(rdev); |
4284 | dev_put(dev); | 4251 | dev_put(dev); |
4285 | out_rtnl: | 4252 | out_rtnl: |
4286 | rtnl_unlock(); | 4253 | rtnl_unlock(); |
4287 | 4254 | ||
4288 | return err; | 4255 | return err; |
4289 | } | 4256 | } |
4290 | 4257 | ||
4291 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | 4258 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) |
4292 | { | 4259 | { |
4293 | struct cfg80211_registered_device *rdev; | 4260 | struct cfg80211_registered_device *rdev; |
4294 | int err; | 4261 | int err; |
4295 | struct net_device *dev; | 4262 | struct net_device *dev; |
4296 | 4263 | ||
4297 | rtnl_lock(); | 4264 | rtnl_lock(); |
4298 | 4265 | ||
4299 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 4266 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4300 | if (err) | 4267 | if (err) |
4301 | goto out_rtnl; | 4268 | goto out_rtnl; |
4302 | 4269 | ||
4303 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4270 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { |
4304 | err = -EOPNOTSUPP; | 4271 | err = -EOPNOTSUPP; |
4305 | goto out; | 4272 | goto out; |
4306 | } | 4273 | } |
4307 | 4274 | ||
4308 | if (!rdev->ops->flush_pmksa) { | 4275 | if (!rdev->ops->flush_pmksa) { |
4309 | err = -EOPNOTSUPP; | 4276 | err = -EOPNOTSUPP; |
4310 | goto out; | 4277 | goto out; |
4311 | } | 4278 | } |
4312 | 4279 | ||
4313 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); | 4280 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); |
4314 | 4281 | ||
4315 | out: | 4282 | out: |
4316 | cfg80211_unlock_rdev(rdev); | 4283 | cfg80211_unlock_rdev(rdev); |
4317 | dev_put(dev); | 4284 | dev_put(dev); |
4318 | out_rtnl: | 4285 | out_rtnl: |
4319 | rtnl_unlock(); | 4286 | rtnl_unlock(); |
4320 | 4287 | ||
4321 | return err; | 4288 | return err; |
4322 | 4289 | ||
4323 | } | 4290 | } |
4324 | 4291 | ||
4325 | static struct genl_ops nl80211_ops[] = { | 4292 | static struct genl_ops nl80211_ops[] = { |
4326 | { | 4293 | { |
4327 | .cmd = NL80211_CMD_GET_WIPHY, | 4294 | .cmd = NL80211_CMD_GET_WIPHY, |
4328 | .doit = nl80211_get_wiphy, | 4295 | .doit = nl80211_get_wiphy, |
4329 | .dumpit = nl80211_dump_wiphy, | 4296 | .dumpit = nl80211_dump_wiphy, |
4330 | .policy = nl80211_policy, | 4297 | .policy = nl80211_policy, |
4331 | /* can be retrieved by unprivileged users */ | 4298 | /* can be retrieved by unprivileged users */ |
4332 | }, | 4299 | }, |
4333 | { | 4300 | { |
4334 | .cmd = NL80211_CMD_SET_WIPHY, | 4301 | .cmd = NL80211_CMD_SET_WIPHY, |
4335 | .doit = nl80211_set_wiphy, | 4302 | .doit = nl80211_set_wiphy, |
4336 | .policy = nl80211_policy, | 4303 | .policy = nl80211_policy, |
4337 | .flags = GENL_ADMIN_PERM, | 4304 | .flags = GENL_ADMIN_PERM, |
4338 | }, | 4305 | }, |
4339 | { | 4306 | { |
4340 | .cmd = NL80211_CMD_GET_INTERFACE, | 4307 | .cmd = NL80211_CMD_GET_INTERFACE, |
4341 | .doit = nl80211_get_interface, | 4308 | .doit = nl80211_get_interface, |
4342 | .dumpit = nl80211_dump_interface, | 4309 | .dumpit = nl80211_dump_interface, |
4343 | .policy = nl80211_policy, | 4310 | .policy = nl80211_policy, |
4344 | /* can be retrieved by unprivileged users */ | 4311 | /* can be retrieved by unprivileged users */ |
4345 | }, | 4312 | }, |
4346 | { | 4313 | { |
4347 | .cmd = NL80211_CMD_SET_INTERFACE, | 4314 | .cmd = NL80211_CMD_SET_INTERFACE, |
4348 | .doit = nl80211_set_interface, | 4315 | .doit = nl80211_set_interface, |
4349 | .policy = nl80211_policy, | 4316 | .policy = nl80211_policy, |
4350 | .flags = GENL_ADMIN_PERM, | 4317 | .flags = GENL_ADMIN_PERM, |
4351 | }, | 4318 | }, |
4352 | { | 4319 | { |
4353 | .cmd = NL80211_CMD_NEW_INTERFACE, | 4320 | .cmd = NL80211_CMD_NEW_INTERFACE, |
4354 | .doit = nl80211_new_interface, | 4321 | .doit = nl80211_new_interface, |
4355 | .policy = nl80211_policy, | 4322 | .policy = nl80211_policy, |
4356 | .flags = GENL_ADMIN_PERM, | 4323 | .flags = GENL_ADMIN_PERM, |
4357 | }, | 4324 | }, |
4358 | { | 4325 | { |
4359 | .cmd = NL80211_CMD_DEL_INTERFACE, | 4326 | .cmd = NL80211_CMD_DEL_INTERFACE, |
4360 | .doit = nl80211_del_interface, | 4327 | .doit = nl80211_del_interface, |
4361 | .policy = nl80211_policy, | 4328 | .policy = nl80211_policy, |
4362 | .flags = GENL_ADMIN_PERM, | 4329 | .flags = GENL_ADMIN_PERM, |
4363 | }, | 4330 | }, |
4364 | { | 4331 | { |
4365 | .cmd = NL80211_CMD_GET_KEY, | 4332 | .cmd = NL80211_CMD_GET_KEY, |
4366 | .doit = nl80211_get_key, | 4333 | .doit = nl80211_get_key, |
4367 | .policy = nl80211_policy, | 4334 | .policy = nl80211_policy, |
4368 | .flags = GENL_ADMIN_PERM, | 4335 | .flags = GENL_ADMIN_PERM, |
4369 | }, | 4336 | }, |
4370 | { | 4337 | { |
4371 | .cmd = NL80211_CMD_SET_KEY, | 4338 | .cmd = NL80211_CMD_SET_KEY, |
4372 | .doit = nl80211_set_key, | 4339 | .doit = nl80211_set_key, |
4373 | .policy = nl80211_policy, | 4340 | .policy = nl80211_policy, |
4374 | .flags = GENL_ADMIN_PERM, | 4341 | .flags = GENL_ADMIN_PERM, |
4375 | }, | 4342 | }, |
4376 | { | 4343 | { |
4377 | .cmd = NL80211_CMD_NEW_KEY, | 4344 | .cmd = NL80211_CMD_NEW_KEY, |
4378 | .doit = nl80211_new_key, | 4345 | .doit = nl80211_new_key, |
4379 | .policy = nl80211_policy, | 4346 | .policy = nl80211_policy, |
4380 | .flags = GENL_ADMIN_PERM, | 4347 | .flags = GENL_ADMIN_PERM, |
4381 | }, | 4348 | }, |
4382 | { | 4349 | { |
4383 | .cmd = NL80211_CMD_DEL_KEY, | 4350 | .cmd = NL80211_CMD_DEL_KEY, |
4384 | .doit = nl80211_del_key, | 4351 | .doit = nl80211_del_key, |
4385 | .policy = nl80211_policy, | 4352 | .policy = nl80211_policy, |
4386 | .flags = GENL_ADMIN_PERM, | 4353 | .flags = GENL_ADMIN_PERM, |
4387 | }, | 4354 | }, |
4388 | { | 4355 | { |
4389 | .cmd = NL80211_CMD_SET_BEACON, | 4356 | .cmd = NL80211_CMD_SET_BEACON, |
4390 | .policy = nl80211_policy, | 4357 | .policy = nl80211_policy, |
4391 | .flags = GENL_ADMIN_PERM, | 4358 | .flags = GENL_ADMIN_PERM, |
4392 | .doit = nl80211_addset_beacon, | 4359 | .doit = nl80211_addset_beacon, |
4393 | }, | 4360 | }, |
4394 | { | 4361 | { |
4395 | .cmd = NL80211_CMD_NEW_BEACON, | 4362 | .cmd = NL80211_CMD_NEW_BEACON, |
4396 | .policy = nl80211_policy, | 4363 | .policy = nl80211_policy, |
4397 | .flags = GENL_ADMIN_PERM, | 4364 | .flags = GENL_ADMIN_PERM, |
4398 | .doit = nl80211_addset_beacon, | 4365 | .doit = nl80211_addset_beacon, |
4399 | }, | 4366 | }, |
4400 | { | 4367 | { |
4401 | .cmd = NL80211_CMD_DEL_BEACON, | 4368 | .cmd = NL80211_CMD_DEL_BEACON, |
4402 | .policy = nl80211_policy, | 4369 | .policy = nl80211_policy, |
4403 | .flags = GENL_ADMIN_PERM, | 4370 | .flags = GENL_ADMIN_PERM, |
4404 | .doit = nl80211_del_beacon, | 4371 | .doit = nl80211_del_beacon, |
4405 | }, | 4372 | }, |
4406 | { | 4373 | { |
4407 | .cmd = NL80211_CMD_GET_STATION, | 4374 | .cmd = NL80211_CMD_GET_STATION, |
4408 | .doit = nl80211_get_station, | 4375 | .doit = nl80211_get_station, |
4409 | .dumpit = nl80211_dump_station, | 4376 | .dumpit = nl80211_dump_station, |
4410 | .policy = nl80211_policy, | 4377 | .policy = nl80211_policy, |
4411 | }, | 4378 | }, |
4412 | { | 4379 | { |
4413 | .cmd = NL80211_CMD_SET_STATION, | 4380 | .cmd = NL80211_CMD_SET_STATION, |
4414 | .doit = nl80211_set_station, | 4381 | .doit = nl80211_set_station, |
4415 | .policy = nl80211_policy, | 4382 | .policy = nl80211_policy, |
4416 | .flags = GENL_ADMIN_PERM, | 4383 | .flags = GENL_ADMIN_PERM, |
4417 | }, | 4384 | }, |
4418 | { | 4385 | { |
4419 | .cmd = NL80211_CMD_NEW_STATION, | 4386 | .cmd = NL80211_CMD_NEW_STATION, |
4420 | .doit = nl80211_new_station, | 4387 | .doit = nl80211_new_station, |
4421 | .policy = nl80211_policy, | 4388 | .policy = nl80211_policy, |
4422 | .flags = GENL_ADMIN_PERM, | 4389 | .flags = GENL_ADMIN_PERM, |
4423 | }, | 4390 | }, |
4424 | { | 4391 | { |
4425 | .cmd = NL80211_CMD_DEL_STATION, | 4392 | .cmd = NL80211_CMD_DEL_STATION, |
4426 | .doit = nl80211_del_station, | 4393 | .doit = nl80211_del_station, |
4427 | .policy = nl80211_policy, | 4394 | .policy = nl80211_policy, |
4428 | .flags = GENL_ADMIN_PERM, | 4395 | .flags = GENL_ADMIN_PERM, |
4429 | }, | 4396 | }, |
4430 | { | 4397 | { |
4431 | .cmd = NL80211_CMD_GET_MPATH, | 4398 | .cmd = NL80211_CMD_GET_MPATH, |
4432 | .doit = nl80211_get_mpath, | 4399 | .doit = nl80211_get_mpath, |
4433 | .dumpit = nl80211_dump_mpath, | 4400 | .dumpit = nl80211_dump_mpath, |
4434 | .policy = nl80211_policy, | 4401 | .policy = nl80211_policy, |
4435 | .flags = GENL_ADMIN_PERM, | 4402 | .flags = GENL_ADMIN_PERM, |
4436 | }, | 4403 | }, |
4437 | { | 4404 | { |
4438 | .cmd = NL80211_CMD_SET_MPATH, | 4405 | .cmd = NL80211_CMD_SET_MPATH, |
4439 | .doit = nl80211_set_mpath, | 4406 | .doit = nl80211_set_mpath, |
4440 | .policy = nl80211_policy, | 4407 | .policy = nl80211_policy, |
4441 | .flags = GENL_ADMIN_PERM, | 4408 | .flags = GENL_ADMIN_PERM, |
4442 | }, | 4409 | }, |
4443 | { | 4410 | { |
4444 | .cmd = NL80211_CMD_NEW_MPATH, | 4411 | .cmd = NL80211_CMD_NEW_MPATH, |
4445 | .doit = nl80211_new_mpath, | 4412 | .doit = nl80211_new_mpath, |
4446 | .policy = nl80211_policy, | 4413 | .policy = nl80211_policy, |
4447 | .flags = GENL_ADMIN_PERM, | 4414 | .flags = GENL_ADMIN_PERM, |
4448 | }, | 4415 | }, |
4449 | { | 4416 | { |
4450 | .cmd = NL80211_CMD_DEL_MPATH, | 4417 | .cmd = NL80211_CMD_DEL_MPATH, |
4451 | .doit = nl80211_del_mpath, | 4418 | .doit = nl80211_del_mpath, |
4452 | .policy = nl80211_policy, | 4419 | .policy = nl80211_policy, |
4453 | .flags = GENL_ADMIN_PERM, | 4420 | .flags = GENL_ADMIN_PERM, |
4454 | }, | 4421 | }, |
4455 | { | 4422 | { |
4456 | .cmd = NL80211_CMD_SET_BSS, | 4423 | .cmd = NL80211_CMD_SET_BSS, |
4457 | .doit = nl80211_set_bss, | 4424 | .doit = nl80211_set_bss, |
4458 | .policy = nl80211_policy, | 4425 | .policy = nl80211_policy, |
4459 | .flags = GENL_ADMIN_PERM, | 4426 | .flags = GENL_ADMIN_PERM, |
4460 | }, | 4427 | }, |
4461 | { | 4428 | { |
4462 | .cmd = NL80211_CMD_GET_REG, | 4429 | .cmd = NL80211_CMD_GET_REG, |
4463 | .doit = nl80211_get_reg, | 4430 | .doit = nl80211_get_reg, |
4464 | .policy = nl80211_policy, | 4431 | .policy = nl80211_policy, |
4465 | /* can be retrieved by unprivileged users */ | 4432 | /* can be retrieved by unprivileged users */ |
4466 | }, | 4433 | }, |
4467 | { | 4434 | { |
4468 | .cmd = NL80211_CMD_SET_REG, | 4435 | .cmd = NL80211_CMD_SET_REG, |
4469 | .doit = nl80211_set_reg, | 4436 | .doit = nl80211_set_reg, |
4470 | .policy = nl80211_policy, | 4437 | .policy = nl80211_policy, |
4471 | .flags = GENL_ADMIN_PERM, | 4438 | .flags = GENL_ADMIN_PERM, |
4472 | }, | 4439 | }, |
4473 | { | 4440 | { |
4474 | .cmd = NL80211_CMD_REQ_SET_REG, | 4441 | .cmd = NL80211_CMD_REQ_SET_REG, |
4475 | .doit = nl80211_req_set_reg, | 4442 | .doit = nl80211_req_set_reg, |
4476 | .policy = nl80211_policy, | 4443 | .policy = nl80211_policy, |
4477 | .flags = GENL_ADMIN_PERM, | 4444 | .flags = GENL_ADMIN_PERM, |
4478 | }, | 4445 | }, |
4479 | { | 4446 | { |
4480 | .cmd = NL80211_CMD_GET_MESH_PARAMS, | 4447 | .cmd = NL80211_CMD_GET_MESH_PARAMS, |
4481 | .doit = nl80211_get_mesh_params, | 4448 | .doit = nl80211_get_mesh_params, |
4482 | .policy = nl80211_policy, | 4449 | .policy = nl80211_policy, |
4483 | /* can be retrieved by unprivileged users */ | 4450 | /* can be retrieved by unprivileged users */ |
4484 | }, | 4451 | }, |
4485 | { | 4452 | { |
4486 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4453 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
4487 | .doit = nl80211_set_mesh_params, | 4454 | .doit = nl80211_set_mesh_params, |
4488 | .policy = nl80211_policy, | 4455 | .policy = nl80211_policy, |
4489 | .flags = GENL_ADMIN_PERM, | 4456 | .flags = GENL_ADMIN_PERM, |
4490 | }, | 4457 | }, |
4491 | { | 4458 | { |
4492 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 4459 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
4493 | .doit = nl80211_trigger_scan, | 4460 | .doit = nl80211_trigger_scan, |
4494 | .policy = nl80211_policy, | 4461 | .policy = nl80211_policy, |
4495 | .flags = GENL_ADMIN_PERM, | 4462 | .flags = GENL_ADMIN_PERM, |
4496 | }, | 4463 | }, |
4497 | { | 4464 | { |
4498 | .cmd = NL80211_CMD_GET_SCAN, | 4465 | .cmd = NL80211_CMD_GET_SCAN, |
4499 | .policy = nl80211_policy, | 4466 | .policy = nl80211_policy, |
4500 | .dumpit = nl80211_dump_scan, | 4467 | .dumpit = nl80211_dump_scan, |
4501 | }, | 4468 | }, |
4502 | { | 4469 | { |
4503 | .cmd = NL80211_CMD_AUTHENTICATE, | 4470 | .cmd = NL80211_CMD_AUTHENTICATE, |
4504 | .doit = nl80211_authenticate, | 4471 | .doit = nl80211_authenticate, |
4505 | .policy = nl80211_policy, | 4472 | .policy = nl80211_policy, |
4506 | .flags = GENL_ADMIN_PERM, | 4473 | .flags = GENL_ADMIN_PERM, |
4507 | }, | 4474 | }, |
4508 | { | 4475 | { |
4509 | .cmd = NL80211_CMD_ASSOCIATE, | 4476 | .cmd = NL80211_CMD_ASSOCIATE, |
4510 | .doit = nl80211_associate, | 4477 | .doit = nl80211_associate, |
4511 | .policy = nl80211_policy, | 4478 | .policy = nl80211_policy, |
4512 | .flags = GENL_ADMIN_PERM, | 4479 | .flags = GENL_ADMIN_PERM, |
4513 | }, | 4480 | }, |
4514 | { | 4481 | { |
4515 | .cmd = NL80211_CMD_DEAUTHENTICATE, | 4482 | .cmd = NL80211_CMD_DEAUTHENTICATE, |
4516 | .doit = nl80211_deauthenticate, | 4483 | .doit = nl80211_deauthenticate, |
4517 | .policy = nl80211_policy, | 4484 | .policy = nl80211_policy, |
4518 | .flags = GENL_ADMIN_PERM, | 4485 | .flags = GENL_ADMIN_PERM, |
4519 | }, | 4486 | }, |
4520 | { | 4487 | { |
4521 | .cmd = NL80211_CMD_DISASSOCIATE, | 4488 | .cmd = NL80211_CMD_DISASSOCIATE, |
4522 | .doit = nl80211_disassociate, | 4489 | .doit = nl80211_disassociate, |
4523 | .policy = nl80211_policy, | 4490 | .policy = nl80211_policy, |
4524 | .flags = GENL_ADMIN_PERM, | 4491 | .flags = GENL_ADMIN_PERM, |
4525 | }, | 4492 | }, |
4526 | { | 4493 | { |
4527 | .cmd = NL80211_CMD_JOIN_IBSS, | 4494 | .cmd = NL80211_CMD_JOIN_IBSS, |
4528 | .doit = nl80211_join_ibss, | 4495 | .doit = nl80211_join_ibss, |
4529 | .policy = nl80211_policy, | 4496 | .policy = nl80211_policy, |
4530 | .flags = GENL_ADMIN_PERM, | 4497 | .flags = GENL_ADMIN_PERM, |
4531 | }, | 4498 | }, |
4532 | { | 4499 | { |
4533 | .cmd = NL80211_CMD_LEAVE_IBSS, | 4500 | .cmd = NL80211_CMD_LEAVE_IBSS, |
4534 | .doit = nl80211_leave_ibss, | 4501 | .doit = nl80211_leave_ibss, |
4535 | .policy = nl80211_policy, | 4502 | .policy = nl80211_policy, |
4536 | .flags = GENL_ADMIN_PERM, | 4503 | .flags = GENL_ADMIN_PERM, |
4537 | }, | 4504 | }, |
4538 | #ifdef CONFIG_NL80211_TESTMODE | 4505 | #ifdef CONFIG_NL80211_TESTMODE |
4539 | { | 4506 | { |
4540 | .cmd = NL80211_CMD_TESTMODE, | 4507 | .cmd = NL80211_CMD_TESTMODE, |
4541 | .doit = nl80211_testmode_do, | 4508 | .doit = nl80211_testmode_do, |
4542 | .policy = nl80211_policy, | 4509 | .policy = nl80211_policy, |
4543 | .flags = GENL_ADMIN_PERM, | 4510 | .flags = GENL_ADMIN_PERM, |
4544 | }, | 4511 | }, |
4545 | #endif | 4512 | #endif |
4546 | { | 4513 | { |
4547 | .cmd = NL80211_CMD_CONNECT, | 4514 | .cmd = NL80211_CMD_CONNECT, |
4548 | .doit = nl80211_connect, | 4515 | .doit = nl80211_connect, |
4549 | .policy = nl80211_policy, | 4516 | .policy = nl80211_policy, |
4550 | .flags = GENL_ADMIN_PERM, | 4517 | .flags = GENL_ADMIN_PERM, |
4551 | }, | 4518 | }, |
4552 | { | 4519 | { |
4553 | .cmd = NL80211_CMD_DISCONNECT, | 4520 | .cmd = NL80211_CMD_DISCONNECT, |
4554 | .doit = nl80211_disconnect, | 4521 | .doit = nl80211_disconnect, |
4555 | .policy = nl80211_policy, | 4522 | .policy = nl80211_policy, |
4556 | .flags = GENL_ADMIN_PERM, | 4523 | .flags = GENL_ADMIN_PERM, |
4557 | }, | 4524 | }, |
4558 | { | 4525 | { |
4559 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | 4526 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, |
4560 | .doit = nl80211_wiphy_netns, | 4527 | .doit = nl80211_wiphy_netns, |
4561 | .policy = nl80211_policy, | 4528 | .policy = nl80211_policy, |
4562 | .flags = GENL_ADMIN_PERM, | 4529 | .flags = GENL_ADMIN_PERM, |
4563 | }, | 4530 | }, |
4564 | { | 4531 | { |
4565 | .cmd = NL80211_CMD_GET_SURVEY, | 4532 | .cmd = NL80211_CMD_GET_SURVEY, |
4566 | .policy = nl80211_policy, | 4533 | .policy = nl80211_policy, |
4567 | .dumpit = nl80211_dump_survey, | 4534 | .dumpit = nl80211_dump_survey, |
4568 | }, | 4535 | }, |
4569 | { | 4536 | { |
4570 | .cmd = NL80211_CMD_SET_PMKSA, | 4537 | .cmd = NL80211_CMD_SET_PMKSA, |
4571 | .doit = nl80211_setdel_pmksa, | 4538 | .doit = nl80211_setdel_pmksa, |
4572 | .policy = nl80211_policy, | 4539 | .policy = nl80211_policy, |
4573 | .flags = GENL_ADMIN_PERM, | 4540 | .flags = GENL_ADMIN_PERM, |
4574 | }, | 4541 | }, |
4575 | { | 4542 | { |
4576 | .cmd = NL80211_CMD_DEL_PMKSA, | 4543 | .cmd = NL80211_CMD_DEL_PMKSA, |
4577 | .doit = nl80211_setdel_pmksa, | 4544 | .doit = nl80211_setdel_pmksa, |
4578 | .policy = nl80211_policy, | 4545 | .policy = nl80211_policy, |
4579 | .flags = GENL_ADMIN_PERM, | 4546 | .flags = GENL_ADMIN_PERM, |
4580 | }, | 4547 | }, |
4581 | { | 4548 | { |
4582 | .cmd = NL80211_CMD_FLUSH_PMKSA, | 4549 | .cmd = NL80211_CMD_FLUSH_PMKSA, |
4583 | .doit = nl80211_flush_pmksa, | 4550 | .doit = nl80211_flush_pmksa, |
4584 | .policy = nl80211_policy, | 4551 | .policy = nl80211_policy, |
4585 | .flags = GENL_ADMIN_PERM, | 4552 | .flags = GENL_ADMIN_PERM, |
4586 | }, | 4553 | }, |
4587 | 4554 | ||
4588 | }; | 4555 | }; |
4589 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4556 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4590 | .name = "mlme", | 4557 | .name = "mlme", |
4591 | }; | 4558 | }; |
4592 | 4559 | ||
4593 | /* multicast groups */ | 4560 | /* multicast groups */ |
4594 | static struct genl_multicast_group nl80211_config_mcgrp = { | 4561 | static struct genl_multicast_group nl80211_config_mcgrp = { |
4595 | .name = "config", | 4562 | .name = "config", |
4596 | }; | 4563 | }; |
4597 | static struct genl_multicast_group nl80211_scan_mcgrp = { | 4564 | static struct genl_multicast_group nl80211_scan_mcgrp = { |
4598 | .name = "scan", | 4565 | .name = "scan", |
4599 | }; | 4566 | }; |
4600 | static struct genl_multicast_group nl80211_regulatory_mcgrp = { | 4567 | static struct genl_multicast_group nl80211_regulatory_mcgrp = { |
4601 | .name = "regulatory", | 4568 | .name = "regulatory", |
4602 | }; | 4569 | }; |
4603 | 4570 | ||
4604 | /* notification functions */ | 4571 | /* notification functions */ |
4605 | 4572 | ||
4606 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | 4573 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) |
4607 | { | 4574 | { |
4608 | struct sk_buff *msg; | 4575 | struct sk_buff *msg; |
4609 | 4576 | ||
4610 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4577 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4611 | if (!msg) | 4578 | if (!msg) |
4612 | return; | 4579 | return; |
4613 | 4580 | ||
4614 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { | 4581 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { |
4615 | nlmsg_free(msg); | 4582 | nlmsg_free(msg); |
4616 | return; | 4583 | return; |
4617 | } | 4584 | } |
4618 | 4585 | ||
4619 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4586 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4620 | nl80211_config_mcgrp.id, GFP_KERNEL); | 4587 | nl80211_config_mcgrp.id, GFP_KERNEL); |
4621 | } | 4588 | } |
4622 | 4589 | ||
4623 | static int nl80211_add_scan_req(struct sk_buff *msg, | 4590 | static int nl80211_add_scan_req(struct sk_buff *msg, |
4624 | struct cfg80211_registered_device *rdev) | 4591 | struct cfg80211_registered_device *rdev) |
4625 | { | 4592 | { |
4626 | struct cfg80211_scan_request *req = rdev->scan_req; | 4593 | struct cfg80211_scan_request *req = rdev->scan_req; |
4627 | struct nlattr *nest; | 4594 | struct nlattr *nest; |
4628 | int i; | 4595 | int i; |
4629 | 4596 | ||
4630 | ASSERT_RDEV_LOCK(rdev); | 4597 | ASSERT_RDEV_LOCK(rdev); |
4631 | 4598 | ||
4632 | if (WARN_ON(!req)) | 4599 | if (WARN_ON(!req)) |
4633 | return 0; | 4600 | return 0; |
4634 | 4601 | ||
4635 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); | 4602 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); |
4636 | if (!nest) | 4603 | if (!nest) |
4637 | goto nla_put_failure; | 4604 | goto nla_put_failure; |
4638 | for (i = 0; i < req->n_ssids; i++) | 4605 | for (i = 0; i < req->n_ssids; i++) |
4639 | NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); | 4606 | NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); |
4640 | nla_nest_end(msg, nest); | 4607 | nla_nest_end(msg, nest); |
4641 | 4608 | ||
4642 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | 4609 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); |
4643 | if (!nest) | 4610 | if (!nest) |
4644 | goto nla_put_failure; | 4611 | goto nla_put_failure; |
4645 | for (i = 0; i < req->n_channels; i++) | 4612 | for (i = 0; i < req->n_channels; i++) |
4646 | NLA_PUT_U32(msg, i, req->channels[i]->center_freq); | 4613 | NLA_PUT_U32(msg, i, req->channels[i]->center_freq); |
4647 | nla_nest_end(msg, nest); | 4614 | nla_nest_end(msg, nest); |
4648 | 4615 | ||
4649 | if (req->ie) | 4616 | if (req->ie) |
4650 | NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); | 4617 | NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); |
4651 | 4618 | ||
4652 | return 0; | 4619 | return 0; |
4653 | nla_put_failure: | 4620 | nla_put_failure: |
4654 | return -ENOBUFS; | 4621 | return -ENOBUFS; |
4655 | } | 4622 | } |
4656 | 4623 | ||
4657 | static int nl80211_send_scan_msg(struct sk_buff *msg, | 4624 | static int nl80211_send_scan_msg(struct sk_buff *msg, |
4658 | struct cfg80211_registered_device *rdev, | 4625 | struct cfg80211_registered_device *rdev, |
4659 | struct net_device *netdev, | 4626 | struct net_device *netdev, |
4660 | u32 pid, u32 seq, int flags, | 4627 | u32 pid, u32 seq, int flags, |
4661 | u32 cmd) | 4628 | u32 cmd) |
4662 | { | 4629 | { |
4663 | void *hdr; | 4630 | void *hdr; |
4664 | 4631 | ||
4665 | hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); | 4632 | hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); |
4666 | if (!hdr) | 4633 | if (!hdr) |
4667 | return -1; | 4634 | return -1; |
4668 | 4635 | ||
4669 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 4636 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
4670 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 4637 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
4671 | 4638 | ||
4672 | /* ignore errors and send incomplete event anyway */ | 4639 | /* ignore errors and send incomplete event anyway */ |
4673 | nl80211_add_scan_req(msg, rdev); | 4640 | nl80211_add_scan_req(msg, rdev); |
4674 | 4641 | ||
4675 | return genlmsg_end(msg, hdr); | 4642 | return genlmsg_end(msg, hdr); |
4676 | 4643 | ||
4677 | nla_put_failure: | 4644 | nla_put_failure: |
4678 | genlmsg_cancel(msg, hdr); | 4645 | genlmsg_cancel(msg, hdr); |
4679 | return -EMSGSIZE; | 4646 | return -EMSGSIZE; |
4680 | } | 4647 | } |
4681 | 4648 | ||
4682 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 4649 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
4683 | struct net_device *netdev) | 4650 | struct net_device *netdev) |
4684 | { | 4651 | { |
4685 | struct sk_buff *msg; | 4652 | struct sk_buff *msg; |
4686 | 4653 | ||
4687 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 4654 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
4688 | if (!msg) | 4655 | if (!msg) |
4689 | return; | 4656 | return; |
4690 | 4657 | ||
4691 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 4658 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, |
4692 | NL80211_CMD_TRIGGER_SCAN) < 0) { | 4659 | NL80211_CMD_TRIGGER_SCAN) < 0) { |
4693 | nlmsg_free(msg); | 4660 | nlmsg_free(msg); |
4694 | return; | 4661 | return; |
4695 | } | 4662 | } |
4696 | 4663 | ||
4697 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4664 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4698 | nl80211_scan_mcgrp.id, GFP_KERNEL); | 4665 | nl80211_scan_mcgrp.id, GFP_KERNEL); |
4699 | } | 4666 | } |
4700 | 4667 | ||
4701 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 4668 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
4702 | struct net_device *netdev) | 4669 | struct net_device *netdev) |
4703 | { | 4670 | { |
4704 | struct sk_buff *msg; | 4671 | struct sk_buff *msg; |
4705 | 4672 | ||
4706 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4673 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4707 | if (!msg) | 4674 | if (!msg) |
4708 | return; | 4675 | return; |
4709 | 4676 | ||
4710 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 4677 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, |
4711 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { | 4678 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { |
4712 | nlmsg_free(msg); | 4679 | nlmsg_free(msg); |
4713 | return; | 4680 | return; |
4714 | } | 4681 | } |
4715 | 4682 | ||
4716 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4683 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4717 | nl80211_scan_mcgrp.id, GFP_KERNEL); | 4684 | nl80211_scan_mcgrp.id, GFP_KERNEL); |
4718 | } | 4685 | } |
4719 | 4686 | ||
4720 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 4687 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
4721 | struct net_device *netdev) | 4688 | struct net_device *netdev) |
4722 | { | 4689 | { |
4723 | struct sk_buff *msg; | 4690 | struct sk_buff *msg; |
4724 | 4691 | ||
4725 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4692 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4726 | if (!msg) | 4693 | if (!msg) |
4727 | return; | 4694 | return; |
4728 | 4695 | ||
4729 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 4696 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, |
4730 | NL80211_CMD_SCAN_ABORTED) < 0) { | 4697 | NL80211_CMD_SCAN_ABORTED) < 0) { |
4731 | nlmsg_free(msg); | 4698 | nlmsg_free(msg); |
4732 | return; | 4699 | return; |
4733 | } | 4700 | } |
4734 | 4701 | ||
4735 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4702 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4736 | nl80211_scan_mcgrp.id, GFP_KERNEL); | 4703 | nl80211_scan_mcgrp.id, GFP_KERNEL); |
4737 | } | 4704 | } |
4738 | 4705 | ||
4739 | /* | 4706 | /* |
4740 | * This can happen on global regulatory changes or device specific settings | 4707 | * This can happen on global regulatory changes or device specific settings |
4741 | * based on custom world regulatory domains. | 4708 | * based on custom world regulatory domains. |
4742 | */ | 4709 | */ |
4743 | void nl80211_send_reg_change_event(struct regulatory_request *request) | 4710 | void nl80211_send_reg_change_event(struct regulatory_request *request) |
4744 | { | 4711 | { |
4745 | struct sk_buff *msg; | 4712 | struct sk_buff *msg; |
4746 | void *hdr; | 4713 | void *hdr; |
4747 | 4714 | ||
4748 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4715 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4749 | if (!msg) | 4716 | if (!msg) |
4750 | return; | 4717 | return; |
4751 | 4718 | ||
4752 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); | 4719 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); |
4753 | if (!hdr) { | 4720 | if (!hdr) { |
4754 | nlmsg_free(msg); | 4721 | nlmsg_free(msg); |
4755 | return; | 4722 | return; |
4756 | } | 4723 | } |
4757 | 4724 | ||
4758 | /* Userspace can always count this one always being set */ | 4725 | /* Userspace can always count this one always being set */ |
4759 | NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator); | 4726 | NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator); |
4760 | 4727 | ||
4761 | if (request->alpha2[0] == '0' && request->alpha2[1] == '0') | 4728 | if (request->alpha2[0] == '0' && request->alpha2[1] == '0') |
4762 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | 4729 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, |
4763 | NL80211_REGDOM_TYPE_WORLD); | 4730 | NL80211_REGDOM_TYPE_WORLD); |
4764 | else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') | 4731 | else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') |
4765 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | 4732 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, |
4766 | NL80211_REGDOM_TYPE_CUSTOM_WORLD); | 4733 | NL80211_REGDOM_TYPE_CUSTOM_WORLD); |
4767 | else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') || | 4734 | else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') || |
4768 | request->intersect) | 4735 | request->intersect) |
4769 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | 4736 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, |
4770 | NL80211_REGDOM_TYPE_INTERSECTION); | 4737 | NL80211_REGDOM_TYPE_INTERSECTION); |
4771 | else { | 4738 | else { |
4772 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | 4739 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, |
4773 | NL80211_REGDOM_TYPE_COUNTRY); | 4740 | NL80211_REGDOM_TYPE_COUNTRY); |
4774 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2); | 4741 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2); |
4775 | } | 4742 | } |
4776 | 4743 | ||
4777 | if (wiphy_idx_valid(request->wiphy_idx)) | 4744 | if (wiphy_idx_valid(request->wiphy_idx)) |
4778 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx); | 4745 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx); |
4779 | 4746 | ||
4780 | if (genlmsg_end(msg, hdr) < 0) { | 4747 | if (genlmsg_end(msg, hdr) < 0) { |
4781 | nlmsg_free(msg); | 4748 | nlmsg_free(msg); |
4782 | return; | 4749 | return; |
4783 | } | 4750 | } |
4784 | 4751 | ||
4785 | rcu_read_lock(); | 4752 | rcu_read_lock(); |
4786 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | 4753 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, |
4787 | GFP_ATOMIC); | 4754 | GFP_ATOMIC); |
4788 | rcu_read_unlock(); | 4755 | rcu_read_unlock(); |
4789 | 4756 | ||
4790 | return; | 4757 | return; |
4791 | 4758 | ||
4792 | nla_put_failure: | 4759 | nla_put_failure: |
4793 | genlmsg_cancel(msg, hdr); | 4760 | genlmsg_cancel(msg, hdr); |
4794 | nlmsg_free(msg); | 4761 | nlmsg_free(msg); |
4795 | } | 4762 | } |
4796 | 4763 | ||
4797 | static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | 4764 | static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, |
4798 | struct net_device *netdev, | 4765 | struct net_device *netdev, |
4799 | const u8 *buf, size_t len, | 4766 | const u8 *buf, size_t len, |
4800 | enum nl80211_commands cmd, gfp_t gfp) | 4767 | enum nl80211_commands cmd, gfp_t gfp) |
4801 | { | 4768 | { |
4802 | struct sk_buff *msg; | 4769 | struct sk_buff *msg; |
4803 | void *hdr; | 4770 | void *hdr; |
4804 | 4771 | ||
4805 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 4772 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
4806 | if (!msg) | 4773 | if (!msg) |
4807 | return; | 4774 | return; |
4808 | 4775 | ||
4809 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | 4776 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); |
4810 | if (!hdr) { | 4777 | if (!hdr) { |
4811 | nlmsg_free(msg); | 4778 | nlmsg_free(msg); |
4812 | return; | 4779 | return; |
4813 | } | 4780 | } |
4814 | 4781 | ||
4815 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 4782 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
4816 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 4783 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
4817 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); | 4784 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); |
4818 | 4785 | ||
4819 | if (genlmsg_end(msg, hdr) < 0) { | 4786 | if (genlmsg_end(msg, hdr) < 0) { |
4820 | nlmsg_free(msg); | 4787 | nlmsg_free(msg); |
4821 | return; | 4788 | return; |
4822 | } | 4789 | } |
4823 | 4790 | ||
4824 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4791 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4825 | nl80211_mlme_mcgrp.id, gfp); | 4792 | nl80211_mlme_mcgrp.id, gfp); |
4826 | return; | 4793 | return; |
4827 | 4794 | ||
4828 | nla_put_failure: | 4795 | nla_put_failure: |
4829 | genlmsg_cancel(msg, hdr); | 4796 | genlmsg_cancel(msg, hdr); |
4830 | nlmsg_free(msg); | 4797 | nlmsg_free(msg); |
4831 | } | 4798 | } |
4832 | 4799 | ||
4833 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | 4800 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, |
4834 | struct net_device *netdev, const u8 *buf, | 4801 | struct net_device *netdev, const u8 *buf, |
4835 | size_t len, gfp_t gfp) | 4802 | size_t len, gfp_t gfp) |
4836 | { | 4803 | { |
4837 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 4804 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
4838 | NL80211_CMD_AUTHENTICATE, gfp); | 4805 | NL80211_CMD_AUTHENTICATE, gfp); |
4839 | } | 4806 | } |
4840 | 4807 | ||
4841 | void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | 4808 | void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, |
4842 | struct net_device *netdev, const u8 *buf, | 4809 | struct net_device *netdev, const u8 *buf, |
4843 | size_t len, gfp_t gfp) | 4810 | size_t len, gfp_t gfp) |
4844 | { | 4811 | { |
4845 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 4812 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
4846 | NL80211_CMD_ASSOCIATE, gfp); | 4813 | NL80211_CMD_ASSOCIATE, gfp); |
4847 | } | 4814 | } |
4848 | 4815 | ||
4849 | void nl80211_send_deauth(struct cfg80211_registered_device *rdev, | 4816 | void nl80211_send_deauth(struct cfg80211_registered_device *rdev, |
4850 | struct net_device *netdev, const u8 *buf, | 4817 | struct net_device *netdev, const u8 *buf, |
4851 | size_t len, gfp_t gfp) | 4818 | size_t len, gfp_t gfp) |
4852 | { | 4819 | { |
4853 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 4820 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
4854 | NL80211_CMD_DEAUTHENTICATE, gfp); | 4821 | NL80211_CMD_DEAUTHENTICATE, gfp); |
4855 | } | 4822 | } |
4856 | 4823 | ||
4857 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | 4824 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
4858 | struct net_device *netdev, const u8 *buf, | 4825 | struct net_device *netdev, const u8 *buf, |
4859 | size_t len, gfp_t gfp) | 4826 | size_t len, gfp_t gfp) |
4860 | { | 4827 | { |
4861 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 4828 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
4862 | NL80211_CMD_DISASSOCIATE, gfp); | 4829 | NL80211_CMD_DISASSOCIATE, gfp); |
4863 | } | 4830 | } |
4864 | 4831 | ||
4865 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 4832 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
4866 | struct net_device *netdev, int cmd, | 4833 | struct net_device *netdev, int cmd, |
4867 | const u8 *addr, gfp_t gfp) | 4834 | const u8 *addr, gfp_t gfp) |
4868 | { | 4835 | { |
4869 | struct sk_buff *msg; | 4836 | struct sk_buff *msg; |
4870 | void *hdr; | 4837 | void *hdr; |
4871 | 4838 | ||
4872 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 4839 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
4873 | if (!msg) | 4840 | if (!msg) |
4874 | return; | 4841 | return; |
4875 | 4842 | ||
4876 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | 4843 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); |
4877 | if (!hdr) { | 4844 | if (!hdr) { |
4878 | nlmsg_free(msg); | 4845 | nlmsg_free(msg); |
4879 | return; | 4846 | return; |
4880 | } | 4847 | } |
4881 | 4848 | ||
4882 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 4849 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
4883 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 4850 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
4884 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); | 4851 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); |
4885 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | 4852 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); |
4886 | 4853 | ||
4887 | if (genlmsg_end(msg, hdr) < 0) { | 4854 | if (genlmsg_end(msg, hdr) < 0) { |
4888 | nlmsg_free(msg); | 4855 | nlmsg_free(msg); |
4889 | return; | 4856 | return; |
4890 | } | 4857 | } |
4891 | 4858 | ||
4892 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4859 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4893 | nl80211_mlme_mcgrp.id, gfp); | 4860 | nl80211_mlme_mcgrp.id, gfp); |
4894 | return; | 4861 | return; |
4895 | 4862 | ||
4896 | nla_put_failure: | 4863 | nla_put_failure: |
4897 | genlmsg_cancel(msg, hdr); | 4864 | genlmsg_cancel(msg, hdr); |
4898 | nlmsg_free(msg); | 4865 | nlmsg_free(msg); |
4899 | } | 4866 | } |
4900 | 4867 | ||
4901 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | 4868 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, |
4902 | struct net_device *netdev, const u8 *addr, | 4869 | struct net_device *netdev, const u8 *addr, |
4903 | gfp_t gfp) | 4870 | gfp_t gfp) |
4904 | { | 4871 | { |
4905 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, | 4872 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, |
4906 | addr, gfp); | 4873 | addr, gfp); |
4907 | } | 4874 | } |
4908 | 4875 | ||
4909 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, | 4876 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, |
4910 | struct net_device *netdev, const u8 *addr, | 4877 | struct net_device *netdev, const u8 *addr, |
4911 | gfp_t gfp) | 4878 | gfp_t gfp) |
4912 | { | 4879 | { |
4913 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, | 4880 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, |
4914 | addr, gfp); | 4881 | addr, gfp); |
4915 | } | 4882 | } |
4916 | 4883 | ||
4917 | void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | 4884 | void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, |
4918 | struct net_device *netdev, const u8 *bssid, | 4885 | struct net_device *netdev, const u8 *bssid, |
4919 | const u8 *req_ie, size_t req_ie_len, | 4886 | const u8 *req_ie, size_t req_ie_len, |
4920 | const u8 *resp_ie, size_t resp_ie_len, | 4887 | const u8 *resp_ie, size_t resp_ie_len, |
4921 | u16 status, gfp_t gfp) | 4888 | u16 status, gfp_t gfp) |
4922 | { | 4889 | { |
4923 | struct sk_buff *msg; | 4890 | struct sk_buff *msg; |
4924 | void *hdr; | 4891 | void *hdr; |
4925 | 4892 | ||
4926 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 4893 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); |
4927 | if (!msg) | 4894 | if (!msg) |
4928 | return; | 4895 | return; |
4929 | 4896 | ||
4930 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT); | 4897 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT); |
4931 | if (!hdr) { | 4898 | if (!hdr) { |
4932 | nlmsg_free(msg); | 4899 | nlmsg_free(msg); |
4933 | return; | 4900 | return; |
4934 | } | 4901 | } |
4935 | 4902 | ||
4936 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 4903 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
4937 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 4904 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
4938 | if (bssid) | 4905 | if (bssid) |
4939 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | 4906 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); |
4940 | NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status); | 4907 | NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status); |
4941 | if (req_ie) | 4908 | if (req_ie) |
4942 | NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); | 4909 | NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); |
4943 | if (resp_ie) | 4910 | if (resp_ie) |
4944 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); | 4911 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); |
4945 | 4912 | ||
4946 | if (genlmsg_end(msg, hdr) < 0) { | 4913 | if (genlmsg_end(msg, hdr) < 0) { |
4947 | nlmsg_free(msg); | 4914 | nlmsg_free(msg); |
4948 | return; | 4915 | return; |
4949 | } | 4916 | } |
4950 | 4917 | ||
4951 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4918 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4952 | nl80211_mlme_mcgrp.id, gfp); | 4919 | nl80211_mlme_mcgrp.id, gfp); |
4953 | return; | 4920 | return; |
4954 | 4921 | ||
4955 | nla_put_failure: | 4922 | nla_put_failure: |
4956 | genlmsg_cancel(msg, hdr); | 4923 | genlmsg_cancel(msg, hdr); |
4957 | nlmsg_free(msg); | 4924 | nlmsg_free(msg); |
4958 | 4925 | ||
4959 | } | 4926 | } |
4960 | 4927 | ||
4961 | void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | 4928 | void nl80211_send_roamed(struct cfg80211_registered_device *rdev, |
4962 | struct net_device *netdev, const u8 *bssid, | 4929 | struct net_device *netdev, const u8 *bssid, |
4963 | const u8 *req_ie, size_t req_ie_len, | 4930 | const u8 *req_ie, size_t req_ie_len, |
4964 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | 4931 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) |
4965 | { | 4932 | { |
4966 | struct sk_buff *msg; | 4933 | struct sk_buff *msg; |
4967 | void *hdr; | 4934 | void *hdr; |
4968 | 4935 | ||
4969 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 4936 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); |
4970 | if (!msg) | 4937 | if (!msg) |
4971 | return; | 4938 | return; |
4972 | 4939 | ||
4973 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM); | 4940 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM); |
4974 | if (!hdr) { | 4941 | if (!hdr) { |
4975 | nlmsg_free(msg); | 4942 | nlmsg_free(msg); |
4976 | return; | 4943 | return; |
4977 | } | 4944 | } |
4978 | 4945 | ||
4979 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 4946 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
4980 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 4947 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
4981 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | 4948 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); |
4982 | if (req_ie) | 4949 | if (req_ie) |
4983 | NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); | 4950 | NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); |
4984 | if (resp_ie) | 4951 | if (resp_ie) |
4985 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); | 4952 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); |
4986 | 4953 | ||
4987 | if (genlmsg_end(msg, hdr) < 0) { | 4954 | if (genlmsg_end(msg, hdr) < 0) { |
4988 | nlmsg_free(msg); | 4955 | nlmsg_free(msg); |
4989 | return; | 4956 | return; |
4990 | } | 4957 | } |
4991 | 4958 | ||
4992 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 4959 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4993 | nl80211_mlme_mcgrp.id, gfp); | 4960 | nl80211_mlme_mcgrp.id, gfp); |
4994 | return; | 4961 | return; |
4995 | 4962 | ||
4996 | nla_put_failure: | 4963 | nla_put_failure: |
4997 | genlmsg_cancel(msg, hdr); | 4964 | genlmsg_cancel(msg, hdr); |
4998 | nlmsg_free(msg); | 4965 | nlmsg_free(msg); |
4999 | 4966 | ||
5000 | } | 4967 | } |
5001 | 4968 | ||
5002 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | 4969 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, |
5003 | struct net_device *netdev, u16 reason, | 4970 | struct net_device *netdev, u16 reason, |
5004 | const u8 *ie, size_t ie_len, bool from_ap) | 4971 | const u8 *ie, size_t ie_len, bool from_ap) |
5005 | { | 4972 | { |
5006 | struct sk_buff *msg; | 4973 | struct sk_buff *msg; |
5007 | void *hdr; | 4974 | void *hdr; |
5008 | 4975 | ||
5009 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 4976 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
5010 | if (!msg) | 4977 | if (!msg) |
5011 | return; | 4978 | return; |
5012 | 4979 | ||
5013 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT); | 4980 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT); |
5014 | if (!hdr) { | 4981 | if (!hdr) { |
5015 | nlmsg_free(msg); | 4982 | nlmsg_free(msg); |
5016 | return; | 4983 | return; |
5017 | } | 4984 | } |
5018 | 4985 | ||
5019 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 4986 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
5020 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 4987 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
5021 | if (from_ap && reason) | 4988 | if (from_ap && reason) |
5022 | NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason); | 4989 | NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason); |
5023 | if (from_ap) | 4990 | if (from_ap) |
5024 | NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP); | 4991 | NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP); |
5025 | if (ie) | 4992 | if (ie) |
5026 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); | 4993 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); |
5027 | 4994 | ||
5028 | if (genlmsg_end(msg, hdr) < 0) { | 4995 | if (genlmsg_end(msg, hdr) < 0) { |
5029 | nlmsg_free(msg); | 4996 | nlmsg_free(msg); |
5030 | return; | 4997 | return; |
5031 | } | 4998 | } |
5032 | 4999 | ||
5033 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 5000 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
5034 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | 5001 | nl80211_mlme_mcgrp.id, GFP_KERNEL); |
5035 | return; | 5002 | return; |
5036 | 5003 | ||
5037 | nla_put_failure: | 5004 | nla_put_failure: |
5038 | genlmsg_cancel(msg, hdr); | 5005 | genlmsg_cancel(msg, hdr); |
5039 | nlmsg_free(msg); | 5006 | nlmsg_free(msg); |
5040 | 5007 | ||
5041 | } | 5008 | } |
5042 | 5009 | ||
5043 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | 5010 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, |
5044 | struct net_device *netdev, const u8 *bssid, | 5011 | struct net_device *netdev, const u8 *bssid, |
5045 | gfp_t gfp) | 5012 | gfp_t gfp) |
5046 | { | 5013 | { |
5047 | struct sk_buff *msg; | 5014 | struct sk_buff *msg; |
5048 | void *hdr; | 5015 | void *hdr; |
5049 | 5016 | ||
5050 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 5017 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
5051 | if (!msg) | 5018 | if (!msg) |
5052 | return; | 5019 | return; |
5053 | 5020 | ||
5054 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); | 5021 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); |
5055 | if (!hdr) { | 5022 | if (!hdr) { |
5056 | nlmsg_free(msg); | 5023 | nlmsg_free(msg); |
5057 | return; | 5024 | return; |
5058 | } | 5025 | } |
5059 | 5026 | ||
5060 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 5027 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
5061 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 5028 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
5062 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | 5029 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); |
5063 | 5030 | ||
5064 | if (genlmsg_end(msg, hdr) < 0) { | 5031 | if (genlmsg_end(msg, hdr) < 0) { |
5065 | nlmsg_free(msg); | 5032 | nlmsg_free(msg); |
5066 | return; | 5033 | return; |
5067 | } | 5034 | } |
5068 | 5035 | ||
5069 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 5036 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
5070 | nl80211_mlme_mcgrp.id, gfp); | 5037 | nl80211_mlme_mcgrp.id, gfp); |
5071 | return; | 5038 | return; |
5072 | 5039 | ||
5073 | nla_put_failure: | 5040 | nla_put_failure: |
5074 | genlmsg_cancel(msg, hdr); | 5041 | genlmsg_cancel(msg, hdr); |
5075 | nlmsg_free(msg); | 5042 | nlmsg_free(msg); |
5076 | } | 5043 | } |
5077 | 5044 | ||
5078 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 5045 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
5079 | struct net_device *netdev, const u8 *addr, | 5046 | struct net_device *netdev, const u8 *addr, |
5080 | enum nl80211_key_type key_type, int key_id, | 5047 | enum nl80211_key_type key_type, int key_id, |
5081 | const u8 *tsc, gfp_t gfp) | 5048 | const u8 *tsc, gfp_t gfp) |
5082 | { | 5049 | { |
5083 | struct sk_buff *msg; | 5050 | struct sk_buff *msg; |
5084 | void *hdr; | 5051 | void *hdr; |
5085 | 5052 | ||
5086 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 5053 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
5087 | if (!msg) | 5054 | if (!msg) |
5088 | return; | 5055 | return; |
5089 | 5056 | ||
5090 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); | 5057 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); |
5091 | if (!hdr) { | 5058 | if (!hdr) { |
5092 | nlmsg_free(msg); | 5059 | nlmsg_free(msg); |
5093 | return; | 5060 | return; |
5094 | } | 5061 | } |
5095 | 5062 | ||
5096 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 5063 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
5097 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 5064 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
5098 | if (addr) | 5065 | if (addr) |
5099 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | 5066 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); |
5100 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); | 5067 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); |
5101 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); | 5068 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); |
5102 | if (tsc) | 5069 | if (tsc) |
5103 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); | 5070 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); |
5104 | 5071 | ||
5105 | if (genlmsg_end(msg, hdr) < 0) { | 5072 | if (genlmsg_end(msg, hdr) < 0) { |
5106 | nlmsg_free(msg); | 5073 | nlmsg_free(msg); |
5107 | return; | 5074 | return; |
5108 | } | 5075 | } |
5109 | 5076 | ||
5110 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 5077 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
5111 | nl80211_mlme_mcgrp.id, gfp); | 5078 | nl80211_mlme_mcgrp.id, gfp); |
5112 | return; | 5079 | return; |
5113 | 5080 | ||
5114 | nla_put_failure: | 5081 | nla_put_failure: |
5115 | genlmsg_cancel(msg, hdr); | 5082 | genlmsg_cancel(msg, hdr); |
5116 | nlmsg_free(msg); | 5083 | nlmsg_free(msg); |
5117 | } | 5084 | } |
5118 | 5085 | ||
5119 | void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | 5086 | void nl80211_send_beacon_hint_event(struct wiphy *wiphy, |
5120 | struct ieee80211_channel *channel_before, | 5087 | struct ieee80211_channel *channel_before, |
5121 | struct ieee80211_channel *channel_after) | 5088 | struct ieee80211_channel *channel_after) |
5122 | { | 5089 | { |
5123 | struct sk_buff *msg; | 5090 | struct sk_buff *msg; |
5124 | void *hdr; | 5091 | void *hdr; |
5125 | struct nlattr *nl_freq; | 5092 | struct nlattr *nl_freq; |
5126 | 5093 | ||
5127 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | 5094 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
5128 | if (!msg) | 5095 | if (!msg) |
5129 | return; | 5096 | return; |
5130 | 5097 | ||
5131 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); | 5098 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); |
5132 | if (!hdr) { | 5099 | if (!hdr) { |
5133 | nlmsg_free(msg); | 5100 | nlmsg_free(msg); |
5134 | return; | 5101 | return; |
5135 | } | 5102 | } |
5136 | 5103 | ||
5137 | /* | 5104 | /* |
5138 | * Since we are applying the beacon hint to a wiphy we know its | 5105 | * Since we are applying the beacon hint to a wiphy we know its |
5139 | * wiphy_idx is valid | 5106 | * wiphy_idx is valid |
5140 | */ | 5107 | */ |
5141 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); | 5108 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); |
5142 | 5109 | ||
5143 | /* Before */ | 5110 | /* Before */ |
5144 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | 5111 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); |
5145 | if (!nl_freq) | 5112 | if (!nl_freq) |
5146 | goto nla_put_failure; | 5113 | goto nla_put_failure; |
5147 | if (nl80211_msg_put_channel(msg, channel_before)) | 5114 | if (nl80211_msg_put_channel(msg, channel_before)) |
5148 | goto nla_put_failure; | 5115 | goto nla_put_failure; |
5149 | nla_nest_end(msg, nl_freq); | 5116 | nla_nest_end(msg, nl_freq); |
5150 | 5117 | ||
5151 | /* After */ | 5118 | /* After */ |
5152 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | 5119 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); |
5153 | if (!nl_freq) | 5120 | if (!nl_freq) |
5154 | goto nla_put_failure; | 5121 | goto nla_put_failure; |
5155 | if (nl80211_msg_put_channel(msg, channel_after)) | 5122 | if (nl80211_msg_put_channel(msg, channel_after)) |
5156 | goto nla_put_failure; | 5123 | goto nla_put_failure; |
5157 | nla_nest_end(msg, nl_freq); | 5124 | nla_nest_end(msg, nl_freq); |
5158 | 5125 | ||
5159 | if (genlmsg_end(msg, hdr) < 0) { | 5126 | if (genlmsg_end(msg, hdr) < 0) { |
5160 | nlmsg_free(msg); | 5127 | nlmsg_free(msg); |
5161 | return; | 5128 | return; |
5162 | } | 5129 | } |
5163 | 5130 | ||
5164 | rcu_read_lock(); | 5131 | rcu_read_lock(); |
5165 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | 5132 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, |
5166 | GFP_ATOMIC); | 5133 | GFP_ATOMIC); |
5167 | rcu_read_unlock(); | 5134 | rcu_read_unlock(); |
5168 | 5135 | ||
5169 | return; | 5136 | return; |
5170 | 5137 | ||
5171 | nla_put_failure: | 5138 | nla_put_failure: |
5172 | genlmsg_cancel(msg, hdr); | 5139 | genlmsg_cancel(msg, hdr); |
5173 | nlmsg_free(msg); | 5140 | nlmsg_free(msg); |
5174 | } | 5141 | } |
5175 | 5142 | ||
5176 | /* initialisation/exit functions */ | 5143 | /* initialisation/exit functions */ |
5177 | 5144 | ||
5178 | int nl80211_init(void) | 5145 | int nl80211_init(void) |
5179 | { | 5146 | { |
5180 | int err; | 5147 | int err; |
5181 | 5148 | ||
5182 | err = genl_register_family_with_ops(&nl80211_fam, | 5149 | err = genl_register_family_with_ops(&nl80211_fam, |
5183 | nl80211_ops, ARRAY_SIZE(nl80211_ops)); | 5150 | nl80211_ops, ARRAY_SIZE(nl80211_ops)); |
5184 | if (err) | 5151 | if (err) |
5185 | return err; | 5152 | return err; |
5186 | 5153 | ||
5187 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); | 5154 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); |
5188 | if (err) | 5155 | if (err) |
5189 | goto err_out; | 5156 | goto err_out; |
5190 | 5157 | ||
5191 | err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp); | 5158 | err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp); |
5192 | if (err) | 5159 | if (err) |
5193 | goto err_out; | 5160 | goto err_out; |
5194 | 5161 | ||
5195 | err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp); | 5162 | err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp); |
5196 | if (err) | 5163 | if (err) |
5197 | goto err_out; | 5164 | goto err_out; |
5198 | 5165 | ||
5199 | err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); | 5166 | err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); |
5200 | if (err) | 5167 | if (err) |
5201 | goto err_out; | 5168 | goto err_out; |
5202 | 5169 | ||
5203 | #ifdef CONFIG_NL80211_TESTMODE | 5170 | #ifdef CONFIG_NL80211_TESTMODE |
5204 | err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp); | 5171 | err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp); |
5205 | if (err) | 5172 | if (err) |
5206 | goto err_out; | 5173 | goto err_out; |
5207 | #endif | 5174 | #endif |
5208 | 5175 | ||
5209 | return 0; | 5176 | return 0; |
5210 | err_out: | 5177 | err_out: |
5211 | genl_unregister_family(&nl80211_fam); | 5178 | genl_unregister_family(&nl80211_fam); |
5212 | return err; | 5179 | return err; |
5213 | } | 5180 | } |
5214 | 5181 | ||
5215 | void nl80211_exit(void) | 5182 | void nl80211_exit(void) |
5216 | { | 5183 | { |
5217 | genl_unregister_family(&nl80211_fam); | 5184 | genl_unregister_family(&nl80211_fam); |
5218 | } | 5185 | } |
5219 | 5186 |
net/wireless/util.c
1 | /* | 1 | /* |
2 | * Wireless utility functions | 2 | * Wireless utility functions |
3 | * | 3 | * |
4 | * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | #include <linux/bitops.h> | 6 | #include <linux/bitops.h> |
7 | #include <linux/etherdevice.h> | 7 | #include <linux/etherdevice.h> |
8 | #include <net/cfg80211.h> | 8 | #include <net/cfg80211.h> |
9 | #include <net/ip.h> | 9 | #include <net/ip.h> |
10 | #include "core.h" | 10 | #include "core.h" |
11 | 11 | ||
12 | struct ieee80211_rate * | 12 | struct ieee80211_rate * |
13 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | 13 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, |
14 | u32 basic_rates, int bitrate) | 14 | u32 basic_rates, int bitrate) |
15 | { | 15 | { |
16 | struct ieee80211_rate *result = &sband->bitrates[0]; | 16 | struct ieee80211_rate *result = &sband->bitrates[0]; |
17 | int i; | 17 | int i; |
18 | 18 | ||
19 | for (i = 0; i < sband->n_bitrates; i++) { | 19 | for (i = 0; i < sband->n_bitrates; i++) { |
20 | if (!(basic_rates & BIT(i))) | 20 | if (!(basic_rates & BIT(i))) |
21 | continue; | 21 | continue; |
22 | if (sband->bitrates[i].bitrate > bitrate) | 22 | if (sband->bitrates[i].bitrate > bitrate) |
23 | continue; | 23 | continue; |
24 | result = &sband->bitrates[i]; | 24 | result = &sband->bitrates[i]; |
25 | } | 25 | } |
26 | 26 | ||
27 | return result; | 27 | return result; |
28 | } | 28 | } |
29 | EXPORT_SYMBOL(ieee80211_get_response_rate); | 29 | EXPORT_SYMBOL(ieee80211_get_response_rate); |
30 | 30 | ||
31 | int ieee80211_channel_to_frequency(int chan) | 31 | int ieee80211_channel_to_frequency(int chan) |
32 | { | 32 | { |
33 | if (chan < 14) | 33 | if (chan < 14) |
34 | return 2407 + chan * 5; | 34 | return 2407 + chan * 5; |
35 | 35 | ||
36 | if (chan == 14) | 36 | if (chan == 14) |
37 | return 2484; | 37 | return 2484; |
38 | 38 | ||
39 | /* FIXME: 802.11j 17.3.8.3.2 */ | 39 | /* FIXME: 802.11j 17.3.8.3.2 */ |
40 | return (chan + 1000) * 5; | 40 | return (chan + 1000) * 5; |
41 | } | 41 | } |
42 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 42 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
43 | 43 | ||
44 | int ieee80211_frequency_to_channel(int freq) | 44 | int ieee80211_frequency_to_channel(int freq) |
45 | { | 45 | { |
46 | if (freq == 2484) | 46 | if (freq == 2484) |
47 | return 14; | 47 | return 14; |
48 | 48 | ||
49 | if (freq < 2484) | 49 | if (freq < 2484) |
50 | return (freq - 2407) / 5; | 50 | return (freq - 2407) / 5; |
51 | 51 | ||
52 | /* FIXME: 802.11j 17.3.8.3.2 */ | 52 | /* FIXME: 802.11j 17.3.8.3.2 */ |
53 | return freq/5 - 1000; | 53 | return freq/5 - 1000; |
54 | } | 54 | } |
55 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 55 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
56 | 56 | ||
57 | struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, | 57 | struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, |
58 | int freq) | 58 | int freq) |
59 | { | 59 | { |
60 | enum ieee80211_band band; | 60 | enum ieee80211_band band; |
61 | struct ieee80211_supported_band *sband; | 61 | struct ieee80211_supported_band *sband; |
62 | int i; | 62 | int i; |
63 | 63 | ||
64 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 64 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
65 | sband = wiphy->bands[band]; | 65 | sband = wiphy->bands[band]; |
66 | 66 | ||
67 | if (!sband) | 67 | if (!sband) |
68 | continue; | 68 | continue; |
69 | 69 | ||
70 | for (i = 0; i < sband->n_channels; i++) { | 70 | for (i = 0; i < sband->n_channels; i++) { |
71 | if (sband->channels[i].center_freq == freq) | 71 | if (sband->channels[i].center_freq == freq) |
72 | return &sband->channels[i]; | 72 | return &sband->channels[i]; |
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | return NULL; | 76 | return NULL; |
77 | } | 77 | } |
78 | EXPORT_SYMBOL(__ieee80211_get_channel); | 78 | EXPORT_SYMBOL(__ieee80211_get_channel); |
79 | 79 | ||
80 | static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, | 80 | static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, |
81 | enum ieee80211_band band) | 81 | enum ieee80211_band band) |
82 | { | 82 | { |
83 | int i, want; | 83 | int i, want; |
84 | 84 | ||
85 | switch (band) { | 85 | switch (band) { |
86 | case IEEE80211_BAND_5GHZ: | 86 | case IEEE80211_BAND_5GHZ: |
87 | want = 3; | 87 | want = 3; |
88 | for (i = 0; i < sband->n_bitrates; i++) { | 88 | for (i = 0; i < sband->n_bitrates; i++) { |
89 | if (sband->bitrates[i].bitrate == 60 || | 89 | if (sband->bitrates[i].bitrate == 60 || |
90 | sband->bitrates[i].bitrate == 120 || | 90 | sband->bitrates[i].bitrate == 120 || |
91 | sband->bitrates[i].bitrate == 240) { | 91 | sband->bitrates[i].bitrate == 240) { |
92 | sband->bitrates[i].flags |= | 92 | sband->bitrates[i].flags |= |
93 | IEEE80211_RATE_MANDATORY_A; | 93 | IEEE80211_RATE_MANDATORY_A; |
94 | want--; | 94 | want--; |
95 | } | 95 | } |
96 | } | 96 | } |
97 | WARN_ON(want); | 97 | WARN_ON(want); |
98 | break; | 98 | break; |
99 | case IEEE80211_BAND_2GHZ: | 99 | case IEEE80211_BAND_2GHZ: |
100 | want = 7; | 100 | want = 7; |
101 | for (i = 0; i < sband->n_bitrates; i++) { | 101 | for (i = 0; i < sband->n_bitrates; i++) { |
102 | if (sband->bitrates[i].bitrate == 10) { | 102 | if (sband->bitrates[i].bitrate == 10) { |
103 | sband->bitrates[i].flags |= | 103 | sband->bitrates[i].flags |= |
104 | IEEE80211_RATE_MANDATORY_B | | 104 | IEEE80211_RATE_MANDATORY_B | |
105 | IEEE80211_RATE_MANDATORY_G; | 105 | IEEE80211_RATE_MANDATORY_G; |
106 | want--; | 106 | want--; |
107 | } | 107 | } |
108 | 108 | ||
109 | if (sband->bitrates[i].bitrate == 20 || | 109 | if (sband->bitrates[i].bitrate == 20 || |
110 | sband->bitrates[i].bitrate == 55 || | 110 | sband->bitrates[i].bitrate == 55 || |
111 | sband->bitrates[i].bitrate == 110 || | 111 | sband->bitrates[i].bitrate == 110 || |
112 | sband->bitrates[i].bitrate == 60 || | 112 | sband->bitrates[i].bitrate == 60 || |
113 | sband->bitrates[i].bitrate == 120 || | 113 | sband->bitrates[i].bitrate == 120 || |
114 | sband->bitrates[i].bitrate == 240) { | 114 | sband->bitrates[i].bitrate == 240) { |
115 | sband->bitrates[i].flags |= | 115 | sband->bitrates[i].flags |= |
116 | IEEE80211_RATE_MANDATORY_G; | 116 | IEEE80211_RATE_MANDATORY_G; |
117 | want--; | 117 | want--; |
118 | } | 118 | } |
119 | 119 | ||
120 | if (sband->bitrates[i].bitrate != 10 && | 120 | if (sband->bitrates[i].bitrate != 10 && |
121 | sband->bitrates[i].bitrate != 20 && | 121 | sband->bitrates[i].bitrate != 20 && |
122 | sband->bitrates[i].bitrate != 55 && | 122 | sband->bitrates[i].bitrate != 55 && |
123 | sband->bitrates[i].bitrate != 110) | 123 | sband->bitrates[i].bitrate != 110) |
124 | sband->bitrates[i].flags |= | 124 | sband->bitrates[i].flags |= |
125 | IEEE80211_RATE_ERP_G; | 125 | IEEE80211_RATE_ERP_G; |
126 | } | 126 | } |
127 | WARN_ON(want != 0 && want != 3 && want != 6); | 127 | WARN_ON(want != 0 && want != 3 && want != 6); |
128 | break; | 128 | break; |
129 | case IEEE80211_NUM_BANDS: | 129 | case IEEE80211_NUM_BANDS: |
130 | WARN_ON(1); | 130 | WARN_ON(1); |
131 | break; | 131 | break; |
132 | } | 132 | } |
133 | } | 133 | } |
134 | 134 | ||
135 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | 135 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy) |
136 | { | 136 | { |
137 | enum ieee80211_band band; | 137 | enum ieee80211_band band; |
138 | 138 | ||
139 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 139 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
140 | if (wiphy->bands[band]) | 140 | if (wiphy->bands[band]) |
141 | set_mandatory_flags_band(wiphy->bands[band], band); | 141 | set_mandatory_flags_band(wiphy->bands[band], band); |
142 | } | 142 | } |
143 | 143 | ||
144 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 144 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
145 | struct key_params *params, int key_idx, | 145 | struct key_params *params, int key_idx, |
146 | const u8 *mac_addr) | 146 | const u8 *mac_addr) |
147 | { | 147 | { |
148 | int i; | 148 | int i; |
149 | 149 | ||
150 | if (key_idx > 5) | 150 | if (key_idx > 5) |
151 | return -EINVAL; | 151 | return -EINVAL; |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * Disallow pairwise keys with non-zero index unless it's WEP | 154 | * Disallow pairwise keys with non-zero index unless it's WEP |
155 | * (because current deployments use pairwise WEP keys with | 155 | * (because current deployments use pairwise WEP keys with |
156 | * non-zero indizes but 802.11i clearly specifies to use zero) | 156 | * non-zero indizes but 802.11i clearly specifies to use zero) |
157 | */ | 157 | */ |
158 | if (mac_addr && key_idx && | 158 | if (mac_addr && key_idx && |
159 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | 159 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && |
160 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 160 | params->cipher != WLAN_CIPHER_SUITE_WEP104) |
161 | return -EINVAL; | 161 | return -EINVAL; |
162 | 162 | ||
163 | switch (params->cipher) { | 163 | switch (params->cipher) { |
164 | case WLAN_CIPHER_SUITE_WEP40: | 164 | case WLAN_CIPHER_SUITE_WEP40: |
165 | if (params->key_len != WLAN_KEY_LEN_WEP40) | 165 | if (params->key_len != WLAN_KEY_LEN_WEP40) |
166 | return -EINVAL; | 166 | return -EINVAL; |
167 | break; | 167 | break; |
168 | case WLAN_CIPHER_SUITE_TKIP: | 168 | case WLAN_CIPHER_SUITE_TKIP: |
169 | if (params->key_len != WLAN_KEY_LEN_TKIP) | 169 | if (params->key_len != WLAN_KEY_LEN_TKIP) |
170 | return -EINVAL; | 170 | return -EINVAL; |
171 | break; | 171 | break; |
172 | case WLAN_CIPHER_SUITE_CCMP: | 172 | case WLAN_CIPHER_SUITE_CCMP: |
173 | if (params->key_len != WLAN_KEY_LEN_CCMP) | 173 | if (params->key_len != WLAN_KEY_LEN_CCMP) |
174 | return -EINVAL; | 174 | return -EINVAL; |
175 | break; | 175 | break; |
176 | case WLAN_CIPHER_SUITE_WEP104: | 176 | case WLAN_CIPHER_SUITE_WEP104: |
177 | if (params->key_len != WLAN_KEY_LEN_WEP104) | 177 | if (params->key_len != WLAN_KEY_LEN_WEP104) |
178 | return -EINVAL; | 178 | return -EINVAL; |
179 | break; | 179 | break; |
180 | case WLAN_CIPHER_SUITE_AES_CMAC: | 180 | case WLAN_CIPHER_SUITE_AES_CMAC: |
181 | if (params->key_len != WLAN_KEY_LEN_AES_CMAC) | 181 | if (params->key_len != WLAN_KEY_LEN_AES_CMAC) |
182 | return -EINVAL; | 182 | return -EINVAL; |
183 | break; | 183 | break; |
184 | default: | 184 | default: |
185 | return -EINVAL; | 185 | return -EINVAL; |
186 | } | 186 | } |
187 | 187 | ||
188 | if (params->seq) { | 188 | if (params->seq) { |
189 | switch (params->cipher) { | 189 | switch (params->cipher) { |
190 | case WLAN_CIPHER_SUITE_WEP40: | 190 | case WLAN_CIPHER_SUITE_WEP40: |
191 | case WLAN_CIPHER_SUITE_WEP104: | 191 | case WLAN_CIPHER_SUITE_WEP104: |
192 | /* These ciphers do not use key sequence */ | 192 | /* These ciphers do not use key sequence */ |
193 | return -EINVAL; | 193 | return -EINVAL; |
194 | case WLAN_CIPHER_SUITE_TKIP: | 194 | case WLAN_CIPHER_SUITE_TKIP: |
195 | case WLAN_CIPHER_SUITE_CCMP: | 195 | case WLAN_CIPHER_SUITE_CCMP: |
196 | case WLAN_CIPHER_SUITE_AES_CMAC: | 196 | case WLAN_CIPHER_SUITE_AES_CMAC: |
197 | if (params->seq_len != 6) | 197 | if (params->seq_len != 6) |
198 | return -EINVAL; | 198 | return -EINVAL; |
199 | break; | 199 | break; |
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) | 203 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) |
204 | if (params->cipher == rdev->wiphy.cipher_suites[i]) | 204 | if (params->cipher == rdev->wiphy.cipher_suites[i]) |
205 | break; | 205 | break; |
206 | if (i == rdev->wiphy.n_cipher_suites) | 206 | if (i == rdev->wiphy.n_cipher_suites) |
207 | return -EINVAL; | 207 | return -EINVAL; |
208 | 208 | ||
209 | return 0; | 209 | return 0; |
210 | } | 210 | } |
211 | 211 | ||
212 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | 212 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ |
213 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | 213 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ |
214 | const unsigned char rfc1042_header[] __aligned(2) = | 214 | const unsigned char rfc1042_header[] __aligned(2) = |
215 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | 215 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
216 | EXPORT_SYMBOL(rfc1042_header); | 216 | EXPORT_SYMBOL(rfc1042_header); |
217 | 217 | ||
218 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | 218 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ |
219 | const unsigned char bridge_tunnel_header[] __aligned(2) = | 219 | const unsigned char bridge_tunnel_header[] __aligned(2) = |
220 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 220 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
221 | EXPORT_SYMBOL(bridge_tunnel_header); | 221 | EXPORT_SYMBOL(bridge_tunnel_header); |
222 | 222 | ||
223 | unsigned int ieee80211_hdrlen(__le16 fc) | 223 | unsigned int ieee80211_hdrlen(__le16 fc) |
224 | { | 224 | { |
225 | unsigned int hdrlen = 24; | 225 | unsigned int hdrlen = 24; |
226 | 226 | ||
227 | if (ieee80211_is_data(fc)) { | 227 | if (ieee80211_is_data(fc)) { |
228 | if (ieee80211_has_a4(fc)) | 228 | if (ieee80211_has_a4(fc)) |
229 | hdrlen = 30; | 229 | hdrlen = 30; |
230 | if (ieee80211_is_data_qos(fc)) | 230 | if (ieee80211_is_data_qos(fc)) |
231 | hdrlen += IEEE80211_QOS_CTL_LEN; | 231 | hdrlen += IEEE80211_QOS_CTL_LEN; |
232 | goto out; | 232 | goto out; |
233 | } | 233 | } |
234 | 234 | ||
235 | if (ieee80211_is_ctl(fc)) { | 235 | if (ieee80211_is_ctl(fc)) { |
236 | /* | 236 | /* |
237 | * ACK and CTS are 10 bytes, all others 16. To see how | 237 | * ACK and CTS are 10 bytes, all others 16. To see how |
238 | * to get this condition consider | 238 | * to get this condition consider |
239 | * subtype mask: 0b0000000011110000 (0x00F0) | 239 | * subtype mask: 0b0000000011110000 (0x00F0) |
240 | * ACK subtype: 0b0000000011010000 (0x00D0) | 240 | * ACK subtype: 0b0000000011010000 (0x00D0) |
241 | * CTS subtype: 0b0000000011000000 (0x00C0) | 241 | * CTS subtype: 0b0000000011000000 (0x00C0) |
242 | * bits that matter: ^^^ (0x00E0) | 242 | * bits that matter: ^^^ (0x00E0) |
243 | * value of those: 0b0000000011000000 (0x00C0) | 243 | * value of those: 0b0000000011000000 (0x00C0) |
244 | */ | 244 | */ |
245 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) | 245 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) |
246 | hdrlen = 10; | 246 | hdrlen = 10; |
247 | else | 247 | else |
248 | hdrlen = 16; | 248 | hdrlen = 16; |
249 | } | 249 | } |
250 | out: | 250 | out: |
251 | return hdrlen; | 251 | return hdrlen; |
252 | } | 252 | } |
253 | EXPORT_SYMBOL(ieee80211_hdrlen); | 253 | EXPORT_SYMBOL(ieee80211_hdrlen); |
254 | 254 | ||
255 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | 255 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) |
256 | { | 256 | { |
257 | const struct ieee80211_hdr *hdr = | 257 | const struct ieee80211_hdr *hdr = |
258 | (const struct ieee80211_hdr *)skb->data; | 258 | (const struct ieee80211_hdr *)skb->data; |
259 | unsigned int hdrlen; | 259 | unsigned int hdrlen; |
260 | 260 | ||
261 | if (unlikely(skb->len < 10)) | 261 | if (unlikely(skb->len < 10)) |
262 | return 0; | 262 | return 0; |
263 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 263 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
264 | if (unlikely(hdrlen > skb->len)) | 264 | if (unlikely(hdrlen > skb->len)) |
265 | return 0; | 265 | return 0; |
266 | return hdrlen; | 266 | return hdrlen; |
267 | } | 267 | } |
268 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 268 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
269 | 269 | ||
270 | static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | 270 | static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) |
271 | { | 271 | { |
272 | int ae = meshhdr->flags & MESH_FLAGS_AE; | 272 | int ae = meshhdr->flags & MESH_FLAGS_AE; |
273 | /* 7.1.3.5a.2 */ | 273 | /* 7.1.3.5a.2 */ |
274 | switch (ae) { | 274 | switch (ae) { |
275 | case 0: | 275 | case 0: |
276 | return 6; | 276 | return 6; |
277 | case MESH_FLAGS_AE_A4: | 277 | case MESH_FLAGS_AE_A4: |
278 | return 12; | 278 | return 12; |
279 | case MESH_FLAGS_AE_A5_A6: | 279 | case MESH_FLAGS_AE_A5_A6: |
280 | return 18; | 280 | return 18; |
281 | case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): | 281 | case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): |
282 | return 24; | 282 | return 24; |
283 | default: | 283 | default: |
284 | return 6; | 284 | return 6; |
285 | } | 285 | } |
286 | } | 286 | } |
287 | 287 | ||
288 | int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | 288 | int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, |
289 | enum nl80211_iftype iftype) | 289 | enum nl80211_iftype iftype) |
290 | { | 290 | { |
291 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 291 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
292 | u16 hdrlen, ethertype; | 292 | u16 hdrlen, ethertype; |
293 | u8 *payload; | 293 | u8 *payload; |
294 | u8 dst[ETH_ALEN]; | 294 | u8 dst[ETH_ALEN]; |
295 | u8 src[ETH_ALEN] __aligned(2); | 295 | u8 src[ETH_ALEN] __aligned(2); |
296 | 296 | ||
297 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 297 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) |
298 | return -1; | 298 | return -1; |
299 | 299 | ||
300 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 300 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
301 | 301 | ||
302 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | 302 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet |
303 | * header | 303 | * header |
304 | * IEEE 802.11 address fields: | 304 | * IEEE 802.11 address fields: |
305 | * ToDS FromDS Addr1 Addr2 Addr3 Addr4 | 305 | * ToDS FromDS Addr1 Addr2 Addr3 Addr4 |
306 | * 0 0 DA SA BSSID n/a | 306 | * 0 0 DA SA BSSID n/a |
307 | * 0 1 DA BSSID SA n/a | 307 | * 0 1 DA BSSID SA n/a |
308 | * 1 0 BSSID SA DA n/a | 308 | * 1 0 BSSID SA DA n/a |
309 | * 1 1 RA TA DA SA | 309 | * 1 1 RA TA DA SA |
310 | */ | 310 | */ |
311 | memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); | 311 | memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); |
312 | memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); | 312 | memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); |
313 | 313 | ||
314 | switch (hdr->frame_control & | 314 | switch (hdr->frame_control & |
315 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | 315 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { |
316 | case cpu_to_le16(IEEE80211_FCTL_TODS): | 316 | case cpu_to_le16(IEEE80211_FCTL_TODS): |
317 | if (unlikely(iftype != NL80211_IFTYPE_AP && | 317 | if (unlikely(iftype != NL80211_IFTYPE_AP && |
318 | iftype != NL80211_IFTYPE_AP_VLAN)) | 318 | iftype != NL80211_IFTYPE_AP_VLAN)) |
319 | return -1; | 319 | return -1; |
320 | break; | 320 | break; |
321 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 321 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): |
322 | if (unlikely(iftype != NL80211_IFTYPE_WDS && | 322 | if (unlikely(iftype != NL80211_IFTYPE_WDS && |
323 | iftype != NL80211_IFTYPE_MESH_POINT && | 323 | iftype != NL80211_IFTYPE_MESH_POINT && |
324 | iftype != NL80211_IFTYPE_AP_VLAN && | 324 | iftype != NL80211_IFTYPE_AP_VLAN && |
325 | iftype != NL80211_IFTYPE_STATION)) | 325 | iftype != NL80211_IFTYPE_STATION)) |
326 | return -1; | 326 | return -1; |
327 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | 327 | if (iftype == NL80211_IFTYPE_MESH_POINT) { |
328 | struct ieee80211s_hdr *meshdr = | 328 | struct ieee80211s_hdr *meshdr = |
329 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | 329 | (struct ieee80211s_hdr *) (skb->data + hdrlen); |
330 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | 330 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); |
331 | if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { | 331 | if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { |
332 | memcpy(dst, meshdr->eaddr1, ETH_ALEN); | 332 | memcpy(dst, meshdr->eaddr1, ETH_ALEN); |
333 | memcpy(src, meshdr->eaddr2, ETH_ALEN); | 333 | memcpy(src, meshdr->eaddr2, ETH_ALEN); |
334 | } | 334 | } |
335 | } | 335 | } |
336 | break; | 336 | break; |
337 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 337 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
338 | if ((iftype != NL80211_IFTYPE_STATION && | 338 | if ((iftype != NL80211_IFTYPE_STATION && |
339 | iftype != NL80211_IFTYPE_MESH_POINT) || | 339 | iftype != NL80211_IFTYPE_MESH_POINT) || |
340 | (is_multicast_ether_addr(dst) && | 340 | (is_multicast_ether_addr(dst) && |
341 | !compare_ether_addr(src, addr))) | 341 | !compare_ether_addr(src, addr))) |
342 | return -1; | 342 | return -1; |
343 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | 343 | if (iftype == NL80211_IFTYPE_MESH_POINT) { |
344 | struct ieee80211s_hdr *meshdr = | 344 | struct ieee80211s_hdr *meshdr = |
345 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | 345 | (struct ieee80211s_hdr *) (skb->data + hdrlen); |
346 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | 346 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); |
347 | if (meshdr->flags & MESH_FLAGS_AE_A4) | 347 | if (meshdr->flags & MESH_FLAGS_AE_A4) |
348 | memcpy(src, meshdr->eaddr1, ETH_ALEN); | 348 | memcpy(src, meshdr->eaddr1, ETH_ALEN); |
349 | } | 349 | } |
350 | break; | 350 | break; |
351 | case cpu_to_le16(0): | 351 | case cpu_to_le16(0): |
352 | if (iftype != NL80211_IFTYPE_ADHOC) | 352 | if (iftype != NL80211_IFTYPE_ADHOC) |
353 | return -1; | 353 | return -1; |
354 | break; | 354 | break; |
355 | } | 355 | } |
356 | 356 | ||
357 | if (unlikely(skb->len - hdrlen < 8)) | 357 | if (unlikely(skb->len - hdrlen < 8)) |
358 | return -1; | 358 | return -1; |
359 | 359 | ||
360 | payload = skb->data + hdrlen; | 360 | payload = skb->data + hdrlen; |
361 | ethertype = (payload[6] << 8) | payload[7]; | 361 | ethertype = (payload[6] << 8) | payload[7]; |
362 | 362 | ||
363 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && | 363 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && |
364 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | 364 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || |
365 | compare_ether_addr(payload, bridge_tunnel_header) == 0)) { | 365 | compare_ether_addr(payload, bridge_tunnel_header) == 0)) { |
366 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | 366 | /* remove RFC1042 or Bridge-Tunnel encapsulation and |
367 | * replace EtherType */ | 367 | * replace EtherType */ |
368 | skb_pull(skb, hdrlen + 6); | 368 | skb_pull(skb, hdrlen + 6); |
369 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | 369 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); |
370 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | 370 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); |
371 | } else { | 371 | } else { |
372 | struct ethhdr *ehdr; | 372 | struct ethhdr *ehdr; |
373 | __be16 len; | 373 | __be16 len; |
374 | 374 | ||
375 | skb_pull(skb, hdrlen); | 375 | skb_pull(skb, hdrlen); |
376 | len = htons(skb->len); | 376 | len = htons(skb->len); |
377 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); | 377 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); |
378 | memcpy(ehdr->h_dest, dst, ETH_ALEN); | 378 | memcpy(ehdr->h_dest, dst, ETH_ALEN); |
379 | memcpy(ehdr->h_source, src, ETH_ALEN); | 379 | memcpy(ehdr->h_source, src, ETH_ALEN); |
380 | ehdr->h_proto = len; | 380 | ehdr->h_proto = len; |
381 | } | 381 | } |
382 | return 0; | 382 | return 0; |
383 | } | 383 | } |
384 | EXPORT_SYMBOL(ieee80211_data_to_8023); | 384 | EXPORT_SYMBOL(ieee80211_data_to_8023); |
385 | 385 | ||
386 | int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, | 386 | int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, |
387 | enum nl80211_iftype iftype, u8 *bssid, bool qos) | 387 | enum nl80211_iftype iftype, u8 *bssid, bool qos) |
388 | { | 388 | { |
389 | struct ieee80211_hdr hdr; | 389 | struct ieee80211_hdr hdr; |
390 | u16 hdrlen, ethertype; | 390 | u16 hdrlen, ethertype; |
391 | __le16 fc; | 391 | __le16 fc; |
392 | const u8 *encaps_data; | 392 | const u8 *encaps_data; |
393 | int encaps_len, skip_header_bytes; | 393 | int encaps_len, skip_header_bytes; |
394 | int nh_pos, h_pos; | 394 | int nh_pos, h_pos; |
395 | int head_need; | 395 | int head_need; |
396 | 396 | ||
397 | if (unlikely(skb->len < ETH_HLEN)) | 397 | if (unlikely(skb->len < ETH_HLEN)) |
398 | return -EINVAL; | 398 | return -EINVAL; |
399 | 399 | ||
400 | nh_pos = skb_network_header(skb) - skb->data; | 400 | nh_pos = skb_network_header(skb) - skb->data; |
401 | h_pos = skb_transport_header(skb) - skb->data; | 401 | h_pos = skb_transport_header(skb) - skb->data; |
402 | 402 | ||
403 | /* convert Ethernet header to proper 802.11 header (based on | 403 | /* convert Ethernet header to proper 802.11 header (based on |
404 | * operation mode) */ | 404 | * operation mode) */ |
405 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 405 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
406 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 406 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
407 | 407 | ||
408 | switch (iftype) { | 408 | switch (iftype) { |
409 | case NL80211_IFTYPE_AP: | 409 | case NL80211_IFTYPE_AP: |
410 | case NL80211_IFTYPE_AP_VLAN: | 410 | case NL80211_IFTYPE_AP_VLAN: |
411 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 411 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
412 | /* DA BSSID SA */ | 412 | /* DA BSSID SA */ |
413 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 413 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
414 | memcpy(hdr.addr2, addr, ETH_ALEN); | 414 | memcpy(hdr.addr2, addr, ETH_ALEN); |
415 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | 415 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); |
416 | hdrlen = 24; | 416 | hdrlen = 24; |
417 | break; | 417 | break; |
418 | case NL80211_IFTYPE_STATION: | 418 | case NL80211_IFTYPE_STATION: |
419 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 419 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
420 | /* BSSID SA DA */ | 420 | /* BSSID SA DA */ |
421 | memcpy(hdr.addr1, bssid, ETH_ALEN); | 421 | memcpy(hdr.addr1, bssid, ETH_ALEN); |
422 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 422 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
423 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 423 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
424 | hdrlen = 24; | 424 | hdrlen = 24; |
425 | break; | 425 | break; |
426 | case NL80211_IFTYPE_ADHOC: | 426 | case NL80211_IFTYPE_ADHOC: |
427 | /* DA SA BSSID */ | 427 | /* DA SA BSSID */ |
428 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 428 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
429 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 429 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
430 | memcpy(hdr.addr3, bssid, ETH_ALEN); | 430 | memcpy(hdr.addr3, bssid, ETH_ALEN); |
431 | hdrlen = 24; | 431 | hdrlen = 24; |
432 | break; | 432 | break; |
433 | default: | 433 | default: |
434 | return -EOPNOTSUPP; | 434 | return -EOPNOTSUPP; |
435 | } | 435 | } |
436 | 436 | ||
437 | if (qos) { | 437 | if (qos) { |
438 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | 438 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
439 | hdrlen += 2; | 439 | hdrlen += 2; |
440 | } | 440 | } |
441 | 441 | ||
442 | hdr.frame_control = fc; | 442 | hdr.frame_control = fc; |
443 | hdr.duration_id = 0; | 443 | hdr.duration_id = 0; |
444 | hdr.seq_ctrl = 0; | 444 | hdr.seq_ctrl = 0; |
445 | 445 | ||
446 | skip_header_bytes = ETH_HLEN; | 446 | skip_header_bytes = ETH_HLEN; |
447 | if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { | 447 | if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { |
448 | encaps_data = bridge_tunnel_header; | 448 | encaps_data = bridge_tunnel_header; |
449 | encaps_len = sizeof(bridge_tunnel_header); | 449 | encaps_len = sizeof(bridge_tunnel_header); |
450 | skip_header_bytes -= 2; | 450 | skip_header_bytes -= 2; |
451 | } else if (ethertype > 0x600) { | 451 | } else if (ethertype > 0x600) { |
452 | encaps_data = rfc1042_header; | 452 | encaps_data = rfc1042_header; |
453 | encaps_len = sizeof(rfc1042_header); | 453 | encaps_len = sizeof(rfc1042_header); |
454 | skip_header_bytes -= 2; | 454 | skip_header_bytes -= 2; |
455 | } else { | 455 | } else { |
456 | encaps_data = NULL; | 456 | encaps_data = NULL; |
457 | encaps_len = 0; | 457 | encaps_len = 0; |
458 | } | 458 | } |
459 | 459 | ||
460 | skb_pull(skb, skip_header_bytes); | 460 | skb_pull(skb, skip_header_bytes); |
461 | nh_pos -= skip_header_bytes; | 461 | nh_pos -= skip_header_bytes; |
462 | h_pos -= skip_header_bytes; | 462 | h_pos -= skip_header_bytes; |
463 | 463 | ||
464 | head_need = hdrlen + encaps_len - skb_headroom(skb); | 464 | head_need = hdrlen + encaps_len - skb_headroom(skb); |
465 | 465 | ||
466 | if (head_need > 0 || skb_cloned(skb)) { | 466 | if (head_need > 0 || skb_cloned(skb)) { |
467 | head_need = max(head_need, 0); | 467 | head_need = max(head_need, 0); |
468 | if (head_need) | 468 | if (head_need) |
469 | skb_orphan(skb); | 469 | skb_orphan(skb); |
470 | 470 | ||
471 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { | 471 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { |
472 | printk(KERN_ERR "failed to reallocate Tx buffer\n"); | 472 | printk(KERN_ERR "failed to reallocate Tx buffer\n"); |
473 | return -ENOMEM; | 473 | return -ENOMEM; |
474 | } | 474 | } |
475 | skb->truesize += head_need; | 475 | skb->truesize += head_need; |
476 | } | 476 | } |
477 | 477 | ||
478 | if (encaps_data) { | 478 | if (encaps_data) { |
479 | memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); | 479 | memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); |
480 | nh_pos += encaps_len; | 480 | nh_pos += encaps_len; |
481 | h_pos += encaps_len; | 481 | h_pos += encaps_len; |
482 | } | 482 | } |
483 | 483 | ||
484 | memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); | 484 | memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); |
485 | 485 | ||
486 | nh_pos += hdrlen; | 486 | nh_pos += hdrlen; |
487 | h_pos += hdrlen; | 487 | h_pos += hdrlen; |
488 | 488 | ||
489 | /* Update skb pointers to various headers since this modified frame | 489 | /* Update skb pointers to various headers since this modified frame |
490 | * is going to go through Linux networking code that may potentially | 490 | * is going to go through Linux networking code that may potentially |
491 | * need things like pointer to IP header. */ | 491 | * need things like pointer to IP header. */ |
492 | skb_set_mac_header(skb, 0); | 492 | skb_set_mac_header(skb, 0); |
493 | skb_set_network_header(skb, nh_pos); | 493 | skb_set_network_header(skb, nh_pos); |
494 | skb_set_transport_header(skb, h_pos); | 494 | skb_set_transport_header(skb, h_pos); |
495 | 495 | ||
496 | return 0; | 496 | return 0; |
497 | } | 497 | } |
498 | EXPORT_SYMBOL(ieee80211_data_from_8023); | 498 | EXPORT_SYMBOL(ieee80211_data_from_8023); |
499 | 499 | ||
500 | /* Given a data frame determine the 802.1p/1d tag to use. */ | 500 | /* Given a data frame determine the 802.1p/1d tag to use. */ |
501 | unsigned int cfg80211_classify8021d(struct sk_buff *skb) | 501 | unsigned int cfg80211_classify8021d(struct sk_buff *skb) |
502 | { | 502 | { |
503 | unsigned int dscp; | 503 | unsigned int dscp; |
504 | 504 | ||
505 | /* skb->priority values from 256->263 are magic values to | 505 | /* skb->priority values from 256->263 are magic values to |
506 | * directly indicate a specific 802.1d priority. This is used | 506 | * directly indicate a specific 802.1d priority. This is used |
507 | * to allow 802.1d priority to be passed directly in from VLAN | 507 | * to allow 802.1d priority to be passed directly in from VLAN |
508 | * tags, etc. | 508 | * tags, etc. |
509 | */ | 509 | */ |
510 | if (skb->priority >= 256 && skb->priority <= 263) | 510 | if (skb->priority >= 256 && skb->priority <= 263) |
511 | return skb->priority - 256; | 511 | return skb->priority - 256; |
512 | 512 | ||
513 | switch (skb->protocol) { | 513 | switch (skb->protocol) { |
514 | case htons(ETH_P_IP): | 514 | case htons(ETH_P_IP): |
515 | dscp = ip_hdr(skb)->tos & 0xfc; | 515 | dscp = ip_hdr(skb)->tos & 0xfc; |
516 | break; | 516 | break; |
517 | default: | 517 | default: |
518 | return 0; | 518 | return 0; |
519 | } | 519 | } |
520 | 520 | ||
521 | return dscp >> 5; | 521 | return dscp >> 5; |
522 | } | 522 | } |
523 | EXPORT_SYMBOL(cfg80211_classify8021d); | 523 | EXPORT_SYMBOL(cfg80211_classify8021d); |
524 | 524 | ||
525 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) | 525 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) |
526 | { | 526 | { |
527 | u8 *end, *pos; | 527 | u8 *end, *pos; |
528 | 528 | ||
529 | pos = bss->information_elements; | 529 | pos = bss->information_elements; |
530 | if (pos == NULL) | 530 | if (pos == NULL) |
531 | return NULL; | 531 | return NULL; |
532 | end = pos + bss->len_information_elements; | 532 | end = pos + bss->len_information_elements; |
533 | 533 | ||
534 | while (pos + 1 < end) { | 534 | while (pos + 1 < end) { |
535 | if (pos + 2 + pos[1] > end) | 535 | if (pos + 2 + pos[1] > end) |
536 | break; | 536 | break; |
537 | if (pos[0] == ie) | 537 | if (pos[0] == ie) |
538 | return pos; | 538 | return pos; |
539 | pos += 2 + pos[1]; | 539 | pos += 2 + pos[1]; |
540 | } | 540 | } |
541 | 541 | ||
542 | return NULL; | 542 | return NULL; |
543 | } | 543 | } |
544 | EXPORT_SYMBOL(ieee80211_bss_get_ie); | 544 | EXPORT_SYMBOL(ieee80211_bss_get_ie); |
545 | 545 | ||
546 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | 546 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev) |
547 | { | 547 | { |
548 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 548 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
549 | struct net_device *dev = wdev->netdev; | 549 | struct net_device *dev = wdev->netdev; |
550 | int i; | 550 | int i; |
551 | 551 | ||
552 | if (!wdev->connect_keys) | 552 | if (!wdev->connect_keys) |
553 | return; | 553 | return; |
554 | 554 | ||
555 | for (i = 0; i < 6; i++) { | 555 | for (i = 0; i < 6; i++) { |
556 | if (!wdev->connect_keys->params[i].cipher) | 556 | if (!wdev->connect_keys->params[i].cipher) |
557 | continue; | 557 | continue; |
558 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | 558 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, |
559 | &wdev->connect_keys->params[i])) { | 559 | &wdev->connect_keys->params[i])) { |
560 | printk(KERN_ERR "%s: failed to set key %d\n", | 560 | printk(KERN_ERR "%s: failed to set key %d\n", |
561 | dev->name, i); | 561 | dev->name, i); |
562 | continue; | 562 | continue; |
563 | } | 563 | } |
564 | if (wdev->connect_keys->def == i) | 564 | if (wdev->connect_keys->def == i) |
565 | if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { | 565 | if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { |
566 | printk(KERN_ERR "%s: failed to set defkey %d\n", | 566 | printk(KERN_ERR "%s: failed to set defkey %d\n", |
567 | dev->name, i); | 567 | dev->name, i); |
568 | continue; | 568 | continue; |
569 | } | 569 | } |
570 | if (wdev->connect_keys->defmgmt == i) | 570 | if (wdev->connect_keys->defmgmt == i) |
571 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) | 571 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) |
572 | printk(KERN_ERR "%s: failed to set mgtdef %d\n", | 572 | printk(KERN_ERR "%s: failed to set mgtdef %d\n", |
573 | dev->name, i); | 573 | dev->name, i); |
574 | } | 574 | } |
575 | 575 | ||
576 | kfree(wdev->connect_keys); | 576 | kfree(wdev->connect_keys); |
577 | wdev->connect_keys = NULL; | 577 | wdev->connect_keys = NULL; |
578 | } | 578 | } |
579 | 579 | ||
580 | static void cfg80211_process_wdev_events(struct wireless_dev *wdev) | 580 | static void cfg80211_process_wdev_events(struct wireless_dev *wdev) |
581 | { | 581 | { |
582 | struct cfg80211_event *ev; | 582 | struct cfg80211_event *ev; |
583 | unsigned long flags; | 583 | unsigned long flags; |
584 | const u8 *bssid = NULL; | 584 | const u8 *bssid = NULL; |
585 | 585 | ||
586 | spin_lock_irqsave(&wdev->event_lock, flags); | 586 | spin_lock_irqsave(&wdev->event_lock, flags); |
587 | while (!list_empty(&wdev->event_list)) { | 587 | while (!list_empty(&wdev->event_list)) { |
588 | ev = list_first_entry(&wdev->event_list, | 588 | ev = list_first_entry(&wdev->event_list, |
589 | struct cfg80211_event, list); | 589 | struct cfg80211_event, list); |
590 | list_del(&ev->list); | 590 | list_del(&ev->list); |
591 | spin_unlock_irqrestore(&wdev->event_lock, flags); | 591 | spin_unlock_irqrestore(&wdev->event_lock, flags); |
592 | 592 | ||
593 | wdev_lock(wdev); | 593 | wdev_lock(wdev); |
594 | switch (ev->type) { | 594 | switch (ev->type) { |
595 | case EVENT_CONNECT_RESULT: | 595 | case EVENT_CONNECT_RESULT: |
596 | if (!is_zero_ether_addr(ev->cr.bssid)) | 596 | if (!is_zero_ether_addr(ev->cr.bssid)) |
597 | bssid = ev->cr.bssid; | 597 | bssid = ev->cr.bssid; |
598 | __cfg80211_connect_result( | 598 | __cfg80211_connect_result( |
599 | wdev->netdev, bssid, | 599 | wdev->netdev, bssid, |
600 | ev->cr.req_ie, ev->cr.req_ie_len, | 600 | ev->cr.req_ie, ev->cr.req_ie_len, |
601 | ev->cr.resp_ie, ev->cr.resp_ie_len, | 601 | ev->cr.resp_ie, ev->cr.resp_ie_len, |
602 | ev->cr.status, | 602 | ev->cr.status, |
603 | ev->cr.status == WLAN_STATUS_SUCCESS, | 603 | ev->cr.status == WLAN_STATUS_SUCCESS, |
604 | NULL); | 604 | NULL); |
605 | break; | 605 | break; |
606 | case EVENT_ROAMED: | 606 | case EVENT_ROAMED: |
607 | __cfg80211_roamed(wdev, ev->rm.bssid, | 607 | __cfg80211_roamed(wdev, ev->rm.bssid, |
608 | ev->rm.req_ie, ev->rm.req_ie_len, | 608 | ev->rm.req_ie, ev->rm.req_ie_len, |
609 | ev->rm.resp_ie, ev->rm.resp_ie_len); | 609 | ev->rm.resp_ie, ev->rm.resp_ie_len); |
610 | break; | 610 | break; |
611 | case EVENT_DISCONNECTED: | 611 | case EVENT_DISCONNECTED: |
612 | __cfg80211_disconnected(wdev->netdev, | 612 | __cfg80211_disconnected(wdev->netdev, |
613 | ev->dc.ie, ev->dc.ie_len, | 613 | ev->dc.ie, ev->dc.ie_len, |
614 | ev->dc.reason, true); | 614 | ev->dc.reason, true); |
615 | break; | 615 | break; |
616 | case EVENT_IBSS_JOINED: | 616 | case EVENT_IBSS_JOINED: |
617 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | 617 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); |
618 | break; | 618 | break; |
619 | } | 619 | } |
620 | wdev_unlock(wdev); | 620 | wdev_unlock(wdev); |
621 | 621 | ||
622 | kfree(ev); | 622 | kfree(ev); |
623 | 623 | ||
624 | spin_lock_irqsave(&wdev->event_lock, flags); | 624 | spin_lock_irqsave(&wdev->event_lock, flags); |
625 | } | 625 | } |
626 | spin_unlock_irqrestore(&wdev->event_lock, flags); | 626 | spin_unlock_irqrestore(&wdev->event_lock, flags); |
627 | } | 627 | } |
628 | 628 | ||
629 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | 629 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) |
630 | { | 630 | { |
631 | struct wireless_dev *wdev; | 631 | struct wireless_dev *wdev; |
632 | 632 | ||
633 | ASSERT_RTNL(); | 633 | ASSERT_RTNL(); |
634 | ASSERT_RDEV_LOCK(rdev); | 634 | ASSERT_RDEV_LOCK(rdev); |
635 | 635 | ||
636 | mutex_lock(&rdev->devlist_mtx); | 636 | mutex_lock(&rdev->devlist_mtx); |
637 | 637 | ||
638 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 638 | list_for_each_entry(wdev, &rdev->netdev_list, list) |
639 | cfg80211_process_wdev_events(wdev); | 639 | cfg80211_process_wdev_events(wdev); |
640 | 640 | ||
641 | mutex_unlock(&rdev->devlist_mtx); | 641 | mutex_unlock(&rdev->devlist_mtx); |
642 | } | 642 | } |
643 | 643 | ||
644 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | 644 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, |
645 | struct net_device *dev, enum nl80211_iftype ntype, | 645 | struct net_device *dev, enum nl80211_iftype ntype, |
646 | u32 *flags, struct vif_params *params) | 646 | u32 *flags, struct vif_params *params) |
647 | { | 647 | { |
648 | int err; | 648 | int err; |
649 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; | 649 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; |
650 | 650 | ||
651 | ASSERT_RDEV_LOCK(rdev); | 651 | ASSERT_RDEV_LOCK(rdev); |
652 | 652 | ||
653 | /* don't support changing VLANs, you just re-create them */ | 653 | /* don't support changing VLANs, you just re-create them */ |
654 | if (otype == NL80211_IFTYPE_AP_VLAN) | 654 | if (otype == NL80211_IFTYPE_AP_VLAN) |
655 | return -EOPNOTSUPP; | 655 | return -EOPNOTSUPP; |
656 | 656 | ||
657 | if (!rdev->ops->change_virtual_intf || | 657 | if (!rdev->ops->change_virtual_intf || |
658 | !(rdev->wiphy.interface_modes & (1 << ntype))) | 658 | !(rdev->wiphy.interface_modes & (1 << ntype))) |
659 | return -EOPNOTSUPP; | 659 | return -EOPNOTSUPP; |
660 | 660 | ||
661 | /* if it's part of a bridge, reject changing type to station/ibss */ | 661 | /* if it's part of a bridge, reject changing type to station/ibss */ |
662 | if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC || | 662 | if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC || |
663 | ntype == NL80211_IFTYPE_STATION)) | 663 | ntype == NL80211_IFTYPE_STATION)) |
664 | return -EBUSY; | 664 | return -EBUSY; |
665 | 665 | ||
666 | if (ntype != otype) { | 666 | if (ntype != otype) { |
667 | dev->ieee80211_ptr->use_4addr = false; | 667 | dev->ieee80211_ptr->use_4addr = false; |
668 | 668 | ||
669 | switch (otype) { | 669 | switch (otype) { |
670 | case NL80211_IFTYPE_ADHOC: | 670 | case NL80211_IFTYPE_ADHOC: |
671 | cfg80211_leave_ibss(rdev, dev, false); | 671 | cfg80211_leave_ibss(rdev, dev, false); |
672 | break; | 672 | break; |
673 | case NL80211_IFTYPE_STATION: | 673 | case NL80211_IFTYPE_STATION: |
674 | cfg80211_disconnect(rdev, dev, | 674 | cfg80211_disconnect(rdev, dev, |
675 | WLAN_REASON_DEAUTH_LEAVING, true); | 675 | WLAN_REASON_DEAUTH_LEAVING, true); |
676 | break; | 676 | break; |
677 | case NL80211_IFTYPE_MESH_POINT: | 677 | case NL80211_IFTYPE_MESH_POINT: |
678 | /* mesh should be handled? */ | 678 | /* mesh should be handled? */ |
679 | break; | 679 | break; |
680 | default: | 680 | default: |
681 | break; | 681 | break; |
682 | } | 682 | } |
683 | 683 | ||
684 | cfg80211_process_rdev_events(rdev); | 684 | cfg80211_process_rdev_events(rdev); |
685 | } | 685 | } |
686 | 686 | ||
687 | err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, | 687 | err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, |
688 | ntype, flags, params); | 688 | ntype, flags, params); |
689 | 689 | ||
690 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); | 690 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); |
691 | 691 | ||
692 | if (!err && params && params->use_4addr != -1) | 692 | if (!err && params && params->use_4addr != -1) |
693 | dev->ieee80211_ptr->use_4addr = params->use_4addr; | 693 | dev->ieee80211_ptr->use_4addr = params->use_4addr; |
694 | 694 | ||
695 | if (!err) { | 695 | if (!err) { |
696 | dev->priv_flags &= ~IFF_DONT_BRIDGE; | 696 | dev->priv_flags &= ~IFF_DONT_BRIDGE; |
697 | switch (ntype) { | 697 | switch (ntype) { |
698 | case NL80211_IFTYPE_STATION: | 698 | case NL80211_IFTYPE_STATION: |
699 | if (dev->ieee80211_ptr->use_4addr) | 699 | if (dev->ieee80211_ptr->use_4addr) |
700 | break; | 700 | break; |
701 | /* fall through */ | 701 | /* fall through */ |
702 | case NL80211_IFTYPE_ADHOC: | 702 | case NL80211_IFTYPE_ADHOC: |
703 | dev->priv_flags |= IFF_DONT_BRIDGE; | 703 | dev->priv_flags |= IFF_DONT_BRIDGE; |
704 | break; | 704 | break; |
705 | case NL80211_IFTYPE_AP: | 705 | case NL80211_IFTYPE_AP: |
706 | case NL80211_IFTYPE_AP_VLAN: | 706 | case NL80211_IFTYPE_AP_VLAN: |
707 | case NL80211_IFTYPE_WDS: | 707 | case NL80211_IFTYPE_WDS: |
708 | case NL80211_IFTYPE_MESH_POINT: | 708 | case NL80211_IFTYPE_MESH_POINT: |
709 | /* bridging OK */ | 709 | /* bridging OK */ |
710 | break; | 710 | break; |
711 | case NL80211_IFTYPE_MONITOR: | 711 | case NL80211_IFTYPE_MONITOR: |
712 | /* monitor can't bridge anyway */ | 712 | /* monitor can't bridge anyway */ |
713 | break; | 713 | break; |
714 | case NL80211_IFTYPE_UNSPECIFIED: | 714 | case NL80211_IFTYPE_UNSPECIFIED: |
715 | case __NL80211_IFTYPE_AFTER_LAST: | 715 | case __NL80211_IFTYPE_AFTER_LAST: |
716 | /* not happening */ | 716 | /* not happening */ |
717 | break; | 717 | break; |
718 | } | 718 | } |
719 | } | 719 | } |
720 | 720 | ||
721 | return err; | 721 | return err; |
722 | } | 722 | } |
723 | |||
724 | u16 cfg80211_calculate_bitrate(struct rate_info *rate) | ||
725 | { | ||
726 | int modulation, streams, bitrate; | ||
727 | |||
728 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | ||
729 | return rate->legacy; | ||
730 | |||
731 | /* the formula below does only work for MCS values smaller than 32 */ | ||
732 | if (rate->mcs >= 32) | ||
733 | return 0; | ||
734 | |||
735 | modulation = rate->mcs & 7; | ||
736 | streams = (rate->mcs >> 3) + 1; | ||
737 | |||
738 | bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? | ||
739 | 13500000 : 6500000; | ||
740 | |||
741 | if (modulation < 4) | ||
742 | bitrate *= (modulation + 1); | ||
743 | else if (modulation == 4) | ||
744 | bitrate *= (modulation + 2); | ||
745 | else | ||
746 | bitrate *= (modulation + 3); | ||
747 | |||
748 | bitrate *= streams; | ||
749 | |||
750 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | ||
751 | bitrate = (bitrate / 9) * 10; | ||
752 | |||
753 | /* do NOT round down here */ | ||
754 | return (bitrate + 50000) / 100000; | ||
755 | } | ||
723 | 756 |
net/wireless/wext-compat.c
1 | /* | 1 | /* |
2 | * cfg80211 - wext compat code | 2 | * cfg80211 - wext compat code |
3 | * | 3 | * |
4 | * This is temporary code until all wireless functionality is migrated | 4 | * This is temporary code until all wireless functionality is migrated |
5 | * into cfg80211, when that happens all the exports here go away and | 5 | * into cfg80211, when that happens all the exports here go away and |
6 | * we directly assign the wireless handlers of wireless interfaces. | 6 | * we directly assign the wireless handlers of wireless interfaces. |
7 | * | 7 | * |
8 | * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> | 8 | * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/wireless.h> | 11 | #include <linux/wireless.h> |
12 | #include <linux/nl80211.h> | 12 | #include <linux/nl80211.h> |
13 | #include <linux/if_arp.h> | 13 | #include <linux/if_arp.h> |
14 | #include <linux/etherdevice.h> | 14 | #include <linux/etherdevice.h> |
15 | #include <net/iw_handler.h> | 15 | #include <net/iw_handler.h> |
16 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
17 | #include "wext-compat.h" | 17 | #include "wext-compat.h" |
18 | #include "core.h" | 18 | #include "core.h" |
19 | 19 | ||
20 | int cfg80211_wext_giwname(struct net_device *dev, | 20 | int cfg80211_wext_giwname(struct net_device *dev, |
21 | struct iw_request_info *info, | 21 | struct iw_request_info *info, |
22 | char *name, char *extra) | 22 | char *name, char *extra) |
23 | { | 23 | { |
24 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 24 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
25 | struct ieee80211_supported_band *sband; | 25 | struct ieee80211_supported_band *sband; |
26 | bool is_ht = false, is_a = false, is_b = false, is_g = false; | 26 | bool is_ht = false, is_a = false, is_b = false, is_g = false; |
27 | 27 | ||
28 | if (!wdev) | 28 | if (!wdev) |
29 | return -EOPNOTSUPP; | 29 | return -EOPNOTSUPP; |
30 | 30 | ||
31 | sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; | 31 | sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; |
32 | if (sband) { | 32 | if (sband) { |
33 | is_a = true; | 33 | is_a = true; |
34 | is_ht |= sband->ht_cap.ht_supported; | 34 | is_ht |= sband->ht_cap.ht_supported; |
35 | } | 35 | } |
36 | 36 | ||
37 | sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; | 37 | sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; |
38 | if (sband) { | 38 | if (sband) { |
39 | int i; | 39 | int i; |
40 | /* Check for mandatory rates */ | 40 | /* Check for mandatory rates */ |
41 | for (i = 0; i < sband->n_bitrates; i++) { | 41 | for (i = 0; i < sband->n_bitrates; i++) { |
42 | if (sband->bitrates[i].bitrate == 10) | 42 | if (sband->bitrates[i].bitrate == 10) |
43 | is_b = true; | 43 | is_b = true; |
44 | if (sband->bitrates[i].bitrate == 60) | 44 | if (sband->bitrates[i].bitrate == 60) |
45 | is_g = true; | 45 | is_g = true; |
46 | } | 46 | } |
47 | is_ht |= sband->ht_cap.ht_supported; | 47 | is_ht |= sband->ht_cap.ht_supported; |
48 | } | 48 | } |
49 | 49 | ||
50 | strcpy(name, "IEEE 802.11"); | 50 | strcpy(name, "IEEE 802.11"); |
51 | if (is_a) | 51 | if (is_a) |
52 | strcat(name, "a"); | 52 | strcat(name, "a"); |
53 | if (is_b) | 53 | if (is_b) |
54 | strcat(name, "b"); | 54 | strcat(name, "b"); |
55 | if (is_g) | 55 | if (is_g) |
56 | strcat(name, "g"); | 56 | strcat(name, "g"); |
57 | if (is_ht) | 57 | if (is_ht) |
58 | strcat(name, "n"); | 58 | strcat(name, "n"); |
59 | 59 | ||
60 | return 0; | 60 | return 0; |
61 | } | 61 | } |
62 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); | 62 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); |
63 | 63 | ||
64 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | 64 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, |
65 | u32 *mode, char *extra) | 65 | u32 *mode, char *extra) |
66 | { | 66 | { |
67 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 67 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
68 | struct cfg80211_registered_device *rdev; | 68 | struct cfg80211_registered_device *rdev; |
69 | struct vif_params vifparams; | 69 | struct vif_params vifparams; |
70 | enum nl80211_iftype type; | 70 | enum nl80211_iftype type; |
71 | int ret; | 71 | int ret; |
72 | 72 | ||
73 | rdev = wiphy_to_dev(wdev->wiphy); | 73 | rdev = wiphy_to_dev(wdev->wiphy); |
74 | 74 | ||
75 | switch (*mode) { | 75 | switch (*mode) { |
76 | case IW_MODE_INFRA: | 76 | case IW_MODE_INFRA: |
77 | type = NL80211_IFTYPE_STATION; | 77 | type = NL80211_IFTYPE_STATION; |
78 | break; | 78 | break; |
79 | case IW_MODE_ADHOC: | 79 | case IW_MODE_ADHOC: |
80 | type = NL80211_IFTYPE_ADHOC; | 80 | type = NL80211_IFTYPE_ADHOC; |
81 | break; | 81 | break; |
82 | case IW_MODE_REPEAT: | 82 | case IW_MODE_REPEAT: |
83 | type = NL80211_IFTYPE_WDS; | 83 | type = NL80211_IFTYPE_WDS; |
84 | break; | 84 | break; |
85 | case IW_MODE_MONITOR: | 85 | case IW_MODE_MONITOR: |
86 | type = NL80211_IFTYPE_MONITOR; | 86 | type = NL80211_IFTYPE_MONITOR; |
87 | break; | 87 | break; |
88 | default: | 88 | default: |
89 | return -EINVAL; | 89 | return -EINVAL; |
90 | } | 90 | } |
91 | 91 | ||
92 | if (type == wdev->iftype) | 92 | if (type == wdev->iftype) |
93 | return 0; | 93 | return 0; |
94 | 94 | ||
95 | memset(&vifparams, 0, sizeof(vifparams)); | 95 | memset(&vifparams, 0, sizeof(vifparams)); |
96 | 96 | ||
97 | cfg80211_lock_rdev(rdev); | 97 | cfg80211_lock_rdev(rdev); |
98 | ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); | 98 | ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); |
99 | cfg80211_unlock_rdev(rdev); | 99 | cfg80211_unlock_rdev(rdev); |
100 | 100 | ||
101 | return ret; | 101 | return ret; |
102 | } | 102 | } |
103 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); | 103 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); |
104 | 104 | ||
105 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | 105 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, |
106 | u32 *mode, char *extra) | 106 | u32 *mode, char *extra) |
107 | { | 107 | { |
108 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 108 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
109 | 109 | ||
110 | if (!wdev) | 110 | if (!wdev) |
111 | return -EOPNOTSUPP; | 111 | return -EOPNOTSUPP; |
112 | 112 | ||
113 | switch (wdev->iftype) { | 113 | switch (wdev->iftype) { |
114 | case NL80211_IFTYPE_AP: | 114 | case NL80211_IFTYPE_AP: |
115 | *mode = IW_MODE_MASTER; | 115 | *mode = IW_MODE_MASTER; |
116 | break; | 116 | break; |
117 | case NL80211_IFTYPE_STATION: | 117 | case NL80211_IFTYPE_STATION: |
118 | *mode = IW_MODE_INFRA; | 118 | *mode = IW_MODE_INFRA; |
119 | break; | 119 | break; |
120 | case NL80211_IFTYPE_ADHOC: | 120 | case NL80211_IFTYPE_ADHOC: |
121 | *mode = IW_MODE_ADHOC; | 121 | *mode = IW_MODE_ADHOC; |
122 | break; | 122 | break; |
123 | case NL80211_IFTYPE_MONITOR: | 123 | case NL80211_IFTYPE_MONITOR: |
124 | *mode = IW_MODE_MONITOR; | 124 | *mode = IW_MODE_MONITOR; |
125 | break; | 125 | break; |
126 | case NL80211_IFTYPE_WDS: | 126 | case NL80211_IFTYPE_WDS: |
127 | *mode = IW_MODE_REPEAT; | 127 | *mode = IW_MODE_REPEAT; |
128 | break; | 128 | break; |
129 | case NL80211_IFTYPE_AP_VLAN: | 129 | case NL80211_IFTYPE_AP_VLAN: |
130 | *mode = IW_MODE_SECOND; /* FIXME */ | 130 | *mode = IW_MODE_SECOND; /* FIXME */ |
131 | break; | 131 | break; |
132 | default: | 132 | default: |
133 | *mode = IW_MODE_AUTO; | 133 | *mode = IW_MODE_AUTO; |
134 | break; | 134 | break; |
135 | } | 135 | } |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); | 138 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); |
139 | 139 | ||
140 | 140 | ||
141 | int cfg80211_wext_giwrange(struct net_device *dev, | 141 | int cfg80211_wext_giwrange(struct net_device *dev, |
142 | struct iw_request_info *info, | 142 | struct iw_request_info *info, |
143 | struct iw_point *data, char *extra) | 143 | struct iw_point *data, char *extra) |
144 | { | 144 | { |
145 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 145 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
146 | struct iw_range *range = (struct iw_range *) extra; | 146 | struct iw_range *range = (struct iw_range *) extra; |
147 | enum ieee80211_band band; | 147 | enum ieee80211_band band; |
148 | int i, c = 0; | 148 | int i, c = 0; |
149 | 149 | ||
150 | if (!wdev) | 150 | if (!wdev) |
151 | return -EOPNOTSUPP; | 151 | return -EOPNOTSUPP; |
152 | 152 | ||
153 | data->length = sizeof(struct iw_range); | 153 | data->length = sizeof(struct iw_range); |
154 | memset(range, 0, sizeof(struct iw_range)); | 154 | memset(range, 0, sizeof(struct iw_range)); |
155 | 155 | ||
156 | range->we_version_compiled = WIRELESS_EXT; | 156 | range->we_version_compiled = WIRELESS_EXT; |
157 | range->we_version_source = 21; | 157 | range->we_version_source = 21; |
158 | range->retry_capa = IW_RETRY_LIMIT; | 158 | range->retry_capa = IW_RETRY_LIMIT; |
159 | range->retry_flags = IW_RETRY_LIMIT; | 159 | range->retry_flags = IW_RETRY_LIMIT; |
160 | range->min_retry = 0; | 160 | range->min_retry = 0; |
161 | range->max_retry = 255; | 161 | range->max_retry = 255; |
162 | range->min_rts = 0; | 162 | range->min_rts = 0; |
163 | range->max_rts = 2347; | 163 | range->max_rts = 2347; |
164 | range->min_frag = 256; | 164 | range->min_frag = 256; |
165 | range->max_frag = 2346; | 165 | range->max_frag = 2346; |
166 | 166 | ||
167 | range->max_encoding_tokens = 4; | 167 | range->max_encoding_tokens = 4; |
168 | 168 | ||
169 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; | 169 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; |
170 | 170 | ||
171 | switch (wdev->wiphy->signal_type) { | 171 | switch (wdev->wiphy->signal_type) { |
172 | case CFG80211_SIGNAL_TYPE_NONE: | 172 | case CFG80211_SIGNAL_TYPE_NONE: |
173 | break; | 173 | break; |
174 | case CFG80211_SIGNAL_TYPE_MBM: | 174 | case CFG80211_SIGNAL_TYPE_MBM: |
175 | range->max_qual.level = -110; | 175 | range->max_qual.level = -110; |
176 | range->max_qual.qual = 70; | 176 | range->max_qual.qual = 70; |
177 | range->avg_qual.qual = 35; | 177 | range->avg_qual.qual = 35; |
178 | range->max_qual.updated |= IW_QUAL_DBM; | 178 | range->max_qual.updated |= IW_QUAL_DBM; |
179 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | 179 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; |
180 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | 180 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; |
181 | break; | 181 | break; |
182 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 182 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
183 | range->max_qual.level = 100; | 183 | range->max_qual.level = 100; |
184 | range->max_qual.qual = 100; | 184 | range->max_qual.qual = 100; |
185 | range->avg_qual.qual = 50; | 185 | range->avg_qual.qual = 50; |
186 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | 186 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; |
187 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | 187 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; |
188 | break; | 188 | break; |
189 | } | 189 | } |
190 | 190 | ||
191 | range->avg_qual.level = range->max_qual.level / 2; | 191 | range->avg_qual.level = range->max_qual.level / 2; |
192 | range->avg_qual.noise = range->max_qual.noise / 2; | 192 | range->avg_qual.noise = range->max_qual.noise / 2; |
193 | range->avg_qual.updated = range->max_qual.updated; | 193 | range->avg_qual.updated = range->max_qual.updated; |
194 | 194 | ||
195 | for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) { | 195 | for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) { |
196 | switch (wdev->wiphy->cipher_suites[i]) { | 196 | switch (wdev->wiphy->cipher_suites[i]) { |
197 | case WLAN_CIPHER_SUITE_TKIP: | 197 | case WLAN_CIPHER_SUITE_TKIP: |
198 | range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP | | 198 | range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP | |
199 | IW_ENC_CAPA_WPA); | 199 | IW_ENC_CAPA_WPA); |
200 | break; | 200 | break; |
201 | 201 | ||
202 | case WLAN_CIPHER_SUITE_CCMP: | 202 | case WLAN_CIPHER_SUITE_CCMP: |
203 | range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP | | 203 | range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP | |
204 | IW_ENC_CAPA_WPA2); | 204 | IW_ENC_CAPA_WPA2); |
205 | break; | 205 | break; |
206 | 206 | ||
207 | case WLAN_CIPHER_SUITE_WEP40: | 207 | case WLAN_CIPHER_SUITE_WEP40: |
208 | range->encoding_size[range->num_encoding_sizes++] = | 208 | range->encoding_size[range->num_encoding_sizes++] = |
209 | WLAN_KEY_LEN_WEP40; | 209 | WLAN_KEY_LEN_WEP40; |
210 | break; | 210 | break; |
211 | 211 | ||
212 | case WLAN_CIPHER_SUITE_WEP104: | 212 | case WLAN_CIPHER_SUITE_WEP104: |
213 | range->encoding_size[range->num_encoding_sizes++] = | 213 | range->encoding_size[range->num_encoding_sizes++] = |
214 | WLAN_KEY_LEN_WEP104; | 214 | WLAN_KEY_LEN_WEP104; |
215 | break; | 215 | break; |
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | 219 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { |
220 | struct ieee80211_supported_band *sband; | 220 | struct ieee80211_supported_band *sband; |
221 | 221 | ||
222 | sband = wdev->wiphy->bands[band]; | 222 | sband = wdev->wiphy->bands[band]; |
223 | 223 | ||
224 | if (!sband) | 224 | if (!sband) |
225 | continue; | 225 | continue; |
226 | 226 | ||
227 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | 227 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { |
228 | struct ieee80211_channel *chan = &sband->channels[i]; | 228 | struct ieee80211_channel *chan = &sband->channels[i]; |
229 | 229 | ||
230 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | 230 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { |
231 | range->freq[c].i = | 231 | range->freq[c].i = |
232 | ieee80211_frequency_to_channel( | 232 | ieee80211_frequency_to_channel( |
233 | chan->center_freq); | 233 | chan->center_freq); |
234 | range->freq[c].m = chan->center_freq; | 234 | range->freq[c].m = chan->center_freq; |
235 | range->freq[c].e = 6; | 235 | range->freq[c].e = 6; |
236 | c++; | 236 | c++; |
237 | } | 237 | } |
238 | } | 238 | } |
239 | } | 239 | } |
240 | range->num_channels = c; | 240 | range->num_channels = c; |
241 | range->num_frequency = c; | 241 | range->num_frequency = c; |
242 | 242 | ||
243 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | 243 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); |
244 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | 244 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); |
245 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | 245 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); |
246 | 246 | ||
247 | if (wdev->wiphy->max_scan_ssids > 0) | 247 | if (wdev->wiphy->max_scan_ssids > 0) |
248 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | 248 | range->scan_capa |= IW_SCAN_CAPA_ESSID; |
249 | 249 | ||
250 | return 0; | 250 | return 0; |
251 | } | 251 | } |
252 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); | 252 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); |
253 | 253 | ||
254 | 254 | ||
255 | /** | 255 | /** |
256 | * cfg80211_wext_freq - get wext frequency for non-"auto" | 256 | * cfg80211_wext_freq - get wext frequency for non-"auto" |
257 | * @wiphy: the wiphy | 257 | * @wiphy: the wiphy |
258 | * @freq: the wext freq encoding | 258 | * @freq: the wext freq encoding |
259 | * | 259 | * |
260 | * Returns a frequency, or a negative error code, or 0 for auto. | 260 | * Returns a frequency, or a negative error code, or 0 for auto. |
261 | */ | 261 | */ |
262 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) | 262 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) |
263 | { | 263 | { |
264 | /* | 264 | /* |
265 | * Parse frequency - return 0 for auto and | 265 | * Parse frequency - return 0 for auto and |
266 | * -EINVAL for impossible things. | 266 | * -EINVAL for impossible things. |
267 | */ | 267 | */ |
268 | if (freq->e == 0) { | 268 | if (freq->e == 0) { |
269 | if (freq->m < 0) | 269 | if (freq->m < 0) |
270 | return 0; | 270 | return 0; |
271 | return ieee80211_channel_to_frequency(freq->m); | 271 | return ieee80211_channel_to_frequency(freq->m); |
272 | } else { | 272 | } else { |
273 | int i, div = 1000000; | 273 | int i, div = 1000000; |
274 | for (i = 0; i < freq->e; i++) | 274 | for (i = 0; i < freq->e; i++) |
275 | div /= 10; | 275 | div /= 10; |
276 | if (div <= 0) | 276 | if (div <= 0) |
277 | return -EINVAL; | 277 | return -EINVAL; |
278 | return freq->m / div; | 278 | return freq->m / div; |
279 | } | 279 | } |
280 | } | 280 | } |
281 | 281 | ||
282 | int cfg80211_wext_siwrts(struct net_device *dev, | 282 | int cfg80211_wext_siwrts(struct net_device *dev, |
283 | struct iw_request_info *info, | 283 | struct iw_request_info *info, |
284 | struct iw_param *rts, char *extra) | 284 | struct iw_param *rts, char *extra) |
285 | { | 285 | { |
286 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 286 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
287 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 287 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
288 | u32 orts = wdev->wiphy->rts_threshold; | 288 | u32 orts = wdev->wiphy->rts_threshold; |
289 | int err; | 289 | int err; |
290 | 290 | ||
291 | if (rts->disabled || !rts->fixed) | 291 | if (rts->disabled || !rts->fixed) |
292 | wdev->wiphy->rts_threshold = (u32) -1; | 292 | wdev->wiphy->rts_threshold = (u32) -1; |
293 | else if (rts->value < 0) | 293 | else if (rts->value < 0) |
294 | return -EINVAL; | 294 | return -EINVAL; |
295 | else | 295 | else |
296 | wdev->wiphy->rts_threshold = rts->value; | 296 | wdev->wiphy->rts_threshold = rts->value; |
297 | 297 | ||
298 | err = rdev->ops->set_wiphy_params(wdev->wiphy, | 298 | err = rdev->ops->set_wiphy_params(wdev->wiphy, |
299 | WIPHY_PARAM_RTS_THRESHOLD); | 299 | WIPHY_PARAM_RTS_THRESHOLD); |
300 | if (err) | 300 | if (err) |
301 | wdev->wiphy->rts_threshold = orts; | 301 | wdev->wiphy->rts_threshold = orts; |
302 | 302 | ||
303 | return err; | 303 | return err; |
304 | } | 304 | } |
305 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); | 305 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); |
306 | 306 | ||
307 | int cfg80211_wext_giwrts(struct net_device *dev, | 307 | int cfg80211_wext_giwrts(struct net_device *dev, |
308 | struct iw_request_info *info, | 308 | struct iw_request_info *info, |
309 | struct iw_param *rts, char *extra) | 309 | struct iw_param *rts, char *extra) |
310 | { | 310 | { |
311 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 311 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
312 | 312 | ||
313 | rts->value = wdev->wiphy->rts_threshold; | 313 | rts->value = wdev->wiphy->rts_threshold; |
314 | rts->disabled = rts->value == (u32) -1; | 314 | rts->disabled = rts->value == (u32) -1; |
315 | rts->fixed = 1; | 315 | rts->fixed = 1; |
316 | 316 | ||
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
319 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); | 319 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); |
320 | 320 | ||
321 | int cfg80211_wext_siwfrag(struct net_device *dev, | 321 | int cfg80211_wext_siwfrag(struct net_device *dev, |
322 | struct iw_request_info *info, | 322 | struct iw_request_info *info, |
323 | struct iw_param *frag, char *extra) | 323 | struct iw_param *frag, char *extra) |
324 | { | 324 | { |
325 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 325 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
326 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 326 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
327 | u32 ofrag = wdev->wiphy->frag_threshold; | 327 | u32 ofrag = wdev->wiphy->frag_threshold; |
328 | int err; | 328 | int err; |
329 | 329 | ||
330 | if (frag->disabled || !frag->fixed) | 330 | if (frag->disabled || !frag->fixed) |
331 | wdev->wiphy->frag_threshold = (u32) -1; | 331 | wdev->wiphy->frag_threshold = (u32) -1; |
332 | else if (frag->value < 256) | 332 | else if (frag->value < 256) |
333 | return -EINVAL; | 333 | return -EINVAL; |
334 | else { | 334 | else { |
335 | /* Fragment length must be even, so strip LSB. */ | 335 | /* Fragment length must be even, so strip LSB. */ |
336 | wdev->wiphy->frag_threshold = frag->value & ~0x1; | 336 | wdev->wiphy->frag_threshold = frag->value & ~0x1; |
337 | } | 337 | } |
338 | 338 | ||
339 | err = rdev->ops->set_wiphy_params(wdev->wiphy, | 339 | err = rdev->ops->set_wiphy_params(wdev->wiphy, |
340 | WIPHY_PARAM_FRAG_THRESHOLD); | 340 | WIPHY_PARAM_FRAG_THRESHOLD); |
341 | if (err) | 341 | if (err) |
342 | wdev->wiphy->frag_threshold = ofrag; | 342 | wdev->wiphy->frag_threshold = ofrag; |
343 | 343 | ||
344 | return err; | 344 | return err; |
345 | } | 345 | } |
346 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); | 346 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); |
347 | 347 | ||
348 | int cfg80211_wext_giwfrag(struct net_device *dev, | 348 | int cfg80211_wext_giwfrag(struct net_device *dev, |
349 | struct iw_request_info *info, | 349 | struct iw_request_info *info, |
350 | struct iw_param *frag, char *extra) | 350 | struct iw_param *frag, char *extra) |
351 | { | 351 | { |
352 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 352 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
353 | 353 | ||
354 | frag->value = wdev->wiphy->frag_threshold; | 354 | frag->value = wdev->wiphy->frag_threshold; |
355 | frag->disabled = frag->value == (u32) -1; | 355 | frag->disabled = frag->value == (u32) -1; |
356 | frag->fixed = 1; | 356 | frag->fixed = 1; |
357 | 357 | ||
358 | return 0; | 358 | return 0; |
359 | } | 359 | } |
360 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); | 360 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); |
361 | 361 | ||
362 | int cfg80211_wext_siwretry(struct net_device *dev, | 362 | int cfg80211_wext_siwretry(struct net_device *dev, |
363 | struct iw_request_info *info, | 363 | struct iw_request_info *info, |
364 | struct iw_param *retry, char *extra) | 364 | struct iw_param *retry, char *extra) |
365 | { | 365 | { |
366 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 366 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
367 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 367 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
368 | u32 changed = 0; | 368 | u32 changed = 0; |
369 | u8 olong = wdev->wiphy->retry_long; | 369 | u8 olong = wdev->wiphy->retry_long; |
370 | u8 oshort = wdev->wiphy->retry_short; | 370 | u8 oshort = wdev->wiphy->retry_short; |
371 | int err; | 371 | int err; |
372 | 372 | ||
373 | if (retry->disabled || | 373 | if (retry->disabled || |
374 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) | 374 | (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) |
375 | return -EINVAL; | 375 | return -EINVAL; |
376 | 376 | ||
377 | if (retry->flags & IW_RETRY_LONG) { | 377 | if (retry->flags & IW_RETRY_LONG) { |
378 | wdev->wiphy->retry_long = retry->value; | 378 | wdev->wiphy->retry_long = retry->value; |
379 | changed |= WIPHY_PARAM_RETRY_LONG; | 379 | changed |= WIPHY_PARAM_RETRY_LONG; |
380 | } else if (retry->flags & IW_RETRY_SHORT) { | 380 | } else if (retry->flags & IW_RETRY_SHORT) { |
381 | wdev->wiphy->retry_short = retry->value; | 381 | wdev->wiphy->retry_short = retry->value; |
382 | changed |= WIPHY_PARAM_RETRY_SHORT; | 382 | changed |= WIPHY_PARAM_RETRY_SHORT; |
383 | } else { | 383 | } else { |
384 | wdev->wiphy->retry_short = retry->value; | 384 | wdev->wiphy->retry_short = retry->value; |
385 | wdev->wiphy->retry_long = retry->value; | 385 | wdev->wiphy->retry_long = retry->value; |
386 | changed |= WIPHY_PARAM_RETRY_LONG; | 386 | changed |= WIPHY_PARAM_RETRY_LONG; |
387 | changed |= WIPHY_PARAM_RETRY_SHORT; | 387 | changed |= WIPHY_PARAM_RETRY_SHORT; |
388 | } | 388 | } |
389 | 389 | ||
390 | if (!changed) | 390 | if (!changed) |
391 | return 0; | 391 | return 0; |
392 | 392 | ||
393 | err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); | 393 | err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); |
394 | if (err) { | 394 | if (err) { |
395 | wdev->wiphy->retry_short = oshort; | 395 | wdev->wiphy->retry_short = oshort; |
396 | wdev->wiphy->retry_long = olong; | 396 | wdev->wiphy->retry_long = olong; |
397 | } | 397 | } |
398 | 398 | ||
399 | return err; | 399 | return err; |
400 | } | 400 | } |
401 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry); | 401 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry); |
402 | 402 | ||
403 | int cfg80211_wext_giwretry(struct net_device *dev, | 403 | int cfg80211_wext_giwretry(struct net_device *dev, |
404 | struct iw_request_info *info, | 404 | struct iw_request_info *info, |
405 | struct iw_param *retry, char *extra) | 405 | struct iw_param *retry, char *extra) |
406 | { | 406 | { |
407 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 407 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
408 | 408 | ||
409 | retry->disabled = 0; | 409 | retry->disabled = 0; |
410 | 410 | ||
411 | if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { | 411 | if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { |
412 | /* | 412 | /* |
413 | * First return short value, iwconfig will ask long value | 413 | * First return short value, iwconfig will ask long value |
414 | * later if needed | 414 | * later if needed |
415 | */ | 415 | */ |
416 | retry->flags |= IW_RETRY_LIMIT; | 416 | retry->flags |= IW_RETRY_LIMIT; |
417 | retry->value = wdev->wiphy->retry_short; | 417 | retry->value = wdev->wiphy->retry_short; |
418 | if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) | 418 | if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) |
419 | retry->flags |= IW_RETRY_LONG; | 419 | retry->flags |= IW_RETRY_LONG; |
420 | 420 | ||
421 | return 0; | 421 | return 0; |
422 | } | 422 | } |
423 | 423 | ||
424 | if (retry->flags & IW_RETRY_LONG) { | 424 | if (retry->flags & IW_RETRY_LONG) { |
425 | retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; | 425 | retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; |
426 | retry->value = wdev->wiphy->retry_long; | 426 | retry->value = wdev->wiphy->retry_long; |
427 | } | 427 | } |
428 | 428 | ||
429 | return 0; | 429 | return 0; |
430 | } | 430 | } |
431 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 431 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
432 | 432 | ||
433 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 433 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
434 | struct net_device *dev, const u8 *addr, | 434 | struct net_device *dev, const u8 *addr, |
435 | bool remove, bool tx_key, int idx, | 435 | bool remove, bool tx_key, int idx, |
436 | struct key_params *params) | 436 | struct key_params *params) |
437 | { | 437 | { |
438 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 438 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
439 | int err, i; | 439 | int err, i; |
440 | bool rejoin = false; | 440 | bool rejoin = false; |
441 | 441 | ||
442 | if (!wdev->wext.keys) { | 442 | if (!wdev->wext.keys) { |
443 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 443 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
444 | GFP_KERNEL); | 444 | GFP_KERNEL); |
445 | if (!wdev->wext.keys) | 445 | if (!wdev->wext.keys) |
446 | return -ENOMEM; | 446 | return -ENOMEM; |
447 | for (i = 0; i < 6; i++) | 447 | for (i = 0; i < 6; i++) |
448 | wdev->wext.keys->params[i].key = | 448 | wdev->wext.keys->params[i].key = |
449 | wdev->wext.keys->data[i]; | 449 | wdev->wext.keys->data[i]; |
450 | } | 450 | } |
451 | 451 | ||
452 | if (wdev->iftype != NL80211_IFTYPE_ADHOC && | 452 | if (wdev->iftype != NL80211_IFTYPE_ADHOC && |
453 | wdev->iftype != NL80211_IFTYPE_STATION) | 453 | wdev->iftype != NL80211_IFTYPE_STATION) |
454 | return -EOPNOTSUPP; | 454 | return -EOPNOTSUPP; |
455 | 455 | ||
456 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | 456 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { |
457 | if (!wdev->current_bss) | 457 | if (!wdev->current_bss) |
458 | return -ENOLINK; | 458 | return -ENOLINK; |
459 | 459 | ||
460 | if (!rdev->ops->set_default_mgmt_key) | 460 | if (!rdev->ops->set_default_mgmt_key) |
461 | return -EOPNOTSUPP; | 461 | return -EOPNOTSUPP; |
462 | 462 | ||
463 | if (idx < 4 || idx > 5) | 463 | if (idx < 4 || idx > 5) |
464 | return -EINVAL; | 464 | return -EINVAL; |
465 | } else if (idx < 0 || idx > 3) | 465 | } else if (idx < 0 || idx > 3) |
466 | return -EINVAL; | 466 | return -EINVAL; |
467 | 467 | ||
468 | if (remove) { | 468 | if (remove) { |
469 | err = 0; | 469 | err = 0; |
470 | if (wdev->current_bss) { | 470 | if (wdev->current_bss) { |
471 | /* | 471 | /* |
472 | * If removing the current TX key, we will need to | 472 | * If removing the current TX key, we will need to |
473 | * join a new IBSS without the privacy bit clear. | 473 | * join a new IBSS without the privacy bit clear. |
474 | */ | 474 | */ |
475 | if (idx == wdev->wext.default_key && | 475 | if (idx == wdev->wext.default_key && |
476 | wdev->iftype == NL80211_IFTYPE_ADHOC) { | 476 | wdev->iftype == NL80211_IFTYPE_ADHOC) { |
477 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 477 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
478 | rejoin = true; | 478 | rejoin = true; |
479 | } | 479 | } |
480 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 480 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); |
481 | } | 481 | } |
482 | /* | 482 | /* |
483 | * Applications using wireless extensions expect to be | 483 | * Applications using wireless extensions expect to be |
484 | * able to delete keys that don't exist, so allow that. | 484 | * able to delete keys that don't exist, so allow that. |
485 | */ | 485 | */ |
486 | if (err == -ENOENT) | 486 | if (err == -ENOENT) |
487 | err = 0; | 487 | err = 0; |
488 | if (!err) { | 488 | if (!err) { |
489 | if (!addr) { | 489 | if (!addr) { |
490 | wdev->wext.keys->params[idx].key_len = 0; | 490 | wdev->wext.keys->params[idx].key_len = 0; |
491 | wdev->wext.keys->params[idx].cipher = 0; | 491 | wdev->wext.keys->params[idx].cipher = 0; |
492 | } | 492 | } |
493 | if (idx == wdev->wext.default_key) | 493 | if (idx == wdev->wext.default_key) |
494 | wdev->wext.default_key = -1; | 494 | wdev->wext.default_key = -1; |
495 | else if (idx == wdev->wext.default_mgmt_key) | 495 | else if (idx == wdev->wext.default_mgmt_key) |
496 | wdev->wext.default_mgmt_key = -1; | 496 | wdev->wext.default_mgmt_key = -1; |
497 | } | 497 | } |
498 | 498 | ||
499 | if (!err && rejoin) | 499 | if (!err && rejoin) |
500 | err = cfg80211_ibss_wext_join(rdev, wdev); | 500 | err = cfg80211_ibss_wext_join(rdev, wdev); |
501 | 501 | ||
502 | return err; | 502 | return err; |
503 | } | 503 | } |
504 | 504 | ||
505 | if (addr) | 505 | if (addr) |
506 | tx_key = false; | 506 | tx_key = false; |
507 | 507 | ||
508 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) | 508 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) |
509 | return -EINVAL; | 509 | return -EINVAL; |
510 | 510 | ||
511 | err = 0; | 511 | err = 0; |
512 | if (wdev->current_bss) | 512 | if (wdev->current_bss) |
513 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | 513 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); |
514 | if (err) | 514 | if (err) |
515 | return err; | 515 | return err; |
516 | 516 | ||
517 | if (!addr) { | 517 | if (!addr) { |
518 | wdev->wext.keys->params[idx] = *params; | 518 | wdev->wext.keys->params[idx] = *params; |
519 | memcpy(wdev->wext.keys->data[idx], | 519 | memcpy(wdev->wext.keys->data[idx], |
520 | params->key, params->key_len); | 520 | params->key, params->key_len); |
521 | wdev->wext.keys->params[idx].key = | 521 | wdev->wext.keys->params[idx].key = |
522 | wdev->wext.keys->data[idx]; | 522 | wdev->wext.keys->data[idx]; |
523 | } | 523 | } |
524 | 524 | ||
525 | if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || | 525 | if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || |
526 | params->cipher == WLAN_CIPHER_SUITE_WEP104) && | 526 | params->cipher == WLAN_CIPHER_SUITE_WEP104) && |
527 | (tx_key || (!addr && wdev->wext.default_key == -1))) { | 527 | (tx_key || (!addr && wdev->wext.default_key == -1))) { |
528 | if (wdev->current_bss) { | 528 | if (wdev->current_bss) { |
529 | /* | 529 | /* |
530 | * If we are getting a new TX key from not having | 530 | * If we are getting a new TX key from not having |
531 | * had one before we need to join a new IBSS with | 531 | * had one before we need to join a new IBSS with |
532 | * the privacy bit set. | 532 | * the privacy bit set. |
533 | */ | 533 | */ |
534 | if (wdev->iftype == NL80211_IFTYPE_ADHOC && | 534 | if (wdev->iftype == NL80211_IFTYPE_ADHOC && |
535 | wdev->wext.default_key == -1) { | 535 | wdev->wext.default_key == -1) { |
536 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 536 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
537 | rejoin = true; | 537 | rejoin = true; |
538 | } | 538 | } |
539 | err = rdev->ops->set_default_key(&rdev->wiphy, | 539 | err = rdev->ops->set_default_key(&rdev->wiphy, |
540 | dev, idx); | 540 | dev, idx); |
541 | } | 541 | } |
542 | if (!err) { | 542 | if (!err) { |
543 | wdev->wext.default_key = idx; | 543 | wdev->wext.default_key = idx; |
544 | if (rejoin) | 544 | if (rejoin) |
545 | err = cfg80211_ibss_wext_join(rdev, wdev); | 545 | err = cfg80211_ibss_wext_join(rdev, wdev); |
546 | } | 546 | } |
547 | return err; | 547 | return err; |
548 | } | 548 | } |
549 | 549 | ||
550 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && | 550 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && |
551 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { | 551 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { |
552 | if (wdev->current_bss) | 552 | if (wdev->current_bss) |
553 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | 553 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, |
554 | dev, idx); | 554 | dev, idx); |
555 | if (!err) | 555 | if (!err) |
556 | wdev->wext.default_mgmt_key = idx; | 556 | wdev->wext.default_mgmt_key = idx; |
557 | return err; | 557 | return err; |
558 | } | 558 | } |
559 | 559 | ||
560 | return 0; | 560 | return 0; |
561 | } | 561 | } |
562 | 562 | ||
563 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 563 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
564 | struct net_device *dev, const u8 *addr, | 564 | struct net_device *dev, const u8 *addr, |
565 | bool remove, bool tx_key, int idx, | 565 | bool remove, bool tx_key, int idx, |
566 | struct key_params *params) | 566 | struct key_params *params) |
567 | { | 567 | { |
568 | int err; | 568 | int err; |
569 | 569 | ||
570 | /* devlist mutex needed for possible IBSS re-join */ | 570 | /* devlist mutex needed for possible IBSS re-join */ |
571 | mutex_lock(&rdev->devlist_mtx); | 571 | mutex_lock(&rdev->devlist_mtx); |
572 | wdev_lock(dev->ieee80211_ptr); | 572 | wdev_lock(dev->ieee80211_ptr); |
573 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | 573 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, |
574 | tx_key, idx, params); | 574 | tx_key, idx, params); |
575 | wdev_unlock(dev->ieee80211_ptr); | 575 | wdev_unlock(dev->ieee80211_ptr); |
576 | mutex_unlock(&rdev->devlist_mtx); | 576 | mutex_unlock(&rdev->devlist_mtx); |
577 | 577 | ||
578 | return err; | 578 | return err; |
579 | } | 579 | } |
580 | 580 | ||
581 | int cfg80211_wext_siwencode(struct net_device *dev, | 581 | int cfg80211_wext_siwencode(struct net_device *dev, |
582 | struct iw_request_info *info, | 582 | struct iw_request_info *info, |
583 | struct iw_point *erq, char *keybuf) | 583 | struct iw_point *erq, char *keybuf) |
584 | { | 584 | { |
585 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 585 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
586 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 586 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
587 | int idx, err; | 587 | int idx, err; |
588 | bool remove = false; | 588 | bool remove = false; |
589 | struct key_params params; | 589 | struct key_params params; |
590 | 590 | ||
591 | if (wdev->iftype != NL80211_IFTYPE_STATION && | 591 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
592 | wdev->iftype != NL80211_IFTYPE_ADHOC) | 592 | wdev->iftype != NL80211_IFTYPE_ADHOC) |
593 | return -EOPNOTSUPP; | 593 | return -EOPNOTSUPP; |
594 | 594 | ||
595 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | 595 | /* no use -- only MFP (set_default_mgmt_key) is optional */ |
596 | if (!rdev->ops->del_key || | 596 | if (!rdev->ops->del_key || |
597 | !rdev->ops->add_key || | 597 | !rdev->ops->add_key || |
598 | !rdev->ops->set_default_key) | 598 | !rdev->ops->set_default_key) |
599 | return -EOPNOTSUPP; | 599 | return -EOPNOTSUPP; |
600 | 600 | ||
601 | idx = erq->flags & IW_ENCODE_INDEX; | 601 | idx = erq->flags & IW_ENCODE_INDEX; |
602 | if (idx == 0) { | 602 | if (idx == 0) { |
603 | idx = wdev->wext.default_key; | 603 | idx = wdev->wext.default_key; |
604 | if (idx < 0) | 604 | if (idx < 0) |
605 | idx = 0; | 605 | idx = 0; |
606 | } else if (idx < 1 || idx > 4) | 606 | } else if (idx < 1 || idx > 4) |
607 | return -EINVAL; | 607 | return -EINVAL; |
608 | else | 608 | else |
609 | idx--; | 609 | idx--; |
610 | 610 | ||
611 | if (erq->flags & IW_ENCODE_DISABLED) | 611 | if (erq->flags & IW_ENCODE_DISABLED) |
612 | remove = true; | 612 | remove = true; |
613 | else if (erq->length == 0) { | 613 | else if (erq->length == 0) { |
614 | /* No key data - just set the default TX key index */ | 614 | /* No key data - just set the default TX key index */ |
615 | err = 0; | 615 | err = 0; |
616 | wdev_lock(wdev); | 616 | wdev_lock(wdev); |
617 | if (wdev->current_bss) | 617 | if (wdev->current_bss) |
618 | err = rdev->ops->set_default_key(&rdev->wiphy, | 618 | err = rdev->ops->set_default_key(&rdev->wiphy, |
619 | dev, idx); | 619 | dev, idx); |
620 | if (!err) | 620 | if (!err) |
621 | wdev->wext.default_key = idx; | 621 | wdev->wext.default_key = idx; |
622 | wdev_unlock(wdev); | 622 | wdev_unlock(wdev); |
623 | return err; | 623 | return err; |
624 | } | 624 | } |
625 | 625 | ||
626 | memset(¶ms, 0, sizeof(params)); | 626 | memset(¶ms, 0, sizeof(params)); |
627 | params.key = keybuf; | 627 | params.key = keybuf; |
628 | params.key_len = erq->length; | 628 | params.key_len = erq->length; |
629 | if (erq->length == 5) | 629 | if (erq->length == 5) |
630 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | 630 | params.cipher = WLAN_CIPHER_SUITE_WEP40; |
631 | else if (erq->length == 13) | 631 | else if (erq->length == 13) |
632 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | 632 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
633 | else if (!remove) | 633 | else if (!remove) |
634 | return -EINVAL; | 634 | return -EINVAL; |
635 | 635 | ||
636 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | 636 | return cfg80211_set_encryption(rdev, dev, NULL, remove, |
637 | wdev->wext.default_key == -1, | 637 | wdev->wext.default_key == -1, |
638 | idx, ¶ms); | 638 | idx, ¶ms); |
639 | } | 639 | } |
640 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); | 640 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); |
641 | 641 | ||
642 | int cfg80211_wext_siwencodeext(struct net_device *dev, | 642 | int cfg80211_wext_siwencodeext(struct net_device *dev, |
643 | struct iw_request_info *info, | 643 | struct iw_request_info *info, |
644 | struct iw_point *erq, char *extra) | 644 | struct iw_point *erq, char *extra) |
645 | { | 645 | { |
646 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 646 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
647 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 647 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
648 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | 648 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; |
649 | const u8 *addr; | 649 | const u8 *addr; |
650 | int idx; | 650 | int idx; |
651 | bool remove = false; | 651 | bool remove = false; |
652 | struct key_params params; | 652 | struct key_params params; |
653 | u32 cipher; | 653 | u32 cipher; |
654 | 654 | ||
655 | if (wdev->iftype != NL80211_IFTYPE_STATION && | 655 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
656 | wdev->iftype != NL80211_IFTYPE_ADHOC) | 656 | wdev->iftype != NL80211_IFTYPE_ADHOC) |
657 | return -EOPNOTSUPP; | 657 | return -EOPNOTSUPP; |
658 | 658 | ||
659 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | 659 | /* no use -- only MFP (set_default_mgmt_key) is optional */ |
660 | if (!rdev->ops->del_key || | 660 | if (!rdev->ops->del_key || |
661 | !rdev->ops->add_key || | 661 | !rdev->ops->add_key || |
662 | !rdev->ops->set_default_key) | 662 | !rdev->ops->set_default_key) |
663 | return -EOPNOTSUPP; | 663 | return -EOPNOTSUPP; |
664 | 664 | ||
665 | switch (ext->alg) { | 665 | switch (ext->alg) { |
666 | case IW_ENCODE_ALG_NONE: | 666 | case IW_ENCODE_ALG_NONE: |
667 | remove = true; | 667 | remove = true; |
668 | cipher = 0; | 668 | cipher = 0; |
669 | break; | 669 | break; |
670 | case IW_ENCODE_ALG_WEP: | 670 | case IW_ENCODE_ALG_WEP: |
671 | if (ext->key_len == 5) | 671 | if (ext->key_len == 5) |
672 | cipher = WLAN_CIPHER_SUITE_WEP40; | 672 | cipher = WLAN_CIPHER_SUITE_WEP40; |
673 | else if (ext->key_len == 13) | 673 | else if (ext->key_len == 13) |
674 | cipher = WLAN_CIPHER_SUITE_WEP104; | 674 | cipher = WLAN_CIPHER_SUITE_WEP104; |
675 | else | 675 | else |
676 | return -EINVAL; | 676 | return -EINVAL; |
677 | break; | 677 | break; |
678 | case IW_ENCODE_ALG_TKIP: | 678 | case IW_ENCODE_ALG_TKIP: |
679 | cipher = WLAN_CIPHER_SUITE_TKIP; | 679 | cipher = WLAN_CIPHER_SUITE_TKIP; |
680 | break; | 680 | break; |
681 | case IW_ENCODE_ALG_CCMP: | 681 | case IW_ENCODE_ALG_CCMP: |
682 | cipher = WLAN_CIPHER_SUITE_CCMP; | 682 | cipher = WLAN_CIPHER_SUITE_CCMP; |
683 | break; | 683 | break; |
684 | case IW_ENCODE_ALG_AES_CMAC: | 684 | case IW_ENCODE_ALG_AES_CMAC: |
685 | cipher = WLAN_CIPHER_SUITE_AES_CMAC; | 685 | cipher = WLAN_CIPHER_SUITE_AES_CMAC; |
686 | break; | 686 | break; |
687 | default: | 687 | default: |
688 | return -EOPNOTSUPP; | 688 | return -EOPNOTSUPP; |
689 | } | 689 | } |
690 | 690 | ||
691 | if (erq->flags & IW_ENCODE_DISABLED) | 691 | if (erq->flags & IW_ENCODE_DISABLED) |
692 | remove = true; | 692 | remove = true; |
693 | 693 | ||
694 | idx = erq->flags & IW_ENCODE_INDEX; | 694 | idx = erq->flags & IW_ENCODE_INDEX; |
695 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | 695 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { |
696 | if (idx < 4 || idx > 5) { | 696 | if (idx < 4 || idx > 5) { |
697 | idx = wdev->wext.default_mgmt_key; | 697 | idx = wdev->wext.default_mgmt_key; |
698 | if (idx < 0) | 698 | if (idx < 0) |
699 | return -EINVAL; | 699 | return -EINVAL; |
700 | } else | 700 | } else |
701 | idx--; | 701 | idx--; |
702 | } else { | 702 | } else { |
703 | if (idx < 1 || idx > 4) { | 703 | if (idx < 1 || idx > 4) { |
704 | idx = wdev->wext.default_key; | 704 | idx = wdev->wext.default_key; |
705 | if (idx < 0) | 705 | if (idx < 0) |
706 | return -EINVAL; | 706 | return -EINVAL; |
707 | } else | 707 | } else |
708 | idx--; | 708 | idx--; |
709 | } | 709 | } |
710 | 710 | ||
711 | addr = ext->addr.sa_data; | 711 | addr = ext->addr.sa_data; |
712 | if (is_broadcast_ether_addr(addr)) | 712 | if (is_broadcast_ether_addr(addr)) |
713 | addr = NULL; | 713 | addr = NULL; |
714 | 714 | ||
715 | memset(¶ms, 0, sizeof(params)); | 715 | memset(¶ms, 0, sizeof(params)); |
716 | params.key = ext->key; | 716 | params.key = ext->key; |
717 | params.key_len = ext->key_len; | 717 | params.key_len = ext->key_len; |
718 | params.cipher = cipher; | 718 | params.cipher = cipher; |
719 | 719 | ||
720 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { | 720 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { |
721 | params.seq = ext->rx_seq; | 721 | params.seq = ext->rx_seq; |
722 | params.seq_len = 6; | 722 | params.seq_len = 6; |
723 | } | 723 | } |
724 | 724 | ||
725 | return cfg80211_set_encryption( | 725 | return cfg80211_set_encryption( |
726 | rdev, dev, addr, remove, | 726 | rdev, dev, addr, remove, |
727 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 727 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
728 | idx, ¶ms); | 728 | idx, ¶ms); |
729 | } | 729 | } |
730 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); | 730 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); |
731 | 731 | ||
732 | int cfg80211_wext_giwencode(struct net_device *dev, | 732 | int cfg80211_wext_giwencode(struct net_device *dev, |
733 | struct iw_request_info *info, | 733 | struct iw_request_info *info, |
734 | struct iw_point *erq, char *keybuf) | 734 | struct iw_point *erq, char *keybuf) |
735 | { | 735 | { |
736 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 736 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
737 | int idx; | 737 | int idx; |
738 | 738 | ||
739 | if (wdev->iftype != NL80211_IFTYPE_STATION && | 739 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
740 | wdev->iftype != NL80211_IFTYPE_ADHOC) | 740 | wdev->iftype != NL80211_IFTYPE_ADHOC) |
741 | return -EOPNOTSUPP; | 741 | return -EOPNOTSUPP; |
742 | 742 | ||
743 | idx = erq->flags & IW_ENCODE_INDEX; | 743 | idx = erq->flags & IW_ENCODE_INDEX; |
744 | if (idx == 0) { | 744 | if (idx == 0) { |
745 | idx = wdev->wext.default_key; | 745 | idx = wdev->wext.default_key; |
746 | if (idx < 0) | 746 | if (idx < 0) |
747 | idx = 0; | 747 | idx = 0; |
748 | } else if (idx < 1 || idx > 4) | 748 | } else if (idx < 1 || idx > 4) |
749 | return -EINVAL; | 749 | return -EINVAL; |
750 | else | 750 | else |
751 | idx--; | 751 | idx--; |
752 | 752 | ||
753 | erq->flags = idx + 1; | 753 | erq->flags = idx + 1; |
754 | 754 | ||
755 | if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) { | 755 | if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) { |
756 | erq->flags |= IW_ENCODE_DISABLED; | 756 | erq->flags |= IW_ENCODE_DISABLED; |
757 | erq->length = 0; | 757 | erq->length = 0; |
758 | return 0; | 758 | return 0; |
759 | } | 759 | } |
760 | 760 | ||
761 | erq->length = min_t(size_t, erq->length, | 761 | erq->length = min_t(size_t, erq->length, |
762 | wdev->wext.keys->params[idx].key_len); | 762 | wdev->wext.keys->params[idx].key_len); |
763 | memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length); | 763 | memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length); |
764 | erq->flags |= IW_ENCODE_ENABLED; | 764 | erq->flags |= IW_ENCODE_ENABLED; |
765 | 765 | ||
766 | return 0; | 766 | return 0; |
767 | } | 767 | } |
768 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | 768 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); |
769 | 769 | ||
770 | int cfg80211_wext_siwfreq(struct net_device *dev, | 770 | int cfg80211_wext_siwfreq(struct net_device *dev, |
771 | struct iw_request_info *info, | 771 | struct iw_request_info *info, |
772 | struct iw_freq *wextfreq, char *extra) | 772 | struct iw_freq *wextfreq, char *extra) |
773 | { | 773 | { |
774 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 774 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
775 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 775 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
776 | int freq, err; | 776 | int freq, err; |
777 | 777 | ||
778 | switch (wdev->iftype) { | 778 | switch (wdev->iftype) { |
779 | case NL80211_IFTYPE_STATION: | 779 | case NL80211_IFTYPE_STATION: |
780 | return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); | 780 | return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); |
781 | case NL80211_IFTYPE_ADHOC: | 781 | case NL80211_IFTYPE_ADHOC: |
782 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); | 782 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); |
783 | default: | 783 | default: |
784 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); | 784 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
785 | if (freq < 0) | 785 | if (freq < 0) |
786 | return freq; | 786 | return freq; |
787 | if (freq == 0) | 787 | if (freq == 0) |
788 | return -EINVAL; | 788 | return -EINVAL; |
789 | mutex_lock(&rdev->devlist_mtx); | 789 | mutex_lock(&rdev->devlist_mtx); |
790 | err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT); | 790 | err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT); |
791 | mutex_unlock(&rdev->devlist_mtx); | 791 | mutex_unlock(&rdev->devlist_mtx); |
792 | return err; | 792 | return err; |
793 | } | 793 | } |
794 | } | 794 | } |
795 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); | 795 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); |
796 | 796 | ||
797 | int cfg80211_wext_giwfreq(struct net_device *dev, | 797 | int cfg80211_wext_giwfreq(struct net_device *dev, |
798 | struct iw_request_info *info, | 798 | struct iw_request_info *info, |
799 | struct iw_freq *freq, char *extra) | 799 | struct iw_freq *freq, char *extra) |
800 | { | 800 | { |
801 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 801 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
802 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 802 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
803 | 803 | ||
804 | switch (wdev->iftype) { | 804 | switch (wdev->iftype) { |
805 | case NL80211_IFTYPE_STATION: | 805 | case NL80211_IFTYPE_STATION: |
806 | return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); | 806 | return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); |
807 | case NL80211_IFTYPE_ADHOC: | 807 | case NL80211_IFTYPE_ADHOC: |
808 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | 808 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); |
809 | default: | 809 | default: |
810 | if (!rdev->channel) | 810 | if (!rdev->channel) |
811 | return -EINVAL; | 811 | return -EINVAL; |
812 | freq->m = rdev->channel->center_freq; | 812 | freq->m = rdev->channel->center_freq; |
813 | freq->e = 6; | 813 | freq->e = 6; |
814 | return 0; | 814 | return 0; |
815 | } | 815 | } |
816 | } | 816 | } |
817 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq); | 817 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq); |
818 | 818 | ||
819 | int cfg80211_wext_siwtxpower(struct net_device *dev, | 819 | int cfg80211_wext_siwtxpower(struct net_device *dev, |
820 | struct iw_request_info *info, | 820 | struct iw_request_info *info, |
821 | union iwreq_data *data, char *extra) | 821 | union iwreq_data *data, char *extra) |
822 | { | 822 | { |
823 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 823 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
824 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 824 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
825 | enum tx_power_setting type; | 825 | enum tx_power_setting type; |
826 | int dbm = 0; | 826 | int dbm = 0; |
827 | 827 | ||
828 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 828 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
829 | return -EINVAL; | 829 | return -EINVAL; |
830 | if (data->txpower.flags & IW_TXPOW_RANGE) | 830 | if (data->txpower.flags & IW_TXPOW_RANGE) |
831 | return -EINVAL; | 831 | return -EINVAL; |
832 | 832 | ||
833 | if (!rdev->ops->set_tx_power) | 833 | if (!rdev->ops->set_tx_power) |
834 | return -EOPNOTSUPP; | 834 | return -EOPNOTSUPP; |
835 | 835 | ||
836 | /* only change when not disabling */ | 836 | /* only change when not disabling */ |
837 | if (!data->txpower.disabled) { | 837 | if (!data->txpower.disabled) { |
838 | rfkill_set_sw_state(rdev->rfkill, false); | 838 | rfkill_set_sw_state(rdev->rfkill, false); |
839 | 839 | ||
840 | if (data->txpower.fixed) { | 840 | if (data->txpower.fixed) { |
841 | /* | 841 | /* |
842 | * wext doesn't support negative values, see | 842 | * wext doesn't support negative values, see |
843 | * below where it's for automatic | 843 | * below where it's for automatic |
844 | */ | 844 | */ |
845 | if (data->txpower.value < 0) | 845 | if (data->txpower.value < 0) |
846 | return -EINVAL; | 846 | return -EINVAL; |
847 | dbm = data->txpower.value; | 847 | dbm = data->txpower.value; |
848 | type = TX_POWER_FIXED; | 848 | type = TX_POWER_FIXED; |
849 | /* TODO: do regulatory check! */ | 849 | /* TODO: do regulatory check! */ |
850 | } else { | 850 | } else { |
851 | /* | 851 | /* |
852 | * Automatic power level setting, max being the value | 852 | * Automatic power level setting, max being the value |
853 | * passed in from userland. | 853 | * passed in from userland. |
854 | */ | 854 | */ |
855 | if (data->txpower.value < 0) { | 855 | if (data->txpower.value < 0) { |
856 | type = TX_POWER_AUTOMATIC; | 856 | type = TX_POWER_AUTOMATIC; |
857 | } else { | 857 | } else { |
858 | dbm = data->txpower.value; | 858 | dbm = data->txpower.value; |
859 | type = TX_POWER_LIMITED; | 859 | type = TX_POWER_LIMITED; |
860 | } | 860 | } |
861 | } | 861 | } |
862 | } else { | 862 | } else { |
863 | rfkill_set_sw_state(rdev->rfkill, true); | 863 | rfkill_set_sw_state(rdev->rfkill, true); |
864 | schedule_work(&rdev->rfkill_sync); | 864 | schedule_work(&rdev->rfkill_sync); |
865 | return 0; | 865 | return 0; |
866 | } | 866 | } |
867 | 867 | ||
868 | return rdev->ops->set_tx_power(wdev->wiphy, type, dbm); | 868 | return rdev->ops->set_tx_power(wdev->wiphy, type, dbm); |
869 | } | 869 | } |
870 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); | 870 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); |
871 | 871 | ||
872 | int cfg80211_wext_giwtxpower(struct net_device *dev, | 872 | int cfg80211_wext_giwtxpower(struct net_device *dev, |
873 | struct iw_request_info *info, | 873 | struct iw_request_info *info, |
874 | union iwreq_data *data, char *extra) | 874 | union iwreq_data *data, char *extra) |
875 | { | 875 | { |
876 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 876 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
877 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 877 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
878 | int err, val; | 878 | int err, val; |
879 | 879 | ||
880 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 880 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
881 | return -EINVAL; | 881 | return -EINVAL; |
882 | if (data->txpower.flags & IW_TXPOW_RANGE) | 882 | if (data->txpower.flags & IW_TXPOW_RANGE) |
883 | return -EINVAL; | 883 | return -EINVAL; |
884 | 884 | ||
885 | if (!rdev->ops->get_tx_power) | 885 | if (!rdev->ops->get_tx_power) |
886 | return -EOPNOTSUPP; | 886 | return -EOPNOTSUPP; |
887 | 887 | ||
888 | err = rdev->ops->get_tx_power(wdev->wiphy, &val); | 888 | err = rdev->ops->get_tx_power(wdev->wiphy, &val); |
889 | if (err) | 889 | if (err) |
890 | return err; | 890 | return err; |
891 | 891 | ||
892 | /* well... oh well */ | 892 | /* well... oh well */ |
893 | data->txpower.fixed = 1; | 893 | data->txpower.fixed = 1; |
894 | data->txpower.disabled = rfkill_blocked(rdev->rfkill); | 894 | data->txpower.disabled = rfkill_blocked(rdev->rfkill); |
895 | data->txpower.value = val; | 895 | data->txpower.value = val; |
896 | data->txpower.flags = IW_TXPOW_DBM; | 896 | data->txpower.flags = IW_TXPOW_DBM; |
897 | 897 | ||
898 | return 0; | 898 | return 0; |
899 | } | 899 | } |
900 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); | 900 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); |
901 | 901 | ||
902 | static int cfg80211_set_auth_alg(struct wireless_dev *wdev, | 902 | static int cfg80211_set_auth_alg(struct wireless_dev *wdev, |
903 | s32 auth_alg) | 903 | s32 auth_alg) |
904 | { | 904 | { |
905 | int nr_alg = 0; | 905 | int nr_alg = 0; |
906 | 906 | ||
907 | if (!auth_alg) | 907 | if (!auth_alg) |
908 | return -EINVAL; | 908 | return -EINVAL; |
909 | 909 | ||
910 | if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM | | 910 | if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM | |
911 | IW_AUTH_ALG_SHARED_KEY | | 911 | IW_AUTH_ALG_SHARED_KEY | |
912 | IW_AUTH_ALG_LEAP)) | 912 | IW_AUTH_ALG_LEAP)) |
913 | return -EINVAL; | 913 | return -EINVAL; |
914 | 914 | ||
915 | if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) { | 915 | if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) { |
916 | nr_alg++; | 916 | nr_alg++; |
917 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; | 917 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; |
918 | } | 918 | } |
919 | 919 | ||
920 | if (auth_alg & IW_AUTH_ALG_SHARED_KEY) { | 920 | if (auth_alg & IW_AUTH_ALG_SHARED_KEY) { |
921 | nr_alg++; | 921 | nr_alg++; |
922 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY; | 922 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY; |
923 | } | 923 | } |
924 | 924 | ||
925 | if (auth_alg & IW_AUTH_ALG_LEAP) { | 925 | if (auth_alg & IW_AUTH_ALG_LEAP) { |
926 | nr_alg++; | 926 | nr_alg++; |
927 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP; | 927 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP; |
928 | } | 928 | } |
929 | 929 | ||
930 | if (nr_alg > 1) | 930 | if (nr_alg > 1) |
931 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 931 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
932 | 932 | ||
933 | return 0; | 933 | return 0; |
934 | } | 934 | } |
935 | 935 | ||
936 | static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) | 936 | static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) |
937 | { | 937 | { |
938 | if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | | 938 | if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | |
939 | IW_AUTH_WPA_VERSION_WPA2| | 939 | IW_AUTH_WPA_VERSION_WPA2| |
940 | IW_AUTH_WPA_VERSION_DISABLED)) | 940 | IW_AUTH_WPA_VERSION_DISABLED)) |
941 | return -EINVAL; | 941 | return -EINVAL; |
942 | 942 | ||
943 | if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) && | 943 | if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) && |
944 | (wpa_versions & (IW_AUTH_WPA_VERSION_WPA| | 944 | (wpa_versions & (IW_AUTH_WPA_VERSION_WPA| |
945 | IW_AUTH_WPA_VERSION_WPA2))) | 945 | IW_AUTH_WPA_VERSION_WPA2))) |
946 | return -EINVAL; | 946 | return -EINVAL; |
947 | 947 | ||
948 | if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) | 948 | if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) |
949 | wdev->wext.connect.crypto.wpa_versions &= | 949 | wdev->wext.connect.crypto.wpa_versions &= |
950 | ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2); | 950 | ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2); |
951 | 951 | ||
952 | if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) | 952 | if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) |
953 | wdev->wext.connect.crypto.wpa_versions |= | 953 | wdev->wext.connect.crypto.wpa_versions |= |
954 | NL80211_WPA_VERSION_1; | 954 | NL80211_WPA_VERSION_1; |
955 | 955 | ||
956 | if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2) | 956 | if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2) |
957 | wdev->wext.connect.crypto.wpa_versions |= | 957 | wdev->wext.connect.crypto.wpa_versions |= |
958 | NL80211_WPA_VERSION_2; | 958 | NL80211_WPA_VERSION_2; |
959 | 959 | ||
960 | return 0; | 960 | return 0; |
961 | } | 961 | } |
962 | 962 | ||
963 | static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) | 963 | static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) |
964 | { | 964 | { |
965 | if (cipher & IW_AUTH_CIPHER_WEP40) | 965 | if (cipher & IW_AUTH_CIPHER_WEP40) |
966 | wdev->wext.connect.crypto.cipher_group = | 966 | wdev->wext.connect.crypto.cipher_group = |
967 | WLAN_CIPHER_SUITE_WEP40; | 967 | WLAN_CIPHER_SUITE_WEP40; |
968 | else if (cipher & IW_AUTH_CIPHER_WEP104) | 968 | else if (cipher & IW_AUTH_CIPHER_WEP104) |
969 | wdev->wext.connect.crypto.cipher_group = | 969 | wdev->wext.connect.crypto.cipher_group = |
970 | WLAN_CIPHER_SUITE_WEP104; | 970 | WLAN_CIPHER_SUITE_WEP104; |
971 | else if (cipher & IW_AUTH_CIPHER_TKIP) | 971 | else if (cipher & IW_AUTH_CIPHER_TKIP) |
972 | wdev->wext.connect.crypto.cipher_group = | 972 | wdev->wext.connect.crypto.cipher_group = |
973 | WLAN_CIPHER_SUITE_TKIP; | 973 | WLAN_CIPHER_SUITE_TKIP; |
974 | else if (cipher & IW_AUTH_CIPHER_CCMP) | 974 | else if (cipher & IW_AUTH_CIPHER_CCMP) |
975 | wdev->wext.connect.crypto.cipher_group = | 975 | wdev->wext.connect.crypto.cipher_group = |
976 | WLAN_CIPHER_SUITE_CCMP; | 976 | WLAN_CIPHER_SUITE_CCMP; |
977 | else if (cipher & IW_AUTH_CIPHER_AES_CMAC) | 977 | else if (cipher & IW_AUTH_CIPHER_AES_CMAC) |
978 | wdev->wext.connect.crypto.cipher_group = | 978 | wdev->wext.connect.crypto.cipher_group = |
979 | WLAN_CIPHER_SUITE_AES_CMAC; | 979 | WLAN_CIPHER_SUITE_AES_CMAC; |
980 | else if (cipher & IW_AUTH_CIPHER_NONE) | 980 | else if (cipher & IW_AUTH_CIPHER_NONE) |
981 | wdev->wext.connect.crypto.cipher_group = 0; | 981 | wdev->wext.connect.crypto.cipher_group = 0; |
982 | else | 982 | else |
983 | return -EINVAL; | 983 | return -EINVAL; |
984 | 984 | ||
985 | return 0; | 985 | return 0; |
986 | } | 986 | } |
987 | 987 | ||
988 | static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) | 988 | static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) |
989 | { | 989 | { |
990 | int nr_ciphers = 0; | 990 | int nr_ciphers = 0; |
991 | u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise; | 991 | u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise; |
992 | 992 | ||
993 | if (cipher & IW_AUTH_CIPHER_WEP40) { | 993 | if (cipher & IW_AUTH_CIPHER_WEP40) { |
994 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40; | 994 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40; |
995 | nr_ciphers++; | 995 | nr_ciphers++; |
996 | } | 996 | } |
997 | 997 | ||
998 | if (cipher & IW_AUTH_CIPHER_WEP104) { | 998 | if (cipher & IW_AUTH_CIPHER_WEP104) { |
999 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104; | 999 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104; |
1000 | nr_ciphers++; | 1000 | nr_ciphers++; |
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | if (cipher & IW_AUTH_CIPHER_TKIP) { | 1003 | if (cipher & IW_AUTH_CIPHER_TKIP) { |
1004 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP; | 1004 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP; |
1005 | nr_ciphers++; | 1005 | nr_ciphers++; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | if (cipher & IW_AUTH_CIPHER_CCMP) { | 1008 | if (cipher & IW_AUTH_CIPHER_CCMP) { |
1009 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP; | 1009 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP; |
1010 | nr_ciphers++; | 1010 | nr_ciphers++; |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | if (cipher & IW_AUTH_CIPHER_AES_CMAC) { | 1013 | if (cipher & IW_AUTH_CIPHER_AES_CMAC) { |
1014 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC; | 1014 | ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC; |
1015 | nr_ciphers++; | 1015 | nr_ciphers++; |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5); | 1018 | BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5); |
1019 | 1019 | ||
1020 | wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers; | 1020 | wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers; |
1021 | 1021 | ||
1022 | return 0; | 1022 | return 0; |
1023 | } | 1023 | } |
1024 | 1024 | ||
1025 | 1025 | ||
1026 | static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) | 1026 | static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) |
1027 | { | 1027 | { |
1028 | int nr_akm_suites = 0; | 1028 | int nr_akm_suites = 0; |
1029 | 1029 | ||
1030 | if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X | | 1030 | if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X | |
1031 | IW_AUTH_KEY_MGMT_PSK)) | 1031 | IW_AUTH_KEY_MGMT_PSK)) |
1032 | return -EINVAL; | 1032 | return -EINVAL; |
1033 | 1033 | ||
1034 | if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) { | 1034 | if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) { |
1035 | wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = | 1035 | wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = |
1036 | WLAN_AKM_SUITE_8021X; | 1036 | WLAN_AKM_SUITE_8021X; |
1037 | nr_akm_suites++; | 1037 | nr_akm_suites++; |
1038 | } | 1038 | } |
1039 | 1039 | ||
1040 | if (key_mgt & IW_AUTH_KEY_MGMT_PSK) { | 1040 | if (key_mgt & IW_AUTH_KEY_MGMT_PSK) { |
1041 | wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = | 1041 | wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = |
1042 | WLAN_AKM_SUITE_PSK; | 1042 | WLAN_AKM_SUITE_PSK; |
1043 | nr_akm_suites++; | 1043 | nr_akm_suites++; |
1044 | } | 1044 | } |
1045 | 1045 | ||
1046 | wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites; | 1046 | wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites; |
1047 | 1047 | ||
1048 | return 0; | 1048 | return 0; |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | int cfg80211_wext_siwauth(struct net_device *dev, | 1051 | int cfg80211_wext_siwauth(struct net_device *dev, |
1052 | struct iw_request_info *info, | 1052 | struct iw_request_info *info, |
1053 | struct iw_param *data, char *extra) | 1053 | struct iw_param *data, char *extra) |
1054 | { | 1054 | { |
1055 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1055 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1056 | 1056 | ||
1057 | if (wdev->iftype != NL80211_IFTYPE_STATION) | 1057 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1058 | return -EOPNOTSUPP; | 1058 | return -EOPNOTSUPP; |
1059 | 1059 | ||
1060 | switch (data->flags & IW_AUTH_INDEX) { | 1060 | switch (data->flags & IW_AUTH_INDEX) { |
1061 | case IW_AUTH_PRIVACY_INVOKED: | 1061 | case IW_AUTH_PRIVACY_INVOKED: |
1062 | wdev->wext.connect.privacy = data->value; | 1062 | wdev->wext.connect.privacy = data->value; |
1063 | return 0; | 1063 | return 0; |
1064 | case IW_AUTH_WPA_VERSION: | 1064 | case IW_AUTH_WPA_VERSION: |
1065 | return cfg80211_set_wpa_version(wdev, data->value); | 1065 | return cfg80211_set_wpa_version(wdev, data->value); |
1066 | case IW_AUTH_CIPHER_GROUP: | 1066 | case IW_AUTH_CIPHER_GROUP: |
1067 | return cfg80211_set_cipher_group(wdev, data->value); | 1067 | return cfg80211_set_cipher_group(wdev, data->value); |
1068 | case IW_AUTH_KEY_MGMT: | 1068 | case IW_AUTH_KEY_MGMT: |
1069 | return cfg80211_set_key_mgt(wdev, data->value); | 1069 | return cfg80211_set_key_mgt(wdev, data->value); |
1070 | case IW_AUTH_CIPHER_PAIRWISE: | 1070 | case IW_AUTH_CIPHER_PAIRWISE: |
1071 | return cfg80211_set_cipher_pairwise(wdev, data->value); | 1071 | return cfg80211_set_cipher_pairwise(wdev, data->value); |
1072 | case IW_AUTH_80211_AUTH_ALG: | 1072 | case IW_AUTH_80211_AUTH_ALG: |
1073 | return cfg80211_set_auth_alg(wdev, data->value); | 1073 | return cfg80211_set_auth_alg(wdev, data->value); |
1074 | case IW_AUTH_WPA_ENABLED: | 1074 | case IW_AUTH_WPA_ENABLED: |
1075 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | 1075 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: |
1076 | case IW_AUTH_DROP_UNENCRYPTED: | 1076 | case IW_AUTH_DROP_UNENCRYPTED: |
1077 | case IW_AUTH_MFP: | 1077 | case IW_AUTH_MFP: |
1078 | return 0; | 1078 | return 0; |
1079 | default: | 1079 | default: |
1080 | return -EOPNOTSUPP; | 1080 | return -EOPNOTSUPP; |
1081 | } | 1081 | } |
1082 | } | 1082 | } |
1083 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth); | 1083 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth); |
1084 | 1084 | ||
1085 | int cfg80211_wext_giwauth(struct net_device *dev, | 1085 | int cfg80211_wext_giwauth(struct net_device *dev, |
1086 | struct iw_request_info *info, | 1086 | struct iw_request_info *info, |
1087 | struct iw_param *data, char *extra) | 1087 | struct iw_param *data, char *extra) |
1088 | { | 1088 | { |
1089 | /* XXX: what do we need? */ | 1089 | /* XXX: what do we need? */ |
1090 | 1090 | ||
1091 | return -EOPNOTSUPP; | 1091 | return -EOPNOTSUPP; |
1092 | } | 1092 | } |
1093 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth); | 1093 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth); |
1094 | 1094 | ||
1095 | int cfg80211_wext_siwpower(struct net_device *dev, | 1095 | int cfg80211_wext_siwpower(struct net_device *dev, |
1096 | struct iw_request_info *info, | 1096 | struct iw_request_info *info, |
1097 | struct iw_param *wrq, char *extra) | 1097 | struct iw_param *wrq, char *extra) |
1098 | { | 1098 | { |
1099 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1099 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1100 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1100 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1101 | bool ps = wdev->wext.ps; | 1101 | bool ps = wdev->wext.ps; |
1102 | int timeout = wdev->wext.ps_timeout; | 1102 | int timeout = wdev->wext.ps_timeout; |
1103 | int err; | 1103 | int err; |
1104 | 1104 | ||
1105 | if (wdev->iftype != NL80211_IFTYPE_STATION) | 1105 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1106 | return -EINVAL; | 1106 | return -EINVAL; |
1107 | 1107 | ||
1108 | if (!rdev->ops->set_power_mgmt) | 1108 | if (!rdev->ops->set_power_mgmt) |
1109 | return -EOPNOTSUPP; | 1109 | return -EOPNOTSUPP; |
1110 | 1110 | ||
1111 | if (wrq->disabled) { | 1111 | if (wrq->disabled) { |
1112 | ps = false; | 1112 | ps = false; |
1113 | } else { | 1113 | } else { |
1114 | switch (wrq->flags & IW_POWER_MODE) { | 1114 | switch (wrq->flags & IW_POWER_MODE) { |
1115 | case IW_POWER_ON: /* If not specified */ | 1115 | case IW_POWER_ON: /* If not specified */ |
1116 | case IW_POWER_MODE: /* If set all mask */ | 1116 | case IW_POWER_MODE: /* If set all mask */ |
1117 | case IW_POWER_ALL_R: /* If explicitely state all */ | 1117 | case IW_POWER_ALL_R: /* If explicitely state all */ |
1118 | ps = true; | 1118 | ps = true; |
1119 | break; | 1119 | break; |
1120 | default: /* Otherwise we ignore */ | 1120 | default: /* Otherwise we ignore */ |
1121 | return -EINVAL; | 1121 | return -EINVAL; |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) | 1124 | if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) |
1125 | return -EINVAL; | 1125 | return -EINVAL; |
1126 | 1126 | ||
1127 | if (wrq->flags & IW_POWER_TIMEOUT) | 1127 | if (wrq->flags & IW_POWER_TIMEOUT) |
1128 | timeout = wrq->value / 1000; | 1128 | timeout = wrq->value / 1000; |
1129 | } | 1129 | } |
1130 | 1130 | ||
1131 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout); | 1131 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout); |
1132 | if (err) | 1132 | if (err) |
1133 | return err; | 1133 | return err; |
1134 | 1134 | ||
1135 | wdev->wext.ps = ps; | 1135 | wdev->wext.ps = ps; |
1136 | wdev->wext.ps_timeout = timeout; | 1136 | wdev->wext.ps_timeout = timeout; |
1137 | 1137 | ||
1138 | return 0; | 1138 | return 0; |
1139 | 1139 | ||
1140 | } | 1140 | } |
1141 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower); | 1141 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower); |
1142 | 1142 | ||
1143 | int cfg80211_wext_giwpower(struct net_device *dev, | 1143 | int cfg80211_wext_giwpower(struct net_device *dev, |
1144 | struct iw_request_info *info, | 1144 | struct iw_request_info *info, |
1145 | struct iw_param *wrq, char *extra) | 1145 | struct iw_param *wrq, char *extra) |
1146 | { | 1146 | { |
1147 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1147 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1148 | 1148 | ||
1149 | wrq->disabled = !wdev->wext.ps; | 1149 | wrq->disabled = !wdev->wext.ps; |
1150 | 1150 | ||
1151 | return 0; | 1151 | return 0; |
1152 | } | 1152 | } |
1153 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); | 1153 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); |
1154 | 1154 | ||
1155 | static int cfg80211_wds_wext_siwap(struct net_device *dev, | 1155 | static int cfg80211_wds_wext_siwap(struct net_device *dev, |
1156 | struct iw_request_info *info, | 1156 | struct iw_request_info *info, |
1157 | struct sockaddr *addr, char *extra) | 1157 | struct sockaddr *addr, char *extra) |
1158 | { | 1158 | { |
1159 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1159 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1160 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1160 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1161 | int err; | 1161 | int err; |
1162 | 1162 | ||
1163 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) | 1163 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) |
1164 | return -EINVAL; | 1164 | return -EINVAL; |
1165 | 1165 | ||
1166 | if (addr->sa_family != ARPHRD_ETHER) | 1166 | if (addr->sa_family != ARPHRD_ETHER) |
1167 | return -EINVAL; | 1167 | return -EINVAL; |
1168 | 1168 | ||
1169 | if (netif_running(dev)) | 1169 | if (netif_running(dev)) |
1170 | return -EBUSY; | 1170 | return -EBUSY; |
1171 | 1171 | ||
1172 | if (!rdev->ops->set_wds_peer) | 1172 | if (!rdev->ops->set_wds_peer) |
1173 | return -EOPNOTSUPP; | 1173 | return -EOPNOTSUPP; |
1174 | 1174 | ||
1175 | err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data); | 1175 | err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data); |
1176 | if (err) | 1176 | if (err) |
1177 | return err; | 1177 | return err; |
1178 | 1178 | ||
1179 | memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN); | 1179 | memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN); |
1180 | 1180 | ||
1181 | return 0; | 1181 | return 0; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | static int cfg80211_wds_wext_giwap(struct net_device *dev, | 1184 | static int cfg80211_wds_wext_giwap(struct net_device *dev, |
1185 | struct iw_request_info *info, | 1185 | struct iw_request_info *info, |
1186 | struct sockaddr *addr, char *extra) | 1186 | struct sockaddr *addr, char *extra) |
1187 | { | 1187 | { |
1188 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1188 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1189 | 1189 | ||
1190 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) | 1190 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) |
1191 | return -EINVAL; | 1191 | return -EINVAL; |
1192 | 1192 | ||
1193 | addr->sa_family = ARPHRD_ETHER; | 1193 | addr->sa_family = ARPHRD_ETHER; |
1194 | memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN); | 1194 | memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN); |
1195 | 1195 | ||
1196 | return 0; | 1196 | return 0; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | int cfg80211_wext_siwrate(struct net_device *dev, | 1199 | int cfg80211_wext_siwrate(struct net_device *dev, |
1200 | struct iw_request_info *info, | 1200 | struct iw_request_info *info, |
1201 | struct iw_param *rate, char *extra) | 1201 | struct iw_param *rate, char *extra) |
1202 | { | 1202 | { |
1203 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1203 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1204 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1204 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1205 | struct cfg80211_bitrate_mask mask; | 1205 | struct cfg80211_bitrate_mask mask; |
1206 | 1206 | ||
1207 | if (!rdev->ops->set_bitrate_mask) | 1207 | if (!rdev->ops->set_bitrate_mask) |
1208 | return -EOPNOTSUPP; | 1208 | return -EOPNOTSUPP; |
1209 | 1209 | ||
1210 | mask.fixed = 0; | 1210 | mask.fixed = 0; |
1211 | mask.maxrate = 0; | 1211 | mask.maxrate = 0; |
1212 | 1212 | ||
1213 | if (rate->value < 0) { | 1213 | if (rate->value < 0) { |
1214 | /* nothing */ | 1214 | /* nothing */ |
1215 | } else if (rate->fixed) { | 1215 | } else if (rate->fixed) { |
1216 | mask.fixed = rate->value / 1000; /* kbps */ | 1216 | mask.fixed = rate->value / 1000; /* kbps */ |
1217 | } else { | 1217 | } else { |
1218 | mask.maxrate = rate->value / 1000; /* kbps */ | 1218 | mask.maxrate = rate->value / 1000; /* kbps */ |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); | 1221 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); |
1222 | } | 1222 | } |
1223 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); | 1223 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); |
1224 | 1224 | ||
1225 | int cfg80211_wext_giwrate(struct net_device *dev, | 1225 | int cfg80211_wext_giwrate(struct net_device *dev, |
1226 | struct iw_request_info *info, | 1226 | struct iw_request_info *info, |
1227 | struct iw_param *rate, char *extra) | 1227 | struct iw_param *rate, char *extra) |
1228 | { | 1228 | { |
1229 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1229 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1230 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1230 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1231 | /* we are under RTNL - globally locked - so can use a static struct */ | 1231 | /* we are under RTNL - globally locked - so can use a static struct */ |
1232 | static struct station_info sinfo; | 1232 | static struct station_info sinfo; |
1233 | u8 addr[ETH_ALEN]; | 1233 | u8 addr[ETH_ALEN]; |
1234 | int err; | 1234 | int err; |
1235 | 1235 | ||
1236 | if (wdev->iftype != NL80211_IFTYPE_STATION) | 1236 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1237 | return -EOPNOTSUPP; | 1237 | return -EOPNOTSUPP; |
1238 | 1238 | ||
1239 | if (!rdev->ops->get_station) | 1239 | if (!rdev->ops->get_station) |
1240 | return -EOPNOTSUPP; | 1240 | return -EOPNOTSUPP; |
1241 | 1241 | ||
1242 | err = 0; | 1242 | err = 0; |
1243 | wdev_lock(wdev); | 1243 | wdev_lock(wdev); |
1244 | if (wdev->current_bss) | 1244 | if (wdev->current_bss) |
1245 | memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); | 1245 | memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); |
1246 | else | 1246 | else |
1247 | err = -EOPNOTSUPP; | 1247 | err = -EOPNOTSUPP; |
1248 | wdev_unlock(wdev); | 1248 | wdev_unlock(wdev); |
1249 | if (err) | 1249 | if (err) |
1250 | return err; | 1250 | return err; |
1251 | 1251 | ||
1252 | err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); | 1252 | err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); |
1253 | if (err) | 1253 | if (err) |
1254 | return err; | 1254 | return err; |
1255 | 1255 | ||
1256 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) | 1256 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) |
1257 | return -EOPNOTSUPP; | 1257 | return -EOPNOTSUPP; |
1258 | 1258 | ||
1259 | rate->value = 0; | 1259 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); |
1260 | |||
1261 | if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) | ||
1262 | rate->value = 100000 * sinfo.txrate.legacy; | ||
1263 | 1260 | ||
1264 | return 0; | 1261 | return 0; |
1265 | } | 1262 | } |
1266 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); | 1263 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); |
1267 | 1264 | ||
1268 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ | 1265 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ |
1269 | struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | 1266 | struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) |
1270 | { | 1267 | { |
1271 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1268 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1272 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1269 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1273 | /* we are under RTNL - globally locked - so can use static structs */ | 1270 | /* we are under RTNL - globally locked - so can use static structs */ |
1274 | static struct iw_statistics wstats; | 1271 | static struct iw_statistics wstats; |
1275 | static struct station_info sinfo; | 1272 | static struct station_info sinfo; |
1276 | u8 bssid[ETH_ALEN]; | 1273 | u8 bssid[ETH_ALEN]; |
1277 | 1274 | ||
1278 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) | 1275 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) |
1279 | return NULL; | 1276 | return NULL; |
1280 | 1277 | ||
1281 | if (!rdev->ops->get_station) | 1278 | if (!rdev->ops->get_station) |
1282 | return NULL; | 1279 | return NULL; |
1283 | 1280 | ||
1284 | /* Grab BSSID of current BSS, if any */ | 1281 | /* Grab BSSID of current BSS, if any */ |
1285 | wdev_lock(wdev); | 1282 | wdev_lock(wdev); |
1286 | if (!wdev->current_bss) { | 1283 | if (!wdev->current_bss) { |
1287 | wdev_unlock(wdev); | 1284 | wdev_unlock(wdev); |
1288 | return NULL; | 1285 | return NULL; |
1289 | } | 1286 | } |
1290 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); | 1287 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); |
1291 | wdev_unlock(wdev); | 1288 | wdev_unlock(wdev); |
1292 | 1289 | ||
1293 | if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo)) | 1290 | if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo)) |
1294 | return NULL; | 1291 | return NULL; |
1295 | 1292 | ||
1296 | memset(&wstats, 0, sizeof(wstats)); | 1293 | memset(&wstats, 0, sizeof(wstats)); |
1297 | 1294 | ||
1298 | switch (rdev->wiphy.signal_type) { | 1295 | switch (rdev->wiphy.signal_type) { |
1299 | case CFG80211_SIGNAL_TYPE_MBM: | 1296 | case CFG80211_SIGNAL_TYPE_MBM: |
1300 | if (sinfo.filled & STATION_INFO_SIGNAL) { | 1297 | if (sinfo.filled & STATION_INFO_SIGNAL) { |
1301 | int sig = sinfo.signal; | 1298 | int sig = sinfo.signal; |
1302 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 1299 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
1303 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 1300 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
1304 | wstats.qual.updated |= IW_QUAL_DBM; | 1301 | wstats.qual.updated |= IW_QUAL_DBM; |
1305 | wstats.qual.level = sig; | 1302 | wstats.qual.level = sig; |
1306 | if (sig < -110) | 1303 | if (sig < -110) |
1307 | sig = -110; | 1304 | sig = -110; |
1308 | else if (sig > -40) | 1305 | else if (sig > -40) |
1309 | sig = -40; | 1306 | sig = -40; |
1310 | wstats.qual.qual = sig + 110; | 1307 | wstats.qual.qual = sig + 110; |
1311 | break; | 1308 | break; |
1312 | } | 1309 | } |
1313 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 1310 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
1314 | if (sinfo.filled & STATION_INFO_SIGNAL) { | 1311 | if (sinfo.filled & STATION_INFO_SIGNAL) { |
1315 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 1312 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
1316 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 1313 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
1317 | wstats.qual.level = sinfo.signal; | 1314 | wstats.qual.level = sinfo.signal; |
1318 | wstats.qual.qual = sinfo.signal; | 1315 | wstats.qual.qual = sinfo.signal; |
1319 | break; | 1316 | break; |
1320 | } | 1317 | } |
1321 | default: | 1318 | default: |
1322 | wstats.qual.updated |= IW_QUAL_LEVEL_INVALID; | 1319 | wstats.qual.updated |= IW_QUAL_LEVEL_INVALID; |
1323 | wstats.qual.updated |= IW_QUAL_QUAL_INVALID; | 1320 | wstats.qual.updated |= IW_QUAL_QUAL_INVALID; |
1324 | } | 1321 | } |
1325 | 1322 | ||
1326 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | 1323 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; |
1327 | 1324 | ||
1328 | return &wstats; | 1325 | return &wstats; |
1329 | } | 1326 | } |
1330 | EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); | 1327 | EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); |
1331 | 1328 | ||
1332 | int cfg80211_wext_siwap(struct net_device *dev, | 1329 | int cfg80211_wext_siwap(struct net_device *dev, |
1333 | struct iw_request_info *info, | 1330 | struct iw_request_info *info, |
1334 | struct sockaddr *ap_addr, char *extra) | 1331 | struct sockaddr *ap_addr, char *extra) |
1335 | { | 1332 | { |
1336 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1333 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1337 | 1334 | ||
1338 | switch (wdev->iftype) { | 1335 | switch (wdev->iftype) { |
1339 | case NL80211_IFTYPE_ADHOC: | 1336 | case NL80211_IFTYPE_ADHOC: |
1340 | return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); | 1337 | return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); |
1341 | case NL80211_IFTYPE_STATION: | 1338 | case NL80211_IFTYPE_STATION: |
1342 | return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); | 1339 | return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); |
1343 | case NL80211_IFTYPE_WDS: | 1340 | case NL80211_IFTYPE_WDS: |
1344 | return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); | 1341 | return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); |
1345 | default: | 1342 | default: |
1346 | return -EOPNOTSUPP; | 1343 | return -EOPNOTSUPP; |
1347 | } | 1344 | } |
1348 | } | 1345 | } |
1349 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwap); | 1346 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwap); |
1350 | 1347 | ||
1351 | int cfg80211_wext_giwap(struct net_device *dev, | 1348 | int cfg80211_wext_giwap(struct net_device *dev, |
1352 | struct iw_request_info *info, | 1349 | struct iw_request_info *info, |
1353 | struct sockaddr *ap_addr, char *extra) | 1350 | struct sockaddr *ap_addr, char *extra) |
1354 | { | 1351 | { |
1355 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1352 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1356 | 1353 | ||
1357 | switch (wdev->iftype) { | 1354 | switch (wdev->iftype) { |
1358 | case NL80211_IFTYPE_ADHOC: | 1355 | case NL80211_IFTYPE_ADHOC: |
1359 | return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); | 1356 | return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); |
1360 | case NL80211_IFTYPE_STATION: | 1357 | case NL80211_IFTYPE_STATION: |
1361 | return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); | 1358 | return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); |
1362 | case NL80211_IFTYPE_WDS: | 1359 | case NL80211_IFTYPE_WDS: |
1363 | return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); | 1360 | return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); |
1364 | default: | 1361 | default: |
1365 | return -EOPNOTSUPP; | 1362 | return -EOPNOTSUPP; |
1366 | } | 1363 | } |
1367 | } | 1364 | } |
1368 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwap); | 1365 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwap); |
1369 | 1366 | ||
1370 | int cfg80211_wext_siwessid(struct net_device *dev, | 1367 | int cfg80211_wext_siwessid(struct net_device *dev, |
1371 | struct iw_request_info *info, | 1368 | struct iw_request_info *info, |
1372 | struct iw_point *data, char *ssid) | 1369 | struct iw_point *data, char *ssid) |
1373 | { | 1370 | { |
1374 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1371 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1375 | 1372 | ||
1376 | switch (wdev->iftype) { | 1373 | switch (wdev->iftype) { |
1377 | case NL80211_IFTYPE_ADHOC: | 1374 | case NL80211_IFTYPE_ADHOC: |
1378 | return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); | 1375 | return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); |
1379 | case NL80211_IFTYPE_STATION: | 1376 | case NL80211_IFTYPE_STATION: |
1380 | return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); | 1377 | return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); |
1381 | default: | 1378 | default: |
1382 | return -EOPNOTSUPP; | 1379 | return -EOPNOTSUPP; |
1383 | } | 1380 | } |
1384 | } | 1381 | } |
1385 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid); | 1382 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid); |
1386 | 1383 | ||
1387 | int cfg80211_wext_giwessid(struct net_device *dev, | 1384 | int cfg80211_wext_giwessid(struct net_device *dev, |
1388 | struct iw_request_info *info, | 1385 | struct iw_request_info *info, |
1389 | struct iw_point *data, char *ssid) | 1386 | struct iw_point *data, char *ssid) |
1390 | { | 1387 | { |
1391 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1388 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1392 | 1389 | ||
1393 | switch (wdev->iftype) { | 1390 | switch (wdev->iftype) { |
1394 | case NL80211_IFTYPE_ADHOC: | 1391 | case NL80211_IFTYPE_ADHOC: |
1395 | return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); | 1392 | return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); |
1396 | case NL80211_IFTYPE_STATION: | 1393 | case NL80211_IFTYPE_STATION: |
1397 | return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); | 1394 | return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); |
1398 | default: | 1395 | default: |
1399 | return -EOPNOTSUPP; | 1396 | return -EOPNOTSUPP; |
1400 | } | 1397 | } |
1401 | } | 1398 | } |
1402 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); | 1399 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); |
1403 | 1400 | ||
1404 | int cfg80211_wext_siwpmksa(struct net_device *dev, | 1401 | int cfg80211_wext_siwpmksa(struct net_device *dev, |
1405 | struct iw_request_info *info, | 1402 | struct iw_request_info *info, |
1406 | struct iw_point *data, char *extra) | 1403 | struct iw_point *data, char *extra) |
1407 | { | 1404 | { |
1408 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1405 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1409 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1406 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1410 | struct cfg80211_pmksa cfg_pmksa; | 1407 | struct cfg80211_pmksa cfg_pmksa; |
1411 | struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; | 1408 | struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; |
1412 | 1409 | ||
1413 | memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa)); | 1410 | memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa)); |
1414 | 1411 | ||
1415 | if (wdev->iftype != NL80211_IFTYPE_STATION) | 1412 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
1416 | return -EINVAL; | 1413 | return -EINVAL; |
1417 | 1414 | ||
1418 | cfg_pmksa.bssid = pmksa->bssid.sa_data; | 1415 | cfg_pmksa.bssid = pmksa->bssid.sa_data; |
1419 | cfg_pmksa.pmkid = pmksa->pmkid; | 1416 | cfg_pmksa.pmkid = pmksa->pmkid; |
1420 | 1417 | ||
1421 | switch (pmksa->cmd) { | 1418 | switch (pmksa->cmd) { |
1422 | case IW_PMKSA_ADD: | 1419 | case IW_PMKSA_ADD: |
1423 | if (!rdev->ops->set_pmksa) | 1420 | if (!rdev->ops->set_pmksa) |
1424 | return -EOPNOTSUPP; | 1421 | return -EOPNOTSUPP; |
1425 | 1422 | ||
1426 | return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); | 1423 | return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); |
1427 | 1424 | ||
1428 | case IW_PMKSA_REMOVE: | 1425 | case IW_PMKSA_REMOVE: |
1429 | if (!rdev->ops->del_pmksa) | 1426 | if (!rdev->ops->del_pmksa) |
1430 | return -EOPNOTSUPP; | 1427 | return -EOPNOTSUPP; |
1431 | 1428 | ||
1432 | return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); | 1429 | return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); |
1433 | 1430 | ||
1434 | case IW_PMKSA_FLUSH: | 1431 | case IW_PMKSA_FLUSH: |
1435 | if (!rdev->ops->flush_pmksa) | 1432 | if (!rdev->ops->flush_pmksa) |
1436 | return -EOPNOTSUPP; | 1433 | return -EOPNOTSUPP; |
1437 | 1434 | ||
1438 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | 1435 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); |
1439 | 1436 | ||
1440 | default: | 1437 | default: |
1441 | return -EOPNOTSUPP; | 1438 | return -EOPNOTSUPP; |
1442 | } | 1439 | } |
1443 | } | 1440 | } |
1444 | 1441 | ||
1445 | static const iw_handler cfg80211_handlers[] = { | 1442 | static const iw_handler cfg80211_handlers[] = { |
1446 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, | 1443 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, |
1447 | [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, | 1444 | [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, |
1448 | [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, | 1445 | [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, |
1449 | [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, | 1446 | [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, |
1450 | [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, | 1447 | [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, |
1451 | [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, | 1448 | [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, |
1452 | [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, | 1449 | [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, |
1453 | [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, | 1450 | [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, |
1454 | [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, | 1451 | [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, |
1455 | [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, | 1452 | [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, |
1456 | [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, | 1453 | [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, |
1457 | [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, | 1454 | [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, |
1458 | [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, | 1455 | [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, |
1459 | [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, | 1456 | [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, |
1460 | [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, | 1457 | [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, |
1461 | [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, | 1458 | [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, |
1462 | [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, | 1459 | [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, |
1463 | [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, | 1460 | [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, |
1464 | [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, | 1461 | [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, |
1465 | [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, | 1462 | [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, |
1466 | [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, | 1463 | [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, |
1467 | [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, | 1464 | [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, |
1468 | [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, | 1465 | [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, |
1469 | [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, | 1466 | [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, |
1470 | [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, | 1467 | [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, |
1471 | [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, | 1468 | [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, |
1472 | [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, | 1469 | [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, |
1473 | [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, | 1470 | [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, |
1474 | [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, | 1471 | [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, |
1475 | [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, | 1472 | [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, |
1476 | [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, | 1473 | [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, |
1477 | [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, | 1474 | [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, |
1478 | }; | 1475 | }; |
1479 | 1476 | ||
1480 | const struct iw_handler_def cfg80211_wext_handler = { | 1477 | const struct iw_handler_def cfg80211_wext_handler = { |
1481 | .num_standard = ARRAY_SIZE(cfg80211_handlers), | 1478 | .num_standard = ARRAY_SIZE(cfg80211_handlers), |
1482 | .standard = cfg80211_handlers, | 1479 | .standard = cfg80211_handlers, |
1483 | .get_wireless_stats = cfg80211_wireless_stats, | 1480 | .get_wireless_stats = cfg80211_wireless_stats, |
1484 | }; | 1481 | }; |
1485 | 1482 |