OSDN Git Service

android-2.1_r1 snapshot
[android-x86/external-wpa_supplicant.git] / driver_prism54.c
1 /*
2  * WPA Supplicant - driver interaction with Linux Prism54.org driver
3  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
4  * Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include "includes.h"
17 #include <sys/ioctl.h>
18
19 #include "wireless_copy.h"
20 #include "common.h"
21 #include "driver.h"
22 #include "driver_wext.h"
23 #include "driver_hostap.h"
24 #include "l2_packet.h"
25 #include "wpa_supplicant.h"
26
27 struct wpa_driver_prism54_data {
28         void *wext; /* private data for driver_wext */
29         void *ctx;
30         char ifname[IFNAMSIZ + 1];
31         int sock;
32 };
33
34 #define PRISM54_SET_WPA                 SIOCIWFIRSTPRIV+12
35 #define PRISM54_HOSTAPD                 SIOCIWFIRSTPRIV+25
36 #define PRISM54_DROP_UNENCRYPTED        SIOCIWFIRSTPRIV+26
37
38 static void show_set_key_error(struct prism2_hostapd_param *);
39
40 static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
41                                  struct prism2_hostapd_param *param,
42                                  int len, int show_err)
43 {
44         struct iwreq iwr;
45
46         os_memset(&iwr, 0, sizeof(iwr));
47         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
48         iwr.u.data.pointer = (caddr_t) param;
49         iwr.u.data.length = len;
50
51         if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
52                 int ret = errno;
53                 if (show_err) 
54                         perror("ioctl[PRISM54_HOSTAPD]");
55                 return ret;
56         }
57
58         return 0;
59 }
60
61
62 static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
63                                          const u8 *wpa_ie,
64                                          size_t wpa_ie_len)
65 {
66         struct prism2_hostapd_param *param;
67         int res;
68         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
69         if (blen < sizeof(*param))
70                 blen = sizeof(*param);
71
72         param = os_zalloc(blen);
73         if (param == NULL)
74                 return -1;
75         
76         param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
77         param->u.generic_elem.len = wpa_ie_len;
78         os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
79         res = hostapd_ioctl_prism54(drv, param, blen, 1);
80
81         os_free(param);
82
83         return res;
84 }
85
86
87 /* This is called at wpa_supplicant daemon init time */
88 static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
89 {
90         struct wpa_driver_prism54_data *drv = priv;
91         struct prism2_hostapd_param *param;
92         int res;
93         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
94         if (blen < sizeof(*param))
95                 blen = sizeof(*param);
96
97         param = os_zalloc(blen);
98         if (param == NULL)
99                 return -1;
100
101         param->cmd = PRISM54_SET_WPA;
102         param->u.generic_elem.len = 0;
103         res = hostapd_ioctl_prism54(drv, param, blen, 1);
104
105         os_free(param);
106
107         return res;
108 }
109
110
111 static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
112                                       const u8 *addr, int key_idx, int set_tx,
113                                       const u8 *seq, size_t seq_len,
114                                       const u8 *key, size_t key_len)
115 {
116         struct wpa_driver_prism54_data *drv = priv;
117         struct prism2_hostapd_param *param;
118         u8 *buf;
119         size_t blen;
120         int ret = 0;
121         char *alg_name;
122
123         switch (alg) {
124         case WPA_ALG_NONE:
125                 alg_name = "none";
126                 return -1;
127                 break;
128         case WPA_ALG_WEP:
129                 alg_name = "WEP";
130                 return -1;
131                 break;
132         case WPA_ALG_TKIP:
133                 alg_name = "TKIP";
134                 break;
135         case WPA_ALG_CCMP:
136                 alg_name = "CCMP";
137                 return -1;
138                 break;
139         default:
140                 return -1;
141         }
142
143         wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
144                    "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
145                    (unsigned long) seq_len, (unsigned long) key_len);
146
147         if (seq_len > 8)
148                 return -2;
149
150         blen = sizeof(*param) + key_len;
151         buf = os_zalloc(blen);
152         if (buf == NULL)
153                 return -1;
154
155         param = (struct prism2_hostapd_param *) buf;
156         param->cmd = PRISM2_SET_ENCRYPTION;
157         /* TODO: In theory, STA in client mode can use five keys; four default
158          * keys for receiving (with keyidx 0..3) and one individual key for
159          * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
160          * keyidx 0 is reserved for this unicast use and default keys can only
161          * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
162          * This should be fine for more or less all cases, but for completeness
163          * sake, the driver could be enhanced to support the missing key. */
164 #if 0
165         if (addr == NULL)
166                 os_memset(param->sta_addr, 0xff, ETH_ALEN);
167         else
168                 os_memcpy(param->sta_addr, addr, ETH_ALEN);
169 #else
170         os_memset(param->sta_addr, 0xff, ETH_ALEN);
171 #endif
172         os_strncpy((char *) param->u.crypt.alg, alg_name,
173                    HOSTAP_CRYPT_ALG_NAME_LEN);
174         param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
175         param->u.crypt.idx = key_idx;
176         os_memcpy(param->u.crypt.seq, seq, seq_len);
177         param->u.crypt.key_len = key_len;
178         os_memcpy((u8 *) (param + 1), key, key_len);
179
180         if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
181                 wpa_printf(MSG_WARNING, "Failed to set encryption.");
182                 show_set_key_error(param);
183                 ret = -1;
184         }
185         os_free(buf);
186
187         return ret;
188 }
189
190
191 static int wpa_driver_prism54_set_countermeasures(void *priv,
192                                                  int enabled)
193 {
194         /* FIX */
195         printf("wpa_driver_prism54_set_countermeasures - not yet "
196                "implemented\n");
197         return 0;
198 }
199
200
201 static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
202                                                   int enabled)
203 {
204         struct wpa_driver_prism54_data *drv = priv;
205         struct prism2_hostapd_param *param;
206         int res;
207         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
208         if (blen < sizeof(*param))
209                 blen = sizeof(*param);
210
211         param = os_zalloc(blen);
212         if (param == NULL)
213                 return -1;
214
215         param->cmd = PRISM54_DROP_UNENCRYPTED;
216         param->u.generic_elem.len = 0;
217         res = hostapd_ioctl_prism54(drv, param, blen, 1);
218
219         os_free(param);
220
221         return res;
222 }
223
224
225 static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
226                                              int reason_code)
227 {
228         /* FIX */
229         printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
230         return 0;
231 }
232
233
234 static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
235                                            int reason_code)
236 {
237         /* FIX */
238         printf("wpa_driver_prism54_disassociate - not yet implemented\n");
239         return 0;
240 }
241
242
243 static int
244 wpa_driver_prism54_associate(void *priv,
245                              struct wpa_driver_associate_params *params)
246 {
247         struct wpa_driver_prism54_data *drv = priv;
248         int ret = 0;
249
250         if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
251                                           params->wpa_ie_len) < 0)
252                 ret = -1;
253         if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
254                 ret = -1;
255         if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
256                                      params->ssid_len) < 0)
257                 ret = -1;
258         if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
259                 ret = -1;
260
261         return ret;
262 }
263
264 static void show_set_key_error(struct prism2_hostapd_param *param)
265 {
266         switch (param->u.crypt.err) {
267         case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
268                 wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
269                            param->u.crypt.alg);
270                 wpa_printf(MSG_INFO, "You may need to load kernel module to "
271                            "register that algorithm.");
272                 wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
273                            "WEP.");
274                 break;
275         case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
276                 wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
277                            MAC2STR(param->sta_addr));
278                 break;
279         case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
280                 wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
281                 break;
282         case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
283                 wpa_printf(MSG_INFO, "Key setting failed.");
284                 break;
285         case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
286                 wpa_printf(MSG_INFO, "TX key index setting failed.");
287                 break;
288         case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
289                 wpa_printf(MSG_INFO, "Card configuration failed.");
290                 break;
291         }
292 }
293
294
295 static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
296 {
297         struct wpa_driver_prism54_data *drv = priv;
298         return wpa_driver_wext_get_bssid(drv->wext, bssid);
299 }
300
301
302 static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
303 {
304         struct wpa_driver_prism54_data *drv = priv;
305         return wpa_driver_wext_get_ssid(drv->wext, ssid);
306 }
307
308
309 static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
310 {
311         struct wpa_driver_prism54_data *drv = priv;
312         return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
313 }
314
315
316 static int wpa_driver_prism54_get_scan_results(void *priv,
317                                             struct wpa_scan_result *results,
318                                             size_t max_size)
319 {
320         struct wpa_driver_prism54_data *drv = priv;
321         return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
322 }
323
324
325 static int wpa_driver_prism54_set_operstate(void *priv, int state)
326 {
327         struct wpa_driver_prism54_data *drv = priv;
328         return wpa_driver_wext_set_operstate(drv->wext, state);
329 }
330
331
332 static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
333 {
334         struct wpa_driver_prism54_data *drv;
335
336         drv = os_zalloc(sizeof(*drv));
337         if (drv == NULL)
338                 return NULL;
339         drv->wext = wpa_driver_wext_init(ctx, ifname);
340         if (drv->wext == NULL) {
341                 os_free(drv);
342                 return NULL;
343         }
344
345         drv->ctx = ctx;
346         os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
347         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
348         if (drv->sock < 0) {
349                 wpa_driver_wext_deinit(drv->wext);
350                 os_free(drv);
351                 return NULL;
352         }
353
354         return drv;
355 }
356
357
358 static void wpa_driver_prism54_deinit(void *priv)
359 {
360         struct wpa_driver_prism54_data *drv = priv;
361         wpa_driver_wext_deinit(drv->wext);
362         close(drv->sock);
363         os_free(drv);
364 }
365
366
367 const struct wpa_driver_ops wpa_driver_prism54_ops = {
368         .name = "prism54",
369         .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
370         .get_bssid = wpa_driver_prism54_get_bssid,
371         .get_ssid = wpa_driver_prism54_get_ssid,
372         .set_wpa = wpa_driver_prism54_set_wpa,
373         .set_key = wpa_driver_prism54_set_key,
374         .set_countermeasures = wpa_driver_prism54_set_countermeasures,
375         .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
376         .scan = wpa_driver_prism54_scan,
377         .get_scan_results = wpa_driver_prism54_get_scan_results,
378         .deauthenticate = wpa_driver_prism54_deauthenticate,
379         .disassociate = wpa_driver_prism54_disassociate,
380         .associate = wpa_driver_prism54_associate,
381         .init = wpa_driver_prism54_init,
382         .deinit = wpa_driver_prism54_deinit,
383         .set_operstate = wpa_driver_prism54_set_operstate,
384 };