aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/wps/wps.h4
-rw-r--r--src/wps/wps_er.c370
-rw-r--r--src/wps/wps_upnp.c7
-rw-r--r--src/wps/wps_upnp_i.h8
-rw-r--r--src/wps/wps_upnp_ssdp.c74
-rw-r--r--wpa_supplicant/Makefile6
-rw-r--r--wpa_supplicant/ctrl_iface.c6
-rw-r--r--wpa_supplicant/wpa_cli.c22
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h1
-rw-r--r--wpa_supplicant/wps_supplicant.c30
-rw-r--r--wpa_supplicant/wps_supplicant.h2
11 files changed, 499 insertions, 31 deletions
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 2661e94..76b818e 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -32,6 +32,7 @@ enum wsc_op_code {
struct wps_registrar;
struct upnp_wps_device_sm;
+struct wps_er;
/**
* struct wps_credential - WPS Credential
@@ -606,4 +607,7 @@ int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
int registrar);
int wps_attr_text(struct wpabuf *data, char *buf, char *end);
+struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname);
+void wps_er_deinit(struct wps_er *er);
+
#endif /* WPS_H */
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
new file mode 100644
index 0000000..2908b38
--- /dev/null
+++ b/src/wps/wps_er.c
@@ -0,0 +1,370 @@
+/*
+ * Wi-Fi Protected Setup - External Registrar
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "uuid.h"
+#include "eloop.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+
+/* TODO:
+ * SSDP M-SEARCH multicast TX for WFA
+ * create AP entry
+ * fetch wps_device info based on LOCATION: from SSDP NOTIFY
+ * parse wps_device info into AP entry (name, SCPD/control/eventSub URLs, etc.
+ * subscribe to events
+ * send notification of new AP device with wpa_msg
+ * re-send notifications with wpa_msg if ER re-started (to update wpa_gui-qt4)
+ * (also re-send SSDP M-SEARCH in this case to find new APs)
+ * parse UPnP event messages
+ */
+
+static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
+
+
+struct wps_er_ap {
+ struct wps_er_ap *next;
+ struct in_addr addr;
+ char *location;
+
+};
+
+struct wps_er {
+ struct wps_registrar *reg;
+ char ifname[17];
+ char *mac_addr_text; /* mac addr of network i.f. we use */
+ u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
+ char *ip_addr_text; /* IP address of network i.f. we use */
+ unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+ int multicast_sd;
+ int ssdp_sd;
+ struct wps_er_ap *ap;
+};
+
+
+static void wps_er_pin_needed_cb(void *ctx, const u8 *uuid_e,
+ const struct wps_device_data *dev)
+{
+ wpa_printf(MSG_DEBUG, "WPS ER: PIN needed");
+}
+
+
+static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
+ struct in_addr *addr)
+{
+ struct wps_er_ap *ap;
+ for (ap = er->ap; ap; ap = ap->next) {
+ if (ap->addr.s_addr == addr->s_addr)
+ break;
+ }
+ return ap;
+}
+
+
+static void wps_er_ap_free(struct wps_er *er, struct wps_er_ap *ap)
+{
+ wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
+ inet_ntoa(ap->addr), ap->location);
+ eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
+ os_free(ap->location);
+ os_free(ap);
+}
+
+
+static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
+{
+ struct wps_er *er = eloop_data;
+ struct wps_er_ap *ap = user_ctx;
+ wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
+ wps_er_ap_free(er, ap);
+}
+
+
+static void wps_er_ap_add(struct wps_er *er, struct in_addr *addr,
+ const char *location, int max_age)
+{
+ struct wps_er_ap *ap;
+
+ ap = wps_er_ap_get(er, addr);
+ if (ap) {
+ /* Update advertisement timeout */
+ eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
+ eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
+ return;
+ }
+
+ ap = os_zalloc(sizeof(*ap));
+ if (ap == NULL)
+ return;
+ ap->location = os_strdup(location);
+ if (ap->location == NULL) {
+ os_free(ap);
+ return;
+ }
+ ap->next = er->ap;
+ er->ap = ap;
+
+ ap->addr.s_addr = addr->s_addr;
+ eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
+
+ wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
+ inet_ntoa(ap->addr), ap->location);
+
+ /* TODO: get device data and subscribe for events */
+}
+
+
+static void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
+{
+ struct wps_er_ap *prev = NULL, *ap = er->ap;
+
+ while (ap) {
+ if (ap->addr.s_addr == addr->s_addr) {
+ if (prev)
+ prev->next = ap->next;
+ else
+ er->ap = ap->next;
+ wps_er_ap_free(er, ap);
+ return;
+ }
+ prev = ap;
+ ap = ap->next;
+ }
+}
+
+
+static void wps_er_ap_remove_all(struct wps_er *er)
+{
+ struct wps_er_ap *prev, *ap;
+
+ ap = er->ap;
+ er->ap = NULL;
+
+ while (ap) {
+ prev = ap;
+ ap = ap->next;
+ wps_er_ap_free(er, prev);
+ }
+}
+
+
+static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct wps_er *er = eloop_ctx;
+ struct sockaddr_in addr; /* client address */
+ socklen_t addr_len;
+ int nread;
+ char buf[MULTICAST_MAX_READ], *pos, *pos2, *start;
+ int wfa = 0, byebye = 0;
+ int max_age = -1;
+ char *location = NULL;
+
+ addr_len = sizeof(addr);
+ nread = recvfrom(sd, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &addr, &addr_len);
+ if (nread <= 0)
+ return;
+ buf[nread] = '\0';
+
+ wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
+ inet_ntoa(addr.sin_addr));
+ wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
+ (u8 *) buf, nread);
+
+ if (sd == er->multicast_sd) {
+ /* Reply to M-SEARCH */
+ if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
+ return; /* unexpected response header */
+ } else {
+ /* Unsolicited message (likely NOTIFY or M-SEARCH) */
+ if (os_strncmp(buf, "NOTIFY ", 7) != 0)
+ return; /* only process notifications */
+ }
+
+ for (start = buf; start && *start; start = pos) {
+ pos = os_strchr(start, '\n');
+ if (pos) {
+ if (pos[-1] == '\r')
+ pos[-1] = '\0';
+ *pos++ = '\0';
+ }
+ if (os_strstr(start, "schemas-wifialliance-org:device:"
+ "WFADevice:1"))
+ wfa = 1;
+ if (os_strstr(start, "schemas-wifialliance-org:service:"
+ "WFAWLANConfig:1"))
+ wfa = 1;
+ if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
+ start += 9;
+ while (*start == ' ')
+ start++;
+ location = start;
+ } else if (os_strncasecmp(start, "NTS:", 4) == 0) {
+ if (os_strstr(start, "ssdp:byebye"))
+ byebye = 1;
+ } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
+ start += 9;
+ while (*start == ' ')
+ start++;
+ pos2 = os_strstr(start, "max-age=");
+ if (pos2 == NULL)
+ continue;
+ pos2 += 8;
+ max_age = atoi(pos2);
+ }
+ }
+
+ if (!wfa)
+ return; /* Not WPS advertisement/reply */
+
+ if (byebye) {
+ wps_er_ap_remove(er, &addr.sin_addr);
+ return;
+ }
+
+ if (!location)
+ return; /* Unknown location */
+
+ if (max_age < 1)
+ return; /* No max-age reported */
+
+ wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
+ "(packet source: %s max-age: %d)",
+ location, inet_ntoa(addr.sin_addr), max_age);
+
+ wps_er_ap_add(er, &addr.sin_addr, location, max_age);
+}
+
+
+static void wps_er_send_ssdp_msearch(struct wps_er *er)
+{
+ struct wpabuf *msg;
+ struct sockaddr_in dest;
+
+ msg = wpabuf_alloc(500);
+ if (msg == NULL)
+ return;
+
+ wpabuf_put_str(msg,
+ "M-SEARCH * HTTP/1.1\r\n"
+ "HOST: 239.255.255.250:1900\r\n"
+ "MAN: \"ssdp:discover\"\r\n"
+ "MX: 3\r\n"
+ "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
+ "\r\n"
+ "\r\n");
+
+ os_memset(&dest, 0, sizeof(dest));
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+ dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+ if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
+ (struct sockaddr *) &dest, sizeof(dest)) < 0)
+ wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
+ "%d (%s)", errno, strerror(errno));
+
+ wpabuf_free(msg);
+}
+
+
+struct wps_er *
+wps_er_init(struct wps_context *wps, const char *ifname)
+{
+ struct wps_er *er;
+ struct wps_registrar_config rcfg;
+
+ er = os_zalloc(sizeof(*er));
+ if (er == NULL)
+ return NULL;
+
+ er->multicast_sd = -1;
+ er->ssdp_sd = -1;
+
+ os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
+ os_memset(&rcfg, 0, sizeof(rcfg));
+ rcfg.pin_needed_cb = wps_er_pin_needed_cb;
+ rcfg.cb_ctx = er;
+
+ er->reg = wps_registrar_init(wps, &rcfg);
+ if (er->reg == NULL) {
+ wps_er_deinit(er);
+ return NULL;
+ }
+
+ if (get_netif_info(ifname,
+ &er->ip_addr, &er->ip_addr_text,
+ er->mac_addr, &er->mac_addr_text)) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
+ "for %s. Does it have IP address?", ifname);
+ wps_er_deinit(er);
+ return NULL;
+ }
+
+ if (add_ssdp_network(ifname)) {
+ wps_er_deinit(er);
+ return NULL;
+ }
+
+ er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
+ if (er->multicast_sd < 0) {
+ wps_er_deinit(er);
+ return NULL;
+ }
+
+ er->ssdp_sd = ssdp_listener_open();
+ if (er->ssdp_sd < 0) {
+ wps_er_deinit(er);
+ return NULL;
+ }
+ if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
+ wps_er_ssdp_rx, er, NULL) ||
+ eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
+ wps_er_ssdp_rx, er, NULL)) {
+ wps_er_deinit(er);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s "
+ "mac_addr=%s)",
+ er->ifname, er->ip_addr_text, er->mac_addr_text);
+
+ wps_er_send_ssdp_msearch(er);
+
+ return er;
+}
+
+
+void wps_er_deinit(struct wps_er *er)
+{
+ if (er == NULL)
+ return;
+ wps_er_ap_remove_all(er);
+ if (er->multicast_sd >= 0) {
+ eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
+ close(er->multicast_sd);
+ }
+ if (er->ssdp_sd >= 0) {
+ eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
+ close(er->ssdp_sd);
+ }
+ wps_registrar_deinit(er->reg);
+ os_free(er->ip_addr_text);
+ os_free(er->mac_addr_text);
+ os_free(er);
+}
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index da488bc..25c6f44 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -885,9 +885,8 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
* @mac_addr_text: Buffer for returning allocated MAC address text
* Returns: 0 on success, -1 on failure
*/
-static int get_netif_info(const char *net_if, unsigned *ip_addr,
- char **ip_addr_text, u8 mac[ETH_ALEN],
- char **mac_addr_text)
+int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
+ u8 mac[ETH_ALEN], char **mac_addr_text)
{
struct ifreq req;
int sock = -1;
@@ -930,7 +929,7 @@ static int get_netif_info(const char *net_if, unsigned *ip_addr,
#else
#error MAC address fetch not implemented
#endif
- os_snprintf(*mac_addr_text, 18, MACSTR, MAC2STR(req.ifr_addr.sa_data));
+ os_snprintf(*mac_addr_text, 18, MACSTR, MAC2STR(mac));
close(sock);
return 0;
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index d4b6569..dd4c44d 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -25,6 +25,8 @@
#define UPNP_WPS_DEVICE_CONTROL_FILE "wps_control"
#define UPNP_WPS_DEVICE_EVENT_FILE "wps_event"
+#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
+
struct web_connection;
struct subscription;
@@ -168,6 +170,8 @@ void subscription_destroy(struct subscription *s);
struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
const u8 uuid[UUID_LEN]);
int send_wpabuf(int fd, struct wpabuf *buf);
+int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
+ u8 mac[ETH_ALEN], char **mac_addr_text);
/* wps_upnp_ssdp.c */
void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
@@ -175,7 +179,9 @@ int advertisement_state_machine_start(struct upnp_wps_device_sm *sm);
void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm);
void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
int ssdp_listener_start(struct upnp_wps_device_sm *sm);
-int add_ssdp_network(char *net_if);
+int ssdp_listener_open(void);
+int add_ssdp_network(const char *net_if);
+int ssdp_open_multicast_sock(u32 ip_addr);
int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
/* wps_upnp_web.c */
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 92b785c..3ffff09 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -24,7 +24,6 @@
#define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1) /* cache time we use */
#define UPNP_CACHE_SEC_MIN 1800 /* min cachable time per UPnP standard */
#define UPNP_ADVERTISE_REPEAT 2 /* no more than 3 */
-#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
#define MAX_MSEARCH 20 /* max simultaneous M-SEARCH replies ongoing */
#define SSDP_TARGET "239.0.0.0"
#define SSDP_NETMASK "255.0.0.0"
@@ -657,7 +656,7 @@ bad:
* ssdp_listener_stop - Stop SSDP listered
* @sm: WPS UPnP state machine from upnp_wps_device_init()
*
- * This function stops the SSDP listerner that was started by calling
+ * This function stops the SSDP listener that was started by calling
* ssdp_listener_start().
*/
void ssdp_listener_stop(struct upnp_wps_device_sm *sm)
@@ -719,23 +718,16 @@ static void ssdp_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
}
-/**
- * ssdp_listener_start - Set up for receiving discovery (UDP) packets
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * Returns: 0 on success, -1 on failure
- *
- * The SSDP listerner is stopped by calling ssdp_listener_stop().
- */
-int ssdp_listener_start(struct upnp_wps_device_sm *sm)
+int ssdp_listener_open(void)
{
- int sd = -1;
struct sockaddr_in addr;
struct ip_mreq mcast_addr;
int on = 1;
/* per UPnP spec, keep IP packet time to live (TTL) small */
unsigned char ttl = 4;
+ int sd;
- sm->ssdp_sd = sd = socket(AF_INET, SOCK_DGRAM, 0);
+ sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0)
goto fail;
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
@@ -757,8 +749,29 @@ int ssdp_listener_start(struct upnp_wps_device_sm *sm)
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl)))
goto fail;
- if (eloop_register_sock(sd, EVENT_TYPE_READ, ssdp_listener_handler,
- NULL, sm))
+
+ return sd;
+
+fail:
+ if (sd >= 0)
+ close(sd);
+ return -1;
+}
+
+
+/**
+ * ssdp_listener_start - Set up for receiving discovery (UDP) packets
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * The SSDP listener is stopped by calling ssdp_listener_stop().
+ */
+int ssdp_listener_start(struct upnp_wps_device_sm *sm)
+{
+ sm->ssdp_sd = ssdp_listener_open();
+
+ if (eloop_register_sock(sm->ssdp_sd, EVENT_TYPE_READ,
+ ssdp_listener_handler, NULL, sm))
goto fail;
sm->ssdp_sd_registered = 1;
return 0;
@@ -782,7 +795,7 @@ fail:
* once after booting up, but it does not hurt to call this more frequently
* "to be safe".
*/
-int add_ssdp_network(char *net_if)
+int add_ssdp_network(const char *net_if)
{
#ifdef __linux__
int ret = -1;
@@ -798,7 +811,7 @@ int add_ssdp_network(char *net_if)
if (sock < 0)
goto fail;
- rt.rt_dev = net_if;
+ rt.rt_dev = (char *) net_if;
sin = aliasing_hide_typecast(&rt.rt_dst, struct sockaddr_in);
sin->sin_family = AF_INET;
sin->sin_port = 0;
@@ -833,19 +846,14 @@ fail:
}
-/**
- * ssdp_open_multicast - Open socket for sending multicast SSDP messages
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * Returns: 0 on success, -1 on failure
- */
-int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
+int ssdp_open_multicast_sock(u32 ip_addr)
{
- int sd = -1;
+ int sd;
/* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
* time to live (TTL) small */
unsigned char ttl = 4;
- sm->multicast_sd = sd = socket(AF_INET, SOCK_DGRAM, 0);
+ sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0)
return -1;
@@ -855,7 +863,7 @@ int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
#endif
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
- &sm->ip_addr, sizeof(sm->ip_addr)))
+ &ip_addr, sizeof(ip_addr)))
return -1;
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl)))
@@ -865,7 +873,7 @@ int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
{
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
- mreq.imr_interface.s_addr = sm->ip_addr;
+ mreq.imr_interface.s_addr = ip_addr;
wpa_printf(MSG_DEBUG, "WPS UPnP: Multicast addr 0x%x if addr "
"0x%x",
mreq.imr_multiaddr.s_addr,
@@ -886,5 +894,19 @@ int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
* which aids debugging I suppose but isn't really necessary?
*/
+ return sd;
+}
+
+
+/**
+ * ssdp_open_multicast - Open socket for sending multicast SSDP messages
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
+{
+ sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
+ if (sm->multicast_sd < 0)
+ return -1;
return 0;
}
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 6e15f24..e234bc8 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -497,6 +497,12 @@ ifdef NEED_WPS_OOB
CFLAGS += -DCONFIG_WPS_OOB
endif
+ifdef CONFIG_WPS_ER
+CONFIG_WPS_UPNP=y
+CFLAGS += -DCONFIG_WPS_ER
+OBJS += ../src/wps/wps_er.o
+endif
+
ifdef CONFIG_WPS_UPNP
CFLAGS += -DCONFIG_WPS_UPNP
OBJS += ../src/wps/wps_upnp.o
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index bebb125..c00169c 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1632,6 +1632,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
reply_len = -1;
+ } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
+ if (wpas_wps_er_start(wpa_s))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
+ if (wpas_wps_er_stop(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_WPS */
#ifdef CONFIG_IBSS_RSN
} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index ec103bf..f19a603 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -533,6 +533,22 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_ER_START");
+
+}
+
+
+static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
+
+}
+
+
static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -1397,6 +1413,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "wps_reg", wpa_cli_cmd_wps_reg,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
+ { "wps_er_start", wpa_cli_cmd_wps_er_start,
+ cli_cmd_flag_none,
+ "= start Wi-Fi Protected Setup External Registrar" },
+ { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
+ cli_cmd_flag_none,
+ "= stop Wi-Fi Protected Setup External Registrar" },
{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d426aaa..e47ac74 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -380,6 +380,7 @@ struct wpa_supplicant {
struct wps_context *wps;
int wps_success; /* WPS success event received */
+ struct wps_er *wps_er;
int blacklist_cleared;
struct wpabuf *pending_eapol_rx;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 95f3b88..5fd94e2 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -814,6 +814,9 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
os_free(wpa_s->wps->network_key);
os_free(wpa_s->wps);
wpa_s->wps = NULL;
+
+ wps_er_deinit(wpa_s->wps_er);
+ wpa_s->wps_er = NULL;
}
@@ -1021,3 +1024,30 @@ int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
wpabuf_free(wps_ie);
return ret;
}
+
+
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS_ER
+ if (wpa_s->wps_er) {
+ /* TODO: re-send ctrl_iface events for current data? */
+ return 0;
+ }
+ wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname);
+ if (wpa_s->wps_er == NULL)
+ return -1;
+ return 0;
+#else /* CONFIG_WPS_ER */
+ return 0;
+#endif /* CONFIG_WPS_ER */
+}
+
+
+int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS_ER
+ wps_er_deinit(wpa_s->wps_er);
+ wpa_s->wps_er = NULL;
+#endif /* CONFIG_WPS_ER */
+ return 0;
+}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 0f23955..e75b3be 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -49,6 +49,8 @@ void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
int wpas_wps_searching(struct wpa_supplicant *wpa_s);
int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
char *end);
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s);
+int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WPS */