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>
13 void cfg80211_ibss_joined(struct net_device
*dev
, const u8
*bssid
, gfp_t gfp
)
15 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
16 struct cfg80211_bss
*bss
;
17 #ifdef CONFIG_WIRELESS_EXT
18 union iwreq_data wrqu
;
21 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
24 if (WARN_ON(!wdev
->ssid_len
))
27 if (memcmp(bssid
, wdev
->bssid
, ETH_ALEN
) == 0)
30 bss
= cfg80211_get_bss(wdev
->wiphy
, NULL
, bssid
,
31 wdev
->ssid
, wdev
->ssid_len
,
32 WLAN_CAPABILITY_IBSS
, WLAN_CAPABILITY_IBSS
);
37 if (wdev
->current_bss
) {
38 cfg80211_unhold_bss(wdev
->current_bss
);
39 cfg80211_put_bss(wdev
->current_bss
);
42 cfg80211_hold_bss(bss
);
43 wdev
->current_bss
= bss
;
44 memcpy(wdev
->bssid
, bssid
, ETH_ALEN
);
46 nl80211_send_ibss_bssid(wiphy_to_dev(wdev
->wiphy
), dev
, bssid
, gfp
);
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
);
53 EXPORT_SYMBOL(cfg80211_ibss_joined
);
55 int cfg80211_join_ibss(struct cfg80211_registered_device
*rdev
,
56 struct net_device
*dev
,
57 struct cfg80211_ibss_params
*params
)
59 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
65 #ifdef CONFIG_WIRELESS_EXT
66 wdev
->wext
.ibss
.channel
= params
->channel
;
68 err
= rdev
->ops
->join_ibss(&rdev
->wiphy
, dev
, params
);
73 memcpy(wdev
->ssid
, params
->ssid
, params
->ssid_len
);
74 wdev
->ssid_len
= params
->ssid_len
;
79 void cfg80211_clear_ibss(struct net_device
*dev
, bool nowext
)
81 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
83 if (wdev
->current_bss
) {
84 cfg80211_unhold_bss(wdev
->current_bss
);
85 cfg80211_put_bss(wdev
->current_bss
);
88 wdev
->current_bss
= NULL
;
90 memset(wdev
->bssid
, 0, ETH_ALEN
);
91 #ifdef CONFIG_WIRELESS_EXT
93 wdev
->wext
.ibss
.ssid_len
= 0;
97 int cfg80211_leave_ibss(struct cfg80211_registered_device
*rdev
,
98 struct net_device
*dev
, bool nowext
)
102 err
= rdev
->ops
->leave_ibss(&rdev
->wiphy
, dev
);
107 cfg80211_clear_ibss(dev
, nowext
);
112 #ifdef CONFIG_WIRELESS_EXT
113 static int cfg80211_ibss_wext_join(struct cfg80211_registered_device
*rdev
,
114 struct wireless_dev
*wdev
)
116 enum ieee80211_band band
;
119 if (!wdev
->wext
.ibss
.beacon_interval
)
120 wdev
->wext
.ibss
.beacon_interval
= 100;
122 /* try to find an IBSS channel if none requested ... */
123 if (!wdev
->wext
.ibss
.channel
) {
124 for (band
= 0; band
< IEEE80211_NUM_BANDS
; band
++) {
125 struct ieee80211_supported_band
*sband
;
126 struct ieee80211_channel
*chan
;
128 sband
= rdev
->wiphy
.bands
[band
];
132 for (i
= 0; i
< sband
->n_channels
; i
++) {
133 chan
= &sband
->channels
[i
];
134 if (chan
->flags
& IEEE80211_CHAN_NO_IBSS
)
136 if (chan
->flags
& IEEE80211_CHAN_DISABLED
)
138 wdev
->wext
.ibss
.channel
= chan
;
142 if (wdev
->wext
.ibss
.channel
)
146 if (!wdev
->wext
.ibss
.channel
)
150 /* don't join -- SSID is not there */
151 if (!wdev
->wext
.ibss
.ssid_len
)
154 if (!netif_running(wdev
->netdev
))
157 return cfg80211_join_ibss(wiphy_to_dev(wdev
->wiphy
),
158 wdev
->netdev
, &wdev
->wext
.ibss
);
161 int cfg80211_ibss_wext_siwfreq(struct net_device
*dev
,
162 struct iw_request_info
*info
,
163 struct iw_freq
*freq
, char *extra
)
165 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
166 struct ieee80211_channel
*chan
;
169 /* call only for ibss! */
170 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
173 if (!wiphy_to_dev(wdev
->wiphy
)->ops
->join_ibss
)
176 chan
= cfg80211_wext_freq(wdev
->wiphy
, freq
);
177 if (chan
&& IS_ERR(chan
))
178 return PTR_ERR(chan
);
181 (chan
->flags
& IEEE80211_CHAN_NO_IBSS
||
182 chan
->flags
& IEEE80211_CHAN_DISABLED
))
185 if (wdev
->wext
.ibss
.channel
== chan
)
188 if (wdev
->ssid_len
) {
189 err
= cfg80211_leave_ibss(wiphy_to_dev(wdev
->wiphy
),
196 wdev
->wext
.ibss
.channel
= chan
;
197 wdev
->wext
.ibss
.channel_fixed
= true;
199 /* cfg80211_ibss_wext_join will pick one if needed */
200 wdev
->wext
.ibss
.channel_fixed
= false;
203 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev
->wiphy
), wdev
);
205 /* temporary symbol - mark GPL - in the future the handler won't be */
206 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq
);
208 int cfg80211_ibss_wext_giwfreq(struct net_device
*dev
,
209 struct iw_request_info
*info
,
210 struct iw_freq
*freq
, char *extra
)
212 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
213 struct ieee80211_channel
*chan
= NULL
;
215 /* call only for ibss! */
216 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
219 if (wdev
->current_bss
)
220 chan
= wdev
->current_bss
->channel
;
221 else if (wdev
->wext
.ibss
.channel
)
222 chan
= wdev
->wext
.ibss
.channel
;
225 freq
->m
= chan
->center_freq
;
230 /* no channel if not joining */
233 /* temporary symbol - mark GPL - in the future the handler won't be */
234 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq
);
236 int cfg80211_ibss_wext_siwessid(struct net_device
*dev
,
237 struct iw_request_info
*info
,
238 struct iw_point
*data
, char *ssid
)
240 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
241 size_t len
= data
->length
;
244 /* call only for ibss! */
245 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
248 if (!wiphy_to_dev(wdev
->wiphy
)->ops
->join_ibss
)
251 if (wdev
->ssid_len
) {
252 err
= cfg80211_leave_ibss(wiphy_to_dev(wdev
->wiphy
),
258 /* iwconfig uses nul termination in SSID.. */
259 if (len
> 0 && ssid
[len
- 1] == '\0')
262 wdev
->wext
.ibss
.ssid
= wdev
->ssid
;
263 memcpy(wdev
->wext
.ibss
.ssid
, ssid
, len
);
264 wdev
->wext
.ibss
.ssid_len
= len
;
266 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev
->wiphy
), wdev
);
268 /* temporary symbol - mark GPL - in the future the handler won't be */
269 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid
);
271 int cfg80211_ibss_wext_giwessid(struct net_device
*dev
,
272 struct iw_request_info
*info
,
273 struct iw_point
*data
, char *ssid
)
275 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
277 /* call only for ibss! */
278 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
283 if (wdev
->ssid_len
) {
285 data
->length
= wdev
->ssid_len
;
286 memcpy(ssid
, wdev
->ssid
, data
->length
);
287 } else if (wdev
->wext
.ibss
.ssid
&& wdev
->wext
.ibss
.ssid_len
) {
289 data
->length
= wdev
->wext
.ibss
.ssid_len
;
290 memcpy(ssid
, wdev
->wext
.ibss
.ssid
, data
->length
);
295 /* temporary symbol - mark GPL - in the future the handler won't be */
296 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid
);
298 int cfg80211_ibss_wext_siwap(struct net_device
*dev
,
299 struct iw_request_info
*info
,
300 struct sockaddr
*ap_addr
, char *extra
)
302 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
303 u8
*bssid
= ap_addr
->sa_data
;
306 /* call only for ibss! */
307 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
310 if (!wiphy_to_dev(wdev
->wiphy
)->ops
->join_ibss
)
313 if (ap_addr
->sa_family
!= ARPHRD_ETHER
)
317 if (is_zero_ether_addr(bssid
) || is_broadcast_ether_addr(bssid
))
321 if (!bssid
&& !wdev
->wext
.ibss
.bssid
)
324 /* fixed already - and no change */
325 if (wdev
->wext
.ibss
.bssid
&& bssid
&&
326 compare_ether_addr(bssid
, wdev
->wext
.ibss
.bssid
) == 0)
329 if (wdev
->ssid_len
) {
330 err
= cfg80211_leave_ibss(wiphy_to_dev(wdev
->wiphy
),
337 memcpy(wdev
->wext
.bssid
, bssid
, ETH_ALEN
);
338 wdev
->wext
.ibss
.bssid
= wdev
->wext
.bssid
;
340 wdev
->wext
.ibss
.bssid
= NULL
;
342 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev
->wiphy
), wdev
);
344 /* temporary symbol - mark GPL - in the future the handler won't be */
345 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap
);
347 int cfg80211_ibss_wext_giwap(struct net_device
*dev
,
348 struct iw_request_info
*info
,
349 struct sockaddr
*ap_addr
, char *extra
)
351 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
353 /* call only for ibss! */
354 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
357 ap_addr
->sa_family
= ARPHRD_ETHER
;
359 if (wdev
->wext
.ibss
.bssid
) {
360 memcpy(ap_addr
->sa_data
, wdev
->wext
.ibss
.bssid
, ETH_ALEN
);
364 memcpy(ap_addr
->sa_data
, wdev
->bssid
, ETH_ALEN
);
367 /* temporary symbol - mark GPL - in the future the handler won't be */
368 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap
);