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:
parent
248654d36b
commit
451ede2c31
8 changed files with 191 additions and 1 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue