Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /* |
2 | * --------------------------------------------------------------------------- | |
3 | * FILE: wext_events.c | |
4 | * | |
5 | * PURPOSE: | |
6 | * Code to generate iwevents. | |
7 | * | |
8 | * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd. | |
9 | * | |
10 | * Refer to LICENSE.txt included with this source code for details on | |
11 | * the license terms. | |
12 | * | |
13 | * --------------------------------------------------------------------------- | |
14 | */ | |
15 | #include <linux/types.h> | |
16 | #include <linux/etherdevice.h> | |
17 | #include <linux/if_arp.h> | |
18 | #include "csr_wifi_hip_unifi.h" | |
19 | #include "unifi_priv.h" | |
20 | ||
21 | ||
22 | ||
23 | /* | |
24 | * --------------------------------------------------------------------------- | |
25 | * wext_send_assoc_event | |
26 | * | |
27 | * Send wireless-extension events up to userland to announce | |
28 | * successful association with an AP. | |
29 | * | |
30 | * Arguments: | |
31 | * priv Pointer to driver context. | |
32 | * bssid MAC address of AP we associated with | |
33 | * req_ie, req_ie_len IEs in the original request | |
34 | * resp_ie, resp_ie_len IEs in the response | |
35 | * | |
36 | * Returns: | |
37 | * None. | |
38 | * | |
39 | * Notes: | |
40 | * This is sent on first successful association, and again if we | |
41 | * roam to another AP. | |
42 | * --------------------------------------------------------------------------- | |
43 | */ | |
44 | void | |
45 | wext_send_assoc_event(unifi_priv_t *priv, unsigned char *bssid, | |
46 | unsigned char *req_ie, int req_ie_len, | |
47 | unsigned char *resp_ie, int resp_ie_len, | |
48 | unsigned char *scan_ie, unsigned int scan_ie_len) | |
49 | { | |
50 | #if WIRELESS_EXT > 17 | |
51 | union iwreq_data wrqu; | |
52 | ||
53 | if (req_ie_len == 0) req_ie = NULL; | |
54 | wrqu.data.length = req_ie_len; | |
55 | wrqu.data.flags = 0; | |
56 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVASSOCREQIE, &wrqu, req_ie); | |
57 | ||
58 | if (resp_ie_len == 0) resp_ie = NULL; | |
59 | wrqu.data.length = resp_ie_len; | |
60 | wrqu.data.flags = 0; | |
61 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVASSOCRESPIE, &wrqu, resp_ie); | |
62 | ||
63 | if (scan_ie_len > 0) { | |
64 | wrqu.data.length = scan_ie_len; | |
65 | wrqu.data.flags = 0; | |
66 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVGENIE, &wrqu, scan_ie); | |
67 | } | |
68 | ||
69 | memcpy(&wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | |
70 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWAP, &wrqu, NULL); | |
71 | #endif | |
72 | } /* wext_send_assoc_event() */ | |
73 | ||
74 | ||
75 | ||
76 | /* | |
77 | * --------------------------------------------------------------------------- | |
78 | * wext_send_disassoc_event | |
79 | * | |
80 | * Send a wireless-extension event up to userland to announce | |
81 | * that we disassociated from an AP. | |
82 | * | |
83 | * Arguments: | |
84 | * priv Pointer to driver context. | |
85 | * | |
86 | * Returns: | |
87 | * None. | |
88 | * | |
89 | * Notes: | |
90 | * The semantics of wpa_supplicant (the userland SME application) are | |
91 | * that a SIOCGIWAP event with MAC address of all zero means | |
92 | * disassociate. | |
93 | * --------------------------------------------------------------------------- | |
94 | */ | |
95 | void | |
96 | wext_send_disassoc_event(unifi_priv_t *priv) | |
97 | { | |
98 | #if WIRELESS_EXT > 17 | |
99 | union iwreq_data wrqu; | |
100 | ||
101 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | |
102 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWAP, &wrqu, NULL); | |
103 | #endif | |
104 | } /* wext_send_disassoc_event() */ | |
105 | ||
106 | ||
107 | ||
108 | /* | |
109 | * --------------------------------------------------------------------------- | |
110 | * wext_send_scan_results_event | |
111 | * | |
112 | * Send wireless-extension events up to userland to announce | |
113 | * completion of a scan. | |
114 | * | |
115 | * Arguments: | |
116 | * priv Pointer to driver context. | |
117 | * | |
118 | * Returns: | |
119 | * None. | |
120 | * | |
121 | * Notes: | |
122 | * This doesn't actually report the results, they are retrieved | |
123 | * using the SIOCGIWSCAN ioctl command. | |
124 | * --------------------------------------------------------------------------- | |
125 | */ | |
126 | void | |
127 | wext_send_scan_results_event(unifi_priv_t *priv) | |
128 | { | |
129 | #if WIRELESS_EXT > 17 | |
130 | union iwreq_data wrqu; | |
131 | ||
132 | wrqu.data.length = 0; | |
133 | wrqu.data.flags = 0; | |
134 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWSCAN, &wrqu, NULL); | |
135 | ||
136 | #endif | |
137 | } /* wext_send_scan_results_event() */ | |
138 | ||
139 | ||
140 | ||
141 | /* | |
142 | * --------------------------------------------------------------------------- | |
143 | * wext_send_michaelmicfailure_event | |
144 | * | |
145 | * Send wireless-extension events up to userland to announce | |
146 | * completion of a scan. | |
147 | * | |
148 | * Arguments: | |
149 | * priv Pointer to driver context. | |
150 | * count, macaddr, key_type, key_idx, tsc | |
151 | * Parameters from report from UniFi. | |
152 | * | |
153 | * Returns: | |
154 | * None. | |
155 | * --------------------------------------------------------------------------- | |
156 | */ | |
157 | #if WIRELESS_EXT >= 18 | |
158 | static inline void | |
159 | _send_michaelmicfailure_event(struct net_device *dev, | |
160 | int count, const unsigned char *macaddr, | |
161 | int key_type, int key_idx, | |
162 | unsigned char *tsc) | |
163 | { | |
164 | union iwreq_data wrqu; | |
165 | struct iw_michaelmicfailure mmf; | |
166 | ||
167 | memset(&mmf, 0, sizeof(mmf)); | |
168 | ||
169 | mmf.flags = key_idx & IW_MICFAILURE_KEY_ID; | |
170 | if (key_type == CSR_GROUP) { | |
171 | mmf.flags |= IW_MICFAILURE_GROUP; | |
172 | } else { | |
173 | mmf.flags |= IW_MICFAILURE_PAIRWISE; | |
174 | } | |
175 | mmf.flags |= ((count << 5) & IW_MICFAILURE_COUNT); | |
176 | ||
177 | mmf.src_addr.sa_family = ARPHRD_ETHER; | |
178 | memcpy(mmf.src_addr.sa_data, macaddr, ETH_ALEN); | |
179 | ||
180 | memcpy(mmf.tsc, tsc, IW_ENCODE_SEQ_MAX_SIZE); | |
181 | ||
182 | memset(&wrqu, 0, sizeof(wrqu)); | |
183 | wrqu.data.length = sizeof(mmf); | |
184 | ||
185 | wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&mmf); | |
186 | } | |
187 | #elif WIRELESS_EXT >= 15 | |
188 | static inline void | |
189 | _send_michaelmicfailure_event(struct net_device *dev, | |
190 | int count, const unsigned char *macaddr, | |
191 | int key_type, int key_idx, | |
192 | unsigned char *tsc) | |
193 | { | |
194 | union iwreq_data wrqu; | |
195 | char buf[128]; | |
196 | ||
197 | sprintf(buf, | |
198 | "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%02x:%02x:%02x:%02x:%02x:%02x)", | |
199 | key_idx, (key_type == CSR_GROUP) ? "broad" : "uni", | |
200 | macaddr[0], macaddr[1], macaddr[2], | |
201 | macaddr[3], macaddr[4], macaddr[5]); | |
202 | memset(&wrqu, 0, sizeof(wrqu)); | |
203 | wrqu.data.length = strlen(buf); | |
204 | wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); | |
205 | } | |
206 | #else /* WIRELESS_EXT >= 15 */ | |
207 | static inline void | |
208 | _send_michaelmicfailure_event(struct net_device *dev, | |
209 | int count, const unsigned char *macaddr, | |
210 | int key_type, int key_idx, | |
211 | unsigned char *tsc) | |
212 | { | |
213 | /* Not supported before WEXT 15 */ | |
214 | } | |
215 | #endif /* WIRELESS_EXT >= 15 */ | |
216 | ||
217 | ||
218 | void | |
219 | wext_send_michaelmicfailure_event(unifi_priv_t *priv, | |
8c87f69a | 220 | u16 count, |
635d2b00 GKH |
221 | CsrWifiMacAddress address, |
222 | CsrWifiSmeKeyType keyType, | |
8c87f69a | 223 | u16 interfaceTag) |
635d2b00 GKH |
224 | { |
225 | unsigned char tsc[8] = {0}; | |
226 | ||
227 | if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { | |
228 | unifi_error(priv, "wext_send_michaelmicfailure_event bad interfaceTag\n"); | |
229 | return; | |
230 | } | |
231 | ||
232 | _send_michaelmicfailure_event(priv->netdev[interfaceTag], | |
233 | count, | |
234 | address.a, | |
235 | keyType, | |
236 | 0, | |
237 | tsc); | |
238 | } /* wext_send_michaelmicfailure_event() */ | |
239 | ||
240 | void | |
5379b13d | 241 | wext_send_pmkid_candidate_event(unifi_priv_t *priv, CsrWifiMacAddress bssid, u8 preauth_allowed, u16 interfaceTag) |
635d2b00 GKH |
242 | { |
243 | #if WIRELESS_EXT > 17 | |
244 | union iwreq_data wrqu; | |
245 | struct iw_pmkid_cand pmkid_cand; | |
246 | ||
247 | if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { | |
248 | unifi_error(priv, "wext_send_pmkid_candidate_event bad interfaceTag\n"); | |
249 | return; | |
250 | } | |
251 | ||
252 | memset(&pmkid_cand, 0, sizeof(pmkid_cand)); | |
253 | ||
254 | if (preauth_allowed) { | |
255 | pmkid_cand.flags |= IW_PMKID_CAND_PREAUTH; | |
256 | } | |
257 | pmkid_cand.bssid.sa_family = ARPHRD_ETHER; | |
258 | memcpy(pmkid_cand.bssid.sa_data, bssid.a, ETH_ALEN); | |
259 | /* Used as priority, smaller the number higher the priority, not really used in our case */ | |
260 | pmkid_cand.index = 1; | |
261 | ||
262 | memset(&wrqu, 0, sizeof(wrqu)); | |
263 | wrqu.data.length = sizeof(pmkid_cand); | |
264 | ||
265 | wireless_send_event(priv->netdev[interfaceTag], IWEVPMKIDCAND, &wrqu, (char *)&pmkid_cand); | |
266 | #endif | |
267 | } /* wext_send_pmkid_candidate_event() */ | |
268 | ||
269 | /* | |
270 | * Send a custom WEXT event to say we have completed initialisation | |
271 | * and are now ready for WEXT ioctls. Used by Android wpa_supplicant. | |
272 | */ | |
273 | void | |
274 | wext_send_started_event(unifi_priv_t *priv) | |
275 | { | |
276 | #if WIRELESS_EXT > 17 | |
277 | union iwreq_data wrqu; | |
278 | char data[] = "STARTED"; | |
279 | ||
280 | wrqu.data.length = sizeof(data); | |
281 | wrqu.data.flags = 0; | |
282 | wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVCUSTOM, &wrqu, data); | |
283 | #endif | |
284 | } /* wext_send_started_event() */ | |
285 |