aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h18
-rw-r--r--include/net/cfg80211.h72
-rw-r--r--include/net/wireless.h14
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c16
-rw-r--r--net/wireless/core.h8
-rw-r--r--net/wireless/ibss.c360
-rw-r--r--net/wireless/nl80211.c182
-rw-r--r--net/wireless/nl80211.h4
-rw-r--r--net/wireless/wext-compat.c30
10 files changed, 693 insertions, 13 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index c01423888db9..25ce3e42bd10 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -223,6 +223,15 @@
223 * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this 223 * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
224 * event matches with MLME-MICHAELMICFAILURE.indication() primitive 224 * event matches with MLME-MICHAELMICFAILURE.indication() primitive
225 * 225 *
226 * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
227 * FREQ attribute (for the initial frequency if no peer can be found)
228 * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
229 * should be fixed rather than automatically determined. Can only be
230 * executed on a network interface that is UP, and fixed BSSID/FREQ
231 * may be rejected.
232 * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
233 * determined by the network interface.
234 *
226 * @NL80211_CMD_MAX: highest used command number 235 * @NL80211_CMD_MAX: highest used command number
227 * @__NL80211_CMD_AFTER_LAST: internal use 236 * @__NL80211_CMD_AFTER_LAST: internal use
228 */ 237 */
@@ -288,6 +297,9 @@ enum nl80211_commands {
288 297
289 NL80211_CMD_REG_BEACON_HINT, 298 NL80211_CMD_REG_BEACON_HINT,
290 299
300 NL80211_CMD_JOIN_IBSS,
301 NL80211_CMD_LEAVE_IBSS,
302
291 /* add new commands above here */ 303 /* add new commands above here */
292 304
293 /* used to define NL80211_CMD_MAX below */ 305 /* used to define NL80211_CMD_MAX below */
@@ -456,6 +468,9 @@ enum nl80211_commands {
456 * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported 468 * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
457 * cipher suites 469 * cipher suites
458 * 470 *
471 * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
472 * for other networks on different channels
473 *
459 * @NL80211_ATTR_MAX: highest attribute number currently defined 474 * @NL80211_ATTR_MAX: highest attribute number currently defined
460 * @__NL80211_ATTR_AFTER_LAST: internal use 475 * @__NL80211_ATTR_AFTER_LAST: internal use
461 */ 476 */
@@ -547,6 +562,9 @@ enum nl80211_attrs {
547 562
548 NL80211_ATTR_FREQ_BEFORE, 563 NL80211_ATTR_FREQ_BEFORE,
549 NL80211_ATTR_FREQ_AFTER, 564 NL80211_ATTR_FREQ_AFTER,
565
566 NL80211_ATTR_FREQ_FIXED,
567
550 /* add attributes here, update the policy in nl80211.c */ 568 /* add attributes here, update the policy in nl80211.c */
551 569
552 __NL80211_ATTR_AFTER_LAST, 570 __NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 019a41efa0bb..5287a3e56e7c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -658,6 +658,31 @@ struct cfg80211_disassoc_request {
658}; 658};
659 659
660/** 660/**
661 * struct cfg80211_ibss_params - IBSS parameters
662 *
663 * This structure defines the IBSS parameters for the join_ibss()
664 * method.
665 *
666 * @ssid: The SSID, will always be non-null.
667 * @ssid_len: The length of the SSID, will always be non-zero.
668 * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not
669 * search for IBSSs with a different BSSID.
670 * @channel: The channel to use if no IBSS can be found to join.
671 * @channel_fixed: The channel should be fixed -- do not search for
672 * IBSSs to join on other channels.
673 * @ie: information element(s) to include in the beacon
674 * @ie_len: length of that
675 */
676struct cfg80211_ibss_params {
677 u8 *ssid;
678 u8 *bssid;
679 struct ieee80211_channel *channel;
680 u8 *ie;
681 u8 ssid_len, ie_len;
682 bool channel_fixed;
683};
684
685/**
661 * struct cfg80211_ops - backend description for wireless configuration 686 * struct cfg80211_ops - backend description for wireless configuration
662 * 687 *
663 * This struct is registered by fullmac card drivers and/or wireless stacks 688 * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -732,6 +757,11 @@ struct cfg80211_disassoc_request {
732 * @assoc: Request to (re)associate with the specified peer 757 * @assoc: Request to (re)associate with the specified peer
733 * @deauth: Request to deauthenticate from the specified peer 758 * @deauth: Request to deauthenticate from the specified peer
734 * @disassoc: Request to disassociate from the specified peer 759 * @disassoc: Request to disassociate from the specified peer
760 *
761 * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
762 * cfg80211_ibss_joined(), also call that function when changing BSSID due
763 * to a merge.
764 * @leave_ibss: Leave the IBSS.
735 */ 765 */
736struct cfg80211_ops { 766struct cfg80211_ops {
737 int (*suspend)(struct wiphy *wiphy); 767 int (*suspend)(struct wiphy *wiphy);
@@ -817,6 +847,10 @@ struct cfg80211_ops {
817 struct cfg80211_deauth_request *req); 847 struct cfg80211_deauth_request *req);
818 int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, 848 int (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
819 struct cfg80211_disassoc_request *req); 849 struct cfg80211_disassoc_request *req);
850
851 int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev,
852 struct cfg80211_ibss_params *params);
853 int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
820}; 854};
821 855
822/* temporary wext handlers */ 856/* temporary wext handlers */
@@ -839,6 +873,28 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
839int cfg80211_wext_giwrange(struct net_device *dev, 873int cfg80211_wext_giwrange(struct net_device *dev,
840 struct iw_request_info *info, 874 struct iw_request_info *info,
841 struct iw_point *data, char *extra); 875 struct iw_point *data, char *extra);
876int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
877 struct iw_request_info *info,
878 struct iw_freq *freq, char *extra);
879int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
880 struct iw_request_info *info,
881 struct iw_freq *freq, char *extra);
882int cfg80211_ibss_wext_siwessid(struct net_device *dev,
883 struct iw_request_info *info,
884 struct iw_point *data, char *ssid);
885int cfg80211_ibss_wext_giwessid(struct net_device *dev,
886 struct iw_request_info *info,
887 struct iw_point *data, char *ssid);
888int cfg80211_ibss_wext_siwap(struct net_device *dev,
889 struct iw_request_info *info,
890 struct sockaddr *ap_addr, char *extra);
891int cfg80211_ibss_wext_giwap(struct net_device *dev,
892 struct iw_request_info *info,
893 struct sockaddr *ap_addr, char *extra);
894
895/* wext helper for now (to be removed) */
896struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
897 struct iw_freq *freq);
842 898
843/** 899/**
844 * cfg80211_scan_done - notify that scan finished 900 * cfg80211_scan_done - notify that scan finished
@@ -984,4 +1040,20 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
984 enum nl80211_key_type key_type, int key_id, 1040 enum nl80211_key_type key_type, int key_id,
985 const u8 *tsc); 1041 const u8 *tsc);
986 1042
1043/**
1044 * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS
1045 *
1046 * @dev: network device
1047 * @bssid: the BSSID of the IBSS joined
1048 * @gfp: allocation flags
1049 *
1050 * This function notifies cfg80211 that the device joined an IBSS or
1051 * switched to a different BSSID. Before this function can be called,
1052 * either a beacon has to have been received from the IBSS, or one of
1053 * the cfg80211_inform_bss{,_frame} functions must have been called
1054 * with the locally generated beacon -- this guarantees that there is
1055 * always a scan result for this IBSS. cfg80211 will handle the rest.
1056 */
1057void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
1058
987#endif /* __NET_CFG80211_H */ 1059#endif /* __NET_CFG80211_H */
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 44c2642d3c06..abd27b033331 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -265,6 +265,8 @@ struct wiphy {
265 * 265 *
266 * @wiphy: pointer to hardware description 266 * @wiphy: pointer to hardware description
267 * @iftype: interface type 267 * @iftype: interface type
268 * @list: (private)
269 * @netdev (private)
268 */ 270 */
269struct wireless_dev { 271struct wireless_dev {
270 struct wiphy *wiphy; 272 struct wiphy *wiphy;
@@ -273,6 +275,18 @@ struct wireless_dev {
273 /* private to the generic wireless code */ 275 /* private to the generic wireless code */
274 struct list_head list; 276 struct list_head list;
275 struct net_device *netdev; 277 struct net_device *netdev;
278
279 /* currently used for IBSS - might be rearranged in the future */
280 struct cfg80211_bss *current_bss;
281 u8 bssid[ETH_ALEN];
282 u8 ssid[IEEE80211_MAX_SSID_LEN];
283 u8 ssid_len;
284
285#ifdef CONFIG_WIRELESS_EXT
286 /* wext data */
287 struct cfg80211_ibss_params wext;
288 u8 wext_bssid[ETH_ALEN];
289#endif
276}; 290};
277 291
278/** 292/**
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 6d1e7b27b752..14ea01c4a103 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 7
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
9cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o 9cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
10 10
11ccflags-y += -D__CHECK_ENDIAN__ 11ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d1f556535f6d..de1ac51ae4e5 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -450,6 +450,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
450 dev->ieee80211_ptr->netdev = dev; 450 dev->ieee80211_ptr->netdev = dev;
451 mutex_unlock(&rdev->devlist_mtx); 451 mutex_unlock(&rdev->devlist_mtx);
452 break; 452 break;
453 case NETDEV_GOING_DOWN:
454 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
455 break;
456 if (!dev->ieee80211_ptr->ssid_len)
457 break;
458 cfg80211_leave_ibss(rdev, dev);
459 break;
460 case NETDEV_UP:
461#ifdef CONFIG_WIRELESS_EXT
462 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
463 break;
464 if (!dev->ieee80211_ptr->wext.ssid_len)
465 break;
466 cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext);
467 break;
468#endif
453 case NETDEV_UNREGISTER: 469 case NETDEV_UNREGISTER:
454 mutex_lock(&rdev->devlist_mtx); 470 mutex_lock(&rdev->devlist_mtx);
455 if (!list_empty(&dev->ieee80211_ptr->list)) { 471 if (!list_empty(&dev->ieee80211_ptr->list)) {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 02668b02e331..2ef3595fd6e0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -144,4 +144,12 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
144void cfg80211_bss_age(struct cfg80211_registered_device *dev, 144void cfg80211_bss_age(struct cfg80211_registered_device *dev,
145 unsigned long age_secs); 145 unsigned long age_secs);
146 146
147/* IBSS */
148int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
149 struct net_device *dev,
150 struct cfg80211_ibss_params *params);
151void cfg80211_clear_ibss(struct net_device *dev);
152int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
153 struct net_device *dev);
154
147#endif /* __NET_WIRELESS_CORE_H */ 155#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
new file mode 100644
index 000000000000..2bf42fdef3a1
--- /dev/null
+++ b/net/wireless/ibss.c
@@ -0,0 +1,360 @@
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 <net/wireless.h>
11#include "nl80211.h"
12
13
14void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
15{
16 struct wireless_dev *wdev = dev->ieee80211_ptr;
17 struct cfg80211_bss *bss;
18#ifdef CONFIG_WIRELESS_EXT
19 union iwreq_data wrqu;
20#endif
21
22 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
23 return;
24
25 if (WARN_ON(!wdev->ssid_len))
26 return;
27
28 if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0)
29 return;
30
31 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
32 wdev->ssid, wdev->ssid_len,
33 WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
34
35 if (WARN_ON(!bss))
36 return;
37
38 if (wdev->current_bss) {
39 cfg80211_unhold_bss(wdev->current_bss);
40 cfg80211_put_bss(wdev->current_bss);
41 }
42
43 cfg80211_hold_bss(bss);
44 wdev->current_bss = bss;
45 memcpy(wdev->bssid, bssid, ETH_ALEN);
46
47 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp);
48#ifdef CONFIG_WIRELESS_EXT
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}
54EXPORT_SYMBOL(cfg80211_ibss_joined);
55
56int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
57 struct net_device *dev,
58 struct cfg80211_ibss_params *params)
59{
60 struct wireless_dev *wdev = dev->ieee80211_ptr;
61 int err;
62
63 if (wdev->ssid_len)
64 return -EALREADY;
65
66#ifdef CONFIG_WIRELESS_EXT
67 wdev->wext.channel = params->channel;
68#endif
69 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
70
71 if (err)
72 return err;
73
74 memcpy(wdev->ssid, params->ssid, params->ssid_len);
75 wdev->ssid_len = params->ssid_len;
76
77 return 0;
78}
79
80void cfg80211_clear_ibss(struct net_device *dev)
81{
82 struct wireless_dev *wdev = dev->ieee80211_ptr;
83
84 if (wdev->current_bss) {
85 cfg80211_unhold_bss(wdev->current_bss);
86 cfg80211_put_bss(wdev->current_bss);
87 }
88
89 wdev->current_bss = NULL;
90 wdev->ssid_len = 0;
91 memset(wdev->bssid, 0, ETH_ALEN);
92}
93
94int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
95 struct net_device *dev)
96{
97 int err;
98
99 err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
100
101 if (err)
102 return err;
103
104 cfg80211_clear_ibss(dev);
105
106 return 0;
107}
108
109#ifdef CONFIG_WIRELESS_EXT
110static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
111 struct wireless_dev *wdev)
112{
113 enum ieee80211_band band;
114 int i;
115
116 /* try to find an IBSS channel if none requested ... */
117 if (!wdev->wext.channel) {
118 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
119 struct ieee80211_supported_band *sband;
120 struct ieee80211_channel *chan;
121
122 sband = rdev->wiphy.bands[band];
123 if (!sband)
124 continue;
125
126 for (i = 0; i < sband->n_channels; i++) {
127 chan = &sband->channels[i];
128 if (chan->flags & IEEE80211_CHAN_NO_IBSS)
129 continue;
130 if (chan->flags & IEEE80211_CHAN_DISABLED)
131 continue;
132 wdev->wext.channel = chan;
133 break;
134 }
135
136 if (wdev->wext.channel)
137 break;
138 }
139
140 if (!wdev->wext.channel)
141 return -EINVAL;
142 }
143
144 /* don't join -- SSID is not there */
145 if (!wdev->wext.ssid_len)
146 return 0;
147
148 if (!netif_running(wdev->netdev))
149 return 0;
150
151 return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
152 wdev->netdev, &wdev->wext);
153}
154
155int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
156 struct iw_request_info *info,
157 struct iw_freq *freq, char *extra)
158{
159 struct wireless_dev *wdev = dev->ieee80211_ptr;
160 struct ieee80211_channel *chan;
161 int err;
162
163 /* call only for ibss! */
164 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
165 return -EINVAL;
166
167 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
168 return -EOPNOTSUPP;
169
170 chan = cfg80211_wext_freq(wdev->wiphy, freq);
171 if (chan && IS_ERR(chan))
172 return PTR_ERR(chan);
173
174 if (chan &&
175 (chan->flags & IEEE80211_CHAN_NO_IBSS ||
176 chan->flags & IEEE80211_CHAN_DISABLED))
177 return -EINVAL;
178
179 if (wdev->wext.channel == chan)
180 return 0;
181
182 if (wdev->ssid_len) {
183 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
184 if (err)
185 return err;
186 }
187
188 if (chan) {
189 wdev->wext.channel = chan;
190 wdev->wext.channel_fixed = true;
191 } else {
192 /* cfg80211_ibss_wext_join will pick one if needed */
193 wdev->wext.channel_fixed = false;
194 }
195
196 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
197}
198/* temporary symbol - mark GPL - in the future the handler won't be */
199EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
200
201int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
202 struct iw_request_info *info,
203 struct iw_freq *freq, char *extra)
204{
205 struct wireless_dev *wdev = dev->ieee80211_ptr;
206 struct ieee80211_channel *chan = NULL;
207
208 /* call only for ibss! */
209 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
210 return -EINVAL;
211
212 if (wdev->current_bss)
213 chan = wdev->current_bss->channel;
214 else if (wdev->wext.channel)
215 chan = wdev->wext.channel;
216
217 if (chan) {
218 freq->m = chan->center_freq;
219 freq->e = 6;
220 return 0;
221 }
222
223 /* no channel if not joining */
224 return -EINVAL;
225}
226/* temporary symbol - mark GPL - in the future the handler won't be */
227EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq);
228
229int cfg80211_ibss_wext_siwessid(struct net_device *dev,
230 struct iw_request_info *info,
231 struct iw_point *data, char *ssid)
232{
233 struct wireless_dev *wdev = dev->ieee80211_ptr;
234 size_t len = data->length;
235 int err;
236
237 /* call only for ibss! */
238 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
239 return -EINVAL;
240
241 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
242 return -EOPNOTSUPP;
243
244 if (wdev->ssid_len) {
245 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
246 if (err)
247 return err;
248 }
249
250 /* iwconfig uses nul termination in SSID.. */
251 if (len > 0 && ssid[len - 1] == '\0')
252 len--;
253
254 wdev->wext.ssid = wdev->ssid;
255 memcpy(wdev->wext.ssid, ssid, len);
256 wdev->wext.ssid_len = len;
257
258 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
259}
260/* temporary symbol - mark GPL - in the future the handler won't be */
261EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
262
263int cfg80211_ibss_wext_giwessid(struct net_device *dev,
264 struct iw_request_info *info,
265 struct iw_point *data, char *ssid)
266{
267 struct wireless_dev *wdev = dev->ieee80211_ptr;
268
269 /* call only for ibss! */
270 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
271 return -EINVAL;
272
273 data->flags = 0;
274
275 if (wdev->ssid_len) {
276 data->flags = 1;
277 data->length = wdev->ssid_len;
278 memcpy(ssid, wdev->ssid, data->length);
279 } else if (wdev->wext.ssid) {
280 data->flags = 1;
281 data->length = wdev->wext.ssid_len;
282 memcpy(ssid, wdev->wext.ssid, data->length);
283 }
284
285 return 0;
286}
287/* temporary symbol - mark GPL - in the future the handler won't be */
288EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid);
289
290int cfg80211_ibss_wext_siwap(struct net_device *dev,
291 struct iw_request_info *info,
292 struct sockaddr *ap_addr, char *extra)
293{
294 struct wireless_dev *wdev = dev->ieee80211_ptr;
295 u8 *bssid = ap_addr->sa_data;
296 int err;
297
298 /* call only for ibss! */
299 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
300 return -EINVAL;
301
302 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
303 return -EOPNOTSUPP;
304
305 if (ap_addr->sa_family != ARPHRD_ETHER)
306 return -EINVAL;
307
308 /* automatic mode */
309 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
310 bssid = NULL;
311
312 /* both automatic */
313 if (!bssid && !wdev->wext.bssid)
314 return 0;
315
316 /* fixed already - and no change */
317 if (wdev->wext.bssid && bssid &&
318 compare_ether_addr(bssid, wdev->wext.bssid) == 0)
319 return 0;
320
321 if (wdev->ssid_len) {
322 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
323 if (err)
324 return err;
325 }
326
327 if (bssid) {
328 memcpy(wdev->wext_bssid, bssid, ETH_ALEN);
329 wdev->wext.bssid = wdev->wext_bssid;
330 } else
331 wdev->wext.bssid = NULL;
332
333 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
334}
335/* temporary symbol - mark GPL - in the future the handler won't be */
336EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
337
338int cfg80211_ibss_wext_giwap(struct net_device *dev,
339 struct iw_request_info *info,
340 struct sockaddr *ap_addr, char *extra)
341{
342 struct wireless_dev *wdev = dev->ieee80211_ptr;
343
344 /* call only for ibss! */
345 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
346 return -EINVAL;
347
348 ap_addr->sa_family = ARPHRD_ETHER;
349
350 if (wdev->wext.bssid) {
351 memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN);
352 return 0;
353 }
354
355 memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN);
356 return 0;
357}
358/* temporary symbol - mark GPL - in the future the handler won't be */
359EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
360#endif
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d2cfde659e76..16f86356ac97 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -116,6 +116,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
116 .len = IEEE80211_MAX_SSID_LEN }, 116 .len = IEEE80211_MAX_SSID_LEN },
117 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, 117 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, 118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
119 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
119}; 120};
120 121
121/* IE validation */ 122/* IE validation */
@@ -322,6 +323,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
322 CMD(assoc, ASSOCIATE); 323 CMD(assoc, ASSOCIATE);
323 CMD(deauth, DEAUTHENTICATE); 324 CMD(deauth, DEAUTHENTICATE);
324 CMD(disassoc, DISASSOCIATE); 325 CMD(disassoc, DISASSOCIATE);
326 CMD(join_ibss, JOIN_IBSS);
325 327
326#undef CMD 328#undef CMD
327 nla_nest_end(msg, nl_cmds); 329 nla_nest_end(msg, nl_cmds);
@@ -668,7 +670,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
668 struct cfg80211_registered_device *drv; 670 struct cfg80211_registered_device *drv;
669 struct vif_params params; 671 struct vif_params params;
670 int err, ifindex; 672 int err, ifindex;
671 enum nl80211_iftype type; 673 enum nl80211_iftype otype, ntype;
672 struct net_device *dev; 674 struct net_device *dev;
673 u32 _flags, *flags = NULL; 675 u32 _flags, *flags = NULL;
674 bool change = false; 676 bool change = false;
@@ -682,30 +684,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
682 goto unlock_rtnl; 684 goto unlock_rtnl;
683 685
684 ifindex = dev->ifindex; 686 ifindex = dev->ifindex;
685 type = dev->ieee80211_ptr->iftype; 687 otype = ntype = dev->ieee80211_ptr->iftype;
686 dev_put(dev); 688 dev_put(dev);
687 689
688 if (info->attrs[NL80211_ATTR_IFTYPE]) { 690 if (info->attrs[NL80211_ATTR_IFTYPE]) {
689 enum nl80211_iftype ntype;
690
691 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); 691 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
692 if (type != ntype) 692 if (otype != ntype)
693 change = true; 693 change = true;
694 type = ntype; 694 if (ntype > NL80211_IFTYPE_MAX) {
695 if (type > NL80211_IFTYPE_MAX) {
696 err = -EINVAL; 695 err = -EINVAL;
697 goto unlock; 696 goto unlock;
698 } 697 }
699 } 698 }
700 699
701 if (!drv->ops->change_virtual_intf || 700 if (!drv->ops->change_virtual_intf ||
702 !(drv->wiphy.interface_modes & (1 << type))) { 701 !(drv->wiphy.interface_modes & (1 << ntype))) {
703 err = -EOPNOTSUPP; 702 err = -EOPNOTSUPP;
704 goto unlock; 703 goto unlock;
705 } 704 }
706 705
707 if (info->attrs[NL80211_ATTR_MESH_ID]) { 706 if (info->attrs[NL80211_ATTR_MESH_ID]) {
708 if (type != NL80211_IFTYPE_MESH_POINT) { 707 if (ntype != NL80211_IFTYPE_MESH_POINT) {
709 err = -EINVAL; 708 err = -EINVAL;
710 goto unlock; 709 goto unlock;
711 } 710 }
@@ -715,7 +714,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
715 } 714 }
716 715
717 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { 716 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
718 if (type != NL80211_IFTYPE_MONITOR) { 717 if (ntype != NL80211_IFTYPE_MONITOR) {
719 err = -EINVAL; 718 err = -EINVAL;
720 goto unlock; 719 goto unlock;
721 } 720 }
@@ -730,12 +729,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
730 729
731 if (change) 730 if (change)
732 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, 731 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
733 type, flags, &params); 732 ntype, flags, &params);
734 else 733 else
735 err = 0; 734 err = 0;
736 735
737 dev = __dev_get_by_index(&init_net, ifindex); 736 dev = __dev_get_by_index(&init_net, ifindex);
738 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); 737 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype));
738
739 if (dev && !err && (ntype != otype)) {
740 if (otype == NL80211_IFTYPE_ADHOC)
741 cfg80211_clear_ibss(dev);
742 }
739 743
740 unlock: 744 unlock:
741 cfg80211_put_dev(drv); 745 cfg80211_put_dev(drv);
@@ -3052,6 +3056,114 @@ unlock_rtnl:
3052 return err; 3056 return err;
3053} 3057}
3054 3058
3059static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
3060{
3061 struct cfg80211_registered_device *drv;
3062 struct net_device *dev;
3063 struct cfg80211_ibss_params ibss;
3064 struct wiphy *wiphy;
3065 int err;
3066
3067 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3068 return -EINVAL;
3069
3070 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
3071 !info->attrs[NL80211_ATTR_SSID] ||
3072 !nla_len(info->attrs[NL80211_ATTR_SSID]))
3073 return -EINVAL;
3074
3075 rtnl_lock();
3076
3077 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
3078 if (err)
3079 goto unlock_rtnl;
3080
3081 if (!drv->ops->join_ibss) {
3082 err = -EOPNOTSUPP;
3083 goto out;
3084 }
3085
3086 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
3087 err = -EOPNOTSUPP;
3088 goto out;
3089 }
3090
3091 if (!netif_running(dev)) {
3092 err = -ENETDOWN;
3093 goto out;
3094 }
3095
3096 wiphy = &drv->wiphy;
3097 memset(&ibss, 0, sizeof(ibss));
3098
3099 if (info->attrs[NL80211_ATTR_MAC])
3100 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3101 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3102 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3103
3104 if (info->attrs[NL80211_ATTR_IE]) {
3105 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3106 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3107 }
3108
3109 ibss.channel = ieee80211_get_channel(wiphy,
3110 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3111 if (!ibss.channel ||
3112 ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
3113 ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
3114 err = -EINVAL;
3115 goto out;
3116 }
3117
3118 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
3119
3120 err = cfg80211_join_ibss(drv, dev, &ibss);
3121
3122out:
3123 cfg80211_put_dev(drv);
3124 dev_put(dev);
3125unlock_rtnl:
3126 rtnl_unlock();
3127 return err;
3128}
3129
3130static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
3131{
3132 struct cfg80211_registered_device *drv;
3133 struct net_device *dev;
3134 int err;
3135
3136 rtnl_lock();
3137
3138 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
3139 if (err)
3140 goto unlock_rtnl;
3141
3142 if (!drv->ops->leave_ibss) {
3143 err = -EOPNOTSUPP;
3144 goto out;
3145 }
3146
3147 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
3148 err = -EOPNOTSUPP;
3149 goto out;
3150 }
3151
3152 if (!netif_running(dev)) {
3153 err = -ENETDOWN;
3154 goto out;
3155 }
3156
3157 err = cfg80211_leave_ibss(drv, dev);
3158
3159out:
3160 cfg80211_put_dev(drv);
3161 dev_put(dev);
3162unlock_rtnl:
3163 rtnl_unlock();
3164 return err;
3165}
3166
3055static struct genl_ops nl80211_ops[] = { 3167static struct genl_ops nl80211_ops[] = {
3056 { 3168 {
3057 .cmd = NL80211_CMD_GET_WIPHY, 3169 .cmd = NL80211_CMD_GET_WIPHY,
@@ -3253,6 +3365,18 @@ static struct genl_ops nl80211_ops[] = {
3253 .policy = nl80211_policy, 3365 .policy = nl80211_policy,
3254 .flags = GENL_ADMIN_PERM, 3366 .flags = GENL_ADMIN_PERM,
3255 }, 3367 },
3368 {
3369 .cmd = NL80211_CMD_JOIN_IBSS,
3370 .doit = nl80211_join_ibss,
3371 .policy = nl80211_policy,
3372 .flags = GENL_ADMIN_PERM,
3373 },
3374 {
3375 .cmd = NL80211_CMD_LEAVE_IBSS,
3376 .doit = nl80211_leave_ibss,
3377 .policy = nl80211_policy,
3378 .flags = GENL_ADMIN_PERM,
3379 },
3256}; 3380};
3257static struct genl_multicast_group nl80211_mlme_mcgrp = { 3381static struct genl_multicast_group nl80211_mlme_mcgrp = {
3258 .name = "mlme", 3382 .name = "mlme",
@@ -3466,6 +3590,40 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
3466 NL80211_CMD_DISASSOCIATE); 3590 NL80211_CMD_DISASSOCIATE);
3467} 3591}
3468 3592
3593void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
3594 struct net_device *netdev, const u8 *bssid,
3595 gfp_t gfp)
3596{
3597 struct sk_buff *msg;
3598 void *hdr;
3599
3600 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
3601 if (!msg)
3602 return;
3603
3604 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
3605 if (!hdr) {
3606 nlmsg_free(msg);
3607 return;
3608 }
3609
3610 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
3611 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
3612 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
3613
3614 if (genlmsg_end(msg, hdr) < 0) {
3615 nlmsg_free(msg);
3616 return;
3617 }
3618
3619 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
3620 return;
3621
3622 nla_put_failure:
3623 genlmsg_cancel(msg, hdr);
3624 nlmsg_free(msg);
3625}
3626
3469void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, 3627void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
3470 struct net_device *netdev, const u8 *addr, 3628 struct net_device *netdev, const u8 *addr,
3471 enum nl80211_key_type key_type, int key_id, 3629 enum nl80211_key_type key_type, int key_id,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index b3aaa59afa08..17d2d8bfaf75 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -34,4 +34,8 @@ nl80211_send_beacon_hint_event(struct wiphy *wiphy,
34 struct ieee80211_channel *channel_before, 34 struct ieee80211_channel *channel_before,
35 struct ieee80211_channel *channel_after); 35 struct ieee80211_channel *channel_after);
36 36
37void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
38 struct net_device *netdev, const u8 *bssid,
39 gfp_t gfp);
40
37#endif /* __NET_WIRELESS_NL80211_H */ 41#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 6fd7bf7b4481..57eaea26b67a 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -285,3 +285,33 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
285 } 285 }
286} 286}
287EXPORT_SYMBOL(cfg80211_wext_siwmlme); 287EXPORT_SYMBOL(cfg80211_wext_siwmlme);
288
289
290/**
291 * cfg80211_wext_freq - get wext frequency for non-"auto"
292 * @wiphy: the wiphy
293 * @freq: the wext freq encoding
294 *
295 * Returns a channel, %NULL for auto, or an ERR_PTR for errors!
296 */
297struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
298 struct iw_freq *freq)
299{
300 if (freq->e == 0) {
301 if (freq->m < 0)
302 return NULL;
303 else
304 return ieee80211_get_channel(wiphy,
305 ieee80211_channel_to_frequency(freq->m));
306 } else {
307 int i, div = 1000000;
308 for (i = 0; i < freq->e; i++)
309 div /= 10;
310 if (div > 0)
311 return ieee80211_get_channel(wiphy, freq->m / div);
312 else
313 return ERR_PTR(-EINVAL);
314 }
315
316}
317EXPORT_SYMBOL(cfg80211_wext_freq);