Skip to content

zephyr: Use k_fifo instead of socketpair for IPC #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 42 additions & 26 deletions hostapd/ctrl_iface_zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,67 @@ void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
char buf[MAX_CTRL_MSG_LEN + 1];
char *pos;
int res;
const char *pos;
char *reply = NULL;
int reply_len = 0;
const int reply_size = MAX_CTRL_MSG_LEN;
const int reply_size = MAX_CTRL_MSG_LEN / 2;
zvfs_eventfd_t value;
struct zephyr_msg *msg;

res = recv(sock, buf, MAX_CTRL_MSG_LEN, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
return;
}
zvfs_eventfd_read(sock, &value);

if (!res) {
eloop_unregister_sock(sock, EVENT_TYPE_READ);
wpa_printf(MSG_DEBUG, "ctrl_iface: Peer unexpectedly shut down "
"socket");
msg = k_fifo_get(&hapd->recv_fifo, K_NO_WAIT);
if (msg == NULL) {
wpa_printf(MSG_ERROR, "fifo(ctrl_iface): %s",
"empty");
return;
}

if ((size_t) res > MAX_CTRL_MSG_LEN) {
wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
return;
if (msg->data != NULL) {
pos = msg->data;

if (msg->len > 1 && pos[msg->len - 1] == '\n') {
/* Remove the LF */
msg->data[msg->len - 1] = '\0';
msg->len--;
} else {
msg->data[msg->len] = '\0';
}

} else if (msg->const_data != NULL) {
pos = msg->const_data;
} else {
wpa_printf(MSG_ERROR, "fifo(global_ctrl_iface): %s",
"no data");
goto out;
}
buf[res] = '\0';

pos = buf;
while (*pos == ' ')
while (*pos == ' ') {
pos++;
}

reply = os_malloc(reply_size);
if (reply == NULL) {
send(sock, "FAIL\n", 5, 0);
send_data_const(&hapd->send_fifo, hapd->send_sock, "FAIL\n", 5);
wpa_printf(MSG_ERROR, "hostapd cli malloc fail for reply buffer");
return;
goto out;
}

reply_len = hostapd_ctrl_iface_receive_process(hapd, pos, reply, reply_size, NULL, 0);
reply_len = hostapd_ctrl_iface_receive_process(hapd, (char *)pos, reply,
reply_size, NULL, 0);
if (reply_len > 0) {
send(sock, reply, reply_len, 0);
send_data(&hapd->send_fifo, hapd->send_sock, reply, reply_len, 0);
} else if (reply_len == 0) {
send(sock, "OK\n", 3, 0);
send_data_const(&hapd->send_fifo, hapd->send_sock, "OK\n", 3);
} else if (reply_len < 0) {
send(sock, "FAIL\n", 5, 0);
send_data_const(&hapd->send_fifo, hapd->send_sock, "FAIL\n", 5);
}
os_free(reply);

out:
if (msg->data != NULL) {
os_free(msg->data);
}

os_free(msg);
}
1 change: 1 addition & 0 deletions hostapd/ctrl_iface_zephyr.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "hostapd.h"
#include "ctrl_iface.h"
#include "common/wpa_ctrl.h"
#include "../wpa_supplicant/ctrl_iface_zephyr.h"

#define MAX_CTRL_MSG_LEN 1024

Expand Down
53 changes: 42 additions & 11 deletions hostapd/hostapd_cli_zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
#include "ctrl_iface_zephyr.h"
#include "hostapd_cli_zephyr.h"

#include <zephyr/zvfs/eventfd.h>

#define CMD_BUF_LEN 1024
#define MAX_CMD_SIZE 512
#define MAX_ARGS 32

int hapd_sockpair[2];
struct wpa_ctrl *hapd_ctrl_conn = NULL;
static struct wpa_ctrl *hapd_ctrl_conn = NULL;

static inline uint16_t supp_strlen(const char *str)
{
Expand Down Expand Up @@ -247,10 +248,11 @@ int zephyr_hostapd_cli_cmd_v(const char *fmt, ...)
static int hostapd_cli_open_connection(struct hostapd_data *hapd)
{
if (!hapd_ctrl_conn) {
hapd_ctrl_conn = wpa_ctrl_open(hapd_sockpair[0]);
hapd_ctrl_conn = wpa_ctrl_open(hapd->recv_sock, &hapd->recv_fifo,
hapd->send_sock, &hapd->send_fifo);
if (hapd_ctrl_conn == NULL) {
wpa_printf(MSG_ERROR, "Failed to open control connection to %d",
hapd_sockpair[0]);
hapd->send_sock);
return -1;
}
}
Expand Down Expand Up @@ -279,23 +281,52 @@ int zephyr_hostapd_ctrl_init(void *ctx)
int ret;
struct hostapd_data *hapd = ctx;

memset(hapd_sockpair, -1, sizeof(hapd_sockpair));
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, hapd_sockpair);
if (ret != 0) {
wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
hapd->send_sock = hapd->recv_sock = -1;

ret = zvfs_eventfd(0, 0);
if (ret < 0) {
ret = errno;
wpa_printf(MSG_ERROR, "eventfd: %s (%d)", strerror(ret), ret);
goto fail;
}

hapd->send_sock = ret;

ret = zvfs_eventfd(0, 0);
if (ret < 0) {
ret = errno;
wpa_printf(MSG_ERROR, "eventfd: %s (%d)", strerror(ret), ret);
goto fail;
}

eloop_register_read_sock(hapd_sockpair[1], hostapd_ctrl_iface_receive,
hapd->recv_sock = ret;

k_fifo_init(&hapd->send_fifo);
k_fifo_init(&hapd->recv_fifo);

wpa_printf(MSG_DEBUG, "hapd ctrl_iface: %d %d", hapd->send_sock,
hapd->recv_sock);
wpa_printf(MSG_DEBUG, "hapd ctrl_iface: %p %p", &hapd->recv_fifo,
&hapd->send_fifo);

eloop_register_read_sock(hapd->recv_sock, hostapd_ctrl_iface_receive,
hapd, NULL);

ret = hostapd_cli_open_connection(hapd);
if (ret < 0) {
wpa_printf(MSG_INFO, "Failed to initialize control interface: %s: %d", hapd->conf->iface, ret);
return ret;
wpa_printf(MSG_INFO, "Failed to initialize control interface: %s: %d",
hapd->conf->iface, ret);
goto fail;
}

return 0;

fail:
if (hapd->send_sock >= 0)
close(hapd->send_sock);
if (hapd->recv_sock >= 0)
close(hapd->recv_sock);

return ret;
}

Expand Down
6 changes: 6 additions & 0 deletions src/ap/hostapd.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ struct hostapd_data {
* this should be the first parameter
*/
int is_hostapd;

struct k_fifo send_fifo;
struct k_fifo recv_fifo;

int send_sock;
int recv_sock;
#endif
struct hostapd_iface *iface;
struct hostapd_config *iconf;
Expand Down
148 changes: 143 additions & 5 deletions src/common/wpa_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@
#include <zephyr/net/socket.h>
#endif

#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_ZEPHYR)
#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
#define CTRL_IFACE_SOCKET
#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */

#if defined(CONFIG_CTRL_IFACE_ZEPHYR)
#include "ctrl_iface_zephyr.h"
#define CTRL_IFACE_FIFO
#endif /* CONFIG_CTRL_IFACE_ZEPHYR */

/**
* struct wpa_ctrl - Internal structure for control interface library
Expand Down Expand Up @@ -79,6 +83,9 @@ struct wpa_ctrl {
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
#ifdef CONFIG_CTRL_IFACE_ZEPHYR
int s;
int r; /* socket used to trigger reading */
struct k_fifo *fifo_read;
struct k_fifo *fifo_send;
#endif /* CONFIG_CTRL_IFACE_ZEPHYR */
};

Expand Down Expand Up @@ -597,13 +604,141 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
}
#endif /* CTRL_IFACE_SOCKET */

#ifdef CTRL_IFACE_FIFO
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
struct os_reltime started_at, ending_at;
int res;
fd_set rfds;
const char *_cmd;
char *cmd_buf = NULL;
size_t _cmd_len;

_cmd = cmd;
_cmd_len = cmd_len;

errno = 0;
started_at.sec = 0;
started_at.usec = 0;
retry_send:
if (send_data(ctrl->fifo_send, ctrl->s, _cmd, _cmd_len, 0) < 0) {
if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
{
/*
* Must be a non-blocking socket... Try for a bit
* longer before giving up.
*/
if (started_at.sec == 0)
os_get_reltime(&started_at);
else {
struct os_reltime n;
os_get_reltime(&n);
/* Try for a few seconds. */
if (os_reltime_expired(&n, &started_at, 5))
goto send_err;
}
os_sleep(1, 0);
goto retry_send;
}
send_err:
os_free(cmd_buf);
return -1;
}
os_free(cmd_buf);

os_get_reltime(&ending_at);
ending_at.sec += CONFIG_WIFI_NM_WPA_CTRL_RESP_TIMEOUT_S;

for (;;) {
struct os_reltime diff;

os_get_reltime(&started_at);
if (os_reltime_before(&ending_at, &started_at))
return -2;
os_reltime_sub(&ending_at, &started_at, &diff);
tv.tv_sec = diff.sec;
tv.tv_usec = diff.usec;

FD_ZERO(&rfds);
FD_SET(ctrl->r, &rfds);
res = select(ctrl->r + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno == EINTR)
continue;
if (res < 0)
return res;
if (FD_ISSET(ctrl->r, &rfds)) {
struct zephyr_msg *msg;
zvfs_eventfd_t value;
const char *buf;

zvfs_eventfd_read(ctrl->r, &value);

msg = k_fifo_get(ctrl->fifo_read, K_NO_WAIT);
if (msg == NULL) {
wpa_printf(MSG_ERROR, "fifo(ctrl_iface): %s",
"empty");
continue;
}

if (msg->data != NULL) {
buf = msg->data;
} else if (msg->const_data != NULL) {
buf = msg->const_data;
} else {
wpa_printf(MSG_ERROR, "fifo(ctrl_iface): %s",
"no data");
k_free(msg);
return -2;
}

res = strlen(buf);
memcpy(reply, buf, res);

if (msg->data != NULL) {
os_free(msg->data);
}

k_free(msg);

if ((res > 0 && reply[0] == '<') ||
(res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
* caller. */
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
if ((size_t) res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
}
continue;
}
*reply_len = res;
break;
} else {
return -2;
}
}
return 0;
}
#endif /* CTRL_IFACE_FIFO */

#ifdef CONFIG_CTRL_IFACE_ZEPHYR
struct wpa_ctrl * wpa_ctrl_open(const int sock)
struct wpa_ctrl * wpa_ctrl_open(const int send_sock,
struct k_fifo *send_fifo,
int read_sock,
struct k_fifo *read_fifo)
{
struct wpa_ctrl *ctrl;

if (sock < 0) {
wpa_printf(MSG_ERROR, "Invalid socket : %d\n", sock);
if (send_sock < 0 || read_sock < 0) {
wpa_printf(MSG_ERROR, "Invalid socket : %d / %d\n", send_sock, read_sock);
return NULL;
}

Expand All @@ -614,7 +749,10 @@ struct wpa_ctrl * wpa_ctrl_open(const int sock)
}

/* We use one of the socketpair opened in ctrl_iface_zephyr.c */
ctrl->s = sock;
ctrl->s = send_sock;
ctrl->r = read_sock;
ctrl->fifo_send = send_fifo;
ctrl->fifo_read = read_fifo;

return ctrl;
}
Expand Down
3 changes: 2 additions & 1 deletion src/common/wpa_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,8 @@ enum wpa_vendor_elem_frame {
* This function is used to open a control interface to wpa_supplicant/hostapd
* using a connected socketpair.
*/
struct wpa_ctrl * wpa_ctrl_open(const int sock);
struct wpa_ctrl * wpa_ctrl_open(const int sock, struct k_fifo *fifo_send,
int read_sock, struct k_fifo *fifo_recv);
#else
/**
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
Expand Down
Loading