hostapd/src/drivers/driver_privsep.c
Jouni Malinen 5bad300565 privsep: Mask out control port capability flag
There is no support for using the control port for sending out EAPOL
frames through privsep yet, so mask out this capability to fall back to
the l2_packet based design.

Signed-off-by: Jouni Malinen <j@w1.fi>
2020-03-01 21:31:07 +02:00

847 lines
21 KiB
C

/*
* WPA Supplicant - privilege separated driver interface
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <sys/un.h>
#include "common.h"
#include "driver.h"
#include "eloop.h"
#include "common/privsep_commands.h"
struct wpa_driver_privsep_data {
void *ctx;
u8 own_addr[ETH_ALEN];
int priv_socket;
char *own_socket_path;
int cmd_socket;
char *own_cmd_path;
struct sockaddr_un priv_addr;
char ifname[16];
};
static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
{
int res;
res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
(struct sockaddr *) &drv->priv_addr,
sizeof(drv->priv_addr));
if (res < 0)
wpa_printf(MSG_ERROR, "sendto: %s", strerror(errno));
return res < 0 ? -1 : 0;
}
static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
const void *data, size_t data_len,
void *reply, size_t *reply_len)
{
struct msghdr msg;
struct iovec io[2];
io[0].iov_base = &cmd;
io[0].iov_len = sizeof(cmd);
io[1].iov_base = (u8 *) data;
io[1].iov_len = data_len;
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
msg.msg_iovlen = data ? 2 : 1;
msg.msg_name = &drv->priv_addr;
msg.msg_namelen = sizeof(drv->priv_addr);
if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(cmd_socket): %s",
strerror(errno));
return -1;
}
if (reply) {
fd_set rfds;
struct timeval tv;
int res;
FD_ZERO(&rfds);
FD_SET(drv->cmd_socket, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
return -1;
}
if (FD_ISSET(drv->cmd_socket, &rfds)) {
res = recv(drv->cmd_socket, reply, *reply_len, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "recv: %s",
strerror(errno));
return -1;
}
*reply_len = res;
} else {
wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
"for reply (cmd=%d)", cmd);
return -1;
}
}
return 0;
}
static int wpa_driver_privsep_scan(void *priv,
struct wpa_driver_scan_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_scan scan;
size_t i;
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
os_memset(&scan, 0, sizeof(scan));
scan.num_ssids = params->num_ssids;
for (i = 0; i < params->num_ssids; i++) {
if (!params->ssids[i].ssid)
continue;
scan.ssid_lens[i] = params->ssids[i].ssid_len;
os_memcpy(scan.ssids[i], params->ssids[i].ssid,
scan.ssid_lens[i]);
}
for (i = 0; i < PRIVSEP_MAX_SCAN_FREQS &&
params->freqs && params->freqs[i]; i++)
scan.freqs[i] = params->freqs[i];
scan.num_freqs = i;
return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, &scan, sizeof(scan),
NULL, NULL);
}
static struct wpa_scan_results *
wpa_driver_privsep_get_scan_results2(void *priv)
{
struct wpa_driver_privsep_data *drv = priv;
int res, num;
u8 *buf, *pos, *end;
size_t reply_len = 60000;
struct wpa_scan_results *results;
struct wpa_scan_res *r;
buf = os_malloc(reply_len);
if (buf == NULL)
return NULL;
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
NULL, 0, buf, &reply_len);
if (res < 0) {
os_free(buf);
return NULL;
}
wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
(unsigned long) reply_len);
if (reply_len < sizeof(int)) {
wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
(unsigned long) reply_len);
os_free(buf);
return NULL;
}
pos = buf;
end = buf + reply_len;
os_memcpy(&num, pos, sizeof(int));
if (num < 0 || num > 1000) {
os_free(buf);
return NULL;
}
pos += sizeof(int);
results = os_zalloc(sizeof(*results));
if (results == NULL) {
os_free(buf);
return NULL;
}
results->res = os_calloc(num, sizeof(struct wpa_scan_res *));
if (results->res == NULL) {
os_free(results);
os_free(buf);
return NULL;
}
while (results->num < (size_t) num && end - pos > (int) sizeof(int)) {
int len;
os_memcpy(&len, pos, sizeof(int));
pos += sizeof(int);
if (len < 0 || len > 10000 || len > end - pos)
break;
r = os_memdup(pos, len);
if (r == NULL)
break;
pos += len;
if (sizeof(*r) + r->ie_len + r->beacon_ie_len > (size_t) len) {
wpa_printf(MSG_ERROR,
"privsep: Invalid scan result len (%d + %d + %d > %d)",
(int) sizeof(*r), (int) r->ie_len,
(int) r->beacon_ie_len, len);
os_free(r);
break;
}
results->res[results->num++] = r;
}
os_free(buf);
return results;
}
static int wpa_driver_privsep_set_key(void *priv,
struct wpa_driver_set_key_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_set_key cmd;
enum wpa_alg alg = params->alg;
const u8 *addr = params->addr;
int key_idx = params->key_idx;
int set_tx = params->set_tx;
const u8 *seq = params->seq;
size_t seq_len = params->seq_len;
const u8 *key = params->key;
size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
__func__, priv, alg, key_idx, set_tx);
os_memset(&cmd, 0, sizeof(cmd));
cmd.alg = alg;
if (addr)
os_memcpy(cmd.addr, addr, ETH_ALEN);
else
os_memset(cmd.addr, 0xff, ETH_ALEN);
cmd.key_idx = key_idx;
cmd.set_tx = set_tx;
cmd.key_flag = params->key_flag;
if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
os_memcpy(cmd.seq, seq, seq_len);
cmd.seq_len = seq_len;
}
if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
os_memcpy(cmd.key, key, key_len);
cmd.key_len = key_len;
}
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
NULL, NULL);
}
static int wpa_driver_privsep_authenticate(
void *priv, struct wpa_driver_auth_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_authenticate *data;
int i, res;
size_t buflen;
u8 *pos;
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d bssid=" MACSTR
" auth_alg=%d local_state_change=%d p2p=%d",
__func__, priv, params->freq, MAC2STR(params->bssid),
params->auth_alg, params->local_state_change, params->p2p);
buflen = sizeof(*data) + params->ie_len + params->auth_data_len;
data = os_zalloc(buflen);
if (data == NULL)
return -1;
data->freq = params->freq;
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
os_memcpy(data->ssid, params->ssid, params->ssid_len);
data->ssid_len = params->ssid_len;
data->auth_alg = params->auth_alg;
data->ie_len = params->ie_len;
for (i = 0; i < 4; i++) {
if (params->wep_key[i])
os_memcpy(data->wep_key[i], params->wep_key[i],
params->wep_key_len[i]);
data->wep_key_len[i] = params->wep_key_len[i];
}
data->wep_tx_keyidx = params->wep_tx_keyidx;
data->local_state_change = params->local_state_change;
data->p2p = params->p2p;
pos = (u8 *) (data + 1);
if (params->ie_len) {
os_memcpy(pos, params->ie, params->ie_len);
pos += params->ie_len;
}
if (params->auth_data_len)
os_memcpy(pos, params->auth_data, params->auth_data_len);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen,
NULL, NULL);
os_free(data);
return res;
}
static int wpa_driver_privsep_associate(
void *priv, struct wpa_driver_associate_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_associate *data;
int res;
size_t buflen;
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
__func__, priv, params->freq.freq, params->pairwise_suite,
params->group_suite, params->key_mgmt_suite,
params->auth_alg, params->mode);
buflen = sizeof(*data) + params->wpa_ie_len;
data = os_zalloc(buflen);
if (data == NULL)
return -1;
if (params->bssid)
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
os_memcpy(data->ssid, params->ssid, params->ssid_len);
data->ssid_len = params->ssid_len;
data->hwmode = params->freq.mode;
data->freq = params->freq.freq;
data->channel = params->freq.channel;
data->pairwise_suite = params->pairwise_suite;
data->group_suite = params->group_suite;
data->key_mgmt_suite = params->key_mgmt_suite;
data->auth_alg = params->auth_alg;
data->mode = params->mode;
data->wpa_ie_len = params->wpa_ie_len;
if (params->wpa_ie)
os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
/* TODO: add support for other assoc parameters */
res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
NULL, NULL);
os_free(data);
return res;
}
static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
{
struct wpa_driver_privsep_data *drv = priv;
int res;
size_t len = ETH_ALEN;
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
if (res < 0 || len != ETH_ALEN)
return -1;
return 0;
}
static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
{
struct wpa_driver_privsep_data *drv = priv;
int res, ssid_len;
u8 reply[sizeof(int) + SSID_MAX_LEN];
size_t len = sizeof(reply);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
if (res < 0 || len < sizeof(int))
return -1;
os_memcpy(&ssid_len, reply, sizeof(int));
if (ssid_len < 0 || ssid_len > SSID_MAX_LEN ||
sizeof(int) + ssid_len > len) {
wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
return -1;
}
os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
return ssid_len;
}
static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
u16 reason_code)
{
//struct wpa_driver_privsep_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
__func__, MAC2STR(addr), reason_code);
wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
return 0;
}
static void wpa_driver_privsep_event_auth(void *ctx, u8 *buf, size_t len)
{
union wpa_event_data data;
struct privsep_event_auth *auth;
os_memset(&data, 0, sizeof(data));
if (len < sizeof(*auth))
return;
auth = (struct privsep_event_auth *) buf;
if (len < sizeof(*auth) + auth->ies_len)
return;
os_memcpy(data.auth.peer, auth->peer, ETH_ALEN);
os_memcpy(data.auth.bssid, auth->bssid, ETH_ALEN);
data.auth.auth_type = auth->auth_type;
data.auth.auth_transaction = auth->auth_transaction;
data.auth.status_code = auth->status_code;
if (auth->ies_len) {
data.auth.ies = (u8 *) (auth + 1);
data.auth.ies_len = auth->ies_len;
}
wpa_supplicant_event(ctx, EVENT_AUTH, &data);
}
static void wpa_driver_privsep_event_assoc(void *ctx,
enum wpa_event_type event,
u8 *buf, size_t len)
{
union wpa_event_data data;
int inc_data = 0;
u8 *pos, *end;
int ie_len;
os_memset(&data, 0, sizeof(data));
pos = buf;
end = buf + len;
if (end - pos < (int) sizeof(int))
return;
os_memcpy(&ie_len, pos, sizeof(int));
pos += sizeof(int);
if (ie_len < 0 || ie_len > end - pos)
return;
if (ie_len) {
data.assoc_info.req_ies = pos;
data.assoc_info.req_ies_len = ie_len;
pos += ie_len;
inc_data = 1;
}
wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
}
static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
size_t len)
{
union wpa_event_data data;
int ievent;
if (len < sizeof(int) ||
len - sizeof(int) > sizeof(data.interface_status.ifname))
return;
os_memcpy(&ievent, buf, sizeof(int));
os_memset(&data, 0, sizeof(data));
data.interface_status.ievent = ievent;
os_memcpy(data.interface_status.ifname, buf + sizeof(int),
len - sizeof(int));
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
}
static void wpa_driver_privsep_event_michael_mic_failure(
void *ctx, u8 *buf, size_t len)
{
union wpa_event_data data;
if (len != sizeof(int))
return;
os_memset(&data, 0, sizeof(data));
os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
}
static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
size_t len)
{
union wpa_event_data data;
if (len != sizeof(struct pmkid_candidate))
return;
os_memset(&data, 0, sizeof(data));
os_memcpy(&data.pmkid_candidate, buf, len);
wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
}
static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
size_t len)
{
union wpa_event_data data;
if (len < sizeof(int) + ETH_ALEN)
return;
os_memset(&data, 0, sizeof(data));
os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
}
static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
{
if (len < ETH_ALEN)
return;
drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
}
static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct wpa_driver_privsep_data *drv = eloop_ctx;
u8 *buf, *event_buf;
size_t event_len;
int res, event;
enum privsep_event e;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
const size_t buflen = 2000;
buf = os_malloc(buflen);
if (buf == NULL)
return;
res = recvfrom(sock, buf, buflen, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(priv_socket): %s",
strerror(errno));
os_free(buf);
return;
}
wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
if (res < (int) sizeof(int)) {
wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
return;
}
os_memcpy(&event, buf, sizeof(int));
event_buf = &buf[sizeof(int)];
event_len = res - sizeof(int);
wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
event, (unsigned long) event_len);
e = event;
switch (e) {
case PRIVSEP_EVENT_SCAN_RESULTS:
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
break;
case PRIVSEP_EVENT_SCAN_STARTED:
wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
break;
case PRIVSEP_EVENT_ASSOC:
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
event_buf, event_len);
break;
case PRIVSEP_EVENT_DISASSOC:
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
break;
case PRIVSEP_EVENT_ASSOCINFO:
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
event_buf, event_len);
break;
case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
wpa_driver_privsep_event_michael_mic_failure(
drv->ctx, event_buf, event_len);
break;
case PRIVSEP_EVENT_INTERFACE_STATUS:
wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
event_len);
break;
case PRIVSEP_EVENT_PMKID_CANDIDATE:
wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
event_len);
break;
case PRIVSEP_EVENT_FT_RESPONSE:
wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
event_len);
break;
case PRIVSEP_EVENT_RX_EAPOL:
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
event_len);
break;
case PRIVSEP_EVENT_AUTH:
wpa_driver_privsep_event_auth(drv->ctx, event_buf, event_len);
break;
}
os_free(buf);
}
static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
{
struct wpa_driver_privsep_data *drv;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
drv->ctx = ctx;
drv->priv_socket = -1;
drv->cmd_socket = -1;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
return drv;
}
static void wpa_driver_privsep_deinit(void *priv)
{
struct wpa_driver_privsep_data *drv = priv;
if (drv->priv_socket >= 0) {
wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
eloop_unregister_read_sock(drv->priv_socket);
close(drv->priv_socket);
}
if (drv->own_socket_path) {
unlink(drv->own_socket_path);
os_free(drv->own_socket_path);
}
if (drv->cmd_socket >= 0) {
eloop_unregister_read_sock(drv->cmd_socket);
close(drv->cmd_socket);
}
if (drv->own_cmd_path) {
unlink(drv->own_cmd_path);
os_free(drv->own_cmd_path);
}
os_free(drv);
}
static int wpa_driver_privsep_set_param(void *priv, const char *param)
{
struct wpa_driver_privsep_data *drv = priv;
const char *pos;
char *own_dir, *priv_dir;
static unsigned int counter = 0;
size_t len;
struct sockaddr_un addr;
wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
if (param == NULL)
pos = NULL;
else
pos = os_strstr(param, "own_dir=");
if (pos) {
char *end;
own_dir = os_strdup(pos + 8);
if (own_dir == NULL)
return -1;
end = os_strchr(own_dir, ' ');
if (end)
*end = '\0';
} else {
own_dir = os_strdup("/tmp");
if (own_dir == NULL)
return -1;
}
if (param == NULL)
pos = NULL;
else
pos = os_strstr(param, "priv_dir=");
if (pos) {
char *end;
priv_dir = os_strdup(pos + 9);
if (priv_dir == NULL) {
os_free(own_dir);
return -1;
}
end = os_strchr(priv_dir, ' ');
if (end)
*end = '\0';
} else {
priv_dir = os_strdup("/var/run/wpa_priv");
if (priv_dir == NULL) {
os_free(own_dir);
return -1;
}
}
len = os_strlen(own_dir) + 50;
drv->own_socket_path = os_malloc(len);
if (drv->own_socket_path == NULL) {
os_free(priv_dir);
os_free(own_dir);
return -1;
}
os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
own_dir, getpid(), counter++);
len = os_strlen(own_dir) + 50;
drv->own_cmd_path = os_malloc(len);
if (drv->own_cmd_path == NULL) {
os_free(drv->own_socket_path);
drv->own_socket_path = NULL;
os_free(priv_dir);
os_free(own_dir);
return -1;
}
os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
own_dir, getpid(), counter++);
os_free(own_dir);
drv->priv_addr.sun_family = AF_UNIX;
os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
"%s/%s", priv_dir, drv->ifname);
os_free(priv_dir);
drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->priv_socket < 0) {
wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_socket_path);
drv->own_socket_path = NULL;
return -1;
}
os_memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
wpa_printf(MSG_ERROR,
"privsep-set-params priv-sock: bind(PF_UNIX): %s",
strerror(errno));
close(drv->priv_socket);
drv->priv_socket = -1;
unlink(drv->own_socket_path);
os_free(drv->own_socket_path);
drv->own_socket_path = NULL;
return -1;
}
eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
drv, NULL);
drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->cmd_socket < 0) {
wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_cmd_path);
drv->own_cmd_path = NULL;
return -1;
}
os_memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
wpa_printf(MSG_ERROR,
"privsep-set-params cmd-sock: bind(PF_UNIX): %s",
strerror(errno));
close(drv->cmd_socket);
drv->cmd_socket = -1;
unlink(drv->own_cmd_path);
os_free(drv->own_cmd_path);
drv->own_cmd_path = NULL;
return -1;
}
if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
return -1;
}
return 0;
}
static int wpa_driver_privsep_get_capa(void *priv,
struct wpa_driver_capa *capa)
{
struct wpa_driver_privsep_data *drv = priv;
int res;
size_t len = sizeof(*capa);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
if (res < 0 || len != sizeof(*capa))
return -1;
/* For now, no support for passing extended_capa pointers */
capa->extended_capa = NULL;
capa->extended_capa_mask = NULL;
capa->extended_capa_len = 0;
/* Control port is not yet supported */
capa->flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
return 0;
}
static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
{
struct wpa_driver_privsep_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s", __func__);
return drv->own_addr;
}
static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
{
struct wpa_driver_privsep_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
os_strlen(alpha2), NULL, NULL);
}
struct wpa_driver_ops wpa_driver_privsep_ops = {
"privsep",
"wpa_supplicant privilege separated driver",
.get_bssid = wpa_driver_privsep_get_bssid,
.get_ssid = wpa_driver_privsep_get_ssid,
.set_key = wpa_driver_privsep_set_key,
.init = wpa_driver_privsep_init,
.deinit = wpa_driver_privsep_deinit,
.set_param = wpa_driver_privsep_set_param,
.scan2 = wpa_driver_privsep_scan,
.deauthenticate = wpa_driver_privsep_deauthenticate,
.authenticate = wpa_driver_privsep_authenticate,
.associate = wpa_driver_privsep_associate,
.get_capa = wpa_driver_privsep_get_capa,
.get_mac_addr = wpa_driver_privsep_get_mac_addr,
.get_scan_results2 = wpa_driver_privsep_get_scan_results2,
.set_country = wpa_driver_privsep_set_country,
};
const struct wpa_driver_ops *const wpa_drivers[] =
{
&wpa_driver_privsep_ops,
NULL
};