diff options
Diffstat (limited to 'net/wireless/ibss.c')
-rw-r--r-- | net/wireless/ibss.c | 133 |
1 files changed, 106 insertions, 27 deletions
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a5330c5a5477..99ef9364b7e8 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include "nl80211.h" | 10 | #include "nl80211.h" |
11 | 11 | ||
12 | 12 | ||
13 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | 13 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) |
14 | { | 14 | { |
15 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 15 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
16 | struct cfg80211_bss *bss; | 16 | struct cfg80211_bss *bss; |
@@ -39,22 +39,45 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | |||
39 | cfg80211_hold_bss(bss_from_pub(bss)); | 39 | cfg80211_hold_bss(bss_from_pub(bss)); |
40 | wdev->current_bss = bss_from_pub(bss); | 40 | wdev->current_bss = bss_from_pub(bss); |
41 | 41 | ||
42 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); | 42 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, |
43 | GFP_KERNEL); | ||
43 | #ifdef CONFIG_WIRELESS_EXT | 44 | #ifdef CONFIG_WIRELESS_EXT |
44 | memset(&wrqu, 0, sizeof(wrqu)); | 45 | memset(&wrqu, 0, sizeof(wrqu)); |
45 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 46 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
46 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 47 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
47 | #endif | 48 | #endif |
48 | } | 49 | } |
50 | |||
51 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | ||
52 | { | ||
53 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
54 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
55 | struct cfg80211_event *ev; | ||
56 | unsigned long flags; | ||
57 | |||
58 | ev = kzalloc(sizeof(*ev), gfp); | ||
59 | if (!ev) | ||
60 | return; | ||
61 | |||
62 | ev->type = EVENT_IBSS_JOINED; | ||
63 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | ||
64 | |||
65 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
66 | list_add_tail(&ev->list, &wdev->event_list); | ||
67 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
68 | schedule_work(&rdev->event_work); | ||
69 | } | ||
49 | EXPORT_SYMBOL(cfg80211_ibss_joined); | 70 | EXPORT_SYMBOL(cfg80211_ibss_joined); |
50 | 71 | ||
51 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 72 | int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, |
52 | struct net_device *dev, | 73 | struct net_device *dev, |
53 | struct cfg80211_ibss_params *params) | 74 | struct cfg80211_ibss_params *params) |
54 | { | 75 | { |
55 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 76 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
56 | int err; | 77 | int err; |
57 | 78 | ||
79 | ASSERT_WDEV_LOCK(wdev); | ||
80 | |||
58 | if (wdev->ssid_len) | 81 | if (wdev->ssid_len) |
59 | return -EALREADY; | 82 | return -EALREADY; |
60 | 83 | ||
@@ -72,10 +95,26 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
72 | return 0; | 95 | return 0; |
73 | } | 96 | } |
74 | 97 | ||
75 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext) | 98 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, |
99 | struct net_device *dev, | ||
100 | struct cfg80211_ibss_params *params) | ||
101 | { | ||
102 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
103 | int err; | ||
104 | |||
105 | wdev_lock(wdev); | ||
106 | err = __cfg80211_join_ibss(rdev, dev, params); | ||
107 | wdev_unlock(wdev); | ||
108 | |||
109 | return err; | ||
110 | } | ||
111 | |||
112 | static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | ||
76 | { | 113 | { |
77 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 114 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
78 | 115 | ||
116 | ASSERT_WDEV_LOCK(wdev); | ||
117 | |||
79 | if (wdev->current_bss) { | 118 | if (wdev->current_bss) { |
80 | cfg80211_unhold_bss(wdev->current_bss); | 119 | cfg80211_unhold_bss(wdev->current_bss); |
81 | cfg80211_put_bss(&wdev->current_bss->pub); | 120 | cfg80211_put_bss(&wdev->current_bss->pub); |
@@ -89,12 +128,23 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
89 | #endif | 128 | #endif |
90 | } | 129 | } |
91 | 130 | ||
92 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 131 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext) |
93 | struct net_device *dev, bool nowext) | 132 | { |
133 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
134 | |||
135 | wdev_lock(wdev); | ||
136 | __cfg80211_clear_ibss(dev, nowext); | ||
137 | wdev_unlock(wdev); | ||
138 | } | ||
139 | |||
140 | static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | ||
141 | struct net_device *dev, bool nowext) | ||
94 | { | 142 | { |
95 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 143 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
96 | int err; | 144 | int err; |
97 | 145 | ||
146 | ASSERT_WDEV_LOCK(wdev); | ||
147 | |||
98 | if (!wdev->ssid_len) | 148 | if (!wdev->ssid_len) |
99 | return -ENOLINK; | 149 | return -ENOLINK; |
100 | 150 | ||
@@ -103,11 +153,24 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | |||
103 | if (err) | 153 | if (err) |
104 | return err; | 154 | return err; |
105 | 155 | ||
106 | cfg80211_clear_ibss(dev, nowext); | 156 | __cfg80211_clear_ibss(dev, nowext); |
107 | 157 | ||
108 | return 0; | 158 | return 0; |
109 | } | 159 | } |
110 | 160 | ||
161 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | ||
162 | struct net_device *dev, bool nowext) | ||
163 | { | ||
164 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
165 | int err; | ||
166 | |||
167 | wdev_lock(wdev); | ||
168 | err = __cfg80211_leave_ibss(rdev, dev, nowext); | ||
169 | wdev_unlock(wdev); | ||
170 | |||
171 | return err; | ||
172 | } | ||
173 | |||
111 | #ifdef CONFIG_WIRELESS_EXT | 174 | #ifdef CONFIG_WIRELESS_EXT |
112 | static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 175 | static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
113 | struct wireless_dev *wdev) | 176 | struct wireless_dev *wdev) |
@@ -184,12 +247,15 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
184 | if (wdev->wext.ibss.channel == chan) | 247 | if (wdev->wext.ibss.channel == chan) |
185 | return 0; | 248 | return 0; |
186 | 249 | ||
187 | if (wdev->ssid_len) { | 250 | wdev_lock(wdev); |
188 | err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 251 | err = 0; |
189 | dev, true); | 252 | if (wdev->ssid_len) |
190 | if (err) | 253 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), |
191 | return err; | 254 | dev, true); |
192 | } | 255 | wdev_unlock(wdev); |
256 | |||
257 | if (err) | ||
258 | return err; | ||
193 | 259 | ||
194 | if (chan) { | 260 | if (chan) { |
195 | wdev->wext.ibss.channel = chan; | 261 | wdev->wext.ibss.channel = chan; |
@@ -215,10 +281,12 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, | |||
215 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 281 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
216 | return -EINVAL; | 282 | return -EINVAL; |
217 | 283 | ||
284 | wdev_lock(wdev); | ||
218 | if (wdev->current_bss) | 285 | if (wdev->current_bss) |
219 | chan = wdev->current_bss->pub.channel; | 286 | chan = wdev->current_bss->pub.channel; |
220 | else if (wdev->wext.ibss.channel) | 287 | else if (wdev->wext.ibss.channel) |
221 | chan = wdev->wext.ibss.channel; | 288 | chan = wdev->wext.ibss.channel; |
289 | wdev_unlock(wdev); | ||
222 | 290 | ||
223 | if (chan) { | 291 | if (chan) { |
224 | freq->m = chan->center_freq; | 292 | freq->m = chan->center_freq; |
@@ -247,12 +315,15 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
247 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 315 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) |
248 | return -EOPNOTSUPP; | 316 | return -EOPNOTSUPP; |
249 | 317 | ||
250 | if (wdev->ssid_len) { | 318 | wdev_lock(wdev); |
251 | err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 319 | err = 0; |
252 | dev, true); | 320 | if (wdev->ssid_len) |
253 | if (err) | 321 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), |
254 | return err; | 322 | dev, true); |
255 | } | 323 | wdev_unlock(wdev); |
324 | |||
325 | if (err) | ||
326 | return err; | ||
256 | 327 | ||
257 | /* iwconfig uses nul termination in SSID.. */ | 328 | /* iwconfig uses nul termination in SSID.. */ |
258 | if (len > 0 && ssid[len - 1] == '\0') | 329 | if (len > 0 && ssid[len - 1] == '\0') |
@@ -279,6 +350,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, | |||
279 | 350 | ||
280 | data->flags = 0; | 351 | data->flags = 0; |
281 | 352 | ||
353 | wdev_lock(wdev); | ||
282 | if (wdev->ssid_len) { | 354 | if (wdev->ssid_len) { |
283 | data->flags = 1; | 355 | data->flags = 1; |
284 | data->length = wdev->ssid_len; | 356 | data->length = wdev->ssid_len; |
@@ -288,6 +360,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, | |||
288 | data->length = wdev->wext.ibss.ssid_len; | 360 | data->length = wdev->wext.ibss.ssid_len; |
289 | memcpy(ssid, wdev->wext.ibss.ssid, data->length); | 361 | memcpy(ssid, wdev->wext.ibss.ssid, data->length); |
290 | } | 362 | } |
363 | wdev_unlock(wdev); | ||
291 | 364 | ||
292 | return 0; | 365 | return 0; |
293 | } | 366 | } |
@@ -325,12 +398,15 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
325 | compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) | 398 | compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) |
326 | return 0; | 399 | return 0; |
327 | 400 | ||
328 | if (wdev->ssid_len) { | 401 | wdev_lock(wdev); |
329 | err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 402 | err = 0; |
330 | dev, true); | 403 | if (wdev->ssid_len) |
331 | if (err) | 404 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), |
332 | return err; | 405 | dev, true); |
333 | } | 406 | wdev_unlock(wdev); |
407 | |||
408 | if (err) | ||
409 | return err; | ||
334 | 410 | ||
335 | if (bssid) { | 411 | if (bssid) { |
336 | memcpy(wdev->wext.bssid, bssid, ETH_ALEN); | 412 | memcpy(wdev->wext.bssid, bssid, ETH_ALEN); |
@@ -355,10 +431,13 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, | |||
355 | 431 | ||
356 | ap_addr->sa_family = ARPHRD_ETHER; | 432 | ap_addr->sa_family = ARPHRD_ETHER; |
357 | 433 | ||
434 | wdev_lock(wdev); | ||
358 | if (wdev->current_bss) | 435 | if (wdev->current_bss) |
359 | memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); | 436 | memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); |
360 | else | 437 | else |
361 | memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); | 438 | memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); |
439 | wdev_unlock(wdev); | ||
440 | |||
362 | return 0; | 441 | return 0; |
363 | } | 442 | } |
364 | /* temporary symbol - mark GPL - in the future the handler won't be */ | 443 | /* temporary symbol - mark GPL - in the future the handler won't be */ |