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