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