2 * WPA Supplicant - privilege separated driver interface
3 * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
15 #include "common/privsep_commands.h"
18 struct wpa_driver_privsep_data
{
20 u8 own_addr
[ETH_ALEN
];
22 char *own_socket_path
;
25 struct sockaddr_un priv_addr
;
30 static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data
*drv
, int cmd
)
34 res
= sendto(drv
->priv_socket
, &cmd
, sizeof(cmd
), 0,
35 (struct sockaddr
*) &drv
->priv_addr
,
36 sizeof(drv
->priv_addr
));
38 wpa_printf(MSG_ERROR
, "sendto: %s", strerror(errno
));
39 return res
< 0 ? -1 : 0;
43 static int wpa_priv_cmd(struct wpa_driver_privsep_data
*drv
, int cmd
,
44 const void *data
, size_t data_len
,
45 void *reply
, size_t *reply_len
)
50 io
[0].iov_base
= &cmd
;
51 io
[0].iov_len
= sizeof(cmd
);
52 io
[1].iov_base
= (u8
*) data
;
53 io
[1].iov_len
= data_len
;
55 os_memset(&msg
, 0, sizeof(msg
));
57 msg
.msg_iovlen
= data
? 2 : 1;
58 msg
.msg_name
= &drv
->priv_addr
;
59 msg
.msg_namelen
= sizeof(drv
->priv_addr
);
61 if (sendmsg(drv
->cmd_socket
, &msg
, 0) < 0) {
62 wpa_printf(MSG_ERROR
, "sendmsg(cmd_socket): %s",
73 FD_SET(drv
->cmd_socket
, &rfds
);
76 res
= select(drv
->cmd_socket
+ 1, &rfds
, NULL
, NULL
, &tv
);
77 if (res
< 0 && errno
!= EINTR
) {
78 wpa_printf(MSG_ERROR
, "select: %s", strerror(errno
));
82 if (FD_ISSET(drv
->cmd_socket
, &rfds
)) {
83 res
= recv(drv
->cmd_socket
, reply
, *reply_len
, 0);
85 wpa_printf(MSG_ERROR
, "recv: %s",
91 wpa_printf(MSG_DEBUG
, "PRIVSEP: Timeout while waiting "
92 "for reply (cmd=%d)", cmd
);
101 static int wpa_driver_privsep_scan(void *priv
,
102 struct wpa_driver_scan_params
*params
)
104 struct wpa_driver_privsep_data
*drv
= priv
;
105 const u8
*ssid
= params
->ssids
[0].ssid
;
106 size_t ssid_len
= params
->ssids
[0].ssid_len
;
107 wpa_printf(MSG_DEBUG
, "%s: priv=%p", __func__
, priv
);
108 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SCAN
, ssid
, ssid_len
,
113 static struct wpa_scan_results
*
114 wpa_driver_privsep_get_scan_results2(void *priv
)
116 struct wpa_driver_privsep_data
*drv
= priv
;
119 size_t reply_len
= 60000;
120 struct wpa_scan_results
*results
;
121 struct wpa_scan_res
*r
;
123 buf
= os_malloc(reply_len
);
126 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_SCAN_RESULTS
,
127 NULL
, 0, buf
, &reply_len
);
133 wpa_printf(MSG_DEBUG
, "privsep: Received %lu bytes of scan results",
134 (unsigned long) reply_len
);
135 if (reply_len
< sizeof(int)) {
136 wpa_printf(MSG_DEBUG
, "privsep: Invalid scan result len %lu",
137 (unsigned long) reply_len
);
143 end
= buf
+ reply_len
;
144 os_memcpy(&num
, pos
, sizeof(int));
145 if (num
< 0 || num
> 1000) {
151 results
= os_zalloc(sizeof(*results
));
152 if (results
== NULL
) {
157 results
->res
= os_calloc(num
, sizeof(struct wpa_scan_res
*));
158 if (results
->res
== NULL
) {
164 while (results
->num
< (size_t) num
&& pos
+ sizeof(int) < end
) {
166 os_memcpy(&len
, pos
, sizeof(int));
168 if (len
< 0 || len
> 10000 || pos
+ len
> end
)
174 os_memcpy(r
, pos
, len
);
176 if (sizeof(*r
) + r
->ie_len
> (size_t) len
) {
181 results
->res
[results
->num
++] = r
;
189 static int wpa_driver_privsep_set_key(const char *ifname
, void *priv
,
190 enum wpa_alg alg
, const u8
*addr
,
191 int key_idx
, int set_tx
,
192 const u8
*seq
, size_t seq_len
,
193 const u8
*key
, size_t key_len
)
195 struct wpa_driver_privsep_data
*drv
= priv
;
196 struct privsep_cmd_set_key cmd
;
198 wpa_printf(MSG_DEBUG
, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
199 __func__
, priv
, alg
, key_idx
, set_tx
);
201 os_memset(&cmd
, 0, sizeof(cmd
));
204 os_memcpy(cmd
.addr
, addr
, ETH_ALEN
);
206 os_memset(cmd
.addr
, 0xff, ETH_ALEN
);
207 cmd
.key_idx
= key_idx
;
209 if (seq
&& seq_len
> 0 && seq_len
< sizeof(cmd
.seq
)) {
210 os_memcpy(cmd
.seq
, seq
, seq_len
);
211 cmd
.seq_len
= seq_len
;
213 if (key
&& key_len
> 0 && key_len
< sizeof(cmd
.key
)) {
214 os_memcpy(cmd
.key
, key
, key_len
);
215 cmd
.key_len
= key_len
;
218 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_KEY
, &cmd
, sizeof(cmd
),
223 static int wpa_driver_privsep_associate(
224 void *priv
, struct wpa_driver_associate_params
*params
)
226 struct wpa_driver_privsep_data
*drv
= priv
;
227 struct privsep_cmd_associate
*data
;
231 wpa_printf(MSG_DEBUG
, "%s: priv=%p freq=%d pairwise_suite=%d "
232 "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
233 __func__
, priv
, params
->freq
.freq
, params
->pairwise_suite
,
234 params
->group_suite
, params
->key_mgmt_suite
,
235 params
->auth_alg
, params
->mode
);
237 buflen
= sizeof(*data
) + params
->wpa_ie_len
;
238 data
= os_zalloc(buflen
);
243 os_memcpy(data
->bssid
, params
->bssid
, ETH_ALEN
);
244 os_memcpy(data
->ssid
, params
->ssid
, params
->ssid_len
);
245 data
->ssid_len
= params
->ssid_len
;
246 data
->hwmode
= params
->freq
.mode
;
247 data
->freq
= params
->freq
.freq
;
248 data
->channel
= params
->freq
.channel
;
249 data
->pairwise_suite
= params
->pairwise_suite
;
250 data
->group_suite
= params
->group_suite
;
251 data
->key_mgmt_suite
= params
->key_mgmt_suite
;
252 data
->auth_alg
= params
->auth_alg
;
253 data
->mode
= params
->mode
;
254 data
->wpa_ie_len
= params
->wpa_ie_len
;
256 os_memcpy(data
+ 1, params
->wpa_ie
, params
->wpa_ie_len
);
257 /* TODO: add support for other assoc parameters */
259 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_ASSOCIATE
, data
, buflen
,
267 static int wpa_driver_privsep_get_bssid(void *priv
, u8
*bssid
)
269 struct wpa_driver_privsep_data
*drv
= priv
;
271 size_t len
= ETH_ALEN
;
273 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_BSSID
, NULL
, 0, bssid
, &len
);
274 if (res
< 0 || len
!= ETH_ALEN
)
280 static int wpa_driver_privsep_get_ssid(void *priv
, u8
*ssid
)
282 struct wpa_driver_privsep_data
*drv
= priv
;
284 u8 reply
[sizeof(int) + SSID_MAX_LEN
];
285 size_t len
= sizeof(reply
);
287 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_SSID
, NULL
, 0, reply
, &len
);
288 if (res
< 0 || len
< sizeof(int))
290 os_memcpy(&ssid_len
, reply
, sizeof(int));
291 if (ssid_len
< 0 || ssid_len
> SSID_MAX_LEN
||
292 sizeof(int) + ssid_len
> len
) {
293 wpa_printf(MSG_DEBUG
, "privsep: Invalid get SSID reply");
296 os_memcpy(ssid
, &reply
[sizeof(int)], ssid_len
);
301 static int wpa_driver_privsep_deauthenticate(void *priv
, const u8
*addr
,
304 //struct wpa_driver_privsep_data *drv = priv;
305 wpa_printf(MSG_DEBUG
, "%s addr=" MACSTR
" reason_code=%d",
306 __func__
, MAC2STR(addr
), reason_code
);
307 wpa_printf(MSG_DEBUG
, "%s - TODO", __func__
);
312 static void wpa_driver_privsep_event_assoc(void *ctx
,
313 enum wpa_event_type event
,
316 union wpa_event_data data
;
321 os_memset(&data
, 0, sizeof(data
));
326 if (end
- pos
< (int) sizeof(int))
328 os_memcpy(&ie_len
, pos
, sizeof(int));
330 if (ie_len
< 0 || ie_len
> end
- pos
)
333 data
.assoc_info
.req_ies
= pos
;
334 data
.assoc_info
.req_ies_len
= ie_len
;
339 wpa_supplicant_event(ctx
, event
, inc_data
? &data
: NULL
);
343 static void wpa_driver_privsep_event_interface_status(void *ctx
, u8
*buf
,
346 union wpa_event_data data
;
349 if (len
< sizeof(int) ||
350 len
- sizeof(int) > sizeof(data
.interface_status
.ifname
))
353 os_memcpy(&ievent
, buf
, sizeof(int));
355 os_memset(&data
, 0, sizeof(data
));
356 data
.interface_status
.ievent
= ievent
;
357 os_memcpy(data
.interface_status
.ifname
, buf
+ sizeof(int),
359 wpa_supplicant_event(ctx
, EVENT_INTERFACE_STATUS
, &data
);
363 static void wpa_driver_privsep_event_michael_mic_failure(
364 void *ctx
, u8
*buf
, size_t len
)
366 union wpa_event_data data
;
368 if (len
!= sizeof(int))
371 os_memset(&data
, 0, sizeof(data
));
372 os_memcpy(&data
.michael_mic_failure
.unicast
, buf
, sizeof(int));
373 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
377 static void wpa_driver_privsep_event_pmkid_candidate(void *ctx
, u8
*buf
,
380 union wpa_event_data data
;
382 if (len
!= sizeof(struct pmkid_candidate
))
385 os_memset(&data
, 0, sizeof(data
));
386 os_memcpy(&data
.pmkid_candidate
, buf
, len
);
387 wpa_supplicant_event(ctx
, EVENT_PMKID_CANDIDATE
, &data
);
391 static void wpa_driver_privsep_event_stkstart(void *ctx
, u8
*buf
, size_t len
)
393 union wpa_event_data data
;
398 os_memset(&data
, 0, sizeof(data
));
399 os_memcpy(data
.stkstart
.peer
, buf
, ETH_ALEN
);
400 wpa_supplicant_event(ctx
, EVENT_STKSTART
, &data
);
404 static void wpa_driver_privsep_event_ft_response(void *ctx
, u8
*buf
,
407 union wpa_event_data data
;
409 if (len
< sizeof(int) + ETH_ALEN
)
412 os_memset(&data
, 0, sizeof(data
));
413 os_memcpy(&data
.ft_ies
.ft_action
, buf
, sizeof(int));
414 os_memcpy(data
.ft_ies
.target_ap
, buf
+ sizeof(int), ETH_ALEN
);
415 data
.ft_ies
.ies
= buf
+ sizeof(int) + ETH_ALEN
;
416 data
.ft_ies
.ies_len
= len
- sizeof(int) - ETH_ALEN
;
417 wpa_supplicant_event(ctx
, EVENT_FT_RESPONSE
, &data
);
421 static void wpa_driver_privsep_event_rx_eapol(void *ctx
, u8
*buf
, size_t len
)
425 drv_event_eapol_rx(ctx
, buf
, buf
+ ETH_ALEN
, len
- ETH_ALEN
);
429 static void wpa_driver_privsep_receive(int sock
, void *eloop_ctx
,
432 struct wpa_driver_privsep_data
*drv
= eloop_ctx
;
436 enum privsep_event e
;
437 struct sockaddr_un from
;
438 socklen_t fromlen
= sizeof(from
);
439 const size_t buflen
= 2000;
441 buf
= os_malloc(buflen
);
444 res
= recvfrom(sock
, buf
, buflen
, 0,
445 (struct sockaddr
*) &from
, &fromlen
);
447 wpa_printf(MSG_ERROR
, "recvfrom(priv_socket): %s",
453 wpa_printf(MSG_DEBUG
, "privsep_driver: received %u bytes", res
);
455 if (res
< (int) sizeof(int)) {
456 wpa_printf(MSG_DEBUG
, "Too short event message (len=%d)", res
);
460 os_memcpy(&event
, buf
, sizeof(int));
461 event_buf
= &buf
[sizeof(int)];
462 event_len
= res
- sizeof(int);
463 wpa_printf(MSG_DEBUG
, "privsep: Event %d received (len=%lu)",
464 event
, (unsigned long) event_len
);
468 case PRIVSEP_EVENT_SCAN_RESULTS
:
469 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_RESULTS
, NULL
);
471 case PRIVSEP_EVENT_ASSOC
:
472 wpa_driver_privsep_event_assoc(drv
->ctx
, EVENT_ASSOC
,
473 event_buf
, event_len
);
475 case PRIVSEP_EVENT_DISASSOC
:
476 wpa_supplicant_event(drv
->ctx
, EVENT_DISASSOC
, NULL
);
478 case PRIVSEP_EVENT_ASSOCINFO
:
479 wpa_driver_privsep_event_assoc(drv
->ctx
, EVENT_ASSOCINFO
,
480 event_buf
, event_len
);
482 case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE
:
483 wpa_driver_privsep_event_michael_mic_failure(
484 drv
->ctx
, event_buf
, event_len
);
486 case PRIVSEP_EVENT_INTERFACE_STATUS
:
487 wpa_driver_privsep_event_interface_status(drv
->ctx
, event_buf
,
490 case PRIVSEP_EVENT_PMKID_CANDIDATE
:
491 wpa_driver_privsep_event_pmkid_candidate(drv
->ctx
, event_buf
,
494 case PRIVSEP_EVENT_STKSTART
:
495 wpa_driver_privsep_event_stkstart(drv
->ctx
, event_buf
,
498 case PRIVSEP_EVENT_FT_RESPONSE
:
499 wpa_driver_privsep_event_ft_response(drv
->ctx
, event_buf
,
502 case PRIVSEP_EVENT_RX_EAPOL
:
503 wpa_driver_privsep_event_rx_eapol(drv
->ctx
, event_buf
,
512 static void * wpa_driver_privsep_init(void *ctx
, const char *ifname
)
514 struct wpa_driver_privsep_data
*drv
;
516 drv
= os_zalloc(sizeof(*drv
));
520 drv
->priv_socket
= -1;
521 drv
->cmd_socket
= -1;
522 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
528 static void wpa_driver_privsep_deinit(void *priv
)
530 struct wpa_driver_privsep_data
*drv
= priv
;
532 if (drv
->priv_socket
>= 0) {
533 wpa_priv_reg_cmd(drv
, PRIVSEP_CMD_UNREGISTER
);
534 eloop_unregister_read_sock(drv
->priv_socket
);
535 close(drv
->priv_socket
);
538 if (drv
->own_socket_path
) {
539 unlink(drv
->own_socket_path
);
540 os_free(drv
->own_socket_path
);
543 if (drv
->cmd_socket
>= 0) {
544 eloop_unregister_read_sock(drv
->cmd_socket
);
545 close(drv
->cmd_socket
);
548 if (drv
->own_cmd_path
) {
549 unlink(drv
->own_cmd_path
);
550 os_free(drv
->own_cmd_path
);
557 static int wpa_driver_privsep_set_param(void *priv
, const char *param
)
559 struct wpa_driver_privsep_data
*drv
= priv
;
561 char *own_dir
, *priv_dir
;
562 static unsigned int counter
= 0;
564 struct sockaddr_un addr
;
566 wpa_printf(MSG_DEBUG
, "%s: param='%s'", __func__
, param
);
570 pos
= os_strstr(param
, "own_dir=");
573 own_dir
= os_strdup(pos
+ 8);
576 end
= os_strchr(own_dir
, ' ');
580 own_dir
= os_strdup("/tmp");
588 pos
= os_strstr(param
, "priv_dir=");
591 priv_dir
= os_strdup(pos
+ 9);
592 if (priv_dir
== NULL
) {
596 end
= os_strchr(priv_dir
, ' ');
600 priv_dir
= os_strdup("/var/run/wpa_priv");
601 if (priv_dir
== NULL
) {
607 len
= os_strlen(own_dir
) + 50;
608 drv
->own_socket_path
= os_malloc(len
);
609 if (drv
->own_socket_path
== NULL
) {
614 os_snprintf(drv
->own_socket_path
, len
, "%s/wpa_privsep-%d-%d",
615 own_dir
, getpid(), counter
++);
617 len
= os_strlen(own_dir
) + 50;
618 drv
->own_cmd_path
= os_malloc(len
);
619 if (drv
->own_cmd_path
== NULL
) {
620 os_free(drv
->own_socket_path
);
621 drv
->own_socket_path
= NULL
;
626 os_snprintf(drv
->own_cmd_path
, len
, "%s/wpa_privsep-%d-%d",
627 own_dir
, getpid(), counter
++);
631 drv
->priv_addr
.sun_family
= AF_UNIX
;
632 os_snprintf(drv
->priv_addr
.sun_path
, sizeof(drv
->priv_addr
.sun_path
),
633 "%s/%s", priv_dir
, drv
->ifname
);
636 drv
->priv_socket
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
637 if (drv
->priv_socket
< 0) {
638 wpa_printf(MSG_ERROR
, "socket(PF_UNIX): %s", strerror(errno
));
639 os_free(drv
->own_socket_path
);
640 drv
->own_socket_path
= NULL
;
644 os_memset(&addr
, 0, sizeof(addr
));
645 addr
.sun_family
= AF_UNIX
;
646 os_strlcpy(addr
.sun_path
, drv
->own_socket_path
, sizeof(addr
.sun_path
));
647 if (bind(drv
->priv_socket
, (struct sockaddr
*) &addr
, sizeof(addr
)) <
649 wpa_printf(MSG_ERROR
,
650 "privsep-set-params priv-sock: bind(PF_UNIX): %s",
652 close(drv
->priv_socket
);
653 drv
->priv_socket
= -1;
654 unlink(drv
->own_socket_path
);
655 os_free(drv
->own_socket_path
);
656 drv
->own_socket_path
= NULL
;
660 eloop_register_read_sock(drv
->priv_socket
, wpa_driver_privsep_receive
,
663 drv
->cmd_socket
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
664 if (drv
->cmd_socket
< 0) {
665 wpa_printf(MSG_ERROR
, "socket(PF_UNIX): %s", strerror(errno
));
666 os_free(drv
->own_cmd_path
);
667 drv
->own_cmd_path
= NULL
;
671 os_memset(&addr
, 0, sizeof(addr
));
672 addr
.sun_family
= AF_UNIX
;
673 os_strlcpy(addr
.sun_path
, drv
->own_cmd_path
, sizeof(addr
.sun_path
));
674 if (bind(drv
->cmd_socket
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
676 wpa_printf(MSG_ERROR
,
677 "privsep-set-params cmd-sock: bind(PF_UNIX): %s",
679 close(drv
->cmd_socket
);
680 drv
->cmd_socket
= -1;
681 unlink(drv
->own_cmd_path
);
682 os_free(drv
->own_cmd_path
);
683 drv
->own_cmd_path
= NULL
;
687 if (wpa_priv_reg_cmd(drv
, PRIVSEP_CMD_REGISTER
) < 0) {
688 wpa_printf(MSG_ERROR
, "Failed to register with wpa_priv");
696 static int wpa_driver_privsep_get_capa(void *priv
,
697 struct wpa_driver_capa
*capa
)
699 struct wpa_driver_privsep_data
*drv
= priv
;
701 size_t len
= sizeof(*capa
);
703 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_CAPA
, NULL
, 0, capa
, &len
);
704 if (res
< 0 || len
!= sizeof(*capa
))
706 /* For now, no support for passing extended_capa pointers */
707 capa
->extended_capa
= NULL
;
708 capa
->extended_capa_mask
= NULL
;
709 capa
->extended_capa_len
= 0;
714 static const u8
* wpa_driver_privsep_get_mac_addr(void *priv
)
716 struct wpa_driver_privsep_data
*drv
= priv
;
717 wpa_printf(MSG_DEBUG
, "%s", __func__
);
718 return drv
->own_addr
;
722 static int wpa_driver_privsep_set_country(void *priv
, const char *alpha2
)
724 struct wpa_driver_privsep_data
*drv
= priv
;
725 wpa_printf(MSG_DEBUG
, "%s country='%s'", __func__
, alpha2
);
726 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_COUNTRY
, alpha2
,
727 os_strlen(alpha2
), NULL
, NULL
);
731 struct wpa_driver_ops wpa_driver_privsep_ops
= {
733 "wpa_supplicant privilege separated driver",
734 .get_bssid
= wpa_driver_privsep_get_bssid
,
735 .get_ssid
= wpa_driver_privsep_get_ssid
,
736 .set_key
= wpa_driver_privsep_set_key
,
737 .init
= wpa_driver_privsep_init
,
738 .deinit
= wpa_driver_privsep_deinit
,
739 .set_param
= wpa_driver_privsep_set_param
,
740 .scan2
= wpa_driver_privsep_scan
,
741 .deauthenticate
= wpa_driver_privsep_deauthenticate
,
742 .associate
= wpa_driver_privsep_associate
,
743 .get_capa
= wpa_driver_privsep_get_capa
,
744 .get_mac_addr
= wpa_driver_privsep_get_mac_addr
,
745 .get_scan_results2
= wpa_driver_privsep_get_scan_results2
,
746 .set_country
= wpa_driver_privsep_set_country
,
750 const struct wpa_driver_ops
*const wpa_drivers
[] =
752 &wpa_driver_privsep_ops
,