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

Merged
merged 2 commits into from
Jun 27, 2025
Merged
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
102 changes: 57 additions & 45 deletions hostapd/ctrl_iface_zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,63 @@ 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;

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

if (!res) {
eloop_unregister_sock(sock, EVENT_TYPE_READ);
wpa_printf(MSG_DEBUG, "ctrl_iface: Peer unexpectedly shut down "
"socket");
return;
}

if ((size_t) res > MAX_CTRL_MSG_LEN) {
wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
return;
}
buf[res] = '\0';

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

reply = os_malloc(reply_size);
if (reply == NULL) {
send(sock, "FAIL\n", 5, 0);
wpa_printf(MSG_ERROR, "hostapd cli malloc fail for reply buffer");
return;
}

reply_len = hostapd_ctrl_iface_receive_process(hapd, pos, reply, reply_size, NULL, 0);
if (reply_len > 0) {
send(sock, reply, reply_len, 0);
} else if (reply_len == 0) {
send(sock, "OK\n", 3, 0);
} else if (reply_len < 0) {
send(sock, "FAIL\n", 5, 0);
}
os_free(reply);
const int reply_size = MAX_CTRL_MSG_LEN / 2;
zvfs_eventfd_t value;
struct zephyr_msg *msg;

do {
zvfs_eventfd_read(sock, &value);

msg = k_fifo_get(&hapd->recv_fifo, K_NO_WAIT);
if (msg == NULL) {
wpa_printf(MSG_ERROR, "fifo(ctrl_iface): %s",
"empty");
return;
}

if (msg->data == NULL) {
wpa_printf(MSG_ERROR, "fifo(global_ctrl_iface): %s",
"no data");
goto out;
}

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

pos = msg->data;

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

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

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

os_free(reply);

out:
os_free(msg->data);
os_free(msg);

} while (!k_fifo_is_empty(&hapd->recv_fifo));
}
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, ZVFS_EFD_NONBLOCK);
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, ZVFS_EFD_NONBLOCK);
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
133 changes: 127 additions & 6 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,125 @@ 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, max_reply_len = *reply_len;
fd_set rfds;

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:
return -1;
}

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;

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) {
wpa_printf(MSG_ERROR, "fifo(ctrl_iface): %s",
"no data");
os_free(msg);
return -2;
}

res = MIN(msg->len, max_reply_len);
memcpy(reply, msg->data, res);

os_free(msg->data);
os_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,14 +733,16 @@ 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;
}

void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
close(ctrl->s);
os_free(ctrl);
}
#endif
Expand Down
Loading