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
.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
.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 /* try to find an IBSS channel if none requested ... */
120 if (!wdev
->wext
.channel
) {
121 for (band
= 0; band
< IEEE80211_NUM_BANDS
; band
++) {
122 struct ieee80211_supported_band
*sband
;
123 struct ieee80211_channel
*chan
;
125 sband
= rdev
->wiphy
.bands
[band
];
129 for (i
= 0; i
< sband
->n_channels
; i
++) {
130 chan
= &sband
->channels
[i
];
131 if (chan
->flags
& IEEE80211_CHAN_NO_IBSS
)
133 if (chan
->flags
& IEEE80211_CHAN_DISABLED
)
135 wdev
->wext
.channel
= chan
;
139 if (wdev
->wext
.channel
)
143 if (!wdev
->wext
.channel
)
147 /* don't join -- SSID is not there */
148 if (!wdev
->wext
.ssid_len
)
151 if (!netif_running(wdev
->netdev
))
154 return cfg80211_join_ibss(wiphy_to_dev(wdev
->wiphy
),
155 wdev
->netdev
, &wdev
->wext
);
158 int cfg80211_ibss_wext_siwfreq(struct net_device
*dev
,
159 struct iw_request_info
*info
,
160 struct iw_freq
*freq
, char *extra
)
162 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
163 struct ieee80211_channel
*chan
;
166 /* call only for ibss! */
167 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
170 if (!wiphy_to_dev(wdev
->wiphy
)->ops
->join_ibss
)
173 chan
= cfg80211_wext_freq(wdev
->wiphy
, freq
);
174 if (chan
&& IS_ERR(chan
))
175 return PTR_ERR(chan
);
178 (chan
->flags
& IEEE80211_CHAN_NO_IBSS
||
179 chan
->flags
& IEEE80211_CHAN_DISABLED
))
182 if (wdev
->wext
.channel
== chan
)
185 if (wdev
->ssid_len
) {
186 err
= cfg80211_leave_ibss(wiphy_to_dev(wdev
->wiphy
),
193 wdev
->wext
.channel
= chan
;
194 wdev
->wext
.channel_fixed
= true;
196 /* cfg80211_ibss_wext_join will pick one if needed */
197 wdev
->wext
.channel_fixed
= false;
200 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev
->wiphy
), wdev
);
202 /* temporary symbol - mark GPL - in the future the handler won't be */
203 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq
);
205 int cfg80211_ibss_wext_giwfreq(struct net_device
*dev
,
206 struct iw_request_info
*info
,
207 struct iw_freq
*freq
, char *extra
)
209 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
210 struct ieee80211_channel
*chan
= NULL
;
212 /* call only for ibss! */
213 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
216 if (wdev
->current_bss
)
217 chan
= wdev
->current_bss
->channel
;
218 else if (wdev
->wext
.channel
)
219 chan
= wdev
->wext
.channel
;
222 freq
->m
= chan
->center_freq
;
227 /* no channel if not joining */
230 /* temporary symbol - mark GPL - in the future the handler won't be */
231 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq
);
233 int cfg80211_ibss_wext_siwessid(struct net_device
*dev
,
234 struct iw_request_info
*info
,
235 struct iw_point
*data
, char *ssid
)
237 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
238 size_t len
= data
->length
;
241 /* call only for ibss! */
242 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
245 if (!wiphy_to_dev(wdev
->wiphy
)->ops
->join_ibss
)
248 if (wdev
->ssid_len
) {
249 err
= cfg80211_leave_ibss(wiphy_to_dev(wdev
->wiphy
),
255 /* iwconfig uses nul termination in SSID.. */
256 if (len
> 0 && ssid
[len
- 1] == '\0')
259 wdev
->wext
.ssid
= wdev
->ssid
;
260 memcpy(wdev
->wext
.ssid
, ssid
, len
);
261 wdev
->wext
.ssid_len
= len
;
263 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev
->wiphy
), wdev
);
265 /* temporary symbol - mark GPL - in the future the handler won't be */
266 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid
);
268 int cfg80211_ibss_wext_giwessid(struct net_device
*dev
,
269 struct iw_request_info
*info
,
270 struct iw_point
*data
, char *ssid
)
272 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
274 /* call only for ibss! */
275 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
280 if (wdev
->ssid_len
) {
282 data
->length
= wdev
->ssid_len
;
283 memcpy(ssid
, wdev
->ssid
, data
->length
);
284 } else if (wdev
->wext
.ssid
&& wdev
->wext
.ssid_len
) {
286 data
->length
= wdev
->wext
.ssid_len
;
287 memcpy(ssid
, wdev
->wext
.ssid
, data
->length
);
292 /* temporary symbol - mark GPL - in the future the handler won't be */
293 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid
);
295 int cfg80211_ibss_wext_siwap(struct net_device
*dev
,
296 struct iw_request_info
*info
,
297 struct sockaddr
*ap_addr
, char *extra
)
299 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
300 u8
*bssid
= ap_addr
->sa_data
;
303 /* call only for ibss! */
304 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
307 if (!wiphy_to_dev(wdev
->wiphy
)->ops
->join_ibss
)
310 if (ap_addr
->sa_family
!= ARPHRD_ETHER
)
314 if (is_zero_ether_addr(bssid
) || is_broadcast_ether_addr(bssid
))
318 if (!bssid
&& !wdev
->wext
.bssid
)
321 /* fixed already - and no change */
322 if (wdev
->wext
.bssid
&& bssid
&&
323 compare_ether_addr(bssid
, wdev
->wext
.bssid
) == 0)
326 if (wdev
->ssid_len
) {
327 err
= cfg80211_leave_ibss(wiphy_to_dev(wdev
->wiphy
),
334 memcpy(wdev
->wext_bssid
, bssid
, ETH_ALEN
);
335 wdev
->wext
.bssid
= wdev
->wext_bssid
;
337 wdev
->wext
.bssid
= NULL
;
339 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev
->wiphy
), wdev
);
341 /* temporary symbol - mark GPL - in the future the handler won't be */
342 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap
);
344 int cfg80211_ibss_wext_giwap(struct net_device
*dev
,
345 struct iw_request_info
*info
,
346 struct sockaddr
*ap_addr
, char *extra
)
348 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
350 /* call only for ibss! */
351 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_ADHOC
))
354 ap_addr
->sa_family
= ARPHRD_ETHER
;
356 if (wdev
->wext
.bssid
) {
357 memcpy(ap_addr
->sa_data
, wdev
->wext
.bssid
, ETH_ALEN
);
361 memcpy(ap_addr
->sa_data
, wdev
->bssid
, ETH_ALEN
);
364 /* temporary symbol - mark GPL - in the future the handler won't be */
365 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap
);