nl80211: introduce new key attributes
[deliverable/linux.git] / net / wireless / ibss.c
CommitLineData
04a773ad
JB
1/*
2 * Some IBSS support code for cfg80211.
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 */
6
7#include <linux/etherdevice.h>
8#include <linux/if_arp.h>
9#include <net/cfg80211.h>
04a773ad
JB
10#include "nl80211.h"
11
12
667503dd 13void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
04a773ad
JB
14{
15 struct wireless_dev *wdev = dev->ieee80211_ptr;
16 struct cfg80211_bss *bss;
17#ifdef CONFIG_WIRELESS_EXT
18 union iwreq_data wrqu;
19#endif
20
21 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
22 return;
23
24 if (WARN_ON(!wdev->ssid_len))
25 return;
26
04a773ad
JB
27 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
28 wdev->ssid, wdev->ssid_len,
29 WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
30
31 if (WARN_ON(!bss))
32 return;
33
34 if (wdev->current_bss) {
35 cfg80211_unhold_bss(wdev->current_bss);
19957bb3 36 cfg80211_put_bss(&wdev->current_bss->pub);
04a773ad
JB
37 }
38
19957bb3
JB
39 cfg80211_hold_bss(bss_from_pub(bss));
40 wdev->current_bss = bss_from_pub(bss);
04a773ad 41
667503dd
JB
42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
43 GFP_KERNEL);
04a773ad
JB
44#ifdef CONFIG_WIRELESS_EXT
45 memset(&wrqu, 0, sizeof(wrqu));
46 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
47 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
48#endif
49}
667503dd
JB
50
51void 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}
04a773ad
JB
70EXPORT_SYMBOL(cfg80211_ibss_joined);
71
667503dd
JB
72int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
73 struct net_device *dev,
74 struct cfg80211_ibss_params *params)
04a773ad
JB
75{
76 struct wireless_dev *wdev = dev->ieee80211_ptr;
77 int err;
78
667503dd
JB
79 ASSERT_WDEV_LOCK(wdev);
80
04a773ad
JB
81 if (wdev->ssid_len)
82 return -EALREADY;
83
84#ifdef CONFIG_WIRELESS_EXT
cbe8fa9c 85 wdev->wext.ibss.channel = params->channel;
04a773ad
JB
86#endif
87 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
88
89 if (err)
90 return err;
91
92 memcpy(wdev->ssid, params->ssid, params->ssid_len);
93 wdev->ssid_len = params->ssid_len;
94
95 return 0;
96}
97
667503dd
JB
98int 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
112static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
04a773ad
JB
113{
114 struct wireless_dev *wdev = dev->ieee80211_ptr;
115
667503dd
JB
116 ASSERT_WDEV_LOCK(wdev);
117
04a773ad
JB
118 if (wdev->current_bss) {
119 cfg80211_unhold_bss(wdev->current_bss);
19957bb3 120 cfg80211_put_bss(&wdev->current_bss->pub);
04a773ad
JB
121 }
122
123 wdev->current_bss = NULL;
124 wdev->ssid_len = 0;
9d308429
JB
125#ifdef CONFIG_WIRELESS_EXT
126 if (!nowext)
cbe8fa9c 127 wdev->wext.ibss.ssid_len = 0;
9d308429 128#endif
04a773ad
JB
129}
130
667503dd
JB
131void cfg80211_clear_ibss(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
140static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
141 struct net_device *dev, bool nowext)
04a773ad 142{
78485475 143 struct wireless_dev *wdev = dev->ieee80211_ptr;
04a773ad
JB
144 int err;
145
667503dd
JB
146 ASSERT_WDEV_LOCK(wdev);
147
78485475
JB
148 if (!wdev->ssid_len)
149 return -ENOLINK;
150
04a773ad
JB
151 err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
152
153 if (err)
154 return err;
155
667503dd 156 __cfg80211_clear_ibss(dev, nowext);
04a773ad
JB
157
158 return 0;
159}
160
667503dd
JB
161int 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
04a773ad
JB
174#ifdef CONFIG_WIRELESS_EXT
175static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
176 struct wireless_dev *wdev)
177{
178 enum ieee80211_band band;
179 int i;
180
cbe8fa9c
JB
181 if (!wdev->wext.ibss.beacon_interval)
182 wdev->wext.ibss.beacon_interval = 100;
8e30bc55 183
04a773ad 184 /* try to find an IBSS channel if none requested ... */
cbe8fa9c 185 if (!wdev->wext.ibss.channel) {
04a773ad
JB
186 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
187 struct ieee80211_supported_band *sband;
188 struct ieee80211_channel *chan;
189
190 sband = rdev->wiphy.bands[band];
191 if (!sband)
192 continue;
193
194 for (i = 0; i < sband->n_channels; i++) {
195 chan = &sband->channels[i];
196 if (chan->flags & IEEE80211_CHAN_NO_IBSS)
197 continue;
198 if (chan->flags & IEEE80211_CHAN_DISABLED)
199 continue;
cbe8fa9c 200 wdev->wext.ibss.channel = chan;
04a773ad
JB
201 break;
202 }
203
cbe8fa9c 204 if (wdev->wext.ibss.channel)
04a773ad
JB
205 break;
206 }
207
cbe8fa9c 208 if (!wdev->wext.ibss.channel)
04a773ad
JB
209 return -EINVAL;
210 }
211
212 /* don't join -- SSID is not there */
cbe8fa9c 213 if (!wdev->wext.ibss.ssid_len)
04a773ad
JB
214 return 0;
215
216 if (!netif_running(wdev->netdev))
217 return 0;
218
219 return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
cbe8fa9c 220 wdev->netdev, &wdev->wext.ibss);
04a773ad
JB
221}
222
223int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
224 struct iw_request_info *info,
225 struct iw_freq *freq, char *extra)
226{
227 struct wireless_dev *wdev = dev->ieee80211_ptr;
228 struct ieee80211_channel *chan;
229 int err;
230
231 /* call only for ibss! */
232 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
233 return -EINVAL;
234
235 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
236 return -EOPNOTSUPP;
237
238 chan = cfg80211_wext_freq(wdev->wiphy, freq);
239 if (chan && IS_ERR(chan))
240 return PTR_ERR(chan);
241
242 if (chan &&
243 (chan->flags & IEEE80211_CHAN_NO_IBSS ||
244 chan->flags & IEEE80211_CHAN_DISABLED))
245 return -EINVAL;
246
cbe8fa9c 247 if (wdev->wext.ibss.channel == chan)
04a773ad
JB
248 return 0;
249
667503dd
JB
250 wdev_lock(wdev);
251 err = 0;
252 if (wdev->ssid_len)
253 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
254 dev, true);
255 wdev_unlock(wdev);
256
257 if (err)
258 return err;
04a773ad
JB
259
260 if (chan) {
cbe8fa9c
JB
261 wdev->wext.ibss.channel = chan;
262 wdev->wext.ibss.channel_fixed = true;
04a773ad
JB
263 } else {
264 /* cfg80211_ibss_wext_join will pick one if needed */
cbe8fa9c 265 wdev->wext.ibss.channel_fixed = false;
04a773ad
JB
266 }
267
268 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
269}
270/* temporary symbol - mark GPL - in the future the handler won't be */
271EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
272
273int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
274 struct iw_request_info *info,
275 struct iw_freq *freq, char *extra)
276{
277 struct wireless_dev *wdev = dev->ieee80211_ptr;
278 struct ieee80211_channel *chan = NULL;
279
280 /* call only for ibss! */
281 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
282 return -EINVAL;
283
667503dd 284 wdev_lock(wdev);
04a773ad 285 if (wdev->current_bss)
19957bb3 286 chan = wdev->current_bss->pub.channel;
cbe8fa9c
JB
287 else if (wdev->wext.ibss.channel)
288 chan = wdev->wext.ibss.channel;
667503dd 289 wdev_unlock(wdev);
04a773ad
JB
290
291 if (chan) {
292 freq->m = chan->center_freq;
293 freq->e = 6;
294 return 0;
295 }
296
297 /* no channel if not joining */
298 return -EINVAL;
299}
300/* temporary symbol - mark GPL - in the future the handler won't be */
301EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq);
302
303int cfg80211_ibss_wext_siwessid(struct net_device *dev,
304 struct iw_request_info *info,
305 struct iw_point *data, char *ssid)
306{
307 struct wireless_dev *wdev = dev->ieee80211_ptr;
308 size_t len = data->length;
309 int err;
310
311 /* call only for ibss! */
312 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
313 return -EINVAL;
314
315 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
316 return -EOPNOTSUPP;
317
667503dd
JB
318 wdev_lock(wdev);
319 err = 0;
320 if (wdev->ssid_len)
321 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
322 dev, true);
323 wdev_unlock(wdev);
324
325 if (err)
326 return err;
04a773ad
JB
327
328 /* iwconfig uses nul termination in SSID.. */
329 if (len > 0 && ssid[len - 1] == '\0')
330 len--;
331
cbe8fa9c
JB
332 wdev->wext.ibss.ssid = wdev->ssid;
333 memcpy(wdev->wext.ibss.ssid, ssid, len);
334 wdev->wext.ibss.ssid_len = len;
04a773ad
JB
335
336 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
337}
338/* temporary symbol - mark GPL - in the future the handler won't be */
339EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
340
341int cfg80211_ibss_wext_giwessid(struct net_device *dev,
342 struct iw_request_info *info,
343 struct iw_point *data, char *ssid)
344{
345 struct wireless_dev *wdev = dev->ieee80211_ptr;
346
347 /* call only for ibss! */
348 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
349 return -EINVAL;
350
351 data->flags = 0;
352
667503dd 353 wdev_lock(wdev);
04a773ad
JB
354 if (wdev->ssid_len) {
355 data->flags = 1;
356 data->length = wdev->ssid_len;
357 memcpy(ssid, wdev->ssid, data->length);
cbe8fa9c 358 } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
04a773ad 359 data->flags = 1;
cbe8fa9c
JB
360 data->length = wdev->wext.ibss.ssid_len;
361 memcpy(ssid, wdev->wext.ibss.ssid, data->length);
04a773ad 362 }
667503dd 363 wdev_unlock(wdev);
04a773ad
JB
364
365 return 0;
366}
367/* temporary symbol - mark GPL - in the future the handler won't be */
368EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid);
369
370int cfg80211_ibss_wext_siwap(struct net_device *dev,
371 struct iw_request_info *info,
372 struct sockaddr *ap_addr, char *extra)
373{
374 struct wireless_dev *wdev = dev->ieee80211_ptr;
375 u8 *bssid = ap_addr->sa_data;
376 int err;
377
378 /* call only for ibss! */
379 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
380 return -EINVAL;
381
382 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
383 return -EOPNOTSUPP;
384
385 if (ap_addr->sa_family != ARPHRD_ETHER)
386 return -EINVAL;
387
388 /* automatic mode */
389 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
390 bssid = NULL;
391
392 /* both automatic */
cbe8fa9c 393 if (!bssid && !wdev->wext.ibss.bssid)
04a773ad
JB
394 return 0;
395
396 /* fixed already - and no change */
cbe8fa9c
JB
397 if (wdev->wext.ibss.bssid && bssid &&
398 compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
04a773ad
JB
399 return 0;
400
667503dd
JB
401 wdev_lock(wdev);
402 err = 0;
403 if (wdev->ssid_len)
404 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
405 dev, true);
406 wdev_unlock(wdev);
407
408 if (err)
409 return err;
04a773ad
JB
410
411 if (bssid) {
cbe8fa9c
JB
412 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
413 wdev->wext.ibss.bssid = wdev->wext.bssid;
04a773ad 414 } else
cbe8fa9c 415 wdev->wext.ibss.bssid = NULL;
04a773ad
JB
416
417 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
418}
419/* temporary symbol - mark GPL - in the future the handler won't be */
420EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
421
422int cfg80211_ibss_wext_giwap(struct net_device *dev,
423 struct iw_request_info *info,
424 struct sockaddr *ap_addr, char *extra)
425{
426 struct wireless_dev *wdev = dev->ieee80211_ptr;
427
428 /* call only for ibss! */
429 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
430 return -EINVAL;
431
432 ap_addr->sa_family = ARPHRD_ETHER;
433
667503dd 434 wdev_lock(wdev);
7ebbe6bd 435 if (wdev->current_bss)
19957bb3 436 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
7ebbe6bd 437 else
cbe8fa9c 438 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
667503dd
JB
439 wdev_unlock(wdev);
440
04a773ad
JB
441 return 0;
442}
443/* temporary symbol - mark GPL - in the future the handler won't be */
444EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
445#endif
This page took 0.064416 seconds and 5 git commands to generate.