DPP: Allow AP/Relay to be configured to listed for new TCP connections

This extends Relay functionality to allow a Controller to intitiate a
new DPP exchange in addition to the previously supported case where the
exchange was initiated through a DPP Public Action frame.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2022-07-09 12:36:34 +03:00 committed by Jouni Malinen
parent 248654d36b
commit 451ede2c31
8 changed files with 191 additions and 1 deletions

View file

@ -4471,6 +4471,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos))
return 1;
} else if (os_strcmp(buf, "dpp_relay_port") == 0) {
bss->dpp_relay_port = atoi(pos);
} else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
bss->dpp_configurator_connectivity = atoi(pos);
} else if (os_strcmp(buf, "dpp_pfs") == 0) {

View file

@ -2520,6 +2520,12 @@ own_ip_addr=127.0.0.1
#dpp_csign
#dpp_controller
# DPP Relay port number
# TCP port to listen to for incoming connections from a Controller. This can be
# used to allow Controller initiated exchanges in addition to the
# Controller-as-responder cases covered by the dpp_controller parameter.
#dpp_relay_port=12345
# Configurator Connectivity indication
# 0: no Configurator is currently connected (default)
# 1: advertise that a Configurator is available

View file

@ -761,6 +761,7 @@ struct hostapd_bss_config {
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
int dpp_relay_port;
int dpp_configurator_connectivity;
int dpp_pfs;
#endif /* CONFIG_DPP2 */

View file

@ -3017,6 +3017,9 @@ static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
struct hostapd_data *hapd = ctx;
u8 *buf;
if (freq == 0)
freq = hapd->iface->freq;
wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
MAC2STR(addr), freq);
buf = os_malloc(2 + len);
@ -3059,6 +3062,10 @@ static int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
&config) < 0)
return -1;
}
if (hapd->conf->dpp_relay_port)
dpp_relay_listen(hapd->iface->interfaces->dpp,
hapd->conf->dpp_relay_port);
#endif /* CONFIG_DPP2 */
return 0;
@ -3099,8 +3106,10 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
NULL);
hostapd_dpp_chirp_stop(hapd);
if (hapd->iface->interfaces)
if (hapd->iface->interfaces) {
dpp_relay_stop_listen(hapd->iface->interfaces->dpp);
dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd);
}
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_DPP3
eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL);

View file

@ -4890,6 +4890,7 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config)
#ifdef CONFIG_DPP2
dl_list_init(&dpp->controllers);
dl_list_init(&dpp->tcp_init);
dpp->relay_sock = -1;
#endif /* CONFIG_DPP2 */
return dpp;

View file

@ -719,6 +719,8 @@ struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
const u8 *kid);
int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config);
int dpp_relay_listen(struct dpp_global *dpp, int port);
void dpp_relay_stop_listen(struct dpp_global *dpp);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
const u8 *buf, size_t len, unsigned int freq,
const u8 *i_bootstrap, const u8 *r_bootstrap,

View file

@ -21,6 +21,7 @@ struct dpp_global {
struct dl_list controllers; /* struct dpp_relay_controller */
struct dpp_controller *controller;
struct dl_list tcp_init; /* struct dpp_connection */
int relay_sock;
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth);

View file

@ -189,6 +189,26 @@ dpp_relay_controller_get_ctx(struct dpp_global *dpp, void *cb_ctx)
}
static struct dpp_relay_controller *
dpp_relay_controller_get_addr(struct dpp_global *dpp,
const struct sockaddr_in *addr)
{
struct dpp_relay_controller *ctrl;
if (!dpp)
return NULL;
dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
list) {
if (ctrl->ipaddr.af == AF_INET &&
addr->sin_addr.s_addr == ctrl->ipaddr.u.v4.s_addr)
return ctrl;
}
return NULL;
}
static void dpp_controller_gas_done(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
@ -543,6 +563,17 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
if (os_memcmp(src, conn->mac_addr,
ETH_ALEN) == 0)
return dpp_relay_tx(conn, hdr, buf, len);
if (type == DPP_PA_AUTHENTICATION_RESP &&
conn->freq == 0 &&
is_broadcast_ether_addr(conn->mac_addr)) {
wpa_printf(MSG_DEBUG,
"DPP: Associate this peer to the new Controller initiated connection");
os_memcpy(conn->mac_addr, src,
ETH_ALEN);
conn->freq = freq;
return dpp_relay_tx(conn, hdr, buf,
len);
}
}
}
}
@ -2240,6 +2271,143 @@ void dpp_relay_flush_controllers(struct dpp_global *dpp)
}
static void dpp_relay_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
{
struct dpp_global *dpp = eloop_ctx;
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int fd;
struct dpp_relay_controller *ctrl;
struct dpp_connection *conn = NULL;
wpa_printf(MSG_DEBUG, "DPP: New TCP connection (Relay)");
fd = accept(dpp->relay_sock, (struct sockaddr *) &addr, &addr_len);
if (fd < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to accept new connection: %s",
strerror(errno));
return;
}
wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ctrl = dpp_relay_controller_get_addr(dpp, &addr);
if (!ctrl) {
wpa_printf(MSG_DEBUG,
"DPP: No Controller found for that address");
goto fail;
}
if (dl_list_len(&ctrl->conn) >= 15) {
wpa_printf(MSG_DEBUG,
"DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
goto fail;
}
conn = os_zalloc(sizeof(*conn));
if (!conn)
goto fail;
conn->global = ctrl->global;
conn->relay = ctrl;
conn->msg_ctx = ctrl->msg_ctx;
conn->cb_ctx = ctrl->global->cb_ctx;
os_memset(conn->mac_addr, 0xff, ETH_ALEN);
conn->sock = fd;
if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
strerror(errno));
goto fail;
}
if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
dpp_controller_rx, conn, NULL) < 0)
goto fail;
conn->read_eloop = 1;
/* TODO: eloop timeout to expire connections that do not complete in
* reasonable time */
dl_list_add(&ctrl->conn, &conn->list);
return;
fail:
close(fd);
os_free(conn);
}
int dpp_relay_listen(struct dpp_global *dpp, int port)
{
int s;
int on = 1;
struct sockaddr_in sin;
if (dpp->relay_sock >= 0) {
wpa_printf(MSG_INFO, "DPP: %s(%d) - relay port already opened",
__func__, port);
return -1;
}
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
wpa_printf(MSG_INFO,
"DPP: socket(SOCK_STREAM) failed: %s",
strerror(errno));
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: setsockopt(SO_REUSEADDR) failed: %s",
strerror(errno));
/* try to continue anyway */
}
if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
strerror(errno));
close(s);
return -1;
}
/* TODO: IPv6 */
os_memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
wpa_printf(MSG_INFO,
"DPP: Failed to bind Relay TCP port: %s",
strerror(errno));
close(s);
return -1;
}
if (listen(s, 10 /* max backlog */) < 0 ||
fcntl(s, F_SETFL, O_NONBLOCK) < 0 ||
eloop_register_sock(s, EVENT_TYPE_READ, dpp_relay_tcp_cb, dpp,
NULL)) {
close(s);
return -1;
}
dpp->relay_sock = s;
wpa_printf(MSG_DEBUG, "DPP: Relay started on TCP port %d", port);
return 0;
}
void dpp_relay_stop_listen(struct dpp_global *dpp)
{
if (!dpp || dpp->relay_sock < 0)
return;
eloop_unregister_sock(dpp->relay_sock, EVENT_TYPE_READ);
close(dpp->relay_sock);
dpp->relay_sock = -1;
}
bool dpp_tcp_conn_status_requested(struct dpp_global *dpp)
{
struct dpp_connection *conn;