aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/sme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r--net/wireless/sme.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
new file mode 100644
index 000000000000..fc117031d0bb
--- /dev/null
+++ b/net/wireless/sme.c
@@ -0,0 +1,224 @@
1/*
2 * SME code for cfg80211's connect emulation.
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 */
7
8#include <linux/etherdevice.h>
9#include <linux/if_arp.h>
10#include <linux/workqueue.h>
11#include <net/cfg80211.h>
12#include <net/rtnetlink.h>
13#include "nl80211.h"
14
15
16void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
17 const u8 *req_ie, size_t req_ie_len,
18 const u8 *resp_ie, size_t resp_ie_len,
19 u16 status, gfp_t gfp)
20{
21 struct wireless_dev *wdev = dev->ieee80211_ptr;
22 struct cfg80211_bss *bss;
23#ifdef CONFIG_WIRELESS_EXT
24 union iwreq_data wrqu;
25#endif
26
27 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
28 return;
29
30 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING))
31 return;
32
33 if (wdev->current_bss) {
34 cfg80211_unhold_bss(wdev->current_bss);
35 cfg80211_put_bss(wdev->current_bss);
36 wdev->current_bss = NULL;
37 }
38
39 if (status == WLAN_STATUS_SUCCESS) {
40 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
41 wdev->ssid, wdev->ssid_len,
42 WLAN_CAPABILITY_ESS,
43 WLAN_CAPABILITY_ESS);
44
45 if (WARN_ON(!bss))
46 return;
47
48 cfg80211_hold_bss(bss);
49 wdev->current_bss = bss;
50
51 wdev->sme_state = CFG80211_SME_CONNECTED;
52 } else {
53 wdev->sme_state = CFG80211_SME_IDLE;
54 }
55
56 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid,
57 req_ie, req_ie_len, resp_ie, resp_ie_len,
58 status, gfp);
59
60#ifdef CONFIG_WIRELESS_EXT
61 if (req_ie && status == WLAN_STATUS_SUCCESS) {
62 memset(&wrqu, 0, sizeof(wrqu));
63 wrqu.data.length = req_ie_len;
64 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
65 }
66
67 if (resp_ie && status == WLAN_STATUS_SUCCESS) {
68 memset(&wrqu, 0, sizeof(wrqu));
69 wrqu.data.length = resp_ie_len;
70 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
71 }
72
73 memset(&wrqu, 0, sizeof(wrqu));
74 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
75 if (bssid)
76 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
77 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
78#endif
79}
80EXPORT_SYMBOL(cfg80211_connect_result);
81
82void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
83 const u8 *req_ie, size_t req_ie_len,
84 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
85{
86 struct wireless_dev *wdev = dev->ieee80211_ptr;
87 struct cfg80211_bss *bss;
88#ifdef CONFIG_WIRELESS_EXT
89 union iwreq_data wrqu;
90#endif
91
92 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
93 return;
94
95 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
96 return;
97
98 /* internal error -- how did we get to CONNECTED w/o BSS? */
99 if (WARN_ON(!wdev->current_bss)) {
100 return;
101 }
102
103 cfg80211_unhold_bss(wdev->current_bss);
104 cfg80211_put_bss(wdev->current_bss);
105 wdev->current_bss = NULL;
106
107 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
108 wdev->ssid, wdev->ssid_len,
109 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
110
111 if (WARN_ON(!bss))
112 return;
113
114 cfg80211_hold_bss(bss);
115 wdev->current_bss = bss;
116
117 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid,
118 req_ie, req_ie_len, resp_ie, resp_ie_len, gfp);
119
120#ifdef CONFIG_WIRELESS_EXT
121 if (req_ie) {
122 memset(&wrqu, 0, sizeof(wrqu));
123 wrqu.data.length = req_ie_len;
124 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
125 }
126
127 if (resp_ie) {
128 memset(&wrqu, 0, sizeof(wrqu));
129 wrqu.data.length = resp_ie_len;
130 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
131 }
132
133 memset(&wrqu, 0, sizeof(wrqu));
134 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
135 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
136 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
137#endif
138}
139EXPORT_SYMBOL(cfg80211_roamed);
140
141static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp,
142 u8 *ie, size_t ie_len, u16 reason,
143 bool from_ap)
144{
145 struct wireless_dev *wdev = dev->ieee80211_ptr;
146#ifdef CONFIG_WIRELESS_EXT
147 union iwreq_data wrqu;
148#endif
149
150 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
151 return;
152
153 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
154 return;
155
156 if (wdev->current_bss) {
157 cfg80211_unhold_bss(wdev->current_bss);
158 cfg80211_put_bss(wdev->current_bss);
159 }
160
161 wdev->current_bss = NULL;
162 wdev->sme_state = CFG80211_SME_IDLE;
163
164 nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
165 reason, ie, ie_len, from_ap, gfp);
166
167#ifdef CONFIG_WIRELESS_EXT
168 memset(&wrqu, 0, sizeof(wrqu));
169 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
170 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
171#endif
172}
173
174void cfg80211_disconnected(struct net_device *dev, u16 reason,
175 u8 *ie, size_t ie_len, gfp_t gfp)
176{
177 __cfg80211_disconnected(dev, reason, ie, ie_len, true, gfp);
178}
179EXPORT_SYMBOL(cfg80211_disconnected);
180
181int cfg80211_connect(struct cfg80211_registered_device *rdev,
182 struct net_device *dev,
183 struct cfg80211_connect_params *connect)
184{
185 int err;
186 struct wireless_dev *wdev = dev->ieee80211_ptr;
187
188 if (wdev->sme_state != CFG80211_SME_IDLE)
189 return -EALREADY;
190
191 if (!rdev->ops->connect) {
192 return -EOPNOTSUPP;
193 } else {
194 wdev->sme_state = CFG80211_SME_CONNECTING;
195 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
196 if (err) {
197 wdev->sme_state = CFG80211_SME_IDLE;
198 return err;
199 }
200 }
201
202 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
203 wdev->ssid_len = connect->ssid_len;
204
205 return 0;
206}
207
208int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
209 struct net_device *dev, u16 reason)
210{
211 int err;
212
213 if (!rdev->ops->disconnect) {
214 return -EOPNOTSUPP;
215 } else {
216 err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
217 if (err)
218 return err;
219 }
220
221 __cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL);
222
223 return 0;
224}