]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/hostapd/driver_test.c
This commit was generated by cvs2svn to compensate for changes in r168616,
[FreeBSD/FreeBSD.git] / contrib / hostapd / driver_test.c
1 /*
2  * Host AP (software wireless LAN access point) user space daemon for
3  * Host AP kernel driver / Driver interface for development testing
4  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <sys/ioctl.h>
22 #include <netinet/in.h>
23 #include <signal.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/uio.h>
28
29 #include "hostapd.h"
30 #include "driver.h"
31 #include "sha1.h"
32 #include "eloop.h"
33 #include "ieee802_1x.h"
34 #include "sta_info.h"
35 #include "eapol_sm.h"
36 #include "wpa.h"
37 #include "accounting.h"
38 #include "radius.h"
39 #include "l2_packet.h"
40 #include "hostap_common.h"
41
42
43 struct test_client_socket {
44         struct test_client_socket *next;
45         u8 addr[ETH_ALEN];
46         struct sockaddr_un un;
47         socklen_t unlen;
48 };
49
50 struct test_driver_data {
51         struct driver_ops ops;
52         struct hostapd_data *hapd;
53         struct test_client_socket *cli;
54         int test_socket;
55         u8 *ie;
56         size_t ielen;
57 };
58
59 static const struct driver_ops test_driver_ops;
60
61
62 static struct test_client_socket *
63 test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from,
64                     socklen_t fromlen)
65 {
66         struct test_client_socket *cli = drv->cli;
67
68         while (cli) {
69                 if (cli->unlen == fromlen &&
70                     strncmp(cli->un.sun_path, from->sun_path, fromlen) == 0)
71                         return cli;
72                 cli = cli->next;
73         }
74
75         return NULL;
76 }
77
78
79 static int test_driver_send_eapol(void *priv, u8 *addr, u8 *data,
80                                   size_t data_len, int encrypt)
81 {
82         struct test_driver_data *drv = priv;
83         struct test_client_socket *cli;
84         struct msghdr msg;
85         struct iovec io[3];
86         struct l2_ethhdr eth;
87
88         if (drv->test_socket < 0)
89                 return -1;
90
91         cli = drv->cli;
92         while (cli) {
93                 if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
94                         break;
95                 cli = cli->next;
96         }
97
98         if (!cli)
99                 return -1;
100
101         memcpy(eth.h_dest, addr, ETH_ALEN);
102         memcpy(eth.h_source, drv->hapd->own_addr, ETH_ALEN);
103         eth.h_proto = htons(ETH_P_EAPOL);
104
105         io[0].iov_base = "EAPOL ";
106         io[0].iov_len = 6;
107         io[1].iov_base = &eth;
108         io[1].iov_len = sizeof(eth);
109         io[2].iov_base = data;
110         io[2].iov_len = data_len;
111
112         memset(&msg, 0, sizeof(msg));
113         msg.msg_iov = io;
114         msg.msg_iovlen = 3;
115         msg.msg_name = &cli->un;
116         msg.msg_namelen = cli->unlen;
117         return sendmsg(drv->test_socket, &msg, 0);
118 }
119
120
121 static void test_driver_scan(struct test_driver_data *drv,
122                              struct sockaddr_un *from, socklen_t fromlen)
123 {
124         char buf[512], *pos, *end;
125         int i;
126
127         pos = buf;
128         end = buf + sizeof(buf);
129
130         wpa_printf(MSG_DEBUG, "test_driver: SCAN");
131
132         /* reply: SCANRESP BSSID SSID IEs */
133         pos += snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
134                         MAC2STR(drv->hapd->own_addr));
135         for (i = 0; i < drv->hapd->conf->ssid_len; i++) {
136                 pos += snprintf(pos, end - pos, "%02x",
137                                 drv->hapd->conf->ssid[i]);
138         }
139         pos += snprintf(pos, end - pos, " ");
140         for (i = 0; i < drv->ielen; i++) {
141                 pos += snprintf(pos, end - pos, "%02x",
142                                 drv->ie[i]);
143         }
144
145         sendto(drv->test_socket, buf, pos - buf, 0,
146                (struct sockaddr *) from, fromlen);
147 }
148
149
150 static int test_driver_new_sta(struct test_driver_data *drv, const u8 *addr,
151                                const u8 *ie, size_t ielen)
152 {
153         struct hostapd_data *hapd = drv->hapd;
154         struct sta_info *sta;
155         int new_assoc, res;
156
157         hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
158                 HOSTAPD_LEVEL_INFO, "associated");
159
160         sta = ap_get_sta(hapd, addr);
161         if (sta) {
162                 accounting_sta_stop(hapd, sta);
163         } else {
164                 sta = ap_sta_add(hapd, addr);
165                 if (sta == NULL)
166                         return -1;
167         }
168         accounting_sta_get_id(hapd, sta);
169
170         if (hapd->conf->wpa) {
171                 if (ie == NULL || ielen == 0) {
172                         printf("test_driver: no IE from STA\n");
173                         return -1;
174                 }
175                 res = wpa_validate_wpa_ie(hapd, sta, ie, ielen,
176                                           ie[0] == WLAN_EID_RSN ?
177                                           HOSTAPD_WPA_VERSION_WPA2 :
178                                           HOSTAPD_WPA_VERSION_WPA);
179                 if (res != WPA_IE_OK) {
180                         printf("WPA/RSN information element rejected? "
181                                "(res %u)\n", res);
182                         return -1;
183                 }
184                 free(sta->wpa_ie);
185                 sta->wpa_ie = malloc(ielen);
186                 if (sta->wpa_ie == NULL)
187                         return -1;
188                 memcpy(sta->wpa_ie, ie, ielen);
189                 sta->wpa_ie_len = ielen;
190         } else {
191                 free(sta->wpa_ie);
192                 sta->wpa_ie = NULL;
193                 sta->wpa_ie_len = 0;
194         }
195
196         new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
197         sta->flags |= WLAN_STA_ASSOC;
198         wpa_sm_event(hapd, sta, WPA_ASSOC);
199
200         hostapd_new_assoc_sta(hapd, sta, !new_assoc);
201
202         ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
203
204         return 0;
205 }
206
207
208 static void test_driver_assoc(struct test_driver_data *drv,
209                               struct sockaddr_un *from, socklen_t fromlen,
210                               char *data)
211 {
212         struct test_client_socket *cli;
213         u8 ie[256];
214         size_t ielen;
215         char *pos, *pos2, cmd[50];
216
217         /* data: STA-addr SSID(hex) IEs(hex) */
218
219         cli = malloc(sizeof(*cli));
220         if (cli == NULL)
221                 return;
222
223         memset(cli, 0, sizeof(*cli));
224         if (hwaddr_aton(data, cli->addr)) {
225                 printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
226                        data);
227                 free(cli);
228                 return;
229         }
230         pos = data + 17;
231         while (*pos == ' ')
232                 pos++;
233         pos2 = strchr(pos, ' ');
234         ielen = 0;
235         if (pos2) {
236                 /* TODO: verify SSID */
237
238                 pos = pos2 + 1;
239                 ielen = strlen(pos) / 2;
240                 if (ielen > sizeof(ie))
241                         ielen = sizeof(ie);
242                 if (hexstr2bin(pos, ie, ielen) < 0)
243                         ielen = 0;
244         }
245
246         memcpy(&cli->un, from, sizeof(cli->un));
247         cli->unlen = fromlen;
248         cli->next = drv->cli;
249         drv->cli = cli;
250         wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
251                           cli->un.sun_path, cli->unlen);
252
253         snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
254                  MAC2STR(drv->hapd->own_addr));
255         sendto(drv->test_socket, cmd, strlen(cmd), 0,
256                (struct sockaddr *) from, fromlen);
257
258         if (test_driver_new_sta(drv, cli->addr, ie, ielen) < 0) {
259                 wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA");
260         }
261 }
262
263
264 static void test_driver_disassoc(struct test_driver_data *drv,
265                                  struct sockaddr_un *from, socklen_t fromlen)
266 {
267         struct test_client_socket *cli;
268         struct sta_info *sta;
269
270         cli = test_driver_get_cli(drv, from, fromlen);
271         if (!cli)
272                 return;
273
274         hostapd_logger(drv->hapd, cli->addr, HOSTAPD_MODULE_IEEE80211,
275                        HOSTAPD_LEVEL_INFO, "disassociated");
276
277         sta = ap_get_sta(drv->hapd, cli->addr);
278         if (sta != NULL) {
279                 sta->flags &= ~WLAN_STA_ASSOC;
280                 wpa_sm_event(drv->hapd, sta, WPA_DISASSOC);
281                 sta->acct_terminate_cause =
282                         RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
283                 ieee802_1x_set_port_enabled(drv->hapd, sta, 0);
284                 ap_free_sta(drv->hapd, sta);
285         }
286 }
287
288
289 static void test_driver_eapol(struct test_driver_data *drv,
290                               struct sockaddr_un *from, socklen_t fromlen,
291                               u8 *data, size_t datalen)
292 {
293         struct test_client_socket *cli;
294         if (datalen > 14) {
295                 /* Skip Ethernet header */
296                 data += 14;
297                 datalen -= 14;
298         }
299         cli = test_driver_get_cli(drv, from, fromlen);
300         if (cli)
301                 ieee802_1x_receive(drv->hapd, cli->addr, data, datalen);
302         else {
303                 wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
304                            "client");
305         }
306 }
307
308
309 static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
310 {
311         struct test_driver_data *drv = eloop_ctx;
312         char buf[2000];
313         int res;
314         struct sockaddr_un from;
315         socklen_t fromlen = sizeof(from);
316
317         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
318                        (struct sockaddr *) &from, &fromlen);
319         if (res < 0) {
320                 perror("recvfrom(test_socket)");
321                 return;
322         }
323         buf[res] = '\0';
324
325         wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
326
327         if (strcmp(buf, "SCAN") == 0) {
328                 test_driver_scan(drv, &from, fromlen);
329         } else if (strncmp(buf, "ASSOC ", 6) == 0) {
330                 test_driver_assoc(drv, &from, fromlen, buf + 6);
331         } else if (strcmp(buf, "DISASSOC") == 0) {
332                 test_driver_disassoc(drv, &from, fromlen);
333         } else if (strncmp(buf, "EAPOL ", 6) == 0) {
334                 test_driver_eapol(drv, &from, fromlen, buf + 6, res - 6);
335         } else {
336                 wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
337                                   (u8 *) buf, res);
338         }
339 }
340
341
342 static int test_driver_set_generic_elem(void *priv,
343                                         const u8 *elem, size_t elem_len)
344 {
345         struct test_driver_data *drv = priv;
346
347         free(drv->ie);
348         drv->ie = malloc(elem_len);
349         if (drv->ie) {
350                 memcpy(drv->ie, elem, elem_len);
351                 drv->ielen = elem_len;
352                 return 0;
353         } else {
354                 drv->ielen = 0;
355                 return -1;
356         }
357 }
358
359
360 static int test_driver_sta_deauth(void *priv, u8 *addr, int reason)
361 {
362         struct test_driver_data *drv = priv;
363         struct test_client_socket *cli;
364
365         if (drv->test_socket < 0)
366                 return -1;
367
368         cli = drv->cli;
369         while (cli) {
370                 if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
371                         break;
372                 cli = cli->next;
373         }
374
375         if (!cli)
376                 return -1;
377
378         return sendto(drv->test_socket, "DEAUTH", 6, 0,
379                       (struct sockaddr *) &cli->un, cli->unlen);
380 }
381
382
383 static int test_driver_sta_disassoc(void *priv, u8 *addr, int reason)
384 {
385         struct test_driver_data *drv = priv;
386         struct test_client_socket *cli;
387
388         if (drv->test_socket < 0)
389                 return -1;
390
391         cli = drv->cli;
392         while (cli) {
393                 if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
394                         break;
395                 cli = cli->next;
396         }
397
398         if (!cli)
399                 return -1;
400
401         return sendto(drv->test_socket, "DISASSOC", 8, 0,
402                       (struct sockaddr *) &cli->un, cli->unlen);
403 }
404
405
406 static int test_driver_init(struct hostapd_data *hapd)
407 {
408         struct test_driver_data *drv;
409         struct sockaddr_un addr;
410
411         drv = malloc(sizeof(struct test_driver_data));
412         if (drv == NULL) {
413                 printf("Could not allocate memory for test driver data\n");
414                 return -1;
415         }
416
417         memset(drv, 0, sizeof(*drv));
418         drv->ops = test_driver_ops;
419         drv->hapd = hapd;
420
421         /* Generate a MAC address to help testing with multiple APs */
422         hapd->own_addr[0] = 0x02; /* locally administered */
423         sha1_prf(hapd->conf->iface, strlen(hapd->conf->iface),
424                  "hostapd test bssid generation",
425                  hapd->conf->ssid, hapd->conf->ssid_len,
426                  hapd->own_addr + 1, ETH_ALEN - 1);
427
428         if (hapd->conf->test_socket) {
429                 if (strlen(hapd->conf->test_socket) >= sizeof(addr.sun_path)) {
430                         printf("Too long test_socket path\n");
431                         free(drv);
432                         return -1;
433                 }
434                 drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
435                 if (drv->test_socket < 0) {
436                         perror("socket(PF_UNIX)");
437                         free(drv);
438                         return -1;
439                 }
440
441                 memset(&addr, 0, sizeof(addr));
442                 addr.sun_family = AF_UNIX;
443                 strncpy(addr.sun_path, hapd->conf->test_socket,
444                         sizeof(addr.sun_path));
445                 if (bind(drv->test_socket, (struct sockaddr *) &addr,
446                          sizeof(addr)) < 0) {
447                         perror("bind(PF_UNIX)");
448                         close(drv->test_socket);
449                         unlink(hapd->conf->test_socket);
450                         free(drv);
451                         return -1;
452                 }
453                 eloop_register_read_sock(drv->test_socket,
454                                          test_driver_receive_unix, drv, NULL);
455         } else
456                 drv->test_socket = -1;
457
458         hapd->driver = &drv->ops;
459         return 0;
460 }
461
462
463 static void test_driver_deinit(void *priv)
464 {
465         struct test_driver_data *drv = priv;
466         struct test_client_socket *cli, *prev;
467
468         cli = drv->cli;
469         while (cli) {
470                 prev = cli;
471                 cli = cli->next;
472                 free(prev);
473         }
474
475         if (drv->test_socket >= 0) {
476                 eloop_unregister_read_sock(drv->test_socket);
477                 close(drv->test_socket);
478                 unlink(drv->hapd->conf->test_socket);
479         }
480
481         drv->hapd->driver = NULL;
482
483         free(drv->ie);
484         free(drv);
485 }
486
487
488 static const struct driver_ops test_driver_ops = {
489         .name = "test",
490         .init = test_driver_init,
491         .deinit = test_driver_deinit,
492         .send_eapol = test_driver_send_eapol,
493         .set_generic_elem = test_driver_set_generic_elem,
494         .sta_deauth = test_driver_sta_deauth,
495         .sta_disassoc = test_driver_sta_disassoc,
496 };
497
498
499 void test_driver_register(void)
500 {
501         driver_register(test_driver_ops.name, &test_driver_ops);
502 }