cc56d52b489b85bea968a97d780113b1652102ec
[wpasupplicant] / src / drivers / driver_prism54.c
1 /*
2  * WPA Supplicant - driver interaction with Linux Prism54.org driver
3  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4  * Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
5  * Copyright (c) 2004, Bell Kin <bell_kin@pek.com.tw>
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
17 #include "includes.h"
18 #include <sys/ioctl.h>
19
20 #include "wireless_copy.h"
21 #include "common.h"
22 #include "driver.h"
23 #include "driver_wext.h"
24 #include "driver_hostap.h"
25
26 #ifdef HOSTAPD
27
28 #include <net/if_arp.h>
29 #include <netpacket/packet.h>
30
31 #include "driver.h"
32 #include "eloop.h"
33 #include "prism54.h"
34 #include "radius/radius.h"
35 #include "../../hostapd/hostapd.h"
36 #include "../../hostapd/config.h"
37 #include "../../hostapd/ieee802_1x.h"
38 #include "../../hostapd/ieee802_11.h"
39 #include "../../hostapd/wpa.h"
40 #include "../../hostapd/sta_info.h"
41 #include "../../hostapd/accounting.h"
42
43
44 const int PIM_BUF_SIZE = 4096;
45
46 struct prism54_driver_data {
47         struct hostapd_data *hapd;
48         char iface[IFNAMSIZ + 1];
49         int sock; /* raw packet socket for 802.3 access */
50         int pim_sock; /* socket for pimfor packet */
51         char macs[2007][6];
52 };
53
54
55 static int mac_id_refresh(struct prism54_driver_data *data, int id, char *mac)
56 {
57         if (id < 0 || id > 2006) {
58                 return -1;
59         }
60         memcpy(&data->macs[id][0], mac, ETH_ALEN);
61         return 0;
62 }
63
64
65 static char * mac_id_get(struct prism54_driver_data *data, int id)
66 {
67         if (id < 0 || id > 2006) {
68                 return NULL;
69         }
70         return &data->macs[id][0];
71 }
72
73
74 /* wait for a specific pimfor, timeout in 10ms resolution */
75 /* pim_sock must be non-block to prevent dead lock from no response */
76 /* or same response type in series */
77 static int prism54_waitpim(void *priv, unsigned long oid, void *buf, int len,
78                            int timeout)
79 {
80         struct prism54_driver_data *drv = priv;
81         struct timeval tv, stv, ctv;
82         fd_set pfd;
83         int rlen;
84         pimdev_hdr *pkt;
85
86         pkt = malloc(8192);
87         if (pkt == NULL)
88                 return -1;
89
90         FD_ZERO(&pfd);
91         gettimeofday(&stv, NULL);
92         do {
93                 FD_SET(drv->pim_sock, &pfd);
94                 tv.tv_sec = 0;
95                 tv.tv_usec = 10000;
96                 if (select(drv->pim_sock + 1, &pfd, NULL, NULL, &tv)) {
97                         rlen = recv(drv->pim_sock, pkt, 8192, 0);
98                         if (rlen > 0) {
99                                 if (pkt->oid == htonl(oid)) {
100                                         if (rlen <= len) {
101                                                 if (buf != NULL) {
102                                                         memcpy(buf, pkt, rlen);
103                                                 }
104                                                 free(pkt);
105                                                 return rlen;
106                                         } else {
107                                                 printf("buffer too small\n");
108                                                 free(pkt);
109                                                 return -1;
110                                         }
111                                 } else {
112                                         gettimeofday(&ctv, NULL);
113                                         continue;
114                                 }
115                         }
116                 }
117                 gettimeofday(&ctv, NULL);
118         } while (((ctv.tv_sec - stv.tv_sec) * 100 +
119                   (ctv.tv_usec - stv.tv_usec) / 10000) > timeout);
120         free(pkt);
121         return 0;
122 }
123
124
125 /* send an eapol packet */
126 static int prism54_send_eapol(void *priv, const u8 *addr,
127                               const u8 *data, size_t data_len, int encrypt,
128                               const u8 *own_addr)
129 {
130         struct prism54_driver_data *drv = priv;
131         ieee802_3_hdr *hdr;
132         size_t len;
133         u8 *pos;
134         int res;
135
136         len = sizeof(*hdr) + data_len;
137         hdr = os_zalloc(len);
138         if (hdr == NULL) {
139                 printf("malloc() failed for prism54_send_data(len=%lu)\n",
140                        (unsigned long) len);
141                 return -1;
142         }
143
144         memcpy(&hdr->da[0], addr, ETH_ALEN);
145         memcpy(&hdr->sa[0], own_addr, ETH_ALEN);
146         hdr->type = htons(ETH_P_PAE);
147         pos = (u8 *) (hdr + 1);
148         memcpy(pos, data, data_len);
149
150         res = send(drv->sock, hdr, len, 0);
151         free(hdr);
152
153         if (res < 0) {
154                 perror("hostapd_send_eapol: send");
155                 printf("hostapd_send_eapol - packet len: %lu - failed\n",
156                        (unsigned long) len);
157         }
158
159         return res;
160 }
161
162
163 /* open data channel(auth-1) or eapol only(unauth-0) */
164 static int prism54_set_sta_authorized(void *priv, const u8 *addr,
165                                       int authorized)
166 {
167         struct prism54_driver_data *drv = priv;
168         pimdev_hdr *hdr;
169         char *pos;
170
171         hdr = malloc(sizeof(*hdr) + ETH_ALEN);
172         if (hdr == NULL)
173                 return -1;
174         hdr->op = htonl(PIMOP_SET);
175         if (authorized) {
176                 hdr->oid = htonl(DOT11_OID_EAPAUTHSTA);
177         } else {
178                 hdr->oid = htonl(DOT11_OID_EAPUNAUTHSTA);
179         }
180         pos = (char *) (hdr + 1);
181         memcpy(pos, addr, ETH_ALEN);
182         send(drv->pim_sock, hdr, sizeof(*hdr) + ETH_ALEN, 0);
183         prism54_waitpim(priv, hdr->oid, hdr, sizeof(*hdr) + ETH_ALEN, 10);
184         free(hdr);
185         return 0;
186 }
187
188
189 static int
190 prism54_sta_set_flags(void *priv, const u8 *addr, int total_flags,
191                       int flags_or, int flags_and)
192 {
193         /* For now, only support setting Authorized flag */
194         if (flags_or & WLAN_STA_AUTHORIZED)
195                 return prism54_set_sta_authorized(priv, addr, 1);
196         if (flags_and & WLAN_STA_AUTHORIZED)
197                 return prism54_set_sta_authorized(priv, addr, 0);
198         return 0;
199 }
200
201
202 static int prism54_set_key(const char *ifname, void *priv, wpa_alg alg,
203                            const u8 *addr, int key_idx, int set_tx,
204                            const u8 *seq, size_t seq_len,
205                            const u8 *key, size_t key_len)
206 {
207         struct prism54_driver_data *drv = priv;
208         pimdev_hdr *hdr;
209         struct obj_stakey *keys;
210         u8 *buf;
211         size_t blen;
212         int ret = 0;
213
214         blen = sizeof(struct obj_stakey) + sizeof(pimdev_hdr);
215         hdr = malloc(blen);
216         if (hdr == NULL) {
217                 printf("memory low\n");
218                 return -1;
219         }
220         keys = (struct obj_stakey *) &hdr[1];
221         if (!addr) {
222                 memset(&keys->address[0], 0xff, ETH_ALEN);
223         } else {
224                 memcpy(&keys->address[0], addr, ETH_ALEN);
225         }
226         switch (alg) {
227         case WPA_ALG_WEP:
228                 keys->type = DOT11_PRIV_WEP;
229                 break;
230         case WPA_ALG_TKIP:
231                 keys->type = DOT11_PRIV_TKIP;
232                 break;
233         case WPA_ALG_NONE:
234                 /* the only way to clear the key is to deauth it */
235                 /* and prism54 is capable to receive unencrypted packet */
236                 /* so we do nothing here */
237                 free(hdr);
238                 return 0;
239         default:
240                 printf("bad auth type: %d\n", alg);
241                 free(hdr);
242                 return -1;
243         }
244         buf = (u8 *) &keys->key[0];
245         keys->length = key_len;
246         keys->keyid = key_idx;
247         keys->options = htons(DOT11_STAKEY_OPTION_DEFAULTKEY);
248         keys->reserved = 0;
249
250         hdr->op = htonl(PIMOP_SET);
251         hdr->oid = htonl(DOT11_OID_STAKEY);
252
253         memcpy(buf, key, key_len);
254         
255         ret = send(drv->pim_sock, hdr, blen, 0);
256         if (ret < 0) {
257                 free(hdr);
258                 return ret;
259         }
260         prism54_waitpim(priv, hdr->oid, hdr, blen, 10);
261
262         free(hdr);
263
264         return 0;
265 }
266
267
268 /* get TKIP station sequence counter, prism54 is only 6 bytes */
269 static int prism54_get_seqnum(const char *ifname, void *priv, const u8 *addr,
270                               int idx, u8 *seq)
271 {
272         struct prism54_driver_data *drv = priv;
273         struct obj_stasc *stasc;
274         pimdev_hdr *hdr;
275         size_t blen;
276         int ret = 0;
277
278         blen = sizeof(*stasc) + sizeof(*hdr);
279         hdr = malloc(blen);
280         if (hdr == NULL)
281                 return -1;
282
283         stasc = (struct obj_stasc *) &hdr[1];
284         
285         if (addr == NULL)
286                 memset(&stasc->address[0], 0xff, ETH_ALEN);
287         else
288                 memcpy(&stasc->address[0], addr, ETH_ALEN);
289
290         hdr->oid = htonl(DOT11_OID_STASC);
291         hdr->op = htonl(PIMOP_GET);
292         stasc->keyid = idx;
293         if (send(drv->pim_sock,hdr,blen,0) <= 0) {
294                 free(hdr);
295                 return -1;
296         }
297         if (prism54_waitpim(priv, DOT11_OID_STASC, hdr, blen, 10) <= 0) {
298                 ret = -1;
299         } else {
300                 if (hdr->op == (int) htonl(PIMOP_RESPONSE)) {
301                         memcpy(seq + 2, &stasc->sc_high, ETH_ALEN);
302                         memset(seq, 0, 2);
303                 } else {
304                         ret = -1;
305                 }
306         }
307         free(hdr);
308
309         return ret;
310 }
311
312
313 /* include unencrypted, set mlme autolevel to extended */
314 static int prism54_init_1x(void *priv)
315 {
316         struct prism54_driver_data *drv = priv;
317         pimdev_hdr *hdr;
318         unsigned long *ul;
319         int blen = sizeof(*hdr) + sizeof(*ul);
320
321         hdr = malloc(blen);
322         if (hdr == NULL)
323                 return -1;
324
325         ul = (unsigned long *) &hdr[1];
326         hdr->op = htonl(PIMOP_SET);
327         hdr->oid = htonl(DOT11_OID_EXUNENCRYPTED);
328         *ul = htonl(DOT11_BOOL_TRUE); /* not accept */
329         send(drv->pim_sock, hdr, blen, 0);
330         prism54_waitpim(priv, DOT11_OID_EXUNENCRYPTED, hdr, blen, 10);
331         hdr->op = htonl(PIMOP_SET);
332         hdr->oid = htonl(DOT11_OID_MLMEAUTOLEVEL);
333         *ul = htonl(DOT11_MLME_EXTENDED);
334         send(drv->pim_sock, hdr, blen, 0);
335         prism54_waitpim(priv, DOT11_OID_MLMEAUTOLEVEL, hdr, blen, 10);
336         hdr->op = htonl(PIMOP_SET);
337         hdr->oid = htonl(DOT11_OID_DOT1XENABLE);
338         *ul = htonl(DOT11_BOOL_TRUE);
339         send(drv->pim_sock, hdr, blen, 0);
340         prism54_waitpim(priv, DOT11_OID_DOT1XENABLE, hdr, blen, 10);
341         hdr->op = htonl(PIMOP_SET);
342         hdr->oid = htonl(DOT11_OID_AUTHENABLE);
343         *ul = htonl(DOT11_AUTH_OS); /* OS */
344         send(drv->pim_sock, hdr, blen, 0);
345         prism54_waitpim(priv, DOT11_OID_AUTHENABLE, hdr, blen, 10);
346         free(hdr);
347         return 0;
348 }
349
350
351 static int prism54_set_privacy_invoked(const char *ifname, void *priv,
352                                        int flag)
353 {
354         struct prism54_driver_data *drv = priv;
355         pimdev_hdr *hdr;
356         unsigned long *ul;
357         int ret;
358         int blen = sizeof(*hdr) + sizeof(*ul);
359         hdr = malloc(blen);
360         if (hdr == NULL)
361                 return -1;
362         ul = (unsigned long *) &hdr[1];
363         hdr->op = htonl(PIMOP_SET);
364         hdr->oid = htonl(DOT11_OID_PRIVACYINVOKED);
365         if (flag) {
366                 *ul = htonl(DOT11_BOOL_TRUE); /* has privacy */
367         } else {
368                 *ul = 0;
369         }
370         ret = send(drv->pim_sock, hdr, blen, 0);
371         if (ret >= 0) {
372                 ret = prism54_waitpim(priv, DOT11_OID_PRIVACYINVOKED, hdr,
373                                       blen, 10);
374         }
375         free(hdr);
376         return ret;
377 }
378
379  
380 static int prism54_ioctl_setiwessid(const char *ifname, void *priv,
381                                     const u8 *buf, int len)
382 {
383 #if 0
384         struct prism54_driver_data *drv = priv;
385         struct iwreq iwr;
386
387         memset(&iwr, 0, sizeof(iwr));
388         os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
389         iwr.u.essid.flags = 1; /* SSID active */
390         iwr.u.essid.pointer = (caddr_t) buf;
391         iwr.u.essid.length = len + 1;
392
393         if (ioctl(drv->pim_sock, SIOCSIWESSID, &iwr) < 0) {
394                 perror("ioctl[SIOCSIWESSID]");
395                 printf("len=%d\n", len);
396                 return -1;
397         }
398 #endif
399         return 0;
400 }
401
402
403 /* kick all stations */
404 /* does not work during init, but at least it won't crash firmware */
405 static int prism54_flush(void *priv)
406 {
407         struct prism54_driver_data *drv = priv;
408         struct obj_mlmeex *mlme;
409         pimdev_hdr *hdr;
410         int ret;
411         unsigned int i;
412         long *nsta;
413         int blen = sizeof(*hdr) + sizeof(*mlme);
414         char *mac_id;
415
416         hdr = os_zalloc(blen);
417         if (hdr == NULL)
418                 return -1;
419
420         mlme = (struct obj_mlmeex *) &hdr[1];
421         nsta = (long *) &hdr[1];
422         hdr->op = htonl(PIMOP_GET);
423         hdr->oid = htonl(DOT11_OID_CLIENTS);
424         ret = send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(long), 0);
425         ret = prism54_waitpim(priv, DOT11_OID_CLIENTS, hdr, blen, 10);
426         if ((ret < 0) || (hdr->op != (int) htonl(PIMOP_RESPONSE)) ||
427             (le_to_host32(*nsta) > 2007)) {
428                 free(hdr);
429                 return 0;
430         }
431         for (i = 0; i < le_to_host32(*nsta); i++) {
432                 mlme->id = -1;
433                 mac_id = mac_id_get(drv, i);
434                 if (mac_id)
435                         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
436                 mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
437                 mlme->state = htons(DOT11_STATE_NONE);
438                 mlme->size = 0;
439                 hdr->op = htonl(PIMOP_SET);
440                 hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
441                 ret = send(drv->pim_sock, hdr, blen, 0);
442                 prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen,
443                                 100);
444         }
445         for (i = 0; i < le_to_host32(*nsta); i++) {
446                 mlme->id = -1;
447                 mac_id = mac_id_get(drv, i);
448                 if (mac_id)
449                         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
450                 mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
451                 mlme->state = htons(DOT11_STATE_NONE);
452                 mlme->size = 0;
453                 hdr->op = htonl(PIMOP_SET);
454                 hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
455                 ret = send(drv->pim_sock, hdr, blen, 0);
456                 prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen,
457                                 100);
458         }
459         free(hdr);
460         return 0;
461 }
462
463
464 static int prism54_sta_deauth(void *priv, const u8 *addr, int reason)
465 {
466         struct prism54_driver_data *drv = priv;
467         pimdev_hdr *hdr;
468         struct obj_mlmeex *mlme;
469         int ret;
470         int blen = sizeof(*hdr) + sizeof(*mlme);
471         hdr = malloc(blen);
472         if (hdr == NULL)
473                 return -1;
474         mlme = (struct obj_mlmeex *) &hdr[1];
475         hdr->op = htonl(PIMOP_SET);
476         hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
477         memcpy(&mlme->address[0], addr, ETH_ALEN);
478         mlme->id = -1;
479         mlme->state = htons(DOT11_STATE_NONE);
480         mlme->code = host_to_le16(reason);
481         mlme->size = 0;
482         ret = send(drv->pim_sock, hdr, blen, 0);
483         prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 10);
484         free(hdr);
485         return ret;
486 }
487
488
489 static int prism54_sta_disassoc(void *priv, const u8 *addr, int reason)
490 {
491         struct prism54_driver_data *drv = priv;
492         pimdev_hdr *hdr;
493         struct obj_mlmeex *mlme;
494         int ret;
495         int blen = sizeof(*hdr) + sizeof(*mlme);
496         hdr = malloc(blen);
497         if (hdr == NULL)
498                 return -1;
499         mlme = (struct obj_mlmeex *) &hdr[1];
500         hdr->op = htonl(PIMOP_SET);
501         hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
502         memcpy(&mlme->address[0], addr, ETH_ALEN);
503         mlme->id = -1;
504         mlme->state = htons(DOT11_STATE_NONE);
505         mlme->code = host_to_le16(reason);
506         mlme->size = 0;
507         ret = send(drv->pim_sock, hdr, blen, 0);
508         prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 10);
509         free(hdr);
510         return ret;
511 }
512
513
514 static int prism54_get_inact_sec(void *priv, const u8 *addr)
515 {
516         struct prism54_driver_data *drv = priv;
517         pimdev_hdr *hdr;
518         struct obj_sta *sta;
519         int blen = sizeof(*hdr) + sizeof(*sta);
520         int ret;
521
522         hdr = malloc(blen);
523         if (hdr == NULL)
524                 return -1;
525         hdr->op = htonl(PIMOP_GET);
526         hdr->oid = htonl(DOT11_OID_CLIENTFIND);
527         sta = (struct obj_sta *) &hdr[1];
528         memcpy(&sta->address[0], addr, ETH_ALEN);
529         ret = send(drv->pim_sock, hdr, blen, 0);
530         ret = prism54_waitpim(priv, DOT11_OID_CLIENTFIND, hdr, blen, 10);
531         if (ret != blen) {
532                 printf("get_inact_sec: bad return %d\n", ret);
533                 free(hdr);
534                 return -1;
535         }
536         if (hdr->op != (int) htonl(PIMOP_RESPONSE)) {
537                 printf("get_inact_sec: bad resp\n");
538                 free(hdr);
539                 return -1;
540         }
541         free(hdr);
542         return le_to_host16(sta->age);
543 }
544
545
546 /* set attachments */
547 static int prism54_set_generic_elem(const char *ifname, void *priv,
548                                     const u8 *elem, size_t elem_len)
549 {
550         struct prism54_driver_data *drv = priv;
551         pimdev_hdr *hdr;
552         char *pos;
553         struct obj_attachment_hdr *attach;
554         size_t blen = sizeof(*hdr) + sizeof(*attach) + elem_len;
555         hdr = os_zalloc(blen);
556         if (hdr == NULL) {
557                 printf("%s: memory low\n", __func__);
558                 return -1;
559         }
560         hdr->op = htonl(PIMOP_SET);
561         hdr->oid = htonl(DOT11_OID_ATTACHMENT);
562         attach = (struct obj_attachment_hdr *)&hdr[1];
563         attach->type = DOT11_PKT_BEACON;
564         attach->id = -1;
565         attach->size = host_to_le16((short)elem_len);
566         pos = ((char*) attach) + sizeof(*attach);
567         if (elem)
568                 memcpy(pos, elem, elem_len);
569         send(drv->pim_sock, hdr, blen, 0);
570         attach->type = DOT11_PKT_PROBE_RESP;
571         send(drv->pim_sock, hdr, blen, 0);
572         free(hdr);
573         return 0;
574 }
575
576
577 /* tell the card to auth the sta */
578 static void prism54_handle_probe(struct prism54_driver_data *drv,
579                                  void *buf, size_t len)
580 {
581         struct obj_mlmeex *mlme;
582         pimdev_hdr *hdr;
583         struct sta_info *sta;
584         hdr = (pimdev_hdr *)buf;
585         mlme = (struct obj_mlmeex *) &hdr[1];
586         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
587         if (sta != NULL) {
588                 if (sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC))
589                         return;
590         }
591         if (len < sizeof(*mlme)) {
592                 printf("bad probe packet\n");
593                 return;
594         }
595         mlme->state = htons(DOT11_STATE_AUTHING);
596         mlme->code = 0;
597         hdr->op = htonl(PIMOP_SET);
598         hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
599         mlme->size = 0;
600         send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
601 }
602
603
604 static void prism54_handle_deauth(struct prism54_driver_data *drv,
605                                   void *buf, size_t len)
606 {
607         struct obj_mlme *mlme;
608         pimdev_hdr *hdr;
609         struct sta_info *sta;
610         char *mac_id;
611
612         hdr = (pimdev_hdr *) buf;
613         mlme = (struct obj_mlme *) &hdr[1];
614         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
615         mac_id = mac_id_get(drv, mlme->id);
616         if (sta == NULL || mac_id == NULL)
617                 return;
618         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
619         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
620         wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
621         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
622         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
623         ap_free_sta(drv->hapd, sta);
624 }
625
626
627 static void prism54_handle_disassoc(struct prism54_driver_data *drv,
628                                     void *buf, size_t len)
629 {
630         struct obj_mlme *mlme;
631         pimdev_hdr *hdr;
632         struct sta_info *sta;
633         char *mac_id;
634
635         hdr = (pimdev_hdr *) buf;
636         mlme = (struct obj_mlme *) &hdr[1];
637         mac_id = mac_id_get(drv, mlme->id);
638         if (mac_id == NULL)
639                 return;
640         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
641         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
642         if (sta == NULL) {
643                 return;
644         }
645         sta->flags &= ~WLAN_STA_ASSOC;
646         wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
647         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
648         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
649         accounting_sta_stop(drv->hapd, sta);
650         ieee802_1x_free_station(sta);
651 }
652
653
654 /* to auth it, just allow it now, later for os/sk */
655 static void prism54_handle_auth(struct prism54_driver_data *drv,
656                                 void *buf, size_t len)
657 {
658         struct obj_mlmeex *mlme;
659         pimdev_hdr *hdr;
660         struct sta_info *sta;
661         int resp;
662
663         hdr = (pimdev_hdr *) buf;
664         mlme = (struct obj_mlmeex *) &hdr[1];
665         if (len < sizeof(*mlme)) {
666                 printf("bad auth packet\n");
667                 return;
668         }
669
670         if (mlme->state == htons(DOT11_STATE_AUTHING)) {
671                 sta = ap_sta_add(drv->hapd, (u8 *) &mlme->address[0]);
672                 if (drv->hapd->tkip_countermeasures) {
673                         resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
674                         goto fail;
675                 }
676                 mac_id_refresh(drv, mlme->id, &mlme->address[0]);
677                 if (!sta) {
678                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
679                         goto fail;
680                 }
681                 sta->flags &= ~WLAN_STA_PREAUTH;
682                 
683                 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
684                 sta->flags |= WLAN_STA_AUTH;
685                 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
686                 mlme->code = 0;
687                 mlme->state=htons(DOT11_STATE_AUTH);
688                 hdr->op = htonl(PIMOP_SET);
689                 hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
690                 mlme->size = 0;
691                 sta->timeout_next = STA_NULLFUNC;
692                 send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
693         }
694         return;
695
696 fail:
697         printf("auth fail: %x\n", resp);
698         mlme->code = host_to_le16(resp);
699         mlme->size = 0;
700         if (sta)
701                 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
702         hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
703         hdr->op = htonl(PIMOP_SET);
704         send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
705 }
706
707
708 /* do the wpa thing */
709 static void prism54_handle_assoc(struct prism54_driver_data *drv,
710                                  void *buf, size_t len)
711 {
712         pimdev_hdr *hdr;
713         struct obj_mlmeex *mlme;
714         struct ieee802_11_elems elems;
715         struct sta_info *sta;
716         u8 *wpa_ie;
717         u8 *cb;
718         int ieofs = 0;
719         size_t wpa_ie_len;
720         int resp, new_assoc;
721         char *mac_id;
722
723         resp = 0;
724         hdr = (pimdev_hdr *) buf;
725         mlme = (struct obj_mlmeex *) &hdr[1];
726         switch (ntohl(hdr->oid)) {
727                 case DOT11_OID_ASSOCIATE:
728                 case DOT11_OID_REASSOCIATE:
729                         mlme->size = 0;
730                 default:
731                         break;
732         }
733         if ((mlme->state == (int) htonl(DOT11_STATE_ASSOCING)) ||
734             (mlme->state == (int) htonl(DOT11_STATE_REASSOCING))) {
735                 if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
736                         printf("bad assoc packet\n");
737                         return;
738                 }
739                 mac_id = mac_id_get(drv, mlme->id);
740                 if (mac_id == NULL)
741                         return;
742                 memcpy(&mlme->address[0], mac_id, ETH_ALEN);
743                 sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
744                 if (sta == NULL) {
745                         printf("cannot get sta\n");
746                         return;
747                 }
748                 cb = (u8 *) &mlme->data[0];
749                 if (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) {
750                         ieofs = 4;
751                 } else if (hdr->oid == htonl(DOT11_OID_REASSOCIATEEX)) {
752                         ieofs = 10;
753                 }
754                 if (le_to_host16(mlme->size) <= ieofs) {
755                         printf("attach too small\n");
756                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
757                         goto fail;
758                 }
759                 if (ieee802_11_parse_elems(cb + ieofs,
760                                            le_to_host16(mlme->size) - ieofs,
761                                            &elems, 1) == ParseFailed) {
762                         printf("STA " MACSTR " sent invalid association "
763                                "request\n", MAC2STR(sta->addr));
764                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
765                         goto fail;
766                 }
767                 if ((drv->hapd->conf->wpa & WPA_PROTO_RSN) &&
768                     elems.rsn_ie) {
769                         wpa_ie = elems.rsn_ie;
770                         wpa_ie_len = elems.rsn_ie_len;
771                 } else if ((drv->hapd->conf->wpa & WPA_PROTO_WPA) &&
772                            elems.wpa_ie) {
773                         wpa_ie = elems.wpa_ie;
774                         wpa_ie_len = elems.wpa_ie_len;
775                 } else {
776                         wpa_ie = NULL;
777                         wpa_ie_len = 0;
778                 }
779                 if (drv->hapd->conf->wpa && wpa_ie == NULL) {
780                         printf("STA " MACSTR ": No WPA/RSN IE in association "
781                                "request\n", MAC2STR(sta->addr));
782                         resp = WLAN_STATUS_INVALID_IE;
783                         goto fail;
784                 }
785                 if (drv->hapd->conf->wpa) {
786                         int res;
787                         wpa_ie -= 2;
788                         wpa_ie_len += 2;
789                         if (sta->wpa_sm == NULL)
790                                 sta->wpa_sm = wpa_auth_sta_init(
791                                         drv->hapd->wpa_auth, sta->addr);
792                         if (sta->wpa_sm == NULL) {
793                                 printf("Failed to initialize WPA state "
794                                        "machine\n");
795                                 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
796                                 goto fail;
797                         }
798                         res = wpa_validate_wpa_ie(drv->hapd->wpa_auth,
799                                                   sta->wpa_sm,
800                                                   wpa_ie, wpa_ie_len,
801                                                   NULL, 0);
802                         if (res == WPA_INVALID_GROUP)
803                                 resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
804                         else if (res == WPA_INVALID_PAIRWISE)
805                                 resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
806                         else if (res == WPA_INVALID_AKMP)
807                                 resp = WLAN_STATUS_AKMP_NOT_VALID;
808                         else if (res == WPA_ALLOC_FAIL)
809                                 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
810                         else if (res != WPA_IE_OK)
811                                 resp = WLAN_STATUS_INVALID_IE;
812                         if (resp != WLAN_STATUS_SUCCESS)
813                                 goto fail;
814                 }
815                 hdr->oid = (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) ?
816                         htonl(DOT11_OID_ASSOCIATEEX) :
817                         htonl(DOT11_OID_REASSOCIATEEX);
818                 hdr->op = htonl(PIMOP_SET);
819                 mlme->code = 0;
820                 mlme->state = htons(DOT11_STATE_ASSOC);
821                 mlme->size = 0;
822                 send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
823                 return;
824         } else if (mlme->state==htons(DOT11_STATE_ASSOC)) {
825                 if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
826                         printf("bad assoc packet\n");
827                         return;
828                 }
829                 mac_id = mac_id_get(drv, mlme->id);
830                 if (mac_id == NULL)
831                         return;
832                 memcpy(&mlme->address[0], mac_id, ETH_ALEN);
833                 sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
834                 if (sta == NULL) {
835                         printf("cannot get sta\n");
836                         return;
837                 }
838                 new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
839                 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
840                 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
841                 hostapd_new_assoc_sta(drv->hapd, sta, !new_assoc);
842                 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
843                 sta->timeout_next = STA_NULLFUNC;
844                 return;
845         }
846         return;
847
848 fail:
849         printf("Prism54: assoc fail: %x\n", resp);
850         mlme->code = host_to_le16(resp);
851         mlme->size = 0;
852         mlme->state = htons(DOT11_STATE_ASSOCING);
853         hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
854         hdr->op = htonl(PIMOP_SET);
855         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
856         send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
857 }
858
859
860 static void handle_pim(int sock, void *eloop_ctx, void *sock_ctx)
861 {
862         struct prism54_driver_data *drv = eloop_ctx;
863         int len;
864         pimdev_hdr *hdr;
865
866         hdr = malloc(PIM_BUF_SIZE);
867         if (hdr == NULL)
868                 return;
869         len = recv(sock, hdr, PIM_BUF_SIZE, 0);
870         if (len < 0) {
871                 perror("recv");
872                 free(hdr);
873                 return;
874         }
875         if (len < 8) {
876                 printf("handle_pim: too short (%d)\n", len);
877                 free(hdr);
878                 return;
879         }
880
881         if (hdr->op != (int) htonl(PIMOP_TRAP)) {
882                 free(hdr);
883                 return;
884         }
885         switch (ntohl(hdr->oid)) {
886                 case DOT11_OID_PROBE:
887                         prism54_handle_probe(drv, hdr, len);
888                         break;
889                 case DOT11_OID_DEAUTHENTICATEEX:
890                 case DOT11_OID_DEAUTHENTICATE:
891                         prism54_handle_deauth(drv, hdr, len);
892                         break;
893                 case DOT11_OID_DISASSOCIATEEX:
894                 case DOT11_OID_DISASSOCIATE:
895                         prism54_handle_disassoc(drv, hdr, len);
896                         break;
897                 case DOT11_OID_AUTHENTICATEEX:
898                 case DOT11_OID_AUTHENTICATE:
899                         prism54_handle_auth(drv, hdr, len);
900                         break;
901                 case DOT11_OID_ASSOCIATEEX:
902                 case DOT11_OID_REASSOCIATEEX:
903                 case DOT11_OID_ASSOCIATE:
904                 case DOT11_OID_REASSOCIATE:
905                         prism54_handle_assoc(drv, hdr, len);
906                 default:
907                         break;
908         }
909
910         free(hdr);
911 }
912
913
914 static void handle_802_3(int sock, void *eloop_ctx, void *sock_ctx)
915 {
916         struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
917         int len;
918         ieee802_3_hdr *hdr;
919
920         hdr = malloc(PIM_BUF_SIZE);
921         if (hdr == NULL)
922                 return;
923         len = recv(sock, hdr, PIM_BUF_SIZE, 0);
924         if (len < 0) {
925                 perror("recv");
926                 free(hdr);
927                 return;
928         }
929         if (len < 14) {
930                 wpa_printf(MSG_MSGDUMP, "handle_802_3: too short (%d)", len);
931                 free(hdr);
932                 return;
933         }
934         if (hdr->type == htons(ETH_P_PAE)) {
935                 hostapd_eapol_receive(hapd, (u8 *) &hdr->sa[0], (u8 *) &hdr[1],
936                                       len - sizeof(*hdr));
937         }
938         free(hdr);
939 }
940
941
942 static int prism54_init_sockets(struct prism54_driver_data *drv)
943 {
944         struct hostapd_data *hapd = drv->hapd;
945         struct ifreq ifr;
946         struct sockaddr_ll addr;
947
948         drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
949         if (drv->sock < 0) {
950                 perror("socket[PF_PACKET,SOCK_RAW]");
951                 return -1;
952         }
953
954         if (eloop_register_read_sock(drv->sock, handle_802_3, drv->hapd, NULL))
955         {
956                 printf("Could not register read socket\n");
957                 return -1;
958         }
959
960         memset(&ifr, 0, sizeof(ifr));
961         if (hapd->conf->bridge[0] != '\0') {
962                 printf("opening bridge: %s\n", hapd->conf->bridge);
963                 os_strlcpy(ifr.ifr_name, hapd->conf->bridge,
964                            sizeof(ifr.ifr_name));
965         } else {
966                 os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
967         }
968         if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
969                 perror("ioctl(SIOCGIFINDEX)");
970                 return -1;
971         }
972
973         memset(&addr, 0, sizeof(addr));
974         addr.sll_family = AF_PACKET;
975         addr.sll_ifindex = ifr.ifr_ifindex;
976         addr.sll_protocol = htons(ETH_P_PAE);
977         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
978                    addr.sll_ifindex);
979
980         if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
981                 perror("bind");
982                 return -1;
983         }
984
985         memset(&ifr, 0, sizeof(ifr));
986         os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
987         if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
988                 perror("ioctl(SIOCGIFHWADDR)");
989                 return -1;
990         }
991
992         if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
993                 printf("Invalid HW-addr family 0x%04x\n",
994                        ifr.ifr_hwaddr.sa_family);
995                 return -1;
996         }
997         memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
998
999         drv->pim_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
1000         if (drv->pim_sock < 0) {
1001                 perror("socket[PF_PACKET,SOCK_RAW]");
1002                 return -1;
1003         }
1004
1005         if (eloop_register_read_sock(drv->pim_sock, handle_pim, drv, NULL)) {
1006                 printf("Could not register read socket\n");
1007                 return -1;
1008         }
1009
1010         memset(&ifr, 0, sizeof(ifr));
1011         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
1012         if (ioctl(drv->pim_sock, SIOCGIFINDEX, &ifr) != 0) {
1013                 perror("ioctl(SIOCGIFINDEX)");
1014                 return -1;
1015         }
1016
1017         memset(&addr, 0, sizeof(addr));
1018         addr.sll_family = AF_PACKET;
1019         addr.sll_ifindex = ifr.ifr_ifindex;
1020         addr.sll_protocol = htons(ETH_P_ALL);
1021         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
1022                    addr.sll_ifindex);
1023
1024         if (bind(drv->pim_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1025                 perror("bind");
1026                 return -1;
1027         }
1028
1029         return 0;
1030 }
1031
1032
1033 static void * prism54_driver_init(struct hostapd_data *hapd,
1034                                   struct wpa_init_params *params)
1035 {
1036         struct prism54_driver_data *drv;
1037
1038         drv = os_zalloc(sizeof(struct prism54_driver_data));
1039         if (drv == NULL) {
1040                 printf("Could not allocate memory for hostapd Prism54 driver "
1041                        "data\n");
1042                 return NULL;
1043         }
1044
1045         drv->hapd = hapd;
1046         drv->pim_sock = drv->sock = -1;
1047         memcpy(drv->iface, params->ifname, sizeof(drv->iface));
1048
1049         if (prism54_init_sockets(drv)) {
1050                 free(drv);
1051                 return NULL;
1052         }
1053         prism54_init_1x(drv);
1054         /* must clean previous elems */
1055         prism54_set_generic_elem(drv->iface, drv, NULL, 0);
1056
1057         return drv;
1058 }
1059
1060
1061 static void prism54_driver_deinit(void *priv)
1062 {
1063         struct prism54_driver_data *drv = priv;
1064
1065         if (drv->pim_sock >= 0)
1066                 close(drv->pim_sock);
1067
1068         if (drv->sock >= 0)
1069                 close(drv->sock);
1070         
1071         free(drv);
1072 }
1073
1074 #else /* HOSTAPD */
1075
1076 struct wpa_driver_prism54_data {
1077         void *wext; /* private data for driver_wext */
1078         void *ctx;
1079         char ifname[IFNAMSIZ + 1];
1080         int sock;
1081 };
1082
1083 #define PRISM54_SET_WPA                 SIOCIWFIRSTPRIV+12
1084 #define PRISM54_HOSTAPD                 SIOCIWFIRSTPRIV+25
1085 #define PRISM54_DROP_UNENCRYPTED        SIOCIWFIRSTPRIV+26
1086
1087 static void show_set_key_error(struct prism2_hostapd_param *);
1088
1089 static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
1090                                  struct prism2_hostapd_param *param,
1091                                  int len, int show_err)
1092 {
1093         struct iwreq iwr;
1094
1095         os_memset(&iwr, 0, sizeof(iwr));
1096         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1097         iwr.u.data.pointer = (caddr_t) param;
1098         iwr.u.data.length = len;
1099
1100         if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
1101                 int ret = errno;
1102                 if (show_err) 
1103                         perror("ioctl[PRISM54_HOSTAPD]");
1104                 return ret;
1105         }
1106
1107         return 0;
1108 }
1109
1110
1111 static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
1112                                          const u8 *wpa_ie,
1113                                          size_t wpa_ie_len)
1114 {
1115         struct prism2_hostapd_param *param;
1116         int res;
1117         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
1118         if (blen < sizeof(*param))
1119                 blen = sizeof(*param);
1120
1121         param = os_zalloc(blen);
1122         if (param == NULL)
1123                 return -1;
1124         
1125         param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
1126         param->u.generic_elem.len = wpa_ie_len;
1127         os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
1128         res = hostapd_ioctl_prism54(drv, param, blen, 1);
1129
1130         os_free(param);
1131
1132         return res;
1133 }
1134
1135
1136 /* This is called at wpa_supplicant daemon init time */
1137 static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
1138 {
1139         struct wpa_driver_prism54_data *drv = priv;
1140         struct prism2_hostapd_param *param;
1141         int res;
1142         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
1143         if (blen < sizeof(*param))
1144                 blen = sizeof(*param);
1145
1146         param = os_zalloc(blen);
1147         if (param == NULL)
1148                 return -1;
1149
1150         param->cmd = PRISM54_SET_WPA;
1151         param->u.generic_elem.len = 0;
1152         res = hostapd_ioctl_prism54(drv, param, blen, 1);
1153
1154         os_free(param);
1155
1156         return res;
1157 }
1158
1159
1160 static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
1161                                       const u8 *addr, int key_idx, int set_tx,
1162                                       const u8 *seq, size_t seq_len,
1163                                       const u8 *key, size_t key_len)
1164 {
1165         struct wpa_driver_prism54_data *drv = priv;
1166         struct prism2_hostapd_param *param;
1167         u8 *buf;
1168         size_t blen;
1169         int ret = 0;
1170         char *alg_name;
1171
1172         switch (alg) {
1173         case WPA_ALG_NONE:
1174                 alg_name = "none";
1175                 return -1;
1176                 break;
1177         case WPA_ALG_WEP:
1178                 alg_name = "WEP";
1179                 return -1;
1180                 break;
1181         case WPA_ALG_TKIP:
1182                 alg_name = "TKIP";
1183                 break;
1184         case WPA_ALG_CCMP:
1185                 alg_name = "CCMP";
1186                 return -1;
1187                 break;
1188         default:
1189                 return -1;
1190         }
1191
1192         wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
1193                    "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
1194                    (unsigned long) seq_len, (unsigned long) key_len);
1195
1196         if (seq_len > 8)
1197                 return -2;
1198
1199         blen = sizeof(*param) + key_len;
1200         buf = os_zalloc(blen);
1201         if (buf == NULL)
1202                 return -1;
1203
1204         param = (struct prism2_hostapd_param *) buf;
1205         param->cmd = PRISM2_SET_ENCRYPTION;
1206         /* TODO: In theory, STA in client mode can use five keys; four default
1207          * keys for receiving (with keyidx 0..3) and one individual key for
1208          * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
1209          * keyidx 0 is reserved for this unicast use and default keys can only
1210          * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
1211          * This should be fine for more or less all cases, but for completeness
1212          * sake, the driver could be enhanced to support the missing key. */
1213 #if 0
1214         if (addr == NULL)
1215                 os_memset(param->sta_addr, 0xff, ETH_ALEN);
1216         else
1217                 os_memcpy(param->sta_addr, addr, ETH_ALEN);
1218 #else
1219         os_memset(param->sta_addr, 0xff, ETH_ALEN);
1220 #endif
1221         os_strlcpy((char *) param->u.crypt.alg, alg_name,
1222                    HOSTAP_CRYPT_ALG_NAME_LEN);
1223         param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
1224         param->u.crypt.idx = key_idx;
1225         os_memcpy(param->u.crypt.seq, seq, seq_len);
1226         param->u.crypt.key_len = key_len;
1227         os_memcpy((u8 *) (param + 1), key, key_len);
1228
1229         if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
1230                 wpa_printf(MSG_WARNING, "Failed to set encryption.");
1231                 show_set_key_error(param);
1232                 ret = -1;
1233         }
1234         os_free(buf);
1235
1236         return ret;
1237 }
1238
1239
1240 static int wpa_driver_prism54_set_countermeasures(void *priv,
1241                                                  int enabled)
1242 {
1243         /* FIX */
1244         printf("wpa_driver_prism54_set_countermeasures - not yet "
1245                "implemented\n");
1246         return 0;
1247 }
1248
1249
1250 static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
1251                                                   int enabled)
1252 {
1253         struct wpa_driver_prism54_data *drv = priv;
1254         struct prism2_hostapd_param *param;
1255         int res;
1256         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
1257         if (blen < sizeof(*param))
1258                 blen = sizeof(*param);
1259
1260         param = os_zalloc(blen);
1261         if (param == NULL)
1262                 return -1;
1263
1264         param->cmd = PRISM54_DROP_UNENCRYPTED;
1265         param->u.generic_elem.len = 0;
1266         res = hostapd_ioctl_prism54(drv, param, blen, 1);
1267
1268         os_free(param);
1269
1270         return res;
1271 }
1272
1273
1274 static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
1275                                              int reason_code)
1276 {
1277         /* FIX */
1278         printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
1279         return 0;
1280 }
1281
1282
1283 static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
1284                                            int reason_code)
1285 {
1286         /* FIX */
1287         printf("wpa_driver_prism54_disassociate - not yet implemented\n");
1288         return 0;
1289 }
1290
1291
1292 static int
1293 wpa_driver_prism54_associate(void *priv,
1294                              struct wpa_driver_associate_params *params)
1295 {
1296         struct wpa_driver_prism54_data *drv = priv;
1297         int ret = 0;
1298
1299         if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
1300                                           params->wpa_ie_len) < 0)
1301                 ret = -1;
1302         if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
1303                 ret = -1;
1304         if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
1305                                      params->ssid_len) < 0)
1306                 ret = -1;
1307         if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
1308                 ret = -1;
1309
1310         return ret;
1311 }
1312
1313 static void show_set_key_error(struct prism2_hostapd_param *param)
1314 {
1315         switch (param->u.crypt.err) {
1316         case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
1317                 wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
1318                            param->u.crypt.alg);
1319                 wpa_printf(MSG_INFO, "You may need to load kernel module to "
1320                            "register that algorithm.");
1321                 wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
1322                            "WEP.");
1323                 break;
1324         case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
1325                 wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
1326                            MAC2STR(param->sta_addr));
1327                 break;
1328         case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
1329                 wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
1330                 break;
1331         case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
1332                 wpa_printf(MSG_INFO, "Key setting failed.");
1333                 break;
1334         case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
1335                 wpa_printf(MSG_INFO, "TX key index setting failed.");
1336                 break;
1337         case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
1338                 wpa_printf(MSG_INFO, "Card configuration failed.");
1339                 break;
1340         }
1341 }
1342
1343
1344 static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
1345 {
1346         struct wpa_driver_prism54_data *drv = priv;
1347         return wpa_driver_wext_get_bssid(drv->wext, bssid);
1348 }
1349
1350
1351 static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
1352 {
1353         struct wpa_driver_prism54_data *drv = priv;
1354         return wpa_driver_wext_get_ssid(drv->wext, ssid);
1355 }
1356
1357
1358 static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
1359 {
1360         struct wpa_driver_prism54_data *drv = priv;
1361         return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
1362 }
1363
1364
1365 static struct wpa_scan_results *
1366 wpa_driver_prism54_get_scan_results(void *priv)
1367 {
1368         struct wpa_driver_prism54_data *drv = priv;
1369         return wpa_driver_wext_get_scan_results(drv->wext);
1370 }
1371
1372
1373 static int wpa_driver_prism54_set_operstate(void *priv, int state)
1374 {
1375         struct wpa_driver_prism54_data *drv = priv;
1376         return wpa_driver_wext_set_operstate(drv->wext, state);
1377 }
1378
1379
1380 static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
1381 {
1382         struct wpa_driver_prism54_data *drv;
1383
1384         drv = os_zalloc(sizeof(*drv));
1385         if (drv == NULL)
1386                 return NULL;
1387         drv->wext = wpa_driver_wext_init(ctx, ifname);
1388         if (drv->wext == NULL) {
1389                 os_free(drv);
1390                 return NULL;
1391         }
1392
1393         drv->ctx = ctx;
1394         os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
1395         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
1396         if (drv->sock < 0) {
1397                 wpa_driver_wext_deinit(drv->wext);
1398                 os_free(drv);
1399                 return NULL;
1400         }
1401
1402         return drv;
1403 }
1404
1405
1406 static void wpa_driver_prism54_deinit(void *priv)
1407 {
1408         struct wpa_driver_prism54_data *drv = priv;
1409         wpa_driver_wext_deinit(drv->wext);
1410         close(drv->sock);
1411         os_free(drv);
1412 }
1413
1414 #endif /* HOSTAPD */
1415
1416
1417 const struct wpa_driver_ops wpa_driver_prism54_ops = {
1418         .name = "prism54",
1419         .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
1420 #ifdef HOSTAPD
1421         .hapd_init = prism54_driver_init,
1422         .hapd_deinit = prism54_driver_deinit,
1423         /* .set_ieee8021x = prism54_init_1x, */
1424         .set_privacy = prism54_set_privacy_invoked,
1425         .hapd_set_key = prism54_set_key,
1426         .get_seqnum = prism54_get_seqnum,
1427         .flush = prism54_flush,
1428         .set_generic_elem = prism54_set_generic_elem,
1429         .hapd_send_eapol = prism54_send_eapol,
1430         .sta_set_flags = prism54_sta_set_flags,
1431         .sta_deauth = prism54_sta_deauth,
1432         .sta_disassoc = prism54_sta_disassoc,
1433         .hapd_set_ssid = prism54_ioctl_setiwessid,
1434         .get_inact_sec = prism54_get_inact_sec,
1435 #else /* HOSTAPD */
1436         .get_bssid = wpa_driver_prism54_get_bssid,
1437         .get_ssid = wpa_driver_prism54_get_ssid,
1438         .set_wpa = wpa_driver_prism54_set_wpa,
1439         .set_key = wpa_driver_prism54_set_key,
1440         .set_countermeasures = wpa_driver_prism54_set_countermeasures,
1441         .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
1442         .scan = wpa_driver_prism54_scan,
1443         .get_scan_results2 = wpa_driver_prism54_get_scan_results,
1444         .deauthenticate = wpa_driver_prism54_deauthenticate,
1445         .disassociate = wpa_driver_prism54_disassociate,
1446         .associate = wpa_driver_prism54_associate,
1447         .init = wpa_driver_prism54_init,
1448         .deinit = wpa_driver_prism54_deinit,
1449         .set_operstate = wpa_driver_prism54_set_operstate,
1450 #endif /* HOSTAPD */
1451 };