2 * WPA Supplicant - privilege separated driver interface
3 * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
21 #include "privsep_commands.h"
24 struct wpa_driver_privsep_data
{
26 u8 own_addr
[ETH_ALEN
];
28 char *own_socket_path
;
31 struct sockaddr_un priv_addr
;
36 static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data
*drv
, int cmd
)
40 res
= sendto(drv
->priv_socket
, &cmd
, sizeof(cmd
), 0,
41 (struct sockaddr
*) &drv
->priv_addr
,
42 sizeof(drv
->priv_addr
));
45 return res
< 0 ? -1 : 0;
49 static int wpa_priv_cmd(struct wpa_driver_privsep_data
*drv
, int cmd
,
50 const void *data
, size_t data_len
,
51 void *reply
, size_t *reply_len
)
56 io
[0].iov_base
= &cmd
;
57 io
[0].iov_len
= sizeof(cmd
);
58 io
[1].iov_base
= (u8
*) data
;
59 io
[1].iov_len
= data_len
;
61 os_memset(&msg
, 0, sizeof(msg
));
63 msg
.msg_iovlen
= data
? 2 : 1;
64 msg
.msg_name
= &drv
->priv_addr
;
65 msg
.msg_namelen
= sizeof(drv
->priv_addr
);
67 if (sendmsg(drv
->cmd_socket
, &msg
, 0) < 0) {
68 perror("sendmsg(cmd_socket)");
78 FD_SET(drv
->cmd_socket
, &rfds
);
81 res
= select(drv
->cmd_socket
+ 1, &rfds
, NULL
, NULL
, &tv
);
82 if (res
< 0 && errno
!= EINTR
) {
87 if (FD_ISSET(drv
->cmd_socket
, &rfds
)) {
88 res
= recv(drv
->cmd_socket
, reply
, *reply_len
, 0);
95 wpa_printf(MSG_DEBUG
, "PRIVSEP: Timeout while waiting "
96 "for reply (cmd=%d)", cmd
);
105 static int wpa_driver_privsep_set_wpa(void *priv
, int enabled
)
107 struct wpa_driver_privsep_data
*drv
= priv
;
108 wpa_printf(MSG_DEBUG
, "%s: enabled=%d", __func__
, enabled
);
109 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_WPA
, &enabled
,
110 sizeof(enabled
), NULL
, NULL
);
114 static int wpa_driver_privsep_scan(void *priv
, const u8
*ssid
, size_t ssid_len
)
116 struct wpa_driver_privsep_data
*drv
= priv
;
117 wpa_printf(MSG_DEBUG
, "%s: priv=%p", __func__
, priv
);
118 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SCAN
, ssid
, ssid_len
,
123 static struct wpa_scan_results
*
124 wpa_driver_privsep_get_scan_results2(void *priv
)
126 struct wpa_driver_privsep_data
*drv
= priv
;
129 size_t reply_len
= 60000;
130 struct wpa_scan_results
*results
;
131 struct wpa_scan_res
*r
;
133 buf
= os_malloc(reply_len
);
136 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_SCAN_RESULTS
,
137 NULL
, 0, buf
, &reply_len
);
143 wpa_printf(MSG_DEBUG
, "privsep: Received %lu bytes of scan results",
144 (unsigned long) reply_len
);
145 if (reply_len
< sizeof(int)) {
146 wpa_printf(MSG_DEBUG
, "privsep: Invalid scan result len %lu",
147 (unsigned long) reply_len
);
153 end
= buf
+ reply_len
;
154 os_memcpy(&num
, pos
, sizeof(int));
155 if (num
< 0 || num
> 1000) {
161 results
= os_zalloc(sizeof(*results
));
162 if (results
== NULL
) {
167 results
->res
= os_zalloc(num
* sizeof(struct wpa_scan_res
*));
168 if (results
->res
== NULL
) {
174 while (results
->num
< (size_t) num
&& pos
+ sizeof(int) < end
) {
176 os_memcpy(&len
, pos
, sizeof(int));
178 if (len
< 0 || len
> 10000 || pos
+ len
> end
)
184 os_memcpy(r
, pos
, len
);
186 if (sizeof(*r
) + r
->ie_len
> (size_t) len
) {
191 results
->res
[results
->num
++] = r
;
199 static int wpa_driver_privsep_set_key(void *priv
, wpa_alg alg
, const u8
*addr
,
200 int key_idx
, int set_tx
,
201 const u8
*seq
, size_t seq_len
,
202 const u8
*key
, size_t key_len
)
204 struct wpa_driver_privsep_data
*drv
= priv
;
205 struct privsep_cmd_set_key cmd
;
207 wpa_printf(MSG_DEBUG
, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
208 __func__
, priv
, alg
, key_idx
, set_tx
);
210 os_memset(&cmd
, 0, sizeof(cmd
));
213 os_memcpy(cmd
.addr
, addr
, ETH_ALEN
);
215 os_memset(cmd
.addr
, 0xff, ETH_ALEN
);
216 cmd
.key_idx
= key_idx
;
218 if (seq
&& seq_len
> 0 && seq_len
< sizeof(cmd
.seq
)) {
219 os_memcpy(cmd
.seq
, seq
, seq_len
);
220 cmd
.seq_len
= seq_len
;
222 if (key
&& key_len
> 0 && key_len
< sizeof(cmd
.key
)) {
223 os_memcpy(cmd
.key
, key
, key_len
);
224 cmd
.key_len
= key_len
;
227 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_KEY
, &cmd
, sizeof(cmd
),
232 static int wpa_driver_privsep_associate(
233 void *priv
, struct wpa_driver_associate_params
*params
)
235 struct wpa_driver_privsep_data
*drv
= priv
;
236 struct privsep_cmd_associate
*data
;
240 wpa_printf(MSG_DEBUG
, "%s: priv=%p freq=%d pairwise_suite=%d "
241 "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
242 __func__
, priv
, params
->freq
, params
->pairwise_suite
,
243 params
->group_suite
, params
->key_mgmt_suite
,
244 params
->auth_alg
, params
->mode
);
246 buflen
= sizeof(*data
) + params
->wpa_ie_len
;
247 data
= os_zalloc(buflen
);
252 os_memcpy(data
->bssid
, params
->bssid
, ETH_ALEN
);
253 os_memcpy(data
->ssid
, params
->ssid
, params
->ssid_len
);
254 data
->ssid_len
= params
->ssid_len
;
255 data
->freq
= params
->freq
;
256 data
->pairwise_suite
= params
->pairwise_suite
;
257 data
->group_suite
= params
->group_suite
;
258 data
->key_mgmt_suite
= params
->key_mgmt_suite
;
259 data
->auth_alg
= params
->auth_alg
;
260 data
->mode
= params
->mode
;
261 data
->wpa_ie_len
= params
->wpa_ie_len
;
263 os_memcpy(data
+ 1, params
->wpa_ie
, params
->wpa_ie_len
);
264 /* TODO: add support for other assoc parameters */
266 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_ASSOCIATE
, data
, buflen
,
274 static int wpa_driver_privsep_get_bssid(void *priv
, u8
*bssid
)
276 struct wpa_driver_privsep_data
*drv
= priv
;
278 size_t len
= ETH_ALEN
;
280 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_BSSID
, NULL
, 0, bssid
, &len
);
281 if (res
< 0 || len
!= ETH_ALEN
)
287 static int wpa_driver_privsep_get_ssid(void *priv
, u8
*ssid
)
289 struct wpa_driver_privsep_data
*drv
= priv
;
291 u8 reply
[sizeof(int) + 32];
292 size_t len
= sizeof(reply
);
294 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_SSID
, NULL
, 0, reply
, &len
);
295 if (res
< 0 || len
< sizeof(int))
297 os_memcpy(&ssid_len
, reply
, sizeof(int));
298 if (ssid_len
< 0 || ssid_len
> 32 || sizeof(int) + ssid_len
> len
) {
299 wpa_printf(MSG_DEBUG
, "privsep: Invalid get SSID reply");
302 os_memcpy(ssid
, &reply
[sizeof(int)], ssid_len
);
307 static int wpa_driver_privsep_deauthenticate(void *priv
, const u8
*addr
,
310 //struct wpa_driver_privsep_data *drv = priv;
311 wpa_printf(MSG_DEBUG
, "%s addr=" MACSTR
" reason_code=%d",
312 __func__
, MAC2STR(addr
), reason_code
);
313 wpa_printf(MSG_DEBUG
, "%s - TODO", __func__
);
318 static int wpa_driver_privsep_disassociate(void *priv
, const u8
*addr
,
321 //struct wpa_driver_privsep_data *drv = priv;
322 wpa_printf(MSG_DEBUG
, "%s addr=" MACSTR
" reason_code=%d",
323 __func__
, MAC2STR(addr
), reason_code
);
324 wpa_printf(MSG_DEBUG
, "%s - TODO", __func__
);
329 static void wpa_driver_privsep_event_assoc(void *ctx
, wpa_event_type event
,
332 union wpa_event_data data
;
337 os_memset(&data
, 0, sizeof(data
));
342 if (end
- pos
< (int) sizeof(int))
344 os_memcpy(&ie_len
, pos
, sizeof(int));
346 if (ie_len
< 0 || ie_len
> end
- pos
)
349 data
.assoc_info
.req_ies
= pos
;
350 data
.assoc_info
.req_ies_len
= ie_len
;
355 wpa_supplicant_event(ctx
, event
, inc_data
? &data
: NULL
);
359 static void wpa_driver_privsep_event_interface_status(void *ctx
, u8
*buf
,
362 union wpa_event_data data
;
365 if (len
< sizeof(int) ||
366 len
- sizeof(int) > sizeof(data
.interface_status
.ifname
))
369 os_memcpy(&ievent
, buf
, sizeof(int));
371 os_memset(&data
, 0, sizeof(data
));
372 data
.interface_status
.ievent
= ievent
;
373 os_memcpy(data
.interface_status
.ifname
, buf
+ sizeof(int),
375 wpa_supplicant_event(ctx
, EVENT_INTERFACE_STATUS
, &data
);
379 static void wpa_driver_privsep_event_michael_mic_failure(
380 void *ctx
, u8
*buf
, size_t len
)
382 union wpa_event_data data
;
384 if (len
!= sizeof(int))
387 os_memset(&data
, 0, sizeof(data
));
388 os_memcpy(&data
.michael_mic_failure
.unicast
, buf
, sizeof(int));
389 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
393 static void wpa_driver_privsep_event_pmkid_candidate(void *ctx
, u8
*buf
,
396 union wpa_event_data data
;
398 if (len
!= sizeof(struct pmkid_candidate
))
401 os_memset(&data
, 0, sizeof(data
));
402 os_memcpy(&data
.pmkid_candidate
, buf
, len
);
403 wpa_supplicant_event(ctx
, EVENT_PMKID_CANDIDATE
, &data
);
407 static void wpa_driver_privsep_event_stkstart(void *ctx
, u8
*buf
, size_t len
)
409 union wpa_event_data data
;
414 os_memset(&data
, 0, sizeof(data
));
415 os_memcpy(data
.stkstart
.peer
, buf
, ETH_ALEN
);
416 wpa_supplicant_event(ctx
, EVENT_STKSTART
, &data
);
420 static void wpa_driver_privsep_event_ft_response(void *ctx
, u8
*buf
,
423 union wpa_event_data data
;
425 if (len
< sizeof(int) + ETH_ALEN
)
428 os_memset(&data
, 0, sizeof(data
));
429 os_memcpy(&data
.ft_ies
.ft_action
, buf
, sizeof(int));
430 os_memcpy(data
.ft_ies
.target_ap
, buf
+ sizeof(int), ETH_ALEN
);
431 data
.ft_ies
.ies
= buf
+ sizeof(int) + ETH_ALEN
;
432 data
.ft_ies
.ies_len
= len
- sizeof(int) - ETH_ALEN
;
433 wpa_supplicant_event(ctx
, EVENT_FT_RESPONSE
, &data
);
437 static void wpa_driver_privsep_event_rx_eapol(void *ctx
, u8
*buf
, size_t len
)
442 wpa_supplicant_rx_eapol(ctx
, buf
, buf
+ ETH_ALEN
, len
- ETH_ALEN
);
446 static void wpa_driver_privsep_event_sta_rx(void *ctx
, u8
*buf
, size_t len
)
448 #ifdef CONFIG_CLIENT_MLME
449 struct ieee80211_rx_status
*rx_status
;
451 if (len
< sizeof(*rx_status
))
453 rx_status
= (struct ieee80211_rx_status
*) buf
;
454 buf
+= sizeof(*rx_status
);
455 len
-= sizeof(*rx_status
);
457 wpa_supplicant_sta_rx(ctx
, buf
, len
, rx_status
);
458 #endif /* CONFIG_CLIENT_MLME */
462 static void wpa_driver_privsep_receive(int sock
, void *eloop_ctx
,
465 struct wpa_driver_privsep_data
*drv
= eloop_ctx
;
469 enum privsep_event e
;
470 struct sockaddr_un from
;
471 socklen_t fromlen
= sizeof(from
);
472 const size_t buflen
= 2000;
474 buf
= os_malloc(buflen
);
477 res
= recvfrom(sock
, buf
, buflen
, 0,
478 (struct sockaddr
*) &from
, &fromlen
);
480 perror("recvfrom(priv_socket)");
485 wpa_printf(MSG_DEBUG
, "privsep_driver: received %u bytes", res
);
487 if (res
< (int) sizeof(int)) {
488 wpa_printf(MSG_DEBUG
, "Too short event message (len=%d)", res
);
492 os_memcpy(&event
, buf
, sizeof(int));
493 event_buf
= &buf
[sizeof(int)];
494 event_len
= res
- sizeof(int);
495 wpa_printf(MSG_DEBUG
, "privsep: Event %d received (len=%lu)",
496 event
, (unsigned long) event_len
);
500 case PRIVSEP_EVENT_SCAN_RESULTS
:
501 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_RESULTS
, NULL
);
503 case PRIVSEP_EVENT_ASSOC
:
504 wpa_driver_privsep_event_assoc(drv
->ctx
, EVENT_ASSOC
,
505 event_buf
, event_len
);
507 case PRIVSEP_EVENT_DISASSOC
:
508 wpa_supplicant_event(drv
->ctx
, EVENT_DISASSOC
, NULL
);
510 case PRIVSEP_EVENT_ASSOCINFO
:
511 wpa_driver_privsep_event_assoc(drv
->ctx
, EVENT_ASSOCINFO
,
512 event_buf
, event_len
);
514 case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE
:
515 wpa_driver_privsep_event_michael_mic_failure(
516 drv
->ctx
, event_buf
, event_len
);
518 case PRIVSEP_EVENT_INTERFACE_STATUS
:
519 wpa_driver_privsep_event_interface_status(drv
->ctx
, event_buf
,
522 case PRIVSEP_EVENT_PMKID_CANDIDATE
:
523 wpa_driver_privsep_event_pmkid_candidate(drv
->ctx
, event_buf
,
526 case PRIVSEP_EVENT_STKSTART
:
527 wpa_driver_privsep_event_stkstart(drv
->ctx
, event_buf
,
530 case PRIVSEP_EVENT_FT_RESPONSE
:
531 wpa_driver_privsep_event_ft_response(drv
->ctx
, event_buf
,
534 case PRIVSEP_EVENT_RX_EAPOL
:
535 wpa_driver_privsep_event_rx_eapol(drv
->ctx
, event_buf
,
538 case PRIVSEP_EVENT_STA_RX
:
539 wpa_driver_privsep_event_sta_rx(drv
->ctx
, event_buf
,
548 static void * wpa_driver_privsep_init(void *ctx
, const char *ifname
)
550 struct wpa_driver_privsep_data
*drv
;
552 drv
= os_zalloc(sizeof(*drv
));
556 drv
->priv_socket
= -1;
557 drv
->cmd_socket
= -1;
558 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
564 static void wpa_driver_privsep_deinit(void *priv
)
566 struct wpa_driver_privsep_data
*drv
= priv
;
568 if (drv
->priv_socket
>= 0) {
569 wpa_priv_reg_cmd(drv
, PRIVSEP_CMD_UNREGISTER
);
570 eloop_unregister_read_sock(drv
->priv_socket
);
571 close(drv
->priv_socket
);
574 if (drv
->own_socket_path
) {
575 unlink(drv
->own_socket_path
);
576 os_free(drv
->own_socket_path
);
579 if (drv
->cmd_socket
>= 0) {
580 eloop_unregister_read_sock(drv
->cmd_socket
);
581 close(drv
->cmd_socket
);
584 if (drv
->own_cmd_path
) {
585 unlink(drv
->own_cmd_path
);
586 os_free(drv
->own_cmd_path
);
593 static int wpa_driver_privsep_set_param(void *priv
, const char *param
)
595 struct wpa_driver_privsep_data
*drv
= priv
;
597 char *own_dir
, *priv_dir
;
598 static unsigned int counter
= 0;
600 struct sockaddr_un addr
;
602 wpa_printf(MSG_DEBUG
, "%s: param='%s'", __func__
, param
);
606 pos
= os_strstr(param
, "own_dir=");
609 own_dir
= os_strdup(pos
+ 8);
612 end
= os_strchr(own_dir
, ' ');
616 own_dir
= os_strdup("/tmp");
624 pos
= os_strstr(param
, "priv_dir=");
627 priv_dir
= os_strdup(pos
+ 9);
628 if (priv_dir
== NULL
) {
632 end
= os_strchr(priv_dir
, ' ');
636 priv_dir
= os_strdup("/var/run/wpa_priv");
637 if (priv_dir
== NULL
) {
643 len
= os_strlen(own_dir
) + 50;
644 drv
->own_socket_path
= os_malloc(len
);
645 if (drv
->own_socket_path
== NULL
) {
650 os_snprintf(drv
->own_socket_path
, len
, "%s/wpa_privsep-%d-%d",
651 own_dir
, getpid(), counter
++);
653 len
= os_strlen(own_dir
) + 50;
654 drv
->own_cmd_path
= os_malloc(len
);
655 if (drv
->own_cmd_path
== NULL
) {
656 os_free(drv
->own_socket_path
);
657 drv
->own_socket_path
= NULL
;
662 os_snprintf(drv
->own_cmd_path
, len
, "%s/wpa_privsep-%d-%d",
663 own_dir
, getpid(), counter
++);
667 drv
->priv_addr
.sun_family
= AF_UNIX
;
668 os_snprintf(drv
->priv_addr
.sun_path
, sizeof(drv
->priv_addr
.sun_path
),
669 "%s/%s", priv_dir
, drv
->ifname
);
672 drv
->priv_socket
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
673 if (drv
->priv_socket
< 0) {
674 perror("socket(PF_UNIX)");
675 os_free(drv
->own_socket_path
);
676 drv
->own_socket_path
= NULL
;
680 os_memset(&addr
, 0, sizeof(addr
));
681 addr
.sun_family
= AF_UNIX
;
682 os_strlcpy(addr
.sun_path
, drv
->own_socket_path
, sizeof(addr
.sun_path
));
683 if (bind(drv
->priv_socket
, (struct sockaddr
*) &addr
, sizeof(addr
)) <
685 perror("bind(PF_UNIX)");
686 close(drv
->priv_socket
);
687 drv
->priv_socket
= -1;
688 unlink(drv
->own_socket_path
);
689 os_free(drv
->own_socket_path
);
690 drv
->own_socket_path
= NULL
;
694 eloop_register_read_sock(drv
->priv_socket
, wpa_driver_privsep_receive
,
697 drv
->cmd_socket
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
698 if (drv
->cmd_socket
< 0) {
699 perror("socket(PF_UNIX)");
700 os_free(drv
->own_cmd_path
);
701 drv
->own_cmd_path
= NULL
;
705 os_memset(&addr
, 0, sizeof(addr
));
706 addr
.sun_family
= AF_UNIX
;
707 os_strlcpy(addr
.sun_path
, drv
->own_cmd_path
, sizeof(addr
.sun_path
));
708 if (bind(drv
->cmd_socket
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
710 perror("bind(PF_UNIX)");
711 close(drv
->cmd_socket
);
712 drv
->cmd_socket
= -1;
713 unlink(drv
->own_cmd_path
);
714 os_free(drv
->own_cmd_path
);
715 drv
->own_cmd_path
= NULL
;
719 if (wpa_priv_reg_cmd(drv
, PRIVSEP_CMD_REGISTER
) < 0) {
720 wpa_printf(MSG_ERROR
, "Failed to register with wpa_priv");
728 static int wpa_driver_privsep_get_capa(void *priv
,
729 struct wpa_driver_capa
*capa
)
731 struct wpa_driver_privsep_data
*drv
= priv
;
733 size_t len
= sizeof(*capa
);
735 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_CAPA
, NULL
, 0, capa
, &len
);
736 if (res
< 0 || len
!= sizeof(*capa
))
742 static const u8
* wpa_driver_privsep_get_mac_addr(void *priv
)
744 struct wpa_driver_privsep_data
*drv
= priv
;
745 wpa_printf(MSG_DEBUG
, "%s", __func__
);
746 return drv
->own_addr
;
750 static int wpa_driver_privsep_set_mode(void *priv
, int mode
)
752 struct wpa_driver_privsep_data
*drv
= priv
;
753 wpa_printf(MSG_DEBUG
, "%s mode=%d", __func__
, mode
);
754 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_MODE
, &mode
, sizeof(mode
),
759 static int wpa_driver_privsep_set_country(void *priv
, const char *alpha2
)
761 struct wpa_driver_privsep_data
*drv
= priv
;
762 wpa_printf(MSG_DEBUG
, "%s country='%s'", __func__
, alpha2
);
763 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_COUNTRY
, alpha2
,
764 os_strlen(alpha2
), NULL
, NULL
);
768 struct wpa_driver_ops wpa_driver_privsep_ops
= {
770 "wpa_supplicant privilege separated driver",
771 .get_bssid
= wpa_driver_privsep_get_bssid
,
772 .get_ssid
= wpa_driver_privsep_get_ssid
,
773 .set_wpa
= wpa_driver_privsep_set_wpa
,
774 .set_key
= wpa_driver_privsep_set_key
,
775 .init
= wpa_driver_privsep_init
,
776 .deinit
= wpa_driver_privsep_deinit
,
777 .set_param
= wpa_driver_privsep_set_param
,
778 .scan
= wpa_driver_privsep_scan
,
779 .deauthenticate
= wpa_driver_privsep_deauthenticate
,
780 .disassociate
= wpa_driver_privsep_disassociate
,
781 .associate
= wpa_driver_privsep_associate
,
782 .get_capa
= wpa_driver_privsep_get_capa
,
783 .get_mac_addr
= wpa_driver_privsep_get_mac_addr
,
784 .get_scan_results2
= wpa_driver_privsep_get_scan_results2
,
785 .set_mode
= wpa_driver_privsep_set_mode
,
786 .set_country
= wpa_driver_privsep_set_country
,
790 struct wpa_driver_ops
*wpa_drivers
[] =
792 &wpa_driver_privsep_ops
,