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