diff --git a/src/wps/wps.h b/src/wps/wps.h index 2661e941c..76b818e3b 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 000000000..2908b3826 --- /dev/null +++ b/src/wps/wps_er.c @@ -0,0 +1,370 @@ +/* + * Wi-Fi Protected Setup - External Registrar + * Copyright (c) 2009, Jouni Malinen + * + * 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 da488bc7d..25c6f4446 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 d4b6569e1..dd4c44db0 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 92b785c44..3ffff092d 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 6e15f2475..e234bc8e5 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 bebb12596..c00169ce7 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 ec103bfb4..f19a6038a 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, " = 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, " = request RSN authentication with in IBSS" }, diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index d426aaa8c..e47ac74fa 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 95f3b8853..5fd94e289 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 0f2395545..e75b3bed1 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 */