diff options
-rw-r--r-- | include/linux/nl80211.h | 18 | ||||
-rw-r--r-- | include/net/cfg80211.h | 72 | ||||
-rw-r--r-- | include/net/wireless.h | 14 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 16 | ||||
-rw-r--r-- | net/wireless/core.h | 8 | ||||
-rw-r--r-- | net/wireless/ibss.c | 360 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 182 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 4 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 30 |
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 | */ | ||
676 | struct 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 | */ |
736 | struct cfg80211_ops { | 766 | struct 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, | |||
839 | int cfg80211_wext_giwrange(struct net_device *dev, | 873 | int 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); |
876 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | ||
877 | struct iw_request_info *info, | ||
878 | struct iw_freq *freq, char *extra); | ||
879 | int cfg80211_ibss_wext_giwfreq(struct net_device *dev, | ||
880 | struct iw_request_info *info, | ||
881 | struct iw_freq *freq, char *extra); | ||
882 | int cfg80211_ibss_wext_siwessid(struct net_device *dev, | ||
883 | struct iw_request_info *info, | ||
884 | struct iw_point *data, char *ssid); | ||
885 | int cfg80211_ibss_wext_giwessid(struct net_device *dev, | ||
886 | struct iw_request_info *info, | ||
887 | struct iw_point *data, char *ssid); | ||
888 | int cfg80211_ibss_wext_siwap(struct net_device *dev, | ||
889 | struct iw_request_info *info, | ||
890 | struct sockaddr *ap_addr, char *extra); | ||
891 | int 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) */ | ||
896 | struct 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 | */ | ||
1057 | void 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 | */ |
269 | struct wireless_dev { | 271 | struct 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 | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o |
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
10 | 10 | ||
11 | ccflags-y += -D__CHECK_ENDIAN__ | 11 | ccflags-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); | |||
144 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | 144 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, |
145 | unsigned long age_secs); | 145 | unsigned long age_secs); |
146 | 146 | ||
147 | /* IBSS */ | ||
148 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | ||
149 | struct net_device *dev, | ||
150 | struct cfg80211_ibss_params *params); | ||
151 | void cfg80211_clear_ibss(struct net_device *dev); | ||
152 | int 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 | |||
14 | void 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 | } | ||
54 | EXPORT_SYMBOL(cfg80211_ibss_joined); | ||
55 | |||
56 | int 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 | |||
80 | void 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 | |||
94 | int 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 | ||
110 | static 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 | |||
155 | int 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 */ | ||
199 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); | ||
200 | |||
201 | int 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 */ | ||
227 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq); | ||
228 | |||
229 | int 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 */ | ||
261 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); | ||
262 | |||
263 | int 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 */ | ||
288 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid); | ||
289 | |||
290 | int 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 */ | ||
336 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); | ||
337 | |||
338 | int 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 */ | ||
359 | EXPORT_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, ¶ms); | 732 | ntype, flags, ¶ms); |
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 | ||
3059 | static 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 | |||
3122 | out: | ||
3123 | cfg80211_put_dev(drv); | ||
3124 | dev_put(dev); | ||
3125 | unlock_rtnl: | ||
3126 | rtnl_unlock(); | ||
3127 | return err; | ||
3128 | } | ||
3129 | |||
3130 | static 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 | |||
3159 | out: | ||
3160 | cfg80211_put_dev(drv); | ||
3161 | dev_put(dev); | ||
3162 | unlock_rtnl: | ||
3163 | rtnl_unlock(); | ||
3164 | return err; | ||
3165 | } | ||
3166 | |||
3055 | static struct genl_ops nl80211_ops[] = { | 3167 | static 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 | }; |
3257 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3381 | static 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 | ||
3593 | void 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 | |||
3469 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 3627 | void 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 | ||
37 | void 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 | } |
287 | EXPORT_SYMBOL(cfg80211_wext_siwmlme); | 287 | EXPORT_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 | */ | ||
297 | struct 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 | } | ||
317 | EXPORT_SYMBOL(cfg80211_wext_freq); | ||