Fix couple of forgotten wpa_hw_modes -> hostapd_hw_modes
[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 static int prism54_set_key(const char *ifname, void *priv, wpa_alg alg,
209                            const u8 *addr, int key_idx, int set_tx,
210                            const u8 *seq, size_t seq_len,
211                            const u8 *key, size_t key_len)
212 {
213         struct prism54_driver_data *drv = priv;
214         pimdev_hdr *hdr;
215         struct obj_stakey *keys;
216         u8 *buf;
217         size_t blen;
218         int ret = 0;
219
220         blen = sizeof(struct obj_stakey) + sizeof(pimdev_hdr);
221         hdr = malloc(blen);
222         if (hdr == NULL) {
223                 printf("memory low\n");
224                 return -1;
225         }
226         keys = (struct obj_stakey *) &hdr[1];
227         if (!addr) {
228                 memset(&keys->address[0], 0xff, ETH_ALEN);
229         } else {
230                 memcpy(&keys->address[0], addr, ETH_ALEN);
231         }
232         switch (alg) {
233         case WPA_ALG_WEP:
234                 keys->type = DOT11_PRIV_WEP;
235                 break;
236         case WPA_ALG_TKIP:
237                 keys->type = DOT11_PRIV_TKIP;
238                 break;
239         case WPA_ALG_NONE:
240                 /* the only way to clear the key is to deauth it */
241                 /* and prism54 is capable to receive unencrypted packet */
242                 /* so we do nothing here */
243                 free(hdr);
244                 return 0;
245         default:
246                 printf("bad auth type: %d\n", alg);
247                 free(hdr);
248                 return -1;
249         }
250         buf = (u8 *) &keys->key[0];
251         keys->length = key_len;
252         keys->keyid = key_idx;
253         keys->options = htons(DOT11_STAKEY_OPTION_DEFAULTKEY);
254         keys->reserved = 0;
255
256         hdr->op = htonl(PIMOP_SET);
257         hdr->oid = htonl(DOT11_OID_STAKEY);
258
259         memcpy(buf, key, key_len);
260         
261         ret = send(drv->pim_sock, hdr, blen, 0);
262         if (ret < 0) {
263                 free(hdr);
264                 return ret;
265         }
266         prism54_waitpim(priv, hdr->oid, hdr, blen, 10);
267
268         free(hdr);
269
270         return 0;
271 }
272
273
274 /* get TKIP station sequence counter, prism54 is only 6 bytes */
275 static int prism54_get_seqnum(const char *ifname, void *priv, const u8 *addr,
276                               int idx, u8 *seq)
277 {
278         struct prism54_driver_data *drv = priv;
279         struct obj_stasc *stasc;
280         pimdev_hdr *hdr;
281         size_t blen;
282         int ret = 0;
283
284         blen = sizeof(*stasc) + sizeof(*hdr);
285         hdr = malloc(blen);
286         if (hdr == NULL)
287                 return -1;
288
289         stasc = (struct obj_stasc *) &hdr[1];
290         
291         if (addr == NULL)
292                 memset(&stasc->address[0], 0xff, ETH_ALEN);
293         else
294                 memcpy(&stasc->address[0], addr, ETH_ALEN);
295
296         hdr->oid = htonl(DOT11_OID_STASC);
297         hdr->op = htonl(PIMOP_GET);
298         stasc->keyid = idx;
299         if (send(drv->pim_sock,hdr,blen,0) <= 0) {
300                 free(hdr);
301                 return -1;
302         }
303         if (prism54_waitpim(priv, DOT11_OID_STASC, hdr, blen, 10) <= 0) {
304                 ret = -1;
305         } else {
306                 if (hdr->op == (int) htonl(PIMOP_RESPONSE)) {
307                         memcpy(seq + 2, &stasc->sc_high, ETH_ALEN);
308                         memset(seq, 0, 2);
309                 } else {
310                         ret = -1;
311                 }
312         }
313         free(hdr);
314
315         return ret;
316 }
317
318
319 /* include unencrypted, set mlme autolevel to extended */
320 static int prism54_init_1x(void *priv)
321 {
322         struct prism54_driver_data *drv = priv;
323         pimdev_hdr *hdr;
324         unsigned long *ul;
325         int blen = sizeof(*hdr) + sizeof(*ul);
326
327         hdr = malloc(blen);
328         if (hdr == NULL)
329                 return -1;
330
331         ul = (unsigned long *) &hdr[1];
332         hdr->op = htonl(PIMOP_SET);
333         hdr->oid = htonl(DOT11_OID_EXUNENCRYPTED);
334         *ul = htonl(DOT11_BOOL_TRUE); /* not accept */
335         send(drv->pim_sock, hdr, blen, 0);
336         prism54_waitpim(priv, DOT11_OID_EXUNENCRYPTED, hdr, blen, 10);
337         hdr->op = htonl(PIMOP_SET);
338         hdr->oid = htonl(DOT11_OID_MLMEAUTOLEVEL);
339         *ul = htonl(DOT11_MLME_EXTENDED);
340         send(drv->pim_sock, hdr, blen, 0);
341         prism54_waitpim(priv, DOT11_OID_MLMEAUTOLEVEL, hdr, blen, 10);
342         hdr->op = htonl(PIMOP_SET);
343         hdr->oid = htonl(DOT11_OID_DOT1XENABLE);
344         *ul = htonl(DOT11_BOOL_TRUE);
345         send(drv->pim_sock, hdr, blen, 0);
346         prism54_waitpim(priv, DOT11_OID_DOT1XENABLE, hdr, blen, 10);
347         hdr->op = htonl(PIMOP_SET);
348         hdr->oid = htonl(DOT11_OID_AUTHENABLE);
349         *ul = htonl(DOT11_AUTH_OS); /* OS */
350         send(drv->pim_sock, hdr, blen, 0);
351         prism54_waitpim(priv, DOT11_OID_AUTHENABLE, hdr, blen, 10);
352         free(hdr);
353         return 0;
354 }
355
356
357 static int prism54_set_privacy_invoked(const char *ifname, void *priv,
358                                        int flag)
359 {
360         struct prism54_driver_data *drv = priv;
361         pimdev_hdr *hdr;
362         unsigned long *ul;
363         int ret;
364         int blen = sizeof(*hdr) + sizeof(*ul);
365         hdr = malloc(blen);
366         if (hdr == NULL)
367                 return -1;
368         ul = (unsigned long *) &hdr[1];
369         hdr->op = htonl(PIMOP_SET);
370         hdr->oid = htonl(DOT11_OID_PRIVACYINVOKED);
371         if (flag) {
372                 *ul = htonl(DOT11_BOOL_TRUE); /* has privacy */
373         } else {
374                 *ul = 0;
375         }
376         ret = send(drv->pim_sock, hdr, blen, 0);
377         if (ret >= 0) {
378                 ret = prism54_waitpim(priv, DOT11_OID_PRIVACYINVOKED, hdr,
379                                       blen, 10);
380         }
381         free(hdr);
382         return ret;
383 }
384
385  
386 static int prism54_ioctl_setiwessid(const char *ifname, void *priv,
387                                     const u8 *buf, int len)
388 {
389 #if 0
390         struct prism54_driver_data *drv = priv;
391         struct iwreq iwr;
392
393         memset(&iwr, 0, sizeof(iwr));
394         os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
395         iwr.u.essid.flags = 1; /* SSID active */
396         iwr.u.essid.pointer = (caddr_t) buf;
397         iwr.u.essid.length = len + 1;
398
399         if (ioctl(drv->pim_sock, SIOCSIWESSID, &iwr) < 0) {
400                 perror("ioctl[SIOCSIWESSID]");
401                 printf("len=%d\n", len);
402                 return -1;
403         }
404 #endif
405         return 0;
406 }
407
408
409 /* kick all stations */
410 /* does not work during init, but at least it won't crash firmware */
411 static int prism54_flush(void *priv)
412 {
413         struct prism54_driver_data *drv = priv;
414         struct obj_mlmeex *mlme;
415         pimdev_hdr *hdr;
416         int ret;
417         unsigned int i;
418         long *nsta;
419         int blen = sizeof(*hdr) + sizeof(*mlme);
420         char *mac_id;
421
422         hdr = os_zalloc(blen);
423         if (hdr == NULL)
424                 return -1;
425
426         mlme = (struct obj_mlmeex *) &hdr[1];
427         nsta = (long *) &hdr[1];
428         hdr->op = htonl(PIMOP_GET);
429         hdr->oid = htonl(DOT11_OID_CLIENTS);
430         ret = send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(long), 0);
431         ret = prism54_waitpim(priv, DOT11_OID_CLIENTS, hdr, blen, 10);
432         if ((ret < 0) || (hdr->op != (int) htonl(PIMOP_RESPONSE)) ||
433             (le_to_host32(*nsta) > 2007)) {
434                 free(hdr);
435                 return 0;
436         }
437         for (i = 0; i < le_to_host32(*nsta); i++) {
438                 mlme->id = -1;
439                 mac_id = mac_id_get(drv, i);
440                 if (mac_id)
441                         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
442                 mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
443                 mlme->state = htons(DOT11_STATE_NONE);
444                 mlme->size = 0;
445                 hdr->op = htonl(PIMOP_SET);
446                 hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
447                 ret = send(drv->pim_sock, hdr, blen, 0);
448                 prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen,
449                                 100);
450         }
451         for (i = 0; i < le_to_host32(*nsta); i++) {
452                 mlme->id = -1;
453                 mac_id = mac_id_get(drv, i);
454                 if (mac_id)
455                         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
456                 mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
457                 mlme->state = htons(DOT11_STATE_NONE);
458                 mlme->size = 0;
459                 hdr->op = htonl(PIMOP_SET);
460                 hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
461                 ret = send(drv->pim_sock, hdr, blen, 0);
462                 prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen,
463                                 100);
464         }
465         free(hdr);
466         return 0;
467 }
468
469
470 static int prism54_sta_deauth(void *priv, const u8 *addr, int reason)
471 {
472         struct prism54_driver_data *drv = priv;
473         pimdev_hdr *hdr;
474         struct obj_mlmeex *mlme;
475         int ret;
476         int blen = sizeof(*hdr) + sizeof(*mlme);
477         hdr = malloc(blen);
478         if (hdr == NULL)
479                 return -1;
480         mlme = (struct obj_mlmeex *) &hdr[1];
481         hdr->op = htonl(PIMOP_SET);
482         hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
483         memcpy(&mlme->address[0], addr, ETH_ALEN);
484         mlme->id = -1;
485         mlme->state = htons(DOT11_STATE_NONE);
486         mlme->code = host_to_le16(reason);
487         mlme->size = 0;
488         ret = send(drv->pim_sock, hdr, blen, 0);
489         prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 10);
490         free(hdr);
491         return ret;
492 }
493
494
495 static int prism54_sta_disassoc(void *priv, const u8 *addr, int reason)
496 {
497         struct prism54_driver_data *drv = priv;
498         pimdev_hdr *hdr;
499         struct obj_mlmeex *mlme;
500         int ret;
501         int blen = sizeof(*hdr) + sizeof(*mlme);
502         hdr = malloc(blen);
503         if (hdr == NULL)
504                 return -1;
505         mlme = (struct obj_mlmeex *) &hdr[1];
506         hdr->op = htonl(PIMOP_SET);
507         hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
508         memcpy(&mlme->address[0], addr, ETH_ALEN);
509         mlme->id = -1;
510         mlme->state = htons(DOT11_STATE_NONE);
511         mlme->code = host_to_le16(reason);
512         mlme->size = 0;
513         ret = send(drv->pim_sock, hdr, blen, 0);
514         prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 10);
515         free(hdr);
516         return ret;
517 }
518
519
520 static int prism54_get_inact_sec(void *priv, const u8 *addr)
521 {
522         struct prism54_driver_data *drv = priv;
523         pimdev_hdr *hdr;
524         struct obj_sta *sta;
525         int blen = sizeof(*hdr) + sizeof(*sta);
526         int ret;
527
528         hdr = malloc(blen);
529         if (hdr == NULL)
530                 return -1;
531         hdr->op = htonl(PIMOP_GET);
532         hdr->oid = htonl(DOT11_OID_CLIENTFIND);
533         sta = (struct obj_sta *) &hdr[1];
534         memcpy(&sta->address[0], addr, ETH_ALEN);
535         ret = send(drv->pim_sock, hdr, blen, 0);
536         ret = prism54_waitpim(priv, DOT11_OID_CLIENTFIND, hdr, blen, 10);
537         if (ret != blen) {
538                 printf("get_inact_sec: bad return %d\n", ret);
539                 free(hdr);
540                 return -1;
541         }
542         if (hdr->op != (int) htonl(PIMOP_RESPONSE)) {
543                 printf("get_inact_sec: bad resp\n");
544                 free(hdr);
545                 return -1;
546         }
547         free(hdr);
548         return le_to_host16(sta->age);
549 }
550
551
552 /* set attachments */
553 static int prism54_set_generic_elem(const char *ifname, void *priv,
554                                     const u8 *elem, size_t elem_len)
555 {
556         struct prism54_driver_data *drv = priv;
557         pimdev_hdr *hdr;
558         char *pos;
559         struct obj_attachment_hdr *attach;
560         size_t blen = sizeof(*hdr) + sizeof(*attach) + elem_len;
561         hdr = os_zalloc(blen);
562         if (hdr == NULL) {
563                 printf("%s: memory low\n", __func__);
564                 return -1;
565         }
566         hdr->op = htonl(PIMOP_SET);
567         hdr->oid = htonl(DOT11_OID_ATTACHMENT);
568         attach = (struct obj_attachment_hdr *)&hdr[1];
569         attach->type = DOT11_PKT_BEACON;
570         attach->id = -1;
571         attach->size = host_to_le16((short)elem_len);
572         pos = ((char*) attach) + sizeof(*attach);
573         if (elem)
574                 memcpy(pos, elem, elem_len);
575         send(drv->pim_sock, hdr, blen, 0);
576         attach->type = DOT11_PKT_PROBE_RESP;
577         send(drv->pim_sock, hdr, blen, 0);
578         free(hdr);
579         return 0;
580 }
581
582
583 /* tell the card to auth the sta */
584 static void prism54_handle_probe(struct prism54_driver_data *drv,
585                                  void *buf, size_t len)
586 {
587         struct obj_mlmeex *mlme;
588         pimdev_hdr *hdr;
589         struct sta_info *sta;
590         hdr = (pimdev_hdr *)buf;
591         mlme = (struct obj_mlmeex *) &hdr[1];
592         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
593         if (sta != NULL) {
594                 if (sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC))
595                         return;
596         }
597         if (len < sizeof(*mlme)) {
598                 printf("bad probe packet\n");
599                 return;
600         }
601         mlme->state = htons(DOT11_STATE_AUTHING);
602         mlme->code = 0;
603         hdr->op = htonl(PIMOP_SET);
604         hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
605         mlme->size = 0;
606         send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
607 }
608
609
610 static void prism54_handle_deauth(struct prism54_driver_data *drv,
611                                   void *buf, size_t len)
612 {
613         struct obj_mlme *mlme;
614         pimdev_hdr *hdr;
615         struct sta_info *sta;
616         char *mac_id;
617
618         hdr = (pimdev_hdr *) buf;
619         mlme = (struct obj_mlme *) &hdr[1];
620         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
621         mac_id = mac_id_get(drv, mlme->id);
622         if (sta == NULL || mac_id == NULL)
623                 return;
624         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
625         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
626         wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
627         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
628         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
629         ap_free_sta(drv->hapd, sta);
630 }
631
632
633 static void prism54_handle_disassoc(struct prism54_driver_data *drv,
634                                     void *buf, size_t len)
635 {
636         struct obj_mlme *mlme;
637         pimdev_hdr *hdr;
638         struct sta_info *sta;
639         char *mac_id;
640
641         hdr = (pimdev_hdr *) buf;
642         mlme = (struct obj_mlme *) &hdr[1];
643         mac_id = mac_id_get(drv, mlme->id);
644         if (mac_id == NULL)
645                 return;
646         memcpy(&mlme->address[0], mac_id, ETH_ALEN);
647         sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
648         if (sta == NULL) {
649                 return;
650         }
651         sta->flags &= ~WLAN_STA_ASSOC;
652         wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
653         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
654         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
655         accounting_sta_stop(drv->hapd, sta);
656         ieee802_1x_free_station(sta);
657 }
658
659
660 /* to auth it, just allow it now, later for os/sk */
661 static void prism54_handle_auth(struct prism54_driver_data *drv,
662                                 void *buf, size_t len)
663 {
664         struct obj_mlmeex *mlme;
665         pimdev_hdr *hdr;
666         struct sta_info *sta;
667         int resp;
668
669         hdr = (pimdev_hdr *) buf;
670         mlme = (struct obj_mlmeex *) &hdr[1];
671         if (len < sizeof(*mlme)) {
672                 printf("bad auth packet\n");
673                 return;
674         }
675
676         if (mlme->state == htons(DOT11_STATE_AUTHING)) {
677                 sta = ap_sta_add(drv->hapd, (u8 *) &mlme->address[0]);
678                 if (drv->hapd->tkip_countermeasures) {
679                         resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
680                         goto fail;
681                 }
682                 mac_id_refresh(drv, mlme->id, &mlme->address[0]);
683                 if (!sta) {
684                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
685                         goto fail;
686                 }
687                 sta->flags &= ~WLAN_STA_PREAUTH;
688                 
689                 ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
690                 sta->flags |= WLAN_STA_AUTH;
691                 wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
692                 mlme->code = 0;
693                 mlme->state=htons(DOT11_STATE_AUTH);
694                 hdr->op = htonl(PIMOP_SET);
695                 hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
696                 mlme->size = 0;
697                 sta->timeout_next = STA_NULLFUNC;
698                 send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
699         }
700         return;
701
702 fail:
703         printf("auth fail: %x\n", resp);
704         mlme->code = host_to_le16(resp);
705         mlme->size = 0;
706         if (sta)
707                 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
708         hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
709         hdr->op = htonl(PIMOP_SET);
710         send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
711 }
712
713
714 /* do the wpa thing */
715 static void prism54_handle_assoc(struct prism54_driver_data *drv,
716                                  void *buf, size_t len)
717 {
718         pimdev_hdr *hdr;
719         struct obj_mlmeex *mlme;
720         struct ieee802_11_elems elems;
721         struct sta_info *sta;
722         u8 *wpa_ie;
723         u8 *cb;
724         int ieofs = 0;
725         size_t wpa_ie_len;
726         int resp, new_assoc;
727         char *mac_id;
728
729         resp = 0;
730         hdr = (pimdev_hdr *) buf;
731         mlme = (struct obj_mlmeex *) &hdr[1];
732         switch (ntohl(hdr->oid)) {
733                 case DOT11_OID_ASSOCIATE:
734                 case DOT11_OID_REASSOCIATE:
735                         mlme->size = 0;
736                 default:
737                         break;
738         }
739         if ((mlme->state == (int) htonl(DOT11_STATE_ASSOCING)) ||
740             (mlme->state == (int) htonl(DOT11_STATE_REASSOCING))) {
741                 if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
742                         printf("bad assoc packet\n");
743                         return;
744                 }
745                 mac_id = mac_id_get(drv, mlme->id);
746                 if (mac_id == NULL)
747                         return;
748                 memcpy(&mlme->address[0], mac_id, ETH_ALEN);
749                 sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
750                 if (sta == NULL) {
751                         printf("cannot get sta\n");
752                         return;
753                 }
754                 cb = (u8 *) &mlme->data[0];
755                 if (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) {
756                         ieofs = 4;
757                 } else if (hdr->oid == htonl(DOT11_OID_REASSOCIATEEX)) {
758                         ieofs = 10;
759                 }
760                 if (le_to_host16(mlme->size) <= ieofs) {
761                         printf("attach too small\n");
762                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
763                         goto fail;
764                 }
765                 if (ieee802_11_parse_elems(cb + ieofs,
766                                            le_to_host16(mlme->size) - ieofs,
767                                            &elems, 1) == ParseFailed) {
768                         printf("STA " MACSTR " sent invalid association "
769                                "request\n", MAC2STR(sta->addr));
770                         resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
771                         goto fail;
772                 }
773                 if ((drv->hapd->conf->wpa & WPA_PROTO_RSN) &&
774                     elems.rsn_ie) {
775                         wpa_ie = elems.rsn_ie;
776                         wpa_ie_len = elems.rsn_ie_len;
777                 } else if ((drv->hapd->conf->wpa & WPA_PROTO_WPA) &&
778                            elems.wpa_ie) {
779                         wpa_ie = elems.wpa_ie;
780                         wpa_ie_len = elems.wpa_ie_len;
781                 } else {
782                         wpa_ie = NULL;
783                         wpa_ie_len = 0;
784                 }
785                 if (drv->hapd->conf->wpa && wpa_ie == NULL) {
786                         printf("STA " MACSTR ": No WPA/RSN IE in association "
787                                "request\n", MAC2STR(sta->addr));
788                         resp = WLAN_STATUS_INVALID_IE;
789                         goto fail;
790                 }
791                 if (drv->hapd->conf->wpa) {
792                         int res;
793                         wpa_ie -= 2;
794                         wpa_ie_len += 2;
795                         if (sta->wpa_sm == NULL)
796                                 sta->wpa_sm = wpa_auth_sta_init(
797                                         drv->hapd->wpa_auth, sta->addr);
798                         if (sta->wpa_sm == NULL) {
799                                 printf("Failed to initialize WPA state "
800                                        "machine\n");
801                                 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
802                                 goto fail;
803                         }
804                         res = wpa_validate_wpa_ie(drv->hapd->wpa_auth,
805                                                   sta->wpa_sm,
806                                                   wpa_ie, wpa_ie_len,
807                                                   NULL, 0);
808                         if (res == WPA_INVALID_GROUP)
809                                 resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
810                         else if (res == WPA_INVALID_PAIRWISE)
811                                 resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
812                         else if (res == WPA_INVALID_AKMP)
813                                 resp = WLAN_STATUS_AKMP_NOT_VALID;
814                         else if (res == WPA_ALLOC_FAIL)
815                                 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
816                         else if (res != WPA_IE_OK)
817                                 resp = WLAN_STATUS_INVALID_IE;
818                         if (resp != WLAN_STATUS_SUCCESS)
819                                 goto fail;
820                 }
821                 hdr->oid = (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) ?
822                         htonl(DOT11_OID_ASSOCIATEEX) :
823                         htonl(DOT11_OID_REASSOCIATEEX);
824                 hdr->op = htonl(PIMOP_SET);
825                 mlme->code = 0;
826                 mlme->state = htons(DOT11_STATE_ASSOC);
827                 mlme->size = 0;
828                 send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
829                 return;
830         } else if (mlme->state==htons(DOT11_STATE_ASSOC)) {
831                 if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
832                         printf("bad assoc packet\n");
833                         return;
834                 }
835                 mac_id = mac_id_get(drv, mlme->id);
836                 if (mac_id == NULL)
837                         return;
838                 memcpy(&mlme->address[0], mac_id, ETH_ALEN);
839                 sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
840                 if (sta == NULL) {
841                         printf("cannot get sta\n");
842                         return;
843                 }
844                 new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
845                 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
846                 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
847                 hostapd_new_assoc_sta(drv->hapd, sta, !new_assoc);
848                 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
849                 sta->timeout_next = STA_NULLFUNC;
850                 return;
851         }
852         return;
853
854 fail:
855         printf("Prism54: assoc fail: %x\n", resp);
856         mlme->code = host_to_le16(resp);
857         mlme->size = 0;
858         mlme->state = htons(DOT11_STATE_ASSOCING);
859         hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
860         hdr->op = htonl(PIMOP_SET);
861         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
862         send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
863 }
864
865
866 static void handle_pim(int sock, void *eloop_ctx, void *sock_ctx)
867 {
868         struct prism54_driver_data *drv = eloop_ctx;
869         int len;
870         pimdev_hdr *hdr;
871
872         hdr = malloc(PIM_BUF_SIZE);
873         if (hdr == NULL)
874                 return;
875         len = recv(sock, hdr, PIM_BUF_SIZE, 0);
876         if (len < 0) {
877                 perror("recv");
878                 free(hdr);
879                 return;
880         }
881         if (len < 8) {
882                 printf("handle_pim: too short (%d)\n", len);
883                 free(hdr);
884                 return;
885         }
886
887         if (hdr->op != (int) htonl(PIMOP_TRAP)) {
888                 free(hdr);
889                 return;
890         }
891         switch (ntohl(hdr->oid)) {
892                 case DOT11_OID_PROBE:
893                         prism54_handle_probe(drv, hdr, len);
894                         break;
895                 case DOT11_OID_DEAUTHENTICATEEX:
896                 case DOT11_OID_DEAUTHENTICATE:
897                         prism54_handle_deauth(drv, hdr, len);
898                         break;
899                 case DOT11_OID_DISASSOCIATEEX:
900                 case DOT11_OID_DISASSOCIATE:
901                         prism54_handle_disassoc(drv, hdr, len);
902                         break;
903                 case DOT11_OID_AUTHENTICATEEX:
904                 case DOT11_OID_AUTHENTICATE:
905                         prism54_handle_auth(drv, hdr, len);
906                         break;
907                 case DOT11_OID_ASSOCIATEEX:
908                 case DOT11_OID_REASSOCIATEEX:
909                 case DOT11_OID_ASSOCIATE:
910                 case DOT11_OID_REASSOCIATE:
911                         prism54_handle_assoc(drv, hdr, len);
912                 default:
913                         break;
914         }
915
916         free(hdr);
917 }
918
919
920 static void handle_802_3(int sock, void *eloop_ctx, void *sock_ctx)
921 {
922         struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
923         int len;
924         ieee802_3_hdr *hdr;
925
926         hdr = malloc(PIM_BUF_SIZE);
927         if (hdr == NULL)
928                 return;
929         len = recv(sock, hdr, PIM_BUF_SIZE, 0);
930         if (len < 0) {
931                 perror("recv");
932                 free(hdr);
933                 return;
934         }
935         if (len < 14) {
936                 wpa_printf(MSG_MSGDUMP, "handle_802_3: too short (%d)", len);
937                 free(hdr);
938                 return;
939         }
940         if (hdr->type == htons(ETH_P_PAE)) {
941                 hostapd_eapol_receive(hapd, (u8 *) &hdr->sa[0], (u8 *) &hdr[1],
942                                       len - sizeof(*hdr));
943         }
944         free(hdr);
945 }
946
947
948 static int prism54_init_sockets(struct prism54_driver_data *drv)
949 {
950         struct hostapd_data *hapd = drv->hapd;
951         struct ifreq ifr;
952         struct sockaddr_ll addr;
953
954         drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
955         if (drv->sock < 0) {
956                 perror("socket[PF_PACKET,SOCK_RAW]");
957                 return -1;
958         }
959
960         if (eloop_register_read_sock(drv->sock, handle_802_3, drv->hapd, NULL))
961         {
962                 printf("Could not register read socket\n");
963                 return -1;
964         }
965
966         memset(&ifr, 0, sizeof(ifr));
967         if (hapd->conf->bridge[0] != '\0') {
968                 printf("opening bridge: %s\n", hapd->conf->bridge);
969                 os_strlcpy(ifr.ifr_name, hapd->conf->bridge,
970                            sizeof(ifr.ifr_name));
971         } else {
972                 os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
973         }
974         if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
975                 perror("ioctl(SIOCGIFINDEX)");
976                 return -1;
977         }
978
979         memset(&addr, 0, sizeof(addr));
980         addr.sll_family = AF_PACKET;
981         addr.sll_ifindex = ifr.ifr_ifindex;
982         addr.sll_protocol = htons(ETH_P_PAE);
983         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
984                    addr.sll_ifindex);
985
986         if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
987                 perror("bind");
988                 return -1;
989         }
990
991         memset(&ifr, 0, sizeof(ifr));
992         os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
993         if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
994                 perror("ioctl(SIOCGIFHWADDR)");
995                 return -1;
996         }
997
998         if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
999                 printf("Invalid HW-addr family 0x%04x\n",
1000                        ifr.ifr_hwaddr.sa_family);
1001                 return -1;
1002         }
1003         memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
1004
1005         drv->pim_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
1006         if (drv->pim_sock < 0) {
1007                 perror("socket[PF_PACKET,SOCK_RAW]");
1008                 return -1;
1009         }
1010
1011         if (eloop_register_read_sock(drv->pim_sock, handle_pim, drv, NULL)) {
1012                 printf("Could not register read socket\n");
1013                 return -1;
1014         }
1015
1016         memset(&ifr, 0, sizeof(ifr));
1017         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
1018         if (ioctl(drv->pim_sock, SIOCGIFINDEX, &ifr) != 0) {
1019                 perror("ioctl(SIOCGIFINDEX)");
1020                 return -1;
1021         }
1022
1023         memset(&addr, 0, sizeof(addr));
1024         addr.sll_family = AF_PACKET;
1025         addr.sll_ifindex = ifr.ifr_ifindex;
1026         addr.sll_protocol = htons(ETH_P_ALL);
1027         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
1028                    addr.sll_ifindex);
1029
1030         if (bind(drv->pim_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1031                 perror("bind");
1032                 return -1;
1033         }
1034
1035         return 0;
1036 }
1037
1038
1039 static void * prism54_driver_init(struct hostapd_data *hapd)
1040 {
1041         struct prism54_driver_data *drv;
1042
1043         drv = os_zalloc(sizeof(struct prism54_driver_data));
1044         if (drv == NULL) {
1045                 printf("Could not allocate memory for hostapd Prism54 driver "
1046                        "data\n");
1047                 return NULL;
1048         }
1049
1050         drv->hapd = hapd;
1051         drv->pim_sock = drv->sock = -1;
1052         memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
1053
1054         if (prism54_init_sockets(drv)) {
1055                 free(drv);
1056                 return NULL;
1057         }
1058         prism54_init_1x(drv);
1059         /* must clean previous elems */
1060         prism54_set_generic_elem(drv->iface, drv, NULL, 0);
1061
1062         return drv;
1063 }
1064
1065
1066 static void prism54_driver_deinit(void *priv)
1067 {
1068         struct prism54_driver_data *drv = priv;
1069
1070         if (drv->pim_sock >= 0)
1071                 close(drv->pim_sock);
1072
1073         if (drv->sock >= 0)
1074                 close(drv->sock);
1075         
1076         free(drv);
1077 }
1078
1079
1080 const struct hapd_driver_ops wpa_driver_prism54_ops = {
1081         .name = "prism54",
1082         .init = prism54_driver_init,
1083         .deinit = prism54_driver_deinit,
1084         /* .set_ieee8021x = prism54_init_1x, */
1085         .set_privacy = prism54_set_privacy_invoked,
1086         .set_key = prism54_set_key,
1087         .get_seqnum = prism54_get_seqnum,
1088         .flush = prism54_flush,
1089         .set_generic_elem = prism54_set_generic_elem,
1090         .send_eapol = prism54_send_eapol,
1091         .sta_set_flags = prism54_sta_set_flags,
1092         .sta_deauth = prism54_sta_deauth,
1093         .sta_disassoc = prism54_sta_disassoc,
1094         .set_ssid = prism54_ioctl_setiwessid,
1095         .get_inact_sec = prism54_get_inact_sec,
1096 };