wext: refactor
[linux-2.6.git] / net / wireless / ibss.c
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>
10 #include "wext-compat.h"
11 #include "nl80211.h"
12
13
14 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
15 {
16         struct wireless_dev *wdev = dev->ieee80211_ptr;
17         struct cfg80211_bss *bss;
18 #ifdef CONFIG_CFG80211_WEXT
19         union iwreq_data wrqu;
20 #endif
21
22         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
23                 return;
24
25         if (!wdev->ssid_len)
26                 return;
27
28         bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
29                                wdev->ssid, wdev->ssid_len,
30                                WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
31
32         if (WARN_ON(!bss))
33                 return;
34
35         if (wdev->current_bss) {
36                 cfg80211_unhold_bss(wdev->current_bss);
37                 cfg80211_put_bss(&wdev->current_bss->pub);
38         }
39
40         cfg80211_hold_bss(bss_from_pub(bss));
41         wdev->current_bss = bss_from_pub(bss);
42
43         cfg80211_upload_connect_keys(wdev);
44
45         nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
46                                 GFP_KERNEL);
47 #ifdef CONFIG_CFG80211_WEXT
48         memset(&wrqu, 0, sizeof(wrqu));
49         memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
50         wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
51 #endif
52 }
53
54 void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
55 {
56         struct wireless_dev *wdev = dev->ieee80211_ptr;
57         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
58         struct cfg80211_event *ev;
59         unsigned long flags;
60
61         CFG80211_DEV_WARN_ON(!wdev->ssid_len);
62
63         ev = kzalloc(sizeof(*ev), gfp);
64         if (!ev)
65                 return;
66
67         ev->type = EVENT_IBSS_JOINED;
68         memcpy(ev->cr.bssid, bssid, ETH_ALEN);
69
70         spin_lock_irqsave(&wdev->event_lock, flags);
71         list_add_tail(&ev->list, &wdev->event_list);
72         spin_unlock_irqrestore(&wdev->event_lock, flags);
73         schedule_work(&rdev->event_work);
74 }
75 EXPORT_SYMBOL(cfg80211_ibss_joined);
76
77 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
78                          struct net_device *dev,
79                          struct cfg80211_ibss_params *params,
80                          struct cfg80211_cached_keys *connkeys)
81 {
82         struct wireless_dev *wdev = dev->ieee80211_ptr;
83         struct ieee80211_channel *chan;
84         int err;
85
86         ASSERT_WDEV_LOCK(wdev);
87
88         chan = rdev_fixed_channel(rdev, wdev);
89         if (chan && chan != params->channel)
90                 return -EBUSY;
91
92         if (wdev->ssid_len)
93                 return -EALREADY;
94
95         if (WARN_ON(wdev->connect_keys))
96                 kfree(wdev->connect_keys);
97         wdev->connect_keys = connkeys;
98
99 #ifdef CONFIG_CFG80211_WEXT
100         wdev->wext.ibss.channel = params->channel;
101 #endif
102         err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
103         if (err) {
104                 wdev->connect_keys = NULL;
105                 return err;
106         }
107
108         memcpy(wdev->ssid, params->ssid, params->ssid_len);
109         wdev->ssid_len = params->ssid_len;
110
111         return 0;
112 }
113
114 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
115                        struct net_device *dev,
116                        struct cfg80211_ibss_params *params,
117                        struct cfg80211_cached_keys *connkeys)
118 {
119         struct wireless_dev *wdev = dev->ieee80211_ptr;
120         int err;
121
122         mutex_lock(&rdev->devlist_mtx);
123         wdev_lock(wdev);
124         err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
125         wdev_unlock(wdev);
126         mutex_unlock(&rdev->devlist_mtx);
127
128         return err;
129 }
130
131 static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
132 {
133         struct wireless_dev *wdev = dev->ieee80211_ptr;
134         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
135         int i;
136
137         ASSERT_WDEV_LOCK(wdev);
138
139         kfree(wdev->connect_keys);
140         wdev->connect_keys = NULL;
141
142         /*
143          * Delete all the keys ... pairwise keys can't really
144          * exist any more anyway, but default keys might.
145          */
146         if (rdev->ops->del_key)
147                 for (i = 0; i < 6; i++)
148                         rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
149
150         if (wdev->current_bss) {
151                 cfg80211_unhold_bss(wdev->current_bss);
152                 cfg80211_put_bss(&wdev->current_bss->pub);
153         }
154
155         wdev->current_bss = NULL;
156         wdev->ssid_len = 0;
157 #ifdef CONFIG_CFG80211_WEXT
158         if (!nowext)
159                 wdev->wext.ibss.ssid_len = 0;
160 #endif
161 }
162
163 void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
164 {
165         struct wireless_dev *wdev = dev->ieee80211_ptr;
166
167         wdev_lock(wdev);
168         __cfg80211_clear_ibss(dev, nowext);
169         wdev_unlock(wdev);
170 }
171
172 static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
173                                  struct net_device *dev, bool nowext)
174 {
175         struct wireless_dev *wdev = dev->ieee80211_ptr;
176         int err;
177
178         ASSERT_WDEV_LOCK(wdev);
179
180         if (!wdev->ssid_len)
181                 return -ENOLINK;
182
183         err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
184
185         if (err)
186                 return err;
187
188         __cfg80211_clear_ibss(dev, nowext);
189
190         return 0;
191 }
192
193 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
194                         struct net_device *dev, bool nowext)
195 {
196         struct wireless_dev *wdev = dev->ieee80211_ptr;
197         int err;
198
199         wdev_lock(wdev);
200         err = __cfg80211_leave_ibss(rdev, dev, nowext);
201         wdev_unlock(wdev);
202
203         return err;
204 }
205
206 #ifdef CONFIG_CFG80211_WEXT
207 int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
208                             struct wireless_dev *wdev)
209 {
210         struct cfg80211_cached_keys *ck = NULL;
211         enum ieee80211_band band;
212         int i, err;
213
214         ASSERT_WDEV_LOCK(wdev);
215
216         if (!wdev->wext.ibss.beacon_interval)
217                 wdev->wext.ibss.beacon_interval = 100;
218
219         /* try to find an IBSS channel if none requested ... */
220         if (!wdev->wext.ibss.channel) {
221                 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
222                         struct ieee80211_supported_band *sband;
223                         struct ieee80211_channel *chan;
224
225                         sband = rdev->wiphy.bands[band];
226                         if (!sband)
227                                 continue;
228
229                         for (i = 0; i < sband->n_channels; i++) {
230                                 chan = &sband->channels[i];
231                                 if (chan->flags & IEEE80211_CHAN_NO_IBSS)
232                                         continue;
233                                 if (chan->flags & IEEE80211_CHAN_DISABLED)
234                                         continue;
235                                 wdev->wext.ibss.channel = chan;
236                                 break;
237                         }
238
239                         if (wdev->wext.ibss.channel)
240                                 break;
241                 }
242
243                 if (!wdev->wext.ibss.channel)
244                         return -EINVAL;
245         }
246
247         /* don't join -- SSID is not there */
248         if (!wdev->wext.ibss.ssid_len)
249                 return 0;
250
251         if (!netif_running(wdev->netdev))
252                 return 0;
253
254         if (wdev->wext.keys)
255                 wdev->wext.keys->def = wdev->wext.default_key;
256
257         wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
258
259         if (wdev->wext.keys) {
260                 ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
261                 if (!ck)
262                         return -ENOMEM;
263                 for (i = 0; i < 6; i++)
264                         ck->params[i].key = ck->data[i];
265         }
266         err = __cfg80211_join_ibss(rdev, wdev->netdev,
267                                    &wdev->wext.ibss, ck);
268         if (err)
269                 kfree(ck);
270
271         return err;
272 }
273
274 int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
275                                struct iw_request_info *info,
276                                struct iw_freq *wextfreq, char *extra)
277 {
278         struct wireless_dev *wdev = dev->ieee80211_ptr;
279         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
280         struct ieee80211_channel *chan = NULL;
281         int err, freq;
282
283         /* call only for ibss! */
284         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
285                 return -EINVAL;
286
287         if (!rdev->ops->join_ibss)
288                 return -EOPNOTSUPP;
289
290         freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
291         if (freq < 0)
292                 return freq;
293
294         if (freq) {
295                 chan = ieee80211_get_channel(wdev->wiphy, freq);
296                 if (!chan)
297                         return -EINVAL;
298                 if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
299                     chan->flags & IEEE80211_CHAN_DISABLED)
300                         return -EINVAL;
301         }
302
303         if (wdev->wext.ibss.channel == chan)
304                 return 0;
305
306         wdev_lock(wdev);
307         err = 0;
308         if (wdev->ssid_len)
309                 err = __cfg80211_leave_ibss(rdev, dev, true);
310         wdev_unlock(wdev);
311
312         if (err)
313                 return err;
314
315         if (chan) {
316                 wdev->wext.ibss.channel = chan;
317                 wdev->wext.ibss.channel_fixed = true;
318         } else {
319                 /* cfg80211_ibss_wext_join will pick one if needed */
320                 wdev->wext.ibss.channel_fixed = false;
321         }
322
323         mutex_lock(&rdev->devlist_mtx);
324         wdev_lock(wdev);
325         err = cfg80211_ibss_wext_join(rdev, wdev);
326         wdev_unlock(wdev);
327         mutex_unlock(&rdev->devlist_mtx);
328
329         return err;
330 }
331
332 int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
333                                struct iw_request_info *info,
334                                struct iw_freq *freq, char *extra)
335 {
336         struct wireless_dev *wdev = dev->ieee80211_ptr;
337         struct ieee80211_channel *chan = NULL;
338
339         /* call only for ibss! */
340         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
341                 return -EINVAL;
342
343         wdev_lock(wdev);
344         if (wdev->current_bss)
345                 chan = wdev->current_bss->pub.channel;
346         else if (wdev->wext.ibss.channel)
347                 chan = wdev->wext.ibss.channel;
348         wdev_unlock(wdev);
349
350         if (chan) {
351                 freq->m = chan->center_freq;
352                 freq->e = 6;
353                 return 0;
354         }
355
356         /* no channel if not joining */
357         return -EINVAL;
358 }
359
360 int cfg80211_ibss_wext_siwessid(struct net_device *dev,
361                                 struct iw_request_info *info,
362                                 struct iw_point *data, char *ssid)
363 {
364         struct wireless_dev *wdev = dev->ieee80211_ptr;
365         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
366         size_t len = data->length;
367         int err;
368
369         /* call only for ibss! */
370         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
371                 return -EINVAL;
372
373         if (!rdev->ops->join_ibss)
374                 return -EOPNOTSUPP;
375
376         wdev_lock(wdev);
377         err = 0;
378         if (wdev->ssid_len)
379                 err = __cfg80211_leave_ibss(rdev, dev, true);
380         wdev_unlock(wdev);
381
382         if (err)
383                 return err;
384
385         /* iwconfig uses nul termination in SSID.. */
386         if (len > 0 && ssid[len - 1] == '\0')
387                 len--;
388
389         wdev->wext.ibss.ssid = wdev->ssid;
390         memcpy(wdev->wext.ibss.ssid, ssid, len);
391         wdev->wext.ibss.ssid_len = len;
392
393         mutex_lock(&rdev->devlist_mtx);
394         wdev_lock(wdev);
395         err = cfg80211_ibss_wext_join(rdev, wdev);
396         wdev_unlock(wdev);
397         mutex_unlock(&rdev->devlist_mtx);
398
399         return err;
400 }
401
402 int cfg80211_ibss_wext_giwessid(struct net_device *dev,
403                                 struct iw_request_info *info,
404                                 struct iw_point *data, char *ssid)
405 {
406         struct wireless_dev *wdev = dev->ieee80211_ptr;
407
408         /* call only for ibss! */
409         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
410                 return -EINVAL;
411
412         data->flags = 0;
413
414         wdev_lock(wdev);
415         if (wdev->ssid_len) {
416                 data->flags = 1;
417                 data->length = wdev->ssid_len;
418                 memcpy(ssid, wdev->ssid, data->length);
419         } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
420                 data->flags = 1;
421                 data->length = wdev->wext.ibss.ssid_len;
422                 memcpy(ssid, wdev->wext.ibss.ssid, data->length);
423         }
424         wdev_unlock(wdev);
425
426         return 0;
427 }
428
429 int cfg80211_ibss_wext_siwap(struct net_device *dev,
430                              struct iw_request_info *info,
431                              struct sockaddr *ap_addr, char *extra)
432 {
433         struct wireless_dev *wdev = dev->ieee80211_ptr;
434         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
435         u8 *bssid = ap_addr->sa_data;
436         int err;
437
438         /* call only for ibss! */
439         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
440                 return -EINVAL;
441
442         if (!rdev->ops->join_ibss)
443                 return -EOPNOTSUPP;
444
445         if (ap_addr->sa_family != ARPHRD_ETHER)
446                 return -EINVAL;
447
448         /* automatic mode */
449         if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
450                 bssid = NULL;
451
452         /* both automatic */
453         if (!bssid && !wdev->wext.ibss.bssid)
454                 return 0;
455
456         /* fixed already - and no change */
457         if (wdev->wext.ibss.bssid && bssid &&
458             compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
459                 return 0;
460
461         wdev_lock(wdev);
462         err = 0;
463         if (wdev->ssid_len)
464                 err = __cfg80211_leave_ibss(rdev, dev, true);
465         wdev_unlock(wdev);
466
467         if (err)
468                 return err;
469
470         if (bssid) {
471                 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
472                 wdev->wext.ibss.bssid = wdev->wext.bssid;
473         } else
474                 wdev->wext.ibss.bssid = NULL;
475
476         mutex_lock(&rdev->devlist_mtx);
477         wdev_lock(wdev);
478         err = cfg80211_ibss_wext_join(rdev, wdev);
479         wdev_unlock(wdev);
480         mutex_unlock(&rdev->devlist_mtx);
481
482         return err;
483 }
484
485 int cfg80211_ibss_wext_giwap(struct net_device *dev,
486                              struct iw_request_info *info,
487                              struct sockaddr *ap_addr, char *extra)
488 {
489         struct wireless_dev *wdev = dev->ieee80211_ptr;
490
491         /* call only for ibss! */
492         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
493                 return -EINVAL;
494
495         ap_addr->sa_family = ARPHRD_ETHER;
496
497         wdev_lock(wdev);
498         if (wdev->current_bss)
499                 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
500         else if (wdev->wext.ibss.bssid)
501                 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
502         else
503                 memset(ap_addr->sa_data, 0, ETH_ALEN);
504
505         wdev_unlock(wdev);
506
507         return 0;
508 }
509 #endif