blob: b90fd86b2d1890fa494bea918195b000f5d1f0dd [file] [log] [blame]
Johannes Berg04a773a2009-04-19 21:24:32 +02001/*
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09009#include <linux/slab.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040010#include <linux/export.h>
Johannes Berg04a773a2009-04-19 21:24:32 +020011#include <net/cfg80211.h>
Johannes Berg0e82ffe2009-07-27 12:01:50 +020012#include "wext-compat.h"
Johannes Berg04a773a2009-04-19 21:24:32 +020013#include "nl80211.h"
14
15
Johannes Berg667503dd2009-07-07 03:56:11 +020016void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
Johannes Berg04a773a2009-04-19 21:24:32 +020017{
18 struct wireless_dev *wdev = dev->ieee80211_ptr;
19 struct cfg80211_bss *bss;
Johannes Berg3d23e342009-09-29 23:27:28 +020020#ifdef CONFIG_CFG80211_WEXT
Johannes Berg04a773a2009-04-19 21:24:32 +020021 union iwreq_data wrqu;
22#endif
23
24 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
25 return;
26
Johannes Bergf7969962009-08-21 12:23:49 +020027 if (!wdev->ssid_len)
Johannes Berg04a773a2009-04-19 21:24:32 +020028 return;
29
Johannes Berg04a773a2009-04-19 21:24:32 +020030 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
31 wdev->ssid, wdev->ssid_len,
32 WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
33
34 if (WARN_ON(!bss))
35 return;
36
37 if (wdev->current_bss) {
38 cfg80211_unhold_bss(wdev->current_bss);
Johannes Berg19957bb2009-07-02 17:20:43 +020039 cfg80211_put_bss(&wdev->current_bss->pub);
Johannes Berg04a773a2009-04-19 21:24:32 +020040 }
41
Johannes Berg19957bb2009-07-02 17:20:43 +020042 cfg80211_hold_bss(bss_from_pub(bss));
43 wdev->current_bss = bss_from_pub(bss);
Johannes Berg04a773a2009-04-19 21:24:32 +020044
Amitkumar Karwar28f33362012-05-29 15:39:06 -070045 wdev->sme_state = CFG80211_SME_CONNECTED;
Johannes Bergfffd0932009-07-08 14:22:54 +020046 cfg80211_upload_connect_keys(wdev);
47
Johannes Berg667503dd2009-07-07 03:56:11 +020048 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
49 GFP_KERNEL);
Johannes Berg3d23e342009-09-29 23:27:28 +020050#ifdef CONFIG_CFG80211_WEXT
Johannes Berg04a773a2009-04-19 21:24:32 +020051 memset(&wrqu, 0, sizeof(wrqu));
52 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
53 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
54#endif
55}
Johannes Berg667503dd2009-07-07 03:56:11 +020056
57void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
58{
59 struct wireless_dev *wdev = dev->ieee80211_ptr;
60 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
61 struct cfg80211_event *ev;
62 unsigned long flags;
63
Amitkumar Karwar28f33362012-05-29 15:39:06 -070064 CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
Johannes Bergf7969962009-08-21 12:23:49 +020065
Johannes Berg667503dd2009-07-07 03:56:11 +020066 ev = kzalloc(sizeof(*ev), gfp);
67 if (!ev)
68 return;
69
70 ev->type = EVENT_IBSS_JOINED;
71 memcpy(ev->cr.bssid, bssid, ETH_ALEN);
72
73 spin_lock_irqsave(&wdev->event_lock, flags);
74 list_add_tail(&ev->list, &wdev->event_list);
75 spin_unlock_irqrestore(&wdev->event_lock, flags);
Alban Browaeyse60d7442009-11-25 15:13:00 +010076 queue_work(cfg80211_wq, &rdev->event_work);
Johannes Berg667503dd2009-07-07 03:56:11 +020077}
Johannes Berg04a773a2009-04-19 21:24:32 +020078EXPORT_SYMBOL(cfg80211_ibss_joined);
79
Johannes Berg667503dd2009-07-07 03:56:11 +020080int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
81 struct net_device *dev,
Johannes Bergfffd0932009-07-08 14:22:54 +020082 struct cfg80211_ibss_params *params,
83 struct cfg80211_cached_keys *connkeys)
Johannes Berg04a773a2009-04-19 21:24:32 +020084{
85 struct wireless_dev *wdev = dev->ieee80211_ptr;
86 int err;
87
Johannes Berg667503dd2009-07-07 03:56:11 +020088 ASSERT_WDEV_LOCK(wdev);
89
Johannes Berg04a773a2009-04-19 21:24:32 +020090 if (wdev->ssid_len)
91 return -EALREADY;
92
Johannes Berg93b05232010-09-28 12:53:14 +020093 if (!params->basic_rates) {
94 /*
95 * If no rates were explicitly configured,
96 * use the mandatory rate set for 11b or
97 * 11a for maximum compatibility.
98 */
99 struct ieee80211_supported_band *sband =
100 rdev->wiphy.bands[params->channel->band];
101 int j;
102 u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ?
103 IEEE80211_RATE_MANDATORY_A :
104 IEEE80211_RATE_MANDATORY_B;
105
106 for (j = 0; j < sband->n_bitrates; j++) {
107 if (sband->bitrates[j].flags & flag)
108 params->basic_rates |= BIT(j);
109 }
110 }
111
Johannes Bergfffd0932009-07-08 14:22:54 +0200112 if (WARN_ON(wdev->connect_keys))
113 kfree(wdev->connect_keys);
114 wdev->connect_keys = connkeys;
115
Michal Kaziorc30a3d32012-06-29 12:46:59 +0200116 wdev->ibss_fixed = params->channel_fixed;
Johannes Berg3d23e342009-09-29 23:27:28 +0200117#ifdef CONFIG_CFG80211_WEXT
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200118 wdev->wext.ibss.channel = params->channel;
Johannes Berg04a773a2009-04-19 21:24:32 +0200119#endif
Amitkumar Karwar28f33362012-05-29 15:39:06 -0700120 wdev->sme_state = CFG80211_SME_CONNECTING;
Johannes Berg04a773a2009-04-19 21:24:32 +0200121 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
Johannes Bergfffd0932009-07-08 14:22:54 +0200122 if (err) {
123 wdev->connect_keys = NULL;
Amitkumar Karwar28f33362012-05-29 15:39:06 -0700124 wdev->sme_state = CFG80211_SME_IDLE;
Johannes Berg04a773a2009-04-19 21:24:32 +0200125 return err;
Johannes Bergfffd0932009-07-08 14:22:54 +0200126 }
Johannes Berg04a773a2009-04-19 21:24:32 +0200127
128 memcpy(wdev->ssid, params->ssid, params->ssid_len);
129 wdev->ssid_len = params->ssid_len;
130
131 return 0;
132}
133
Johannes Berg667503dd2009-07-07 03:56:11 +0200134int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
135 struct net_device *dev,
Johannes Bergfffd0932009-07-08 14:22:54 +0200136 struct cfg80211_ibss_params *params,
137 struct cfg80211_cached_keys *connkeys)
Johannes Berg04a773a2009-04-19 21:24:32 +0200138{
139 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg667503dd2009-07-07 03:56:11 +0200140 int err;
141
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200142 mutex_lock(&rdev->devlist_mtx);
Johannes Berg667503dd2009-07-07 03:56:11 +0200143 wdev_lock(wdev);
Johannes Bergfffd0932009-07-08 14:22:54 +0200144 err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
Johannes Berg667503dd2009-07-07 03:56:11 +0200145 wdev_unlock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200146 mutex_unlock(&rdev->devlist_mtx);
Johannes Berg667503dd2009-07-07 03:56:11 +0200147
148 return err;
149}
150
151static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
152{
153 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Bergfffd0932009-07-08 14:22:54 +0200154 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
155 int i;
Johannes Berg667503dd2009-07-07 03:56:11 +0200156
157 ASSERT_WDEV_LOCK(wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200158
Johannes Bergfffd0932009-07-08 14:22:54 +0200159 kfree(wdev->connect_keys);
160 wdev->connect_keys = NULL;
161
162 /*
163 * Delete all the keys ... pairwise keys can't really
164 * exist any more anyway, but default keys might.
165 */
166 if (rdev->ops->del_key)
167 for (i = 0; i < 6; i++)
Johannes Berge31b8212010-10-05 19:39:30 +0200168 rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
Johannes Bergfffd0932009-07-08 14:22:54 +0200169
Johannes Berg04a773a2009-04-19 21:24:32 +0200170 if (wdev->current_bss) {
171 cfg80211_unhold_bss(wdev->current_bss);
Johannes Berg19957bb2009-07-02 17:20:43 +0200172 cfg80211_put_bss(&wdev->current_bss->pub);
Johannes Berg04a773a2009-04-19 21:24:32 +0200173 }
174
175 wdev->current_bss = NULL;
Amitkumar Karwar28f33362012-05-29 15:39:06 -0700176 wdev->sme_state = CFG80211_SME_IDLE;
Johannes Berg04a773a2009-04-19 21:24:32 +0200177 wdev->ssid_len = 0;
Johannes Berg3d23e342009-09-29 23:27:28 +0200178#ifdef CONFIG_CFG80211_WEXT
Johannes Berg9d308422009-04-20 18:43:46 +0200179 if (!nowext)
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200180 wdev->wext.ibss.ssid_len = 0;
Johannes Berg9d308422009-04-20 18:43:46 +0200181#endif
Johannes Berg04a773a2009-04-19 21:24:32 +0200182}
183
Johannes Berg667503dd2009-07-07 03:56:11 +0200184void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
185{
186 struct wireless_dev *wdev = dev->ieee80211_ptr;
187
188 wdev_lock(wdev);
189 __cfg80211_clear_ibss(dev, nowext);
190 wdev_unlock(wdev);
191}
192
Johannes Berg98d3a7c2009-11-18 13:03:43 +0100193int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
194 struct net_device *dev, bool nowext)
Johannes Berg04a773a2009-04-19 21:24:32 +0200195{
Johannes Berg78485472009-07-07 03:56:05 +0200196 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg04a773a2009-04-19 21:24:32 +0200197 int err;
198
Johannes Berg667503dd2009-07-07 03:56:11 +0200199 ASSERT_WDEV_LOCK(wdev);
200
Johannes Berg78485472009-07-07 03:56:05 +0200201 if (!wdev->ssid_len)
202 return -ENOLINK;
203
Johannes Berg04a773a2009-04-19 21:24:32 +0200204 err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
205
206 if (err)
207 return err;
208
Johannes Berg667503dd2009-07-07 03:56:11 +0200209 __cfg80211_clear_ibss(dev, nowext);
Johannes Berg04a773a2009-04-19 21:24:32 +0200210
211 return 0;
212}
213
Johannes Berg667503dd2009-07-07 03:56:11 +0200214int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
215 struct net_device *dev, bool nowext)
216{
217 struct wireless_dev *wdev = dev->ieee80211_ptr;
218 int err;
219
220 wdev_lock(wdev);
221 err = __cfg80211_leave_ibss(rdev, dev, nowext);
222 wdev_unlock(wdev);
223
224 return err;
225}
226
Johannes Berg3d23e342009-09-29 23:27:28 +0200227#ifdef CONFIG_CFG80211_WEXT
Johannes Bergfffd0932009-07-08 14:22:54 +0200228int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
229 struct wireless_dev *wdev)
Johannes Berg04a773a2009-04-19 21:24:32 +0200230{
Johannes Bergfffd0932009-07-08 14:22:54 +0200231 struct cfg80211_cached_keys *ck = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +0200232 enum ieee80211_band band;
Johannes Bergfffd0932009-07-08 14:22:54 +0200233 int i, err;
234
235 ASSERT_WDEV_LOCK(wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200236
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200237 if (!wdev->wext.ibss.beacon_interval)
238 wdev->wext.ibss.beacon_interval = 100;
Johannes Berg8e30bc52009-04-22 17:45:38 +0200239
Johannes Berg04a773a2009-04-19 21:24:32 +0200240 /* try to find an IBSS channel if none requested ... */
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200241 if (!wdev->wext.ibss.channel) {
Johannes Berg04a773a2009-04-19 21:24:32 +0200242 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
243 struct ieee80211_supported_band *sband;
244 struct ieee80211_channel *chan;
245
246 sband = rdev->wiphy.bands[band];
247 if (!sband)
248 continue;
249
250 for (i = 0; i < sband->n_channels; i++) {
251 chan = &sband->channels[i];
252 if (chan->flags & IEEE80211_CHAN_NO_IBSS)
253 continue;
254 if (chan->flags & IEEE80211_CHAN_DISABLED)
255 continue;
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200256 wdev->wext.ibss.channel = chan;
Johannes Berg04a773a2009-04-19 21:24:32 +0200257 break;
258 }
259
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200260 if (wdev->wext.ibss.channel)
Johannes Berg04a773a2009-04-19 21:24:32 +0200261 break;
262 }
263
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200264 if (!wdev->wext.ibss.channel)
Johannes Berg04a773a2009-04-19 21:24:32 +0200265 return -EINVAL;
266 }
267
268 /* don't join -- SSID is not there */
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200269 if (!wdev->wext.ibss.ssid_len)
Johannes Berg04a773a2009-04-19 21:24:32 +0200270 return 0;
271
272 if (!netif_running(wdev->netdev))
273 return 0;
274
Johannes Berg3be61a32010-07-22 13:59:15 +0200275 if (wdev->wext.keys) {
Johannes Bergfffd0932009-07-08 14:22:54 +0200276 wdev->wext.keys->def = wdev->wext.default_key;
Johannes Berg3be61a32010-07-22 13:59:15 +0200277 wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
278 }
Johannes Bergfffd0932009-07-08 14:22:54 +0200279
280 wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
281
282 if (wdev->wext.keys) {
283 ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
284 if (!ck)
285 return -ENOMEM;
286 for (i = 0; i < 6; i++)
287 ck->params[i].key = ck->data[i];
288 }
289 err = __cfg80211_join_ibss(rdev, wdev->netdev,
290 &wdev->wext.ibss, ck);
291 if (err)
292 kfree(ck);
293
294 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200295}
296
297int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
298 struct iw_request_info *info,
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200299 struct iw_freq *wextfreq, char *extra)
Johannes Berg04a773a2009-04-19 21:24:32 +0200300{
301 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200302 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
303 struct ieee80211_channel *chan = NULL;
304 int err, freq;
Johannes Berg04a773a2009-04-19 21:24:32 +0200305
306 /* call only for ibss! */
307 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
308 return -EINVAL;
309
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200310 if (!rdev->ops->join_ibss)
Johannes Berg04a773a2009-04-19 21:24:32 +0200311 return -EOPNOTSUPP;
312
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200313 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
314 if (freq < 0)
315 return freq;
Johannes Berg04a773a2009-04-19 21:24:32 +0200316
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200317 if (freq) {
318 chan = ieee80211_get_channel(wdev->wiphy, freq);
319 if (!chan)
320 return -EINVAL;
321 if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
322 chan->flags & IEEE80211_CHAN_DISABLED)
323 return -EINVAL;
324 }
Johannes Berg04a773a2009-04-19 21:24:32 +0200325
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200326 if (wdev->wext.ibss.channel == chan)
Johannes Berg04a773a2009-04-19 21:24:32 +0200327 return 0;
328
Johannes Berg667503dd2009-07-07 03:56:11 +0200329 wdev_lock(wdev);
330 err = 0;
331 if (wdev->ssid_len)
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200332 err = __cfg80211_leave_ibss(rdev, dev, true);
Johannes Berg667503dd2009-07-07 03:56:11 +0200333 wdev_unlock(wdev);
334
335 if (err)
336 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200337
338 if (chan) {
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200339 wdev->wext.ibss.channel = chan;
340 wdev->wext.ibss.channel_fixed = true;
Johannes Berg04a773a2009-04-19 21:24:32 +0200341 } else {
342 /* cfg80211_ibss_wext_join will pick one if needed */
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200343 wdev->wext.ibss.channel_fixed = false;
Johannes Berg04a773a2009-04-19 21:24:32 +0200344 }
345
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200346 mutex_lock(&rdev->devlist_mtx);
Johannes Bergfffd0932009-07-08 14:22:54 +0200347 wdev_lock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200348 err = cfg80211_ibss_wext_join(rdev, wdev);
Johannes Bergfffd0932009-07-08 14:22:54 +0200349 wdev_unlock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200350 mutex_unlock(&rdev->devlist_mtx);
Johannes Bergfffd0932009-07-08 14:22:54 +0200351
352 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200353}
Johannes Berg04a773a2009-04-19 21:24:32 +0200354
355int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
356 struct iw_request_info *info,
357 struct iw_freq *freq, char *extra)
358{
359 struct wireless_dev *wdev = dev->ieee80211_ptr;
360 struct ieee80211_channel *chan = NULL;
361
362 /* call only for ibss! */
363 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
364 return -EINVAL;
365
Johannes Berg667503dd2009-07-07 03:56:11 +0200366 wdev_lock(wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200367 if (wdev->current_bss)
Johannes Berg19957bb2009-07-02 17:20:43 +0200368 chan = wdev->current_bss->pub.channel;
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200369 else if (wdev->wext.ibss.channel)
370 chan = wdev->wext.ibss.channel;
Johannes Berg667503dd2009-07-07 03:56:11 +0200371 wdev_unlock(wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200372
373 if (chan) {
374 freq->m = chan->center_freq;
375 freq->e = 6;
376 return 0;
377 }
378
379 /* no channel if not joining */
380 return -EINVAL;
381}
Johannes Berg04a773a2009-04-19 21:24:32 +0200382
383int cfg80211_ibss_wext_siwessid(struct net_device *dev,
384 struct iw_request_info *info,
385 struct iw_point *data, char *ssid)
386{
387 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200388 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
Johannes Berg04a773a2009-04-19 21:24:32 +0200389 size_t len = data->length;
390 int err;
391
392 /* call only for ibss! */
393 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
394 return -EINVAL;
395
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200396 if (!rdev->ops->join_ibss)
Johannes Berg04a773a2009-04-19 21:24:32 +0200397 return -EOPNOTSUPP;
398
Johannes Berg667503dd2009-07-07 03:56:11 +0200399 wdev_lock(wdev);
400 err = 0;
401 if (wdev->ssid_len)
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200402 err = __cfg80211_leave_ibss(rdev, dev, true);
Johannes Berg667503dd2009-07-07 03:56:11 +0200403 wdev_unlock(wdev);
404
405 if (err)
406 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200407
408 /* iwconfig uses nul termination in SSID.. */
409 if (len > 0 && ssid[len - 1] == '\0')
410 len--;
411
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200412 wdev->wext.ibss.ssid = wdev->ssid;
413 memcpy(wdev->wext.ibss.ssid, ssid, len);
414 wdev->wext.ibss.ssid_len = len;
Johannes Berg04a773a2009-04-19 21:24:32 +0200415
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200416 mutex_lock(&rdev->devlist_mtx);
Johannes Bergfffd0932009-07-08 14:22:54 +0200417 wdev_lock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200418 err = cfg80211_ibss_wext_join(rdev, wdev);
Johannes Bergfffd0932009-07-08 14:22:54 +0200419 wdev_unlock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200420 mutex_unlock(&rdev->devlist_mtx);
Johannes Bergfffd0932009-07-08 14:22:54 +0200421
422 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200423}
Johannes Berg04a773a2009-04-19 21:24:32 +0200424
425int cfg80211_ibss_wext_giwessid(struct net_device *dev,
426 struct iw_request_info *info,
427 struct iw_point *data, char *ssid)
428{
429 struct wireless_dev *wdev = dev->ieee80211_ptr;
430
431 /* call only for ibss! */
432 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
433 return -EINVAL;
434
435 data->flags = 0;
436
Johannes Berg667503dd2009-07-07 03:56:11 +0200437 wdev_lock(wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200438 if (wdev->ssid_len) {
439 data->flags = 1;
440 data->length = wdev->ssid_len;
441 memcpy(ssid, wdev->ssid, data->length);
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200442 } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
Johannes Berg04a773a2009-04-19 21:24:32 +0200443 data->flags = 1;
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200444 data->length = wdev->wext.ibss.ssid_len;
445 memcpy(ssid, wdev->wext.ibss.ssid, data->length);
Johannes Berg04a773a2009-04-19 21:24:32 +0200446 }
Johannes Berg667503dd2009-07-07 03:56:11 +0200447 wdev_unlock(wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200448
449 return 0;
450}
Johannes Berg04a773a2009-04-19 21:24:32 +0200451
452int cfg80211_ibss_wext_siwap(struct net_device *dev,
453 struct iw_request_info *info,
454 struct sockaddr *ap_addr, char *extra)
455{
456 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200457 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
Johannes Berg04a773a2009-04-19 21:24:32 +0200458 u8 *bssid = ap_addr->sa_data;
459 int err;
460
461 /* call only for ibss! */
462 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
463 return -EINVAL;
464
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200465 if (!rdev->ops->join_ibss)
Johannes Berg04a773a2009-04-19 21:24:32 +0200466 return -EOPNOTSUPP;
467
468 if (ap_addr->sa_family != ARPHRD_ETHER)
469 return -EINVAL;
470
471 /* automatic mode */
472 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
473 bssid = NULL;
474
475 /* both automatic */
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200476 if (!bssid && !wdev->wext.ibss.bssid)
Johannes Berg04a773a2009-04-19 21:24:32 +0200477 return 0;
478
479 /* fixed already - and no change */
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200480 if (wdev->wext.ibss.bssid && bssid &&
Joe Perchesac422d32012-05-08 18:56:55 +0000481 ether_addr_equal(bssid, wdev->wext.ibss.bssid))
Johannes Berg04a773a2009-04-19 21:24:32 +0200482 return 0;
483
Johannes Berg667503dd2009-07-07 03:56:11 +0200484 wdev_lock(wdev);
485 err = 0;
486 if (wdev->ssid_len)
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200487 err = __cfg80211_leave_ibss(rdev, dev, true);
Johannes Berg667503dd2009-07-07 03:56:11 +0200488 wdev_unlock(wdev);
489
490 if (err)
491 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200492
493 if (bssid) {
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200494 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
495 wdev->wext.ibss.bssid = wdev->wext.bssid;
Johannes Berg04a773a2009-04-19 21:24:32 +0200496 } else
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200497 wdev->wext.ibss.bssid = NULL;
Johannes Berg04a773a2009-04-19 21:24:32 +0200498
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200499 mutex_lock(&rdev->devlist_mtx);
Johannes Bergfffd0932009-07-08 14:22:54 +0200500 wdev_lock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200501 err = cfg80211_ibss_wext_join(rdev, wdev);
Johannes Bergfffd0932009-07-08 14:22:54 +0200502 wdev_unlock(wdev);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200503 mutex_unlock(&rdev->devlist_mtx);
Johannes Bergfffd0932009-07-08 14:22:54 +0200504
505 return err;
Johannes Berg04a773a2009-04-19 21:24:32 +0200506}
Johannes Berg04a773a2009-04-19 21:24:32 +0200507
508int cfg80211_ibss_wext_giwap(struct net_device *dev,
509 struct iw_request_info *info,
510 struct sockaddr *ap_addr, char *extra)
511{
512 struct wireless_dev *wdev = dev->ieee80211_ptr;
513
514 /* call only for ibss! */
515 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
516 return -EINVAL;
517
518 ap_addr->sa_family = ARPHRD_ETHER;
519
Johannes Berg667503dd2009-07-07 03:56:11 +0200520 wdev_lock(wdev);
Johannes Berg7ebbe6b2009-07-01 21:26:48 +0200521 if (wdev->current_bss)
Johannes Berg19957bb2009-07-02 17:20:43 +0200522 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
Zhu Yi80e5b062009-07-09 16:59:49 +0800523 else if (wdev->wext.ibss.bssid)
Johannes Bergcbe8fa92009-05-09 20:09:03 +0200524 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
Zhu Yi80e5b062009-07-09 16:59:49 +0800525 else
526 memset(ap_addr->sa_data, 0, ETH_ALEN);
527
Johannes Berg667503dd2009-07-07 03:56:11 +0200528 wdev_unlock(wdev);
529
Johannes Berg04a773a2009-04-19 21:24:32 +0200530 return 0;
531}
Johannes Berg04a773a2009-04-19 21:24:32 +0200532#endif