cfg80211: clean up includes
[pandora-kernel.git] / net / wireless / ibss.c
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 <net/cfg80211.h>
10 #include "nl80211.h"
11
12
13 void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
14 {
15         struct wireless_dev *wdev = dev->ieee80211_ptr;
16         struct cfg80211_bss *bss;
17 #ifdef CONFIG_WIRELESS_EXT
18         union iwreq_data wrqu;
19 #endif
20
21         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
22                 return;
23
24         if (WARN_ON(!wdev->ssid_len))
25                 return;
26
27         if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0)
28                 return;
29
30         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);
39                 cfg80211_put_bss(wdev->current_bss);
40         }
41
42         cfg80211_hold_bss(bss);
43         wdev->current_bss = bss;
44         memcpy(wdev->bssid, bssid, ETH_ALEN);
45
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);
51 #endif
52 }
53 EXPORT_SYMBOL(cfg80211_ibss_joined);
54
55 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
56                        struct net_device *dev,
57                        struct cfg80211_ibss_params *params)
58 {
59         struct wireless_dev *wdev = dev->ieee80211_ptr;
60         int err;
61
62         if (wdev->ssid_len)
63                 return -EALREADY;
64
65 #ifdef CONFIG_WIRELESS_EXT
66         wdev->wext.channel = params->channel;
67 #endif
68         err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
69
70         if (err)
71                 return err;
72
73         memcpy(wdev->ssid, params->ssid, params->ssid_len);
74         wdev->ssid_len = params->ssid_len;
75
76         return 0;
77 }
78
79 void cfg80211_clear_ibss(struct net_device *dev)
80 {
81         struct wireless_dev *wdev = dev->ieee80211_ptr;
82
83         if (wdev->current_bss) {
84                 cfg80211_unhold_bss(wdev->current_bss);
85                 cfg80211_put_bss(wdev->current_bss);
86         }
87
88         wdev->current_bss = NULL;
89         wdev->ssid_len = 0;
90         memset(wdev->bssid, 0, ETH_ALEN);
91 }
92
93 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
94                         struct net_device *dev)
95 {
96         int err;
97
98         err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
99
100         if (err)
101                 return err;
102
103         cfg80211_clear_ibss(dev);
104
105         return 0;
106 }
107
108 #ifdef CONFIG_WIRELESS_EXT
109 static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
110                                    struct wireless_dev *wdev)
111 {
112         enum ieee80211_band band;
113         int i;
114
115         /* try to find an IBSS channel if none requested ... */
116         if (!wdev->wext.channel) {
117                 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
118                         struct ieee80211_supported_band *sband;
119                         struct ieee80211_channel *chan;
120
121                         sband = rdev->wiphy.bands[band];
122                         if (!sband)
123                                 continue;
124
125                         for (i = 0; i < sband->n_channels; i++) {
126                                 chan = &sband->channels[i];
127                                 if (chan->flags & IEEE80211_CHAN_NO_IBSS)
128                                         continue;
129                                 if (chan->flags & IEEE80211_CHAN_DISABLED)
130                                         continue;
131                                 wdev->wext.channel = chan;
132                                 break;
133                         }
134
135                         if (wdev->wext.channel)
136                                 break;
137                 }
138
139                 if (!wdev->wext.channel)
140                         return -EINVAL;
141         }
142
143         /* don't join -- SSID is not there */
144         if (!wdev->wext.ssid_len)
145                 return 0;
146
147         if (!netif_running(wdev->netdev))
148                 return 0;
149
150         return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
151                                   wdev->netdev, &wdev->wext);
152 }
153
154 int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
155                                struct iw_request_info *info,
156                                struct iw_freq *freq, char *extra)
157 {
158         struct wireless_dev *wdev = dev->ieee80211_ptr;
159         struct ieee80211_channel *chan;
160         int err;
161
162         /* call only for ibss! */
163         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
164                 return -EINVAL;
165
166         if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
167                 return -EOPNOTSUPP;
168
169         chan = cfg80211_wext_freq(wdev->wiphy, freq);
170         if (chan && IS_ERR(chan))
171                 return PTR_ERR(chan);
172
173         if (chan &&
174             (chan->flags & IEEE80211_CHAN_NO_IBSS ||
175              chan->flags & IEEE80211_CHAN_DISABLED))
176                 return -EINVAL;
177
178         if (wdev->wext.channel == chan)
179                 return 0;
180
181         if (wdev->ssid_len) {
182                 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
183                 if (err)
184                         return err;
185         }
186
187         if (chan) {
188                 wdev->wext.channel = chan;
189                 wdev->wext.channel_fixed = true;
190         } else {
191                 /* cfg80211_ibss_wext_join will pick one if needed */
192                 wdev->wext.channel_fixed = false;
193         }
194
195         return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
196 }
197 /* temporary symbol - mark GPL - in the future the handler won't be */
198 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
199
200 int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
201                                struct iw_request_info *info,
202                                struct iw_freq *freq, char *extra)
203 {
204         struct wireless_dev *wdev = dev->ieee80211_ptr;
205         struct ieee80211_channel *chan = NULL;
206
207         /* call only for ibss! */
208         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
209                 return -EINVAL;
210
211         if (wdev->current_bss)
212                 chan = wdev->current_bss->channel;
213         else if (wdev->wext.channel)
214                 chan = wdev->wext.channel;
215
216         if (chan) {
217                 freq->m = chan->center_freq;
218                 freq->e = 6;
219                 return 0;
220         }
221
222         /* no channel if not joining */
223         return -EINVAL;
224 }
225 /* temporary symbol - mark GPL - in the future the handler won't be */
226 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq);
227
228 int cfg80211_ibss_wext_siwessid(struct net_device *dev,
229                                 struct iw_request_info *info,
230                                 struct iw_point *data, char *ssid)
231 {
232         struct wireless_dev *wdev = dev->ieee80211_ptr;
233         size_t len = data->length;
234         int err;
235
236         /* call only for ibss! */
237         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
238                 return -EINVAL;
239
240         if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
241                 return -EOPNOTSUPP;
242
243         if (wdev->ssid_len) {
244                 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
245                 if (err)
246                         return err;
247         }
248
249         /* iwconfig uses nul termination in SSID.. */
250         if (len > 0 && ssid[len - 1] == '\0')
251                 len--;
252
253         wdev->wext.ssid = wdev->ssid;
254         memcpy(wdev->wext.ssid, ssid, len);
255         wdev->wext.ssid_len = len;
256
257         return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
258 }
259 /* temporary symbol - mark GPL - in the future the handler won't be */
260 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
261
262 int cfg80211_ibss_wext_giwessid(struct net_device *dev,
263                                 struct iw_request_info *info,
264                                 struct iw_point *data, char *ssid)
265 {
266         struct wireless_dev *wdev = dev->ieee80211_ptr;
267
268         /* call only for ibss! */
269         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
270                 return -EINVAL;
271
272         data->flags = 0;
273
274         if (wdev->ssid_len) {
275                 data->flags = 1;
276                 data->length = wdev->ssid_len;
277                 memcpy(ssid, wdev->ssid, data->length);
278         } else if (wdev->wext.ssid) {
279                 data->flags = 1;
280                 data->length = wdev->wext.ssid_len;
281                 memcpy(ssid, wdev->wext.ssid, data->length);
282         }
283
284         return 0;
285 }
286 /* temporary symbol - mark GPL - in the future the handler won't be */
287 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid);
288
289 int cfg80211_ibss_wext_siwap(struct net_device *dev,
290                              struct iw_request_info *info,
291                              struct sockaddr *ap_addr, char *extra)
292 {
293         struct wireless_dev *wdev = dev->ieee80211_ptr;
294         u8 *bssid = ap_addr->sa_data;
295         int err;
296
297         /* call only for ibss! */
298         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
299                 return -EINVAL;
300
301         if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
302                 return -EOPNOTSUPP;
303
304         if (ap_addr->sa_family != ARPHRD_ETHER)
305                 return -EINVAL;
306
307         /* automatic mode */
308         if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
309                 bssid = NULL;
310
311         /* both automatic */
312         if (!bssid && !wdev->wext.bssid)
313                 return 0;
314
315         /* fixed already - and no change */
316         if (wdev->wext.bssid && bssid &&
317             compare_ether_addr(bssid, wdev->wext.bssid) == 0)
318                 return 0;
319
320         if (wdev->ssid_len) {
321                 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
322                 if (err)
323                         return err;
324         }
325
326         if (bssid) {
327                 memcpy(wdev->wext_bssid, bssid, ETH_ALEN);
328                 wdev->wext.bssid = wdev->wext_bssid;
329         } else
330                 wdev->wext.bssid = NULL;
331
332         return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
333 }
334 /* temporary symbol - mark GPL - in the future the handler won't be */
335 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
336
337 int cfg80211_ibss_wext_giwap(struct net_device *dev,
338                              struct iw_request_info *info,
339                              struct sockaddr *ap_addr, char *extra)
340 {
341         struct wireless_dev *wdev = dev->ieee80211_ptr;
342
343         /* call only for ibss! */
344         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
345                 return -EINVAL;
346
347         ap_addr->sa_family = ARPHRD_ETHER;
348
349         if (wdev->wext.bssid) {
350                 memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN);
351                 return 0;
352         }
353
354         memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN);
355         return 0;
356 }
357 /* temporary symbol - mark GPL - in the future the handler won't be */
358 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
359 #endif