37d5c47fb6e4825167d5ea564adb8aaf89dbe854
[wpasupplicant] / hostapd / driver_prism54.c
1 /*
2  * hostapd / Driver interaction with Prism54 PIMFOR interface
3  * Copyright (c) 2004, Bell Kin <bell_kin@pek.com.tw>
4  * based on hostap driver.c, ieee802_11.c
5  * Copyright (c) 2002-2007, 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
17 #include "includes.h"
18 #include <sys/ioctl.h>
19 #include <sys/select.h>
20
21 #ifdef USE_KERNEL_HEADERS
22 /* compat-wireless does not include linux/compiler.h to define __user, so
23  * define it here */
24 #ifndef __user
25 #define __user
26 #endif /* __user */
27 #include <asm/types.h>
28 #include <linux/if_packet.h>
29 #include <linux/if_ether.h>   /* The L2 protocols */
30 #include <linux/if_arp.h>
31 #include <linux/wireless.h>
32 #else /* USE_KERNEL_HEADERS */
33 #include <net/if_arp.h>
34 #include <netpacket/packet.h>
35 #include "wireless_copy.h"
36 #endif /* USE_KERNEL_HEADERS */
37
38 #include "hostapd.h"
39 #include "config.h"
40 #include "driver.h"
41 #include "ieee802_1x.h"
42 #include "eloop.h"
43 #include "ieee802_11.h"
44 #include "prism54.h"
45 #include "wpa.h"
46 #include "radius/radius.h"
47 #include "sta_info.h"
48 #include "accounting.h"
49
50 const int PIM_BUF_SIZE = 4096;
51
52 struct prism54_driver_data {
53         struct hostapd_data *hapd;
54         char iface[IFNAMSIZ + 1];
55         int sock; /* raw packet socket for 802.3 access */
56         int pim_sock; /* socket for pimfor packet */
57         char macs[2007][6];
58 };
59
60
61 static int mac_id_refresh(struct prism54_driver_data *data, int id, char *mac)
62 {
63         if (id < 0 || id > 2006) {
64                 return -1;
65         }
66         memcpy(&data->macs[id][0], mac, ETH_ALEN);
67         return 0;
68 }
69
70
71 static char * mac_id_get(struct prism54_driver_data *data, int id)
72 {
73         if (id < 0 || id > 2006) {
74                 return NULL;
75         }
76         return &data->macs[id][0];
77 }
78
79
80 /* wait for a specific pimfor, timeout in 10ms resolution */
81 /* pim_sock must be non-block to prevent dead lock from no response */
82 /* or same response type in series */
83 static int prism54_waitpim(void *priv, unsigned long oid, void *buf, int len,
84                            int timeout)
85 {
86         struct prism54_driver_data *drv = priv;
87         struct timeval tv, stv, ctv;
88         fd_set pfd;
89         int rlen;
90         pimdev_hdr *pkt;
91
92         pkt = malloc(8192);
93         if (pkt == NULL)
94                 return -1;
95
96         FD_ZERO(&pfd);
97         gettimeofday(&stv, NULL);
98         do {
99                 FD_SET(drv->pim_sock, &pfd);
100                 tv.tv_sec = 0;
101                 tv.tv_usec = 10000;
102                 if (select(drv->pim_sock + 1, &pfd, NULL, NULL, &tv)) {
103                         rlen = recv(drv->pim_sock, pkt, 8192, 0);
104                         if (rlen > 0) {
105                                 if (pkt->oid == htonl(oid)) {
106                                         if (rlen <= len) {
107                                                 if (buf != NULL) {
108                                                         memcpy(buf, pkt, rlen);
109                                                 }
110                                                 free(pkt);
111                                                 return rlen;
112                                         } else {
113                                                 printf("buffer too small\n");
114                                                 free(pkt);
115                                                 return -1;
116                                         }
117                                 } else {
118                                         gettimeofday(&ctv, NULL);
119                                         continue;
120                                 }
121                         }
122                 }
123                 gettimeofday(&ctv, NULL);
124         } while (((ctv.tv_sec - stv.tv_sec) * 100 +
125                   (ctv.tv_usec - stv.tv_usec) / 10000) > timeout);
126         free(pkt);
127         return 0;
128 }
129
130
131 /* send an eapol packet */
132 static int prism54_send_eapol(void *priv, const u8 *addr,
133                               const u8 *data, size_t data_len, int encrypt,
134                               const u8 *own_addr)
135 {
136         struct prism54_driver_data *drv = priv;
137         ieee802_3_hdr *hdr;
138         size_t len;
139         u8 *pos;
140         int res;
141
142         len = sizeof(*hdr) + data_len;
143         hdr = os_zalloc(len);
144         if (hdr == NULL) {
145                 printf("malloc() failed for prism54_send_data(len=%lu)\n",
146                        (unsigned long) len);
147                 return -1;
148         }
149
150         memcpy(&hdr->da[0], addr, ETH_ALEN);
151         memcpy(&hdr->sa[0], own_addr, ETH_ALEN);
152         hdr->type = htons(ETH_P_PAE);
153         pos = (u8 *) (hdr + 1);
154         memcpy(pos, data, data_len);
155
156         res = send(drv->sock, hdr, len, 0);
157         free(hdr);
158
159         if (res < 0) {
160                 perror("hostapd_send_eapol: send");
161                 printf("hostapd_send_eapol - packet len: %lu - failed\n",
162                        (unsigned long) len);
163         }
164
165         return res;
166 }
167
168
169 /* open data channel(auth-1) or eapol only(unauth-0) */
170 static int prism54_set_sta_authorized(void *priv, const u8 *addr,
171                                       int authorized)
172 {
173         struct prism54_driver_data *drv = priv;
174         pimdev_hdr *hdr;
175         char *pos;
176
177         hdr = malloc(sizeof(*hdr) + ETH_ALEN);
178         if (hdr == NULL)
179                 return -1;
180         hdr->op = htonl(PIMOP_SET);
181         if (authorized) {
182                 hdr->oid = htonl(DOT11_OID_EAPAUTHSTA);
183         } else {
184                 hdr->oid = htonl(DOT11_OID_EAPUNAUTHSTA);
185         }
186         pos = (char *) (hdr + 1);
187         memcpy(pos, addr, ETH_ALEN);
188         send(drv->pim_sock, hdr, sizeof(*hdr) + ETH_ALEN, 0);
189         prism54_waitpim(priv, hdr->oid, hdr, sizeof(*hdr) + ETH_ALEN, 10);
190         free(hdr);
191         return 0;
192 }
193
194
195 static int
196 prism54_sta_set_flags(void *priv, const u8 *addr, int total_flags,
197                       int flags_or, int flags_and)
198 {
199         /* For now, only support setting Authorized flag */
200         if (flags_or & WLAN_STA_AUTHORIZED)
201                 return prism54_set_sta_authorized(priv, addr, 1);
202         if (flags_and & WLAN_STA_AUTHORIZED)
203                 return prism54_set_sta_authorized(priv, addr, 0);
204         return 0;
205 }
206
207
208 /* set per station key */
209 static int prism54_set_encryption(const char *ifname, void *priv,
210                                   const char *alg, const u8 *addr,
211                                   int idx, const u8 *key, size_t key_len,
212                                   int txkey)
213 {
214         struct prism54_driver_data *drv = priv;
215         pimdev_hdr *hdr;
216         struct obj_stakey *keys;
217         u8 *buf;
218         size_t blen;
219         int ret = 0;
220
221         blen = sizeof(struct obj_stakey) + sizeof(pimdev_hdr);
222         hdr = malloc(blen);
223         if (hdr == NULL) {
224                 printf("memory low\n");
225                 return -1;
226         }
227         keys = (struct obj_stakey *) &hdr[1];
228         if (!addr) {
229                 memset(&keys->address[0], 0xff, ETH_ALEN);
230         } else {
231                 memcpy(&keys->address[0], addr, ETH_ALEN);
232         }
233         if (!strcmp(alg, "WEP")) {
234                 keys->type = DOT11_PRIV_WEP;
235         } else if (!strcmp(alg, "TKIP")) {
236                 keys->type = DOT11_PRIV_TKIP;
237         } else if (!strcmp(alg, "none")) {
238                 /* the only way to clear the key is to deauth it */
239                 /* and prism54 is capable to receive unencrypted packet */
240                 /* so we do nothing here */
241                 free(hdr);
242                 return 0;
243         } else {
244                 printf("bad auth type: %s\n", alg);
245         }
246         buf = (u8 *) &keys->key[0];
247         keys->length = key_len;
248         keys->keyid = idx;
249         keys->options = htons(DOT11_STAKEY_OPTION_DEFAULTKEY);
250         keys->reserved = 0;
251
252         hdr->op = htonl(PIMOP_SET);
253         hdr->oid = htonl(DOT11_OID_STAKEY);
254
255         memcpy(buf, key, key_len);
256         
257         ret = send(drv->pim_sock, hdr, blen, 0);
258         if (ret < 0) {
259                 free(hdr);
260                 return ret;
261         }
262         prism54_waitpim(priv, hdr->oid, hdr, blen, 10);
263
264         free(hdr);
265
266         return 0;
267 }
268
269
270 /* get TKIP station sequence counter, prism54 is only 6 bytes */
271 static int prism54_get_seqnum(const char *ifname, void *priv, const u8 *addr,
272                               int idx, u8 *seq)
273 {
274         struct prism54_driver_data *drv = priv;
275         struct obj_stasc *stasc;
276         pimdev_hdr *hdr;
277         size_t blen;
278         int ret = 0;
279
280         blen = sizeof(*stasc) + sizeof(*hdr);
281         hdr = malloc(blen);
282         if (hdr == NULL)
283                 return -1;
284
285         stasc = (struct obj_stasc *) &hdr[1];
286         
287         if (addr == NULL)
288                 memset(&stasc->address[0], 0xff, ETH_ALEN);
289         else
290                 memcpy(&stasc->address[0], addr, ETH_ALEN);
291
292         hdr->oid = htonl(DOT11_OID_STASC);
293         hdr->op = htonl(PIMOP_GET);
294         stasc->keyid = idx;
295         if (send(drv->pim_sock,hdr,blen,0) <= 0) {
296                 free(hdr);
297                 return -1;
298         }
299         if (prism54_waitpim(priv, DOT11_OID_STASC, hdr, blen, 10) <= 0) {
300                 ret = -1;
301         } else {
302                 if (hdr->op == (int) htonl(PIMOP_RESPONSE)) {
303                         memcpy(seq + 2, &stasc->sc_high, ETH_ALEN);
304                         memset(seq, 0, 2);
305                 } else {
306                         ret = -1;
307                 }
308         }
309         free(hdr);
310
311         return ret;
312 }
313
314
315 /* include unencrypted, set mlme autolevel to extended */
316 static int prism54_init_1x(void *priv)
317 {
318         struct prism54_driver_data *drv = priv;
319         pimdev_hdr *hdr;
320         unsigned long *ul;
321         int blen = sizeof(*hdr) + sizeof(*ul);
322
323         hdr = malloc(blen);
324         if (hdr == NULL)
325                 return -1;
326
327         ul = (unsigned long *) &hdr[1];
328         hdr->op = htonl(PIMOP_SET);
329         hdr->oid = htonl(DOT11_OID_EXUNENCRYPTED);
330         *ul = htonl(DOT11_BOOL_TRUE); /* not accept */
331         send(drv->pim_sock, hdr, blen, 0);
332         prism54_waitpim(priv, DOT11_OID_EXUNENCRYPTED, hdr, blen, 10);
333         hdr->op = htonl(PIMOP_SET);
334         hdr->oid = htonl(DOT11_OID_MLMEAUTOLEVEL);
335         *ul = htonl(DOT11_MLME_EXTENDED);
336         send(drv->pim_sock, hdr, blen, 0);
337         prism54_waitpim(priv, DOT11_OID_MLMEAUTOLEVEL, hdr, blen, 10);
338         hdr->op = htonl(PIMOP_SET);
339         hdr->oid = htonl(DOT11_OID_DOT1XENABLE);
340         *ul = htonl(DOT11_BOOL_TRUE);
341         send(drv->pim_sock, hdr, blen, 0);
342         prism54_waitpim(priv, DOT11_OID_DOT1XENABLE, hdr, blen, 10);
343         hdr->op = htonl(PIMOP_SET);
344         hdr->oid = htonl(DOT11_OID_AUTHENABLE);
345         *ul = htonl(DOT11_AUTH_OS); /* OS */
346         send(drv->pim_sock, hdr, blen, 0);
347         prism54_waitpim(priv, DOT11_OID_AUTHENABLE, hdr, blen, 10);
348         free(hdr);
349         return 0;
350 }
351
352
353 static int prism54_set_privacy_invoked(const char *ifname, void *priv,
354                                        int flag)
355 {
356         struct prism54_driver_data *drv = priv;
357         pimdev_hdr *hdr;
358         unsigned long *ul;
359         int ret;
360         int blen = sizeof(*hdr) + sizeof(*ul);
361         hdr = malloc(blen);
362         if (hdr == NULL)
363                 return -1;
364         ul = (unsigned long *) &hdr[1];
365         hdr->op = htonl(PIMOP_SET);
366         hdr->oid = htonl(DOT11_OID_PRIVACYINVOKED);
367         if (flag) {
368                 *ul = htonl(DOT11_BOOL_TRUE); /* has privacy */
369         } else {
370                 *ul = 0;
371         }
372         ret = send(drv->pim_sock, hdr, blen, 0);
373         if (ret >= 0) {
374                 ret = prism54_waitpim(priv, DOT11_OID_PRIVACYINVOKED, hdr,
375                                       blen, 10);
376         }
377         free(hdr);
378         return ret;
379 }
380
381  
382 static int prism54_ioctl_setiwessid(const char *ifname, void *priv,
383                                     const u8 *buf, int len)
384 {
385 #if 0
386         struct prism54_driver_data *drv = priv;
387         struct iwreq iwr;
388
389         memset(&iwr, 0, sizeof(iwr));
390         os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
391         iwr.u.essid.flags = 1; /* SSID active */
392         iwr.u.essid.pointer = (caddr_t) buf;
393         iwr.u.essid.length = len + 1;
394
395         if (ioctl(drv->pim_sock, SIOCSIWESSID, &iwr) < 0) {
396                 perror("ioctl[SIOCSIWESSID]");
397                 printf("len=%d\n", len);
398                 return -1;
399         }
400 #endif
401         return 0;
402 }
403
404
405 /* kick all stations */
406 /* does not work during init, but at least it won't crash firmware */
407 static int prism54_flush(void *priv)
408 {
409         struct prism54_driver_data *drv = priv;
410         struct obj_mlmeex *mlme;
411         pimdev_hdr *hdr;
412         int ret;
413         unsigned int i;
414         long *nsta;
415         int blen = sizeof(*hdr) + sizeof(*mlme);
416         char *mac_id;
417
418         hdr = os_zalloc(blen);
419         if (hdr == NULL)
420                 return -1;
421
422         mlme = (struct obj_mlmeex *) &hdr[1];
423         nsta = (long *) &hdr[1];
424         hdr->op = htonl(PIMOP_GET);
425         hdr->oid = htonl(DOT11_OID_CLIENTS);
426         ret = send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(long), 0);
427         ret = prism54_waitpim(priv, DOT11_OID_CLIENTS, hdr, blen, 10);
428         if ((ret < 0) || (hdr->op != (int) htonl(PIMOP_RESPONSE)) ||
429             (le_to_host32(*nsta) > 2007)) {
430                 free(hdr);
431                 return 0;
432         }
433         for (i = 0; i < le_to_host32(*nsta); i++) {
434                 mlme->id = -1;
435                 mac_id = mac_id_get(drv, i);
436                 if (mac_id)
437                         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
438                 mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
439                 mlme->state = htons(DOT11_STATE_NONE);
440                 mlme->size = 0;
441                 hdr->op = htonl(PIMOP_SET);
442                 hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
443                 ret = send(drv->pim_sock, hdr, blen, 0);
444                 prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen,
445                                 100);
446         }
447         for (i = 0; i < le_to_host32(*nsta); i++) {
448                 mlme->id = -1;
449                 mac_id = mac_id_get(drv, i);
450                 if (mac_id)
451                         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
452                 mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
453                 mlme->state = htons(DOT11_STATE_NONE);
454                 mlme->size = 0;
455                 hdr->op = htonl(PIMOP_SET);
456                 hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
457                 ret = send(drv->pim_sock, hdr, blen, 0);
458                 prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen,
459                                 100);
460         }
461         free(hdr);
462         return 0;
463 }
464
465
466 static int prism54_sta_deauth(void *priv, const u8 *addr, int reason)
467 {
468         struct prism54_driver_data *drv = priv;
469         pimdev_hdr *hdr;
470         struct obj_mlmeex *mlme;
471         int ret;
472         int blen = sizeof(*hdr) + sizeof(*mlme);
473         hdr = malloc(blen);
474         if (hdr == NULL)
475                 return -1;
476         mlme = (struct obj_mlmeex *) &hdr[1];
477         hdr->op = htonl(PIMOP_SET);
478         hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
479         memcpy(&mlme->address[0], addr, ETH_ALEN);
480         mlme->id = -1;
481         mlme->state = htons(DOT11_STATE_NONE);
482         mlme->code = host_to_le16(reason);
483         mlme->size = 0;
484         ret = send(drv->pim_sock, hdr, blen, 0);
485         prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 10);
486         free(hdr);
487         return ret;
488 }
489
490
491 static int prism54_sta_disassoc(void *priv, const u8 *addr, int reason)
492 {
493         struct prism54_driver_data *drv = priv;
494         pimdev_hdr *hdr;
495         struct obj_mlmeex *mlme;
496         int ret;
497         int blen = sizeof(*hdr) + sizeof(*mlme);
498         hdr = malloc(blen);
499         if (hdr == NULL)
500                 return -1;
501         mlme = (struct obj_mlmeex *) &hdr[1];
502         hdr->op = htonl(PIMOP_SET);
503         hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
504         memcpy(&mlme->address[0], addr, ETH_ALEN);
505         mlme->id = -1;
506         mlme->state = htons(DOT11_STATE_NONE);
507         mlme->code = host_to_le16(reason);
508         mlme->size = 0;
509         ret = send(drv->pim_sock, hdr, blen, 0);
510         prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 10);
511         free(hdr);
512         return ret;
513 }
514
515
516 static int prism54_get_inact_sec(void *priv, const u8 *addr)
517 {
518         struct prism54_driver_data *drv = priv;
519         pimdev_hdr *hdr;
520         struct obj_sta *sta;
521         int blen = sizeof(*hdr) + sizeof(*sta);
522         int ret;
523
524         hdr = malloc(blen);
525         if (hdr == NULL)
526                 return -1;
527         hdr->op = htonl(PIMOP_GET);
528         hdr->oid = htonl(DOT11_OID_CLIENTFIND);
529         sta = (struct obj_sta *) &hdr[1];
530         memcpy(&sta->address[0], addr, ETH_ALEN);
531         ret = send(drv->pim_sock, hdr, blen, 0);
532         ret = prism54_waitpim(priv, DOT11_OID_CLIENTFIND, hdr, blen, 10);
533         if (ret != blen) {
534                 printf("get_inact_sec: bad return %d\n", ret);
535                 free(hdr);
536                 return -1;
537         }
538         if (hdr->op != (int) htonl(PIMOP_RESPONSE)) {
539                 printf("get_inact_sec: bad resp\n");
540                 free(hdr);
541                 return -1;
542         }
543         free(hdr);
544         return le_to_host16(sta->age);
545 }
546
547
548 /* set attachments */
549 static int prism54_set_generic_elem(const char *ifname, void *priv,
550                                     const u8 *elem, size_t elem_len)
551 {
552         struct prism54_driver_data *drv = priv;
553         pimdev_hdr *hdr;
554         char *pos;
555         struct obj_attachment_hdr *attach;
556         size_t blen = sizeof(*hdr) + sizeof(*attach) + elem_len;
557         hdr = os_zalloc(blen);
558         if (hdr == NULL) {
559                 printf("%s: memory low\n", __func__);
560                 return -1;
561         }
562         hdr->op = htonl(PIMOP_SET);
563         hdr->oid = htonl(DOT11_OID_ATTACHMENT);
564         attach = (struct obj_attachment_hdr *)&hdr[1];
565         attach->type = DOT11_PKT_BEACON;
566         attach->id = -1;
567         attach->size = host_to_le16((short)elem_len);
568         pos = ((char*) attach) + sizeof(*attach);
569         if (elem)
570                 memcpy(pos, elem, elem_len);
571         send(drv->pim_sock, hdr, blen, 0);
572         attach->type = DOT11_PKT_PROBE_RESP;
573         send(drv->pim_sock, hdr, blen, 0);
574         free(hdr);
575         return 0;
576 }
577
578
579 /* tell the card to auth the sta */
580 static void prism54_handle_probe(struct prism54_driver_data *drv,
581                                  void *buf, size_t len)
582 {
583         struct obj_mlmeex *mlme;
584         pimdev_hdr *hdr;
585         struct sta_info *sta;
586         hdr = (pimdev_hdr *)buf;
587         mlme = (struct obj_mlmeex *) &hdr[1];
588         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
589         if (sta != NULL) {
590                 if (sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC))
591                         return;
592         }
593         if (len < sizeof(*mlme)) {
594                 printf("bad probe packet\n");
595                 return;
596         }
597         mlme->state = htons(DOT11_STATE_AUTHING);
598         mlme->code = 0;
599         hdr->op = htonl(PIMOP_SET);
600         hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
601         mlme->size = 0;
602         send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
603 }
604
605
606 static void prism54_handle_deauth(struct prism54_driver_data *drv,
607                                   void *buf, size_t len)
608 {
609         struct obj_mlme *mlme;
610         pimdev_hdr *hdr;
611         struct sta_info *sta;
612         char *mac_id;
613
614         hdr = (pimdev_hdr *) buf;
615         mlme = (struct obj_mlme *) &hdr[1];
616         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
617         mac_id = mac_id_get(drv, mlme->id);
618         if (sta == NULL || mac_id == NULL)
619                 return;
620         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
621         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
622         wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
623         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
624         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
625         ap_free_sta(drv->hapd, sta);
626 }
627
628
629 static void prism54_handle_disassoc(struct prism54_driver_data *drv,
630                                     void *buf, size_t len)
631 {
632         struct obj_mlme *mlme;
633         pimdev_hdr *hdr;
634         struct sta_info *sta;
635         char *mac_id;
636
637         hdr = (pimdev_hdr *) buf;
638         mlme = (struct obj_mlme *) &hdr[1];
639         mac_id = mac_id_get(drv, mlme->id);
640         if (mac_id == NULL)
641                 return;
642         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
643         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
644         if (sta == NULL) {
645                 return;
646         }
647         sta->flags &= ~WLAN_STA_ASSOC;
648         wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
649         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
650         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
651         accounting_sta_stop(drv->hapd, sta);
652         ieee802_1x_free_station(sta);
653 }
654
655
656 /* to auth it, just allow it now, later for os/sk */
657 static void prism54_handle_auth(struct prism54_driver_data *drv,
658                                 void *buf, size_t len)
659 {
660         struct obj_mlmeex *mlme;
661         pimdev_hdr *hdr;
662         struct sta_info *sta;
663         int resp;
664
665         hdr = (pimdev_hdr *) buf;
666         mlme = (struct obj_mlmeex *) &hdr[1];
667         if (len < sizeof(*mlme)) {
668                 printf("bad auth packet\n");
669                 return;
670         }
671
672         if (mlme->state == htons(DOT11_STATE_AUTHING)) {
673                 sta = ap_sta_add(drv->hapd, (u8 *) &mlme->address[0]);
674                 if (drv->hapd->tkip_countermeasures) {
675                         resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
676                         goto fail;
677                 }
678                 mac_id_refresh(drv, mlme->id, &mlme->address[0]);
679                 if (!sta) {
680                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
681                         goto fail;
682                 }
683                 sta->flags &= ~WLAN_STA_PREAUTH;
684                 
685                 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
686                 sta->flags |= WLAN_STA_AUTH;
687                 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
688                 mlme->code = 0;
689                 mlme->state=htons(DOT11_STATE_AUTH);
690                 hdr->op = htonl(PIMOP_SET);
691                 hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
692                 mlme->size = 0;
693                 sta->timeout_next = STA_NULLFUNC;
694                 send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
695         }
696         return;
697
698 fail:
699         printf("auth fail: %x\n", resp);
700         mlme->code = host_to_le16(resp);
701         mlme->size = 0;
702         if (sta)
703                 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
704         hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
705         hdr->op = htonl(PIMOP_SET);
706         send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
707 }
708
709
710 /* do the wpa thing */
711 static void prism54_handle_assoc(struct prism54_driver_data *drv,
712                                  void *buf, size_t len)
713 {
714         pimdev_hdr *hdr;
715         struct obj_mlmeex *mlme;
716         struct ieee802_11_elems elems;
717         struct sta_info *sta;
718         u8 *wpa_ie;
719         u8 *cb;
720         int ieofs = 0;
721         size_t wpa_ie_len;
722         int resp, new_assoc;
723         char *mac_id;
724
725         resp = 0;
726         hdr = (pimdev_hdr *) buf;
727         mlme = (struct obj_mlmeex *) &hdr[1];
728         switch (ntohl(hdr->oid)) {
729                 case DOT11_OID_ASSOCIATE:
730                 case DOT11_OID_REASSOCIATE:
731                         mlme->size = 0;
732                 default:
733                         break;
734         }
735         if ((mlme->state == (int) htonl(DOT11_STATE_ASSOCING)) ||
736             (mlme->state == (int) htonl(DOT11_STATE_REASSOCING))) {
737                 if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
738                         printf("bad assoc packet\n");
739                         return;
740                 }
741                 mac_id = mac_id_get(drv, mlme->id);
742                 if (mac_id == NULL)
743                         return;
744                 memcpy(&mlme->address[0], mac_id, ETH_ALEN);
745                 sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
746                 if (sta == NULL) {
747                         printf("cannot get sta\n");
748                         return;
749                 }
750                 cb = (u8 *) &mlme->data[0];
751                 if (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) {
752                         ieofs = 4;
753                 } else if (hdr->oid == htonl(DOT11_OID_REASSOCIATEEX)) {
754                         ieofs = 10;
755                 }
756                 if (le_to_host16(mlme->size) <= ieofs) {
757                         printf("attach too small\n");
758                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
759                         goto fail;
760                 }
761                 if (ieee802_11_parse_elems(cb + ieofs,
762                                            le_to_host16(mlme->size) - ieofs,
763                                            &elems, 1) == ParseFailed) {
764                         printf("STA " MACSTR " sent invalid association "
765                                "request\n", MAC2STR(sta->addr));
766                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
767                         goto fail;
768                 }
769                 if ((drv->hapd->conf->wpa & WPA_PROTO_RSN) &&
770                     elems.rsn_ie) {
771                         wpa_ie = elems.rsn_ie;
772                         wpa_ie_len = elems.rsn_ie_len;
773                 } else if ((drv->hapd->conf->wpa & WPA_PROTO_WPA) &&
774                            elems.wpa_ie) {
775                         wpa_ie = elems.wpa_ie;
776                         wpa_ie_len = elems.wpa_ie_len;
777                 } else {
778                         wpa_ie = NULL;
779                         wpa_ie_len = 0;
780                 }
781                 if (drv->hapd->conf->wpa && wpa_ie == NULL) {
782                         printf("STA " MACSTR ": No WPA/RSN IE in association "
783                                "request\n", MAC2STR(sta->addr));
784                         resp = WLAN_STATUS_INVALID_IE;
785                         goto fail;
786                 }
787                 if (drv->hapd->conf->wpa) {
788                         int res;
789                         wpa_ie -= 2;
790                         wpa_ie_len += 2;
791                         if (sta->wpa_sm == NULL)
792                                 sta->wpa_sm = wpa_auth_sta_init(
793                                         drv->hapd->wpa_auth, sta->addr);
794                         if (sta->wpa_sm == NULL) {
795                                 printf("Failed to initialize WPA state "
796                                        "machine\n");
797                                 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
798                                 goto fail;
799                         }
800                         res = wpa_validate_wpa_ie(drv->hapd->wpa_auth,
801                                                   sta->wpa_sm,
802                                                   wpa_ie, wpa_ie_len,
803                                                   NULL, 0);
804                         if (res == WPA_INVALID_GROUP)
805                                 resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
806                         else if (res == WPA_INVALID_PAIRWISE)
807                                 resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
808                         else if (res == WPA_INVALID_AKMP)
809                                 resp = WLAN_STATUS_AKMP_NOT_VALID;
810                         else if (res == WPA_ALLOC_FAIL)
811                                 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
812                         else if (res != WPA_IE_OK)
813                                 resp = WLAN_STATUS_INVALID_IE;
814                         if (resp != WLAN_STATUS_SUCCESS)
815                                 goto fail;
816                 }
817                 hdr->oid = (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) ?
818                         htonl(DOT11_OID_ASSOCIATEEX) :
819                         htonl(DOT11_OID_REASSOCIATEEX);
820                 hdr->op = htonl(PIMOP_SET);
821                 mlme->code = 0;
822                 mlme->state = htons(DOT11_STATE_ASSOC);
823                 mlme->size = 0;
824                 send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
825                 return;
826         } else if (mlme->state==htons(DOT11_STATE_ASSOC)) {
827                 if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
828                         printf("bad assoc packet\n");
829                         return;
830                 }
831                 mac_id = mac_id_get(drv, mlme->id);
832                 if (mac_id == NULL)
833                         return;
834                 memcpy(&mlme->address[0], mac_id, ETH_ALEN);
835                 sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
836                 if (sta == NULL) {
837                         printf("cannot get sta\n");
838                         return;
839                 }
840                 new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
841                 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
842                 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
843                 hostapd_new_assoc_sta(drv->hapd, sta, !new_assoc);
844                 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
845                 sta->timeout_next = STA_NULLFUNC;
846                 return;
847         }
848         return;
849
850 fail:
851         printf("Prism54: assoc fail: %x\n", resp);
852         mlme->code = host_to_le16(resp);
853         mlme->size = 0;
854         mlme->state = htons(DOT11_STATE_ASSOCING);
855         hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
856         hdr->op = htonl(PIMOP_SET);
857         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
858         send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
859 }
860
861
862 static void handle_pim(int sock, void *eloop_ctx, void *sock_ctx)
863 {
864         struct prism54_driver_data *drv = eloop_ctx;
865         int len;
866         pimdev_hdr *hdr;
867
868         hdr = malloc(PIM_BUF_SIZE);
869         if (hdr == NULL)
870                 return;
871         len = recv(sock, hdr, PIM_BUF_SIZE, 0);
872         if (len < 0) {
873                 perror("recv");
874                 free(hdr);
875                 return;
876         }
877         if (len < 8) {
878                 printf("handle_pim: too short (%d)\n", len);
879                 free(hdr);
880                 return;
881         }
882
883         if (hdr->op != (int) htonl(PIMOP_TRAP)) {
884                 free(hdr);
885                 return;
886         }
887         switch (ntohl(hdr->oid)) {
888                 case DOT11_OID_PROBE:
889                         prism54_handle_probe(drv, hdr, len);
890                         break;
891                 case DOT11_OID_DEAUTHENTICATEEX:
892                 case DOT11_OID_DEAUTHENTICATE:
893                         prism54_handle_deauth(drv, hdr, len);
894                         break;
895                 case DOT11_OID_DISASSOCIATEEX:
896                 case DOT11_OID_DISASSOCIATE:
897                         prism54_handle_disassoc(drv, hdr, len);
898                         break;
899                 case DOT11_OID_AUTHENTICATEEX:
900                 case DOT11_OID_AUTHENTICATE:
901                         prism54_handle_auth(drv, hdr, len);
902                         break;
903                 case DOT11_OID_ASSOCIATEEX:
904                 case DOT11_OID_REASSOCIATEEX:
905                 case DOT11_OID_ASSOCIATE:
906                 case DOT11_OID_REASSOCIATE:
907                         prism54_handle_assoc(drv, hdr, len);
908                 default:
909                         break;
910         }
911
912         free(hdr);
913 }
914
915
916 static void handle_802_3(int sock, void *eloop_ctx, void *sock_ctx)
917 {
918         struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
919         int len;
920         ieee802_3_hdr *hdr;
921
922         hdr = malloc(PIM_BUF_SIZE);
923         if (hdr == NULL)
924                 return;
925         len = recv(sock, hdr, PIM_BUF_SIZE, 0);
926         if (len < 0) {
927                 perror("recv");
928                 free(hdr);
929                 return;
930         }
931         if (len < 14) {
932                 wpa_printf(MSG_MSGDUMP, "handle_802_3: too short (%d)", len);
933                 free(hdr);
934                 return;
935         }
936         if (hdr->type == htons(ETH_P_PAE)) {
937                 hostapd_eapol_receive(hapd, (u8 *) &hdr->sa[0], (u8 *) &hdr[1],
938                                       len - sizeof(*hdr));
939         }
940         free(hdr);
941 }
942
943
944 static int prism54_init_sockets(struct prism54_driver_data *drv)
945 {
946         struct hostapd_data *hapd = drv->hapd;
947         struct ifreq ifr;
948         struct sockaddr_ll addr;
949
950         drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
951         if (drv->sock < 0) {
952                 perror("socket[PF_PACKET,SOCK_RAW]");
953                 return -1;
954         }
955
956         if (eloop_register_read_sock(drv->sock, handle_802_3, drv->hapd, NULL))
957         {
958                 printf("Could not register read socket\n");
959                 return -1;
960         }
961
962         memset(&ifr, 0, sizeof(ifr));
963         if (hapd->conf->bridge[0] != '\0') {
964                 printf("opening bridge: %s\n", hapd->conf->bridge);
965                 os_strlcpy(ifr.ifr_name, hapd->conf->bridge,
966                            sizeof(ifr.ifr_name));
967         } else {
968                 os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
969         }
970         if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
971                 perror("ioctl(SIOCGIFINDEX)");
972                 return -1;
973         }
974
975         memset(&addr, 0, sizeof(addr));
976         addr.sll_family = AF_PACKET;
977         addr.sll_ifindex = ifr.ifr_ifindex;
978         addr.sll_protocol = htons(ETH_P_PAE);
979         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
980                    addr.sll_ifindex);
981
982         if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
983                 perror("bind");
984                 return -1;
985         }
986
987         memset(&ifr, 0, sizeof(ifr));
988         os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
989         if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
990                 perror("ioctl(SIOCGIFHWADDR)");
991                 return -1;
992         }
993
994         if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
995                 printf("Invalid HW-addr family 0x%04x\n",
996                        ifr.ifr_hwaddr.sa_family);
997                 return -1;
998         }
999         memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
1000
1001         drv->pim_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
1002         if (drv->pim_sock < 0) {
1003                 perror("socket[PF_PACKET,SOCK_RAW]");
1004                 return -1;
1005         }
1006
1007         if (eloop_register_read_sock(drv->pim_sock, handle_pim, drv, NULL)) {
1008                 printf("Could not register read socket\n");
1009                 return -1;
1010         }
1011
1012         memset(&ifr, 0, sizeof(ifr));
1013         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
1014         if (ioctl(drv->pim_sock, SIOCGIFINDEX, &ifr) != 0) {
1015                 perror("ioctl(SIOCGIFINDEX)");
1016                 return -1;
1017         }
1018
1019         memset(&addr, 0, sizeof(addr));
1020         addr.sll_family = AF_PACKET;
1021         addr.sll_ifindex = ifr.ifr_ifindex;
1022         addr.sll_protocol = htons(ETH_P_ALL);
1023         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
1024                    addr.sll_ifindex);
1025
1026         if (bind(drv->pim_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1027                 perror("bind");
1028                 return -1;
1029         }
1030
1031         return 0;
1032 }
1033
1034
1035 static void * prism54_driver_init(struct hostapd_data *hapd)
1036 {
1037         struct prism54_driver_data *drv;
1038
1039         drv = os_zalloc(sizeof(struct prism54_driver_data));
1040         if (drv == NULL) {
1041                 printf("Could not allocate memory for hostapd Prism54 driver "
1042                        "data\n");
1043                 return NULL;
1044         }
1045
1046         drv->hapd = hapd;
1047         drv->pim_sock = drv->sock = -1;
1048         memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
1049
1050         if (prism54_init_sockets(drv)) {
1051                 free(drv);
1052                 return NULL;
1053         }
1054         prism54_init_1x(drv);
1055         /* must clean previous elems */
1056         prism54_set_generic_elem(drv->iface, drv, NULL, 0);
1057
1058         return drv;
1059 }
1060
1061
1062 static void prism54_driver_deinit(void *priv)
1063 {
1064         struct prism54_driver_data *drv = priv;
1065
1066         if (drv->pim_sock >= 0)
1067                 close(drv->pim_sock);
1068
1069         if (drv->sock >= 0)
1070                 close(drv->sock);
1071         
1072         free(drv);
1073 }
1074
1075
1076 const struct wpa_driver_ops wpa_driver_prism54_ops = {
1077         .name = "prism54",
1078         .init = prism54_driver_init,
1079         .deinit = prism54_driver_deinit,
1080         /* .set_ieee8021x = prism54_init_1x, */
1081         .set_privacy = prism54_set_privacy_invoked,
1082         .set_encryption = prism54_set_encryption,
1083         .get_seqnum = prism54_get_seqnum,
1084         .flush = prism54_flush,
1085         .set_generic_elem = prism54_set_generic_elem,
1086         .send_eapol = prism54_send_eapol,
1087         .sta_set_flags = prism54_sta_set_flags,
1088         .sta_deauth = prism54_sta_deauth,
1089         .sta_disassoc = prism54_sta_disassoc,
1090         .set_ssid = prism54_ioctl_setiwessid,
1091         .get_inact_sec = prism54_get_inact_sec,
1092 };