udp: Merge udp_send and udp_output
[dragonfly.git] / contrib / wpa_supplicant / src / drivers / driver_ipw.c
1 /*
2  * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
3  * Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com>
4  * Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk>
5  * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * Alternatively, this software may be distributed under the terms of BSD
12  * license.
13  *
14  * See README and COPYING for more details.
15  *
16  * Please note that ipw2100/2200 drivers change to use generic Linux wireless
17  * extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
18  * or newer). driver_wext.c should be used in those cases.
19  */
20
21 #include "includes.h"
22 #include <sys/ioctl.h>
23
24 #include "wireless_copy.h"
25 #include "common.h"
26 #include "driver.h"
27 #include "driver_wext.h"
28
29 struct wpa_driver_ipw_data {
30         void *wext; /* private data for driver_wext */
31         void *ctx;
32         char ifname[IFNAMSIZ + 1];
33         int sock;
34 };
35
36 /* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
37
38 #define IPW_IOCTL_WPA_SUPPLICANT                SIOCIWFIRSTPRIV+30
39
40 #define IPW_CMD_SET_WPA_PARAM                   1
41 #define IPW_CMD_SET_WPA_IE                      2
42 #define IPW_CMD_SET_ENCRYPTION                  3
43 #define IPW_CMD_MLME                            4
44
45 #define IPW_PARAM_WPA_ENABLED                   1
46 #define IPW_PARAM_TKIP_COUNTERMEASURES          2
47 #define IPW_PARAM_DROP_UNENCRYPTED              3
48 #define IPW_PARAM_PRIVACY_INVOKED               4
49 #define IPW_PARAM_AUTH_ALGS                     5
50 #define IPW_PARAM_IEEE_802_1X                   6
51
52 #define IPW_MLME_STA_DEAUTH                     1
53 #define IPW_MLME_STA_DISASSOC                   2
54
55 #define IPW_CRYPT_ERR_UNKNOWN_ALG               2
56 #define IPW_CRYPT_ERR_UNKNOWN_ADDR              3
57 #define IPW_CRYPT_ERR_CRYPT_INIT_FAILED         4
58 #define IPW_CRYPT_ERR_KEY_SET_FAILED            5
59 #define IPW_CRYPT_ERR_TX_KEY_SET_FAILED         6
60 #define IPW_CRYPT_ERR_CARD_CONF_FAILED          7
61
62 #define IPW_CRYPT_ALG_NAME_LEN                  16
63
64 struct ipw_param {
65         u32 cmd;
66         u8 sta_addr[ETH_ALEN];
67         union {
68                 struct {
69                         u8 name;
70                         u32 value;
71                 } wpa_param;
72                 struct {
73                         u32 len;
74                         u8 reserved[32];
75                         u8 data[0];
76                 } wpa_ie;
77                 struct{
78                         u32 command;
79                         u32 reason_code;
80                 } mlme;
81                 struct {
82                         u8 alg[IPW_CRYPT_ALG_NAME_LEN];
83                         u8 set_tx;
84                         u32 err;
85                         u8 idx;
86                         u8 seq[8];
87                         u16 key_len;
88                         u8 key[0];
89                 } crypt;
90
91         } u;
92 };
93
94 /* end of ipw2100.c and ipw2200.c code */
95
96 static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
97                      struct ipw_param *param, int len, int show_err)
98 {
99         struct iwreq iwr;
100
101         os_memset(&iwr, 0, sizeof(iwr));
102         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
103         iwr.u.data.pointer = (caddr_t) param;
104         iwr.u.data.length = len;
105
106         if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
107                 int ret = errno;
108                 if (show_err) 
109                         perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
110                 return ret;
111         }
112
113         return 0;
114 }
115
116
117 static void ipw_show_set_key_error(struct ipw_param *param)
118 {
119         switch (param->u.crypt.err) {
120         case IPW_CRYPT_ERR_UNKNOWN_ALG:
121                 wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
122                            param->u.crypt.alg);
123                 wpa_printf(MSG_INFO, "You may need to load kernel module to "
124                            "register that algorithm.");
125                 wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
126                            " WEP.");
127                 break;
128         case IPW_CRYPT_ERR_UNKNOWN_ADDR:
129                 wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
130                            MAC2STR(param->sta_addr));
131                 break;
132         case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
133                 wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
134                 break;
135         case IPW_CRYPT_ERR_KEY_SET_FAILED:
136                 wpa_printf(MSG_INFO, "Key setting failed.");
137                 break;
138         case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
139                 wpa_printf(MSG_INFO, "TX key index setting failed.");
140                 break;
141         case IPW_CRYPT_ERR_CARD_CONF_FAILED:
142                 wpa_printf(MSG_INFO, "Card configuration failed.");
143                 break;
144         }
145 }
146
147
148 static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
149                           const u8 *wpa_ie, size_t wpa_ie_len)
150 {
151         struct ipw_param *param;
152         int ret;
153         size_t blen = sizeof(*param) + wpa_ie_len;
154
155         param = os_zalloc(blen);
156         if (param == NULL)
157                 return -1;
158
159         param->cmd = IPW_CMD_SET_WPA_IE;
160         param->u.wpa_ie.len = wpa_ie_len;
161         os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
162         
163         ret = ipw_ioctl(drv, param, blen, 1);
164
165         os_free(param);
166         return ret;
167 }
168
169
170 static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
171                              u32 value)
172 {
173         struct ipw_param param;
174
175         os_memset(&param, 0, sizeof(param));
176         param.cmd = IPW_CMD_SET_WPA_PARAM;
177         param.u.wpa_param.name = name;
178         param.u.wpa_param.value = value;
179
180         return ipw_ioctl(drv, &param, sizeof(param), 1);
181 }
182
183
184 static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
185                     int cmd, int reason)
186 {
187         struct ipw_param param;
188
189         os_memset(&param, 0, sizeof(param));
190         os_memcpy(param.sta_addr, addr, ETH_ALEN);      
191         param.cmd = IPW_CMD_MLME;
192         param.u.mlme.command = cmd;
193         param.u.mlme.reason_code = reason;
194
195         return ipw_ioctl(drv, &param, sizeof(param), 1);
196 }
197
198
199 static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
200 {
201         struct wpa_driver_ipw_data *drv = priv;
202         int ret = 0;
203
204         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
205
206         if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
207                 ret = -1;
208
209         if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
210                 ret = -1;
211
212         return ret;
213 }
214
215
216 static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
217                                       const u8 *addr, int key_idx, int set_tx,
218                                       const u8 *seq, size_t seq_len,
219                                       const u8 *key, size_t key_len)
220 {
221         struct wpa_driver_ipw_data *drv = priv;
222         struct ipw_param *param;
223         u8 *buf;
224         size_t blen;
225         int ret = 0;
226         char *alg_name;
227
228         switch (alg) {
229         case WPA_ALG_NONE:
230                 alg_name = "none";
231                 break;
232         case WPA_ALG_WEP:
233                 alg_name = "WEP";
234                 break;
235         case WPA_ALG_TKIP:
236                 alg_name = "TKIP";
237                 break;
238         case WPA_ALG_CCMP:
239                 alg_name = "CCMP";
240                 break;
241         default:
242                 return -1;
243         }
244
245         wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
246                    "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
247                    (unsigned long) seq_len, (unsigned long) key_len);
248
249         if (seq_len > 8)
250                 return -2;
251
252         blen = sizeof(*param) + key_len;
253         buf = os_zalloc(blen);
254         if (buf == NULL)
255                 return -1;
256
257         param = (struct ipw_param *) buf;
258         param->cmd = IPW_CMD_SET_ENCRYPTION;
259         os_memset(param->sta_addr, 0xff, ETH_ALEN);
260         os_strlcpy((char *) param->u.crypt.alg, alg_name,
261                    IPW_CRYPT_ALG_NAME_LEN);
262         param->u.crypt.set_tx = set_tx ? 1 : 0;
263         param->u.crypt.idx = key_idx;
264         os_memcpy(param->u.crypt.seq, seq, seq_len);
265         param->u.crypt.key_len = key_len;
266         os_memcpy((u8 *) (param + 1), key, key_len);
267
268         if (ipw_ioctl(drv, param, blen, 1)) {
269                 wpa_printf(MSG_WARNING, "Failed to set encryption.");
270                 ipw_show_set_key_error(param);
271                 ret = -1;
272         }
273         os_free(buf);
274
275         return ret;
276 }
277
278
279 static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
280 {
281         struct wpa_driver_ipw_data *drv = priv;
282         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
283         return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
284                                      enabled);
285
286 }
287
288
289 static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
290 {
291         struct wpa_driver_ipw_data *drv = priv;
292         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
293         return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
294                                      enabled);
295 }
296
297
298 static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
299                                          int reason_code)
300 {
301         struct wpa_driver_ipw_data *drv = priv;
302         return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
303 }
304
305
306 static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
307                                        int reason_code)
308 {
309         struct wpa_driver_ipw_data *drv = priv;
310         return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
311 }
312
313
314 static int
315 wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
316 {
317         struct wpa_driver_ipw_data *drv = priv;
318         int ret = 0;
319         int unencrypted_eapol;
320
321         if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
322                 ret = -1;
323         if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
324                                      params->ssid_len) < 0)
325                 ret = -1;
326         if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
327                 ret = -1;
328
329         if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
330             params->key_mgmt_suite == KEY_MGMT_PSK)
331                 unencrypted_eapol = 0;
332         else
333                 unencrypted_eapol = 1;
334         
335         if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
336                               unencrypted_eapol) < 0) {
337                 wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
338                            "ieee_802_1x param");
339         }
340
341         return ret;
342 }
343
344
345 static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
346 {
347         struct wpa_driver_ipw_data *drv = priv;
348         int algs = 0;
349
350         if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
351                 algs |= 1;
352         if (auth_alg & AUTH_ALG_SHARED_KEY)
353                 algs |= 2;
354         if (auth_alg & AUTH_ALG_LEAP)
355                 algs |= 4;
356         if (algs == 0)
357                 algs = 1; /* at least one algorithm should be set */
358
359         wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
360         return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
361 }
362
363
364 static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
365 {
366         struct wpa_driver_ipw_data *drv = priv;
367         return wpa_driver_wext_get_bssid(drv->wext, bssid);
368 }
369
370
371 static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
372 {
373         struct wpa_driver_ipw_data *drv = priv;
374         return wpa_driver_wext_get_ssid(drv->wext, ssid);
375 }
376
377
378 static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
379 {
380         struct wpa_driver_ipw_data *drv = priv;
381         return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
382 }
383
384
385 static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
386 {
387         struct wpa_driver_ipw_data *drv = priv;
388         return wpa_driver_wext_get_scan_results(drv->wext);
389 }
390
391
392 static int wpa_driver_ipw_set_operstate(void *priv, int state)
393 {
394         struct wpa_driver_ipw_data *drv = priv;
395         return wpa_driver_wext_set_operstate(drv->wext, state);
396 }
397
398
399 static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
400 {
401         struct wpa_driver_ipw_data *drv;
402         int ver;
403
404         wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
405         drv = os_zalloc(sizeof(*drv));
406         if (drv == NULL)
407                 return NULL;
408         drv->wext = wpa_driver_wext_init(ctx, ifname);
409         if (drv->wext == NULL) {
410                 os_free(drv);
411                 return NULL;
412         }
413
414         ver = wpa_driver_wext_get_version(drv->wext);
415         if (ver >= 18) {
416                 wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
417                            "detected.", ver);
418                 wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
419                            "(-Dwext) instead of driver_ipw.");
420         }
421
422         drv->ctx = ctx;
423         os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
424         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
425         if (drv->sock < 0) {
426                 wpa_driver_wext_deinit(drv->wext);
427                 os_free(drv);
428                 return NULL;
429         }
430
431         return drv;
432 }
433
434
435 static void wpa_driver_ipw_deinit(void *priv)
436 {
437         struct wpa_driver_ipw_data *drv = priv;
438         wpa_driver_wext_deinit(drv->wext);
439         close(drv->sock);
440         os_free(drv);
441 }
442
443
444 const struct wpa_driver_ops wpa_driver_ipw_ops = {
445         .name = "ipw",
446         .desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
447         "or newer)",
448         .get_bssid = wpa_driver_ipw_get_bssid,
449         .get_ssid = wpa_driver_ipw_get_ssid,
450         .set_wpa = wpa_driver_ipw_set_wpa,
451         .set_key = wpa_driver_ipw_set_key,
452         .set_countermeasures = wpa_driver_ipw_set_countermeasures,
453         .set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
454         .scan = wpa_driver_ipw_scan,
455         .get_scan_results2 = wpa_driver_ipw_get_scan_results,
456         .deauthenticate = wpa_driver_ipw_deauthenticate,
457         .disassociate = wpa_driver_ipw_disassociate,
458         .associate = wpa_driver_ipw_associate,
459         .set_auth_alg = wpa_driver_ipw_set_auth_alg,
460         .init = wpa_driver_ipw_init,
461         .deinit = wpa_driver_ipw_deinit,
462         .set_operstate = wpa_driver_ipw_set_operstate,
463 };