From 3ec97afe571f159ea95213262c1c6b89965827d4 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 21 Apr 2009 16:45:16 +0300 Subject: [PATCH] wpa_supplicant AP: Add preliminary support for WPS Internal Registrar When in AP mode, wpa_supplicant is now enabling WPS (only Internal Registrar). wpa_cli wps_pbc and wps_pin commands can be used to initiate WPS negotiation similarly to how this is done in station mode (though, the BSSID parameter is ignored). --- src/eap_server/eap_methods.h | 6 ++--- wpa_supplicant/ap.c | 41 +++++++++++++++++++++++++++++++++ wpa_supplicant/ap.h | 3 +++ wpa_supplicant/ctrl_iface.c | 21 +++++++++++++---- wpa_supplicant/wpa_supplicant.c | 15 ++++++++++++ 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h index 0fd53909f..4b19e6830 100644 --- a/src/eap_server/eap_methods.h +++ b/src/eap_server/eap_methods.h @@ -12,8 +12,8 @@ * See README and COPYING for more details. */ -#ifndef EAP_METHODS_H -#define EAP_METHODS_H +#ifndef EAP_SERVER_METHODS_H +#define EAP_SERVER_METHODS_H const struct eap_method * eap_server_get_eap_method(int vendor, EapType method); @@ -26,4 +26,4 @@ EapType eap_server_get_type(const char *name, int *vendor); int eap_server_register_methods(void); void eap_server_unregister_methods(void); -#endif /* EAP_METHODS_H */ +#endif /* EAP_SERVER_METHODS_H */ diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 684ec851b..999d7e08e 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -21,9 +21,11 @@ #ifdef NEED_MLME #include "../hostapd/ieee802_11.h" #endif /* NEED_MLME */ +#include "../hostapd/wps_hostapd.h" #include "eap_common/eap_defs.h" #include "eap_server/eap_methods.h" #include "eap_common/eap_wsc_common.h" +#include "wps/wps.h" #include "config_ssid.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -382,6 +384,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, else bss->ssid.security_policy = SECURITY_PLAINTEXT; +#ifdef CONFIG_WPS + /* + * Enable WPS by default, but require user interaction to actually use + * it. Only the internal Registrar is supported. + */ + bss->eap_server = 1; + bss->wps_state = 2; + bss->ap_setup_locked = 1; + bss->config_methods = os_strdup("display push_button"); +#endif /* CONFIG_WPS */ + return 0; } @@ -507,3 +520,31 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, { hostapd_eapol_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len); } + + +#ifdef CONFIG_WPS + +int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0]); +} + + +int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin, char *buf, size_t buflen) +{ + int ret, ret_len = 0; + + if (pin == NULL) { + unsigned int rpin = wps_generate_pin(); + ret_len = os_snprintf(buf, buflen, "%d", rpin); + pin = buf; + } + + ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin); + if (ret) + return -1; + return ret_len; +} + +#endif /* CONFIG_WPS */ diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 782c53ae2..935dba108 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -21,5 +21,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s); void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, const u8 *src_addr, const u8 *buf, size_t len); +int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin, char *buf, size_t buflen); #endif /* AP_H */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index a7536d363..08121b6dd 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -31,6 +31,7 @@ #include "wps_supplicant.h" #include "wps/wps.h" #include "ibss_rsn.h" +#include "ap.h" extern struct wpa_driver_ops *wpa_drivers[]; @@ -150,18 +151,22 @@ static int wpa_supplicant_ctrl_iface_ft_ds( static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, char *cmd) { - u8 bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN], *_bssid = bssid; if (cmd == NULL || os_strcmp(cmd, "any") == 0) - return wpas_wps_start_pbc(wpa_s, NULL); - - if (hwaddr_aton(cmd, bssid)) { + _bssid = NULL; + else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", cmd); return -1; } - return wpas_wps_start_pbc(wpa_s, bssid); +#ifdef CONFIG_AP + if (wpa_s->ap_iface) + return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid); +#endif /* CONFIG_AP */ + + return wpas_wps_start_pbc(wpa_s, _bssid); } @@ -185,6 +190,12 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, return -1; } +#ifdef CONFIG_AP + if (wpa_s->ap_iface) + return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin, + buf, buflen); +#endif /* CONFIG_AP */ + if (pin) { ret = wpas_wps_start_pin(wpa_s, _bssid, pin); if (ret < 0) diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 7804f7b39..723e2edfd 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -21,6 +21,7 @@ #include "common.h" #include "eapol_supp/eapol_supp_sm.h" #include "eap_peer/eap.h" +#include "eap_server/eap_methods.h" #include "wpa.h" #include "eloop.h" #include "config.h" @@ -2118,6 +2119,17 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) return NULL; } +#ifdef CONFIG_AP + ret = eap_server_register_methods(); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to register EAP server methods"); + if (ret == -2) + wpa_printf(MSG_ERROR, "Two or more EAP methods used " + "the same EAP type."); + return NULL; + } +#endif /* CONFIG_AP */ + global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; @@ -2241,6 +2253,9 @@ void wpa_supplicant_deinit(struct wpa_global *global) wpa_supplicant_dbus_ctrl_iface_deinit(global->dbus_ctrl_iface); eap_peer_unregister_methods(); +#ifdef CONFIG_AP + eap_server_unregister_methods(); +#endif /* CONFIG_AP */ for (i = 0; wpa_drivers[i] && global->drv_priv; i++) { if (!global->drv_priv[i])