Merge remote-tracking branch 'upstream' into next
[cascardo/linux.git] / drivers / staging / csr / wext_events.c
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,
220                                   u16 count,
221                                   CsrWifiMacAddress address,
222                                   CsrWifiSmeKeyType keyType,
223                                   u16 interfaceTag)
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
241 wext_send_pmkid_candidate_event(unifi_priv_t *priv, CsrWifiMacAddress bssid, u8 preauth_allowed, u16 interfaceTag)
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