2 * Some IBSS support code for cfg80211.
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
7 #include <linux/etherdevice.h>
8 #include <linux/if_arp.h>
9 #include <net/cfg80211.h>
10 #include "wext-compat.h"
14 void __cfg80211_ibss_joined(struct net_device
*dev
, const u8
*bssid
)
16 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
17 struct cfg80211_bss
*bss
;
18 #ifdef CONFIG_WIRELESS_EXT
19 union iwreq_data wrqu
;
22 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
28 bss
= cfg80211_get_bss(wdev
->wiphy
, NULL
, bssid
,
29 wdev
->ssid
, wdev
->ssid_len
,
30 WLAN_CAPABILITY_IBSS
, WLAN_CAPABILITY_IBSS
);
35 if (wdev
->current_bss
) {
36 cfg80211_unhold_bss(wdev
->current_bss
);
37 cfg80211_put_bss(&wdev
->current_bss
->pub
);
40 cfg80211_hold_bss(bss_from_pub(bss
));
41 wdev
->current_bss
= bss_from_pub(bss
);
43 cfg80211_upload_connect_keys(wdev
);
45 nl80211_send_ibss_bssid(wiphy_to_dev(wdev
->wiphy
), dev
, bssid
,
47 #ifdef CONFIG_WIRELESS_EXT
48 memset(&wrqu
, 0, sizeof(wrqu
));
49 memcpy(wrqu
.ap_addr
.sa_data
, bssid
, ETH_ALEN
);
50 wireless_send_event(dev
, SIOCGIWAP
, &wrqu
, NULL
);
54 void cfg80211_ibss_joined(struct net_device
*dev
, const u8
*bssid
, gfp_t gfp
)
56 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
57 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
58 struct cfg80211_event
*ev
;
61 CFG80211_DEV_WARN_ON(!wdev
->ssid_len
);
63 ev
= kzalloc(sizeof(*ev
), gfp
);
67 ev
->type
= EVENT_IBSS_JOINED
;
68 memcpy(ev
->cr
.bssid
, bssid
, ETH_ALEN
);
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
);
75 EXPORT_SYMBOL(cfg80211_ibss_joined
);
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
)
82 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
83 struct ieee80211_channel
*chan
;
86 ASSERT_WDEV_LOCK(wdev
);
88 chan
= rdev_fixed_channel(rdev
, wdev
);
89 if (chan
&& chan
!= params
->channel
)
95 if (WARN_ON(wdev
->connect_keys
))
96 kfree(wdev
->connect_keys
);
97 wdev
->connect_keys
= connkeys
;
99 #ifdef CONFIG_WIRELESS_EXT
100 wdev
->wext
.ibss
.channel
= params
->channel
;
102 err
= rdev
->ops
->join_ibss(&rdev
->wiphy
, dev
, params
);
104 wdev
->connect_keys
= NULL
;
108 memcpy(wdev
->ssid
, params
->ssid
, params
->ssid_len
);
109 wdev
->ssid_len
= params
->ssid_len
;
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
)
119 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
122 mutex_lock(&rdev
->devlist_mtx
);
124 err
= __cfg80211_join_ibss(rdev
, dev
, params
, connkeys
);
126 mutex_unlock(&rdev
->devlist_mtx
);
131 static void __cfg80211_clear_ibss(struct net_device
*dev
, bool nowext
)
133 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
134 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
137 ASSERT_WDEV_LOCK(wdev
);
139 kfree(wdev
->connect_keys
);
140 wdev
->connect_keys
= NULL
;
143 * Delete all the keys ... pairwise keys can't really
144 * exist any more anyway, but default keys might.
146 if (rdev
->ops
->del_key
)
147 for (i
= 0; i
< 6; i
++)
148 rdev
->ops
->del_key(wdev
->wiphy
, dev
, i
, NULL
);
150 if (wdev
->current_bss
) {
151 cfg80211_unhold_bss(wdev
->current_bss
);
152 cfg80211_put_bss(&wdev
->current_bss
->pub
);
155 wdev
->current_bss
= NULL
;
157 #ifdef CONFIG_WIRELESS_EXT
159 wdev
->wext
.ibss
.ssid_len
= 0;
163 void cfg80211_clear_ibss(struct net_device
*dev
, bool nowext
)
165 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
168 __cfg80211_clear_ibss(dev
, nowext
);
172 static int __cfg80211_leave_ibss(struct cfg80211_registered_device
*rdev
,
173 struct net_device
*dev
, bool nowext
)
175 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
178 ASSERT_WDEV_LOCK(wdev
);
183 err
= rdev
->ops
->leave_ibss(&rdev
->wiphy
, dev
);
188 __cfg80211_clear_ibss(dev
, nowext
);
193 int cfg80211_leave_ibss(struct cfg80211_registered_device
*rdev
,
194 struct net_device
*dev
, bool nowext
)
196 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
200 err
= __cfg80211_leave_ibss(rdev
, dev
, nowext
);
206 #ifdef CONFIG_WIRELESS_EXT
207 int cfg80211_ibss_wext_join(struct cfg80211_registered_device
*rdev
,
208 struct wireless_dev
*wdev
)
210 struct cfg80211_cached_keys
*ck
= NULL
;
211 enum ieee80211_band band
;
214 ASSERT_WDEV_LOCK(wdev
);
216 if (!wdev
->wext
.ibss
.beacon_interval
)
217 wdev
->wext
.ibss
.beacon_interval
= 100;
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
;
225 sband
= rdev
->wiphy
.bands
[band
];
229 for (i
= 0; i
< sband
->n_channels
; i
++) {
230 chan
= &sband
->channels
[i
];
231 if (chan
->flags
& IEEE80211_CHAN_NO_IBSS
)
233 if (chan
->flags
& IEEE80211_CHAN_DISABLED
)
235 wdev
->wext
.ibss
.channel
= chan
;
239 if (wdev
->wext
.ibss
.channel
)
243 if (!wdev
->wext
.ibss
.channel
)
247 /* don't join -- SSID is not there */
248 if (!wdev
->wext
.ibss
.ssid_len
)
251 if (!netif_running(wdev
->netdev
))
255 wdev
->wext
.keys
->def
= wdev
->wext
.default_key
;
257 wdev
->wext
.ibss
.privacy
= wdev
->wext
.default_key
!= -1;
259 if (wdev
->wext
.keys
) {
260 ck
= kmemdup(wdev
->wext
.keys
, sizeof(*ck
), GFP_KERNEL
);
263 for (i
= 0; i
< 6; i
++)
264 ck
->params
[i
].key
= ck
->data
[i
];
266 err
= __cfg80211_join_ibss(rdev
, wdev
->netdev
,
267 &wdev
->wext
.ibss
, ck
);
274 int cfg80211_ibss_wext_siwfreq(struct net_device
*dev
,
275 struct iw_request_info
*info
,
276 struct iw_freq
*wextfreq
, char *extra
)
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
;
283 /* call only for ibss! */
284 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
287 if (!rdev
->ops
->join_ibss
)
290 freq
= cfg80211_wext_freq(wdev
->wiphy
, wextfreq
);
295 chan
= ieee80211_get_channel(wdev
->wiphy
, freq
);
298 if (chan
->flags
& IEEE80211_CHAN_NO_IBSS
||
299 chan
->flags
& IEEE80211_CHAN_DISABLED
)
303 if (wdev
->wext
.ibss
.channel
== chan
)
309 err
= __cfg80211_leave_ibss(rdev
, dev
, true);
316 wdev
->wext
.ibss
.channel
= chan
;
317 wdev
->wext
.ibss
.channel_fixed
= true;
319 /* cfg80211_ibss_wext_join will pick one if needed */
320 wdev
->wext
.ibss
.channel_fixed
= false;
323 mutex_lock(&rdev
->devlist_mtx
);
325 err
= cfg80211_ibss_wext_join(rdev
, wdev
);
327 mutex_unlock(&rdev
->devlist_mtx
);
332 int cfg80211_ibss_wext_giwfreq(struct net_device
*dev
,
333 struct iw_request_info
*info
,
334 struct iw_freq
*freq
, char *extra
)
336 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
337 struct ieee80211_channel
*chan
= NULL
;
339 /* call only for ibss! */
340 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
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
;
351 freq
->m
= chan
->center_freq
;
356 /* no channel if not joining */
360 int cfg80211_ibss_wext_siwessid(struct net_device
*dev
,
361 struct iw_request_info
*info
,
362 struct iw_point
*data
, char *ssid
)
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
;
369 /* call only for ibss! */
370 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
373 if (!rdev
->ops
->join_ibss
)
379 err
= __cfg80211_leave_ibss(rdev
, dev
, true);
385 /* iwconfig uses nul termination in SSID.. */
386 if (len
> 0 && ssid
[len
- 1] == '\0')
389 wdev
->wext
.ibss
.ssid
= wdev
->ssid
;
390 memcpy(wdev
->wext
.ibss
.ssid
, ssid
, len
);
391 wdev
->wext
.ibss
.ssid_len
= len
;
393 mutex_lock(&rdev
->devlist_mtx
);
395 err
= cfg80211_ibss_wext_join(rdev
, wdev
);
397 mutex_unlock(&rdev
->devlist_mtx
);
402 int cfg80211_ibss_wext_giwessid(struct net_device
*dev
,
403 struct iw_request_info
*info
,
404 struct iw_point
*data
, char *ssid
)
406 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
408 /* call only for ibss! */
409 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
415 if (wdev
->ssid_len
) {
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
) {
421 data
->length
= wdev
->wext
.ibss
.ssid_len
;
422 memcpy(ssid
, wdev
->wext
.ibss
.ssid
, data
->length
);
429 int cfg80211_ibss_wext_siwap(struct net_device
*dev
,
430 struct iw_request_info
*info
,
431 struct sockaddr
*ap_addr
, char *extra
)
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
;
438 /* call only for ibss! */
439 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
442 if (!rdev
->ops
->join_ibss
)
445 if (ap_addr
->sa_family
!= ARPHRD_ETHER
)
449 if (is_zero_ether_addr(bssid
) || is_broadcast_ether_addr(bssid
))
453 if (!bssid
&& !wdev
->wext
.ibss
.bssid
)
456 /* fixed already - and no change */
457 if (wdev
->wext
.ibss
.bssid
&& bssid
&&
458 compare_ether_addr(bssid
, wdev
->wext
.ibss
.bssid
) == 0)
464 err
= __cfg80211_leave_ibss(rdev
, dev
, true);
471 memcpy(wdev
->wext
.bssid
, bssid
, ETH_ALEN
);
472 wdev
->wext
.ibss
.bssid
= wdev
->wext
.bssid
;
474 wdev
->wext
.ibss
.bssid
= NULL
;
476 mutex_lock(&rdev
->devlist_mtx
);
478 err
= cfg80211_ibss_wext_join(rdev
, wdev
);
480 mutex_unlock(&rdev
->devlist_mtx
);
485 int cfg80211_ibss_wext_giwap(struct net_device
*dev
,
486 struct iw_request_info
*info
,
487 struct sockaddr
*ap_addr
, char *extra
)
489 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
491 /* call only for ibss! */
492 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
495 ap_addr
->sa_family
= ARPHRD_ETHER
;
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
);
503 memset(ap_addr
->sa_data
, 0, ETH_ALEN
);