X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fap%2Fwps_hostapd.c;h=38ac937a87e2471c304ddae59597b118ef5477e1;hb=fc215bfe864ff56028a7c4605533a2814ec0a736;hp=2c893f4bf966d7792a718018a93964677544f195;hpb=6226e38d002cac786709ef1c24fe09811f70b6d7;p=libeap.git diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 2c893f4..38ac937 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -1,6 +1,6 @@ /* * hostapd / WPS integration - * Copyright (c) 2008-2009, Jouni Malinen + * Copyright (c) 2008-2010, 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 @@ -28,6 +28,7 @@ #include "wps/wps_dev_attr.h" #include "hostapd.h" #include "ap_config.h" +#include "beacon.h" #include "sta_info.h" #include "wps_hostapd.h" @@ -39,8 +40,48 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd, static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd); #endif /* CONFIG_WPS_UPNP */ -static void hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, - const u8 *ie, size_t ie_len); +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, + const u8 *ie, size_t ie_len); +static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); + + +struct wps_for_each_data { + int (*func)(struct hostapd_data *h, void *ctx); + void *ctx; +}; + + +static int wps_for_each(struct hostapd_iface *iface, void *ctx) +{ + struct wps_for_each_data *data = ctx; + size_t j; + + if (iface == NULL) + return 0; + for (j = 0; j < iface->num_bss; j++) { + struct hostapd_data *hapd = iface->bss[j]; + int ret = data->func(hapd, data->ctx); + if (ret) + return ret; + } + + return 0; +} + + +static int hostapd_wps_for_each(struct hostapd_data *hapd, + int (*func)(struct hostapd_data *h, void *ctx), + void *ctx) +{ + struct hostapd_iface *iface = hapd->iface; + struct wps_for_each_data data; + data.func = func; + data.ctx = ctx; + if (iface->for_each_interface == NULL) + return wps_for_each(iface, &data); + return iface->for_each_interface(iface->interfaces, wps_for_each, + &data); +} static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, @@ -98,8 +139,8 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, hapd->wps_beacon_ie = beacon_ie; wpabuf_free(hapd->wps_probe_resp_ie); hapd->wps_probe_resp_ie = probe_resp_ie; - return hapd->drv.set_ap_wps_ie(hapd, hapd->wps_beacon_ie, - hapd->wps_probe_resp_ie); + ieee802_11_set_beacon(hapd); + return hapd->drv.set_ap_wps_ie(hapd); } @@ -151,6 +192,32 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, return; wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", MAC2STR(mac_addr), uuid); + if (hapd->wps_reg_success_cb) + hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, + mac_addr, uuid_e); +} + + +static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, + const u8 *uuid_e, + const u8 *pri_dev_type, + u16 config_methods, + u16 dev_password_id, u8 request_type, + const char *dev_name) +{ + struct hostapd_data *hapd = ctx; + char uuid[40]; + char devtype[WPS_DEV_TYPE_BUFSIZE]; + if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) + return; + if (dev_name == NULL) + dev_name = ""; + wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR + " %s %s 0x%x %u %u [%s]", + MAC2STR(addr), uuid, + wps_dev_type_bin2str(pri_dev_type, devtype, + sizeof(devtype)), + config_methods, dev_password_id, request_type, dev_name); } @@ -172,9 +239,9 @@ static void wps_reload_config(void *eloop_data, void *user_ctx) } -static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) +static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) { - struct hostapd_data *hapd = ctx; + const struct wps_credential *cred = ctx; FILE *oconf, *nconf; size_t len, i; char *tmp_fname; @@ -182,6 +249,9 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) int multi_bss; int wpa; + if (hapd->wps == NULL) + return 0; + wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", cred->cred_attr, cred->cred_attr_len); @@ -386,52 +456,88 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, NULL); - /* TODO: dualband AP may need to update multiple configuration files */ - wpa_printf(MSG_DEBUG, "WPS: AP configuration updated"); return 0; } -static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, - struct wps_event_pwd_auth_fail *data) +static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) { - FILE *f; + struct hostapd_data *hapd = ctx; + return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred); +} + - if (!data->enrollee) +static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + if (hapd->conf->ap_setup_locked) return; + wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); + hapd->wps->ap_setup_locked = 0; + wps_registrar_update_ie(hapd->wps->registrar); +} + + +static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx) +{ + struct wps_event_pwd_auth_fail *data = ctx; + + if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL) + return 0; + /* * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup - * if this happens multiple times. + * for some time if this happens multiple times to slow down brute + * force attacks. */ hapd->ap_pin_failures++; - if (hapd->ap_pin_failures < 4) - return; + wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u", + hapd->ap_pin_failures); + if (hapd->ap_pin_failures < 3) + return 0; wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); hapd->wps->ap_setup_locked = 1; wps_registrar_update_ie(hapd->wps->registrar); - if (hapd->conf->wps_cred_processing == 1) - return; - - f = fopen(hapd->iface->config_fname, "a"); - if (f == NULL) { - wpa_printf(MSG_WARNING, "WPS: Could not append to the current " - "configuration file"); - return; + if (!hapd->conf->ap_setup_locked) { + if (hapd->ap_pin_lockout_time == 0) + hapd->ap_pin_lockout_time = 60; + else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && + (hapd->ap_pin_failures % 3) == 0) + hapd->ap_pin_lockout_time *= 2; + + wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", + hapd->ap_pin_lockout_time); + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + eloop_register_timeout(hapd->ap_pin_lockout_time, 0, + hostapd_wps_reenable_ap_pin, hapd, + NULL); } - fprintf(f, "# WPS AP Setup Locked based on possible attack\n"); - fprintf(f, "ap_setup_locked=1\n"); - fclose(f); + return 0; +} - /* TODO: dualband AP may need to update multiple configuration files */ - wpa_printf(MSG_DEBUG, "WPS: AP configuration updated"); +static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, + struct wps_event_pwd_auth_fail *data) +{ + hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data); +} + + +static void hostapd_wps_event_fail(struct hostapd_data *hapd, + struct wps_event_fail *fail) +{ + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d", + fail->msg, fail->config_error); } @@ -440,8 +546,32 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event, { struct hostapd_data *hapd = ctx; - if (event == WPS_EV_PWD_AUTH_FAIL) + switch (event) { + case WPS_EV_M2D: + break; + case WPS_EV_FAIL: + hostapd_wps_event_fail(hapd, &data->fail); + break; + case WPS_EV_SUCCESS: + break; + case WPS_EV_PWD_AUTH_FAIL: hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); + break; + case WPS_EV_PBC_OVERLAP: + break; + case WPS_EV_PBC_TIMEOUT: + break; + case WPS_EV_ER_AP_ADD: + break; + case WPS_EV_ER_AP_REMOVE: + break; + case WPS_EV_ER_ENROLLEE_ADD: + break; + case WPS_EV_ER_ENROLLEE_REMOVE: + break; + case WPS_EV_ER_AP_SETTINGS: + break; + } } @@ -453,7 +583,56 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd) wpabuf_free(hapd->wps_probe_resp_ie); hapd->wps_probe_resp_ie = NULL; - hapd->drv.set_ap_wps_ie(hapd, NULL, NULL); + hapd->drv.set_ap_wps_ie(hapd); +} + + +static int get_uuid_cb(struct hostapd_iface *iface, void *ctx) +{ + const u8 **uuid = ctx; + size_t j; + + if (iface == NULL) + return 0; + for (j = 0; j < iface->num_bss; j++) { + struct hostapd_data *hapd = iface->bss[j]; + if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) { + *uuid = hapd->wps->uuid; + return 1; + } + } + + return 0; +} + + +static const u8 * get_own_uuid(struct hostapd_iface *iface) +{ + const u8 *uuid; + if (iface->for_each_interface == NULL) + return NULL; + uuid = NULL; + iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid); + return uuid; +} + + +static int count_interface_cb(struct hostapd_iface *iface, void *ctx) +{ + int *count= ctx; + (*count)++; + return 0; +} + + +static int interface_count(struct hostapd_iface *iface) +{ + int count = 0; + if (iface->for_each_interface == NULL) + return 0; + iface->for_each_interface(iface->interfaces, count_interface_cb, + &count); + return count; } @@ -480,11 +659,22 @@ int hostapd_init_wps(struct hostapd_data *hapd, wps->wps_state = hapd->conf->wps_state; wps->ap_setup_locked = hapd->conf->ap_setup_locked; if (is_nil_uuid(hapd->conf->uuid)) { - uuid_gen_mac_addr(hapd->own_addr, wps->uuid); - wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address", - wps->uuid, UUID_LEN); - } else + const u8 *uuid; + uuid = get_own_uuid(hapd->iface); + if (uuid) { + os_memcpy(wps->uuid, uuid, UUID_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another " + "interface", wps->uuid, UUID_LEN); + } else { + uuid_gen_mac_addr(hapd->own_addr, wps->uuid); + wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " + "address", wps->uuid, UUID_LEN); + } + } else { os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID", + wps->uuid, UUID_LEN); + } wps->ssid_len = hapd->conf->ssid.ssid_len; os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len); wps->ap = 1; @@ -501,6 +691,22 @@ int hostapd_init_wps(struct hostapd_data *hapd, os_strdup(hapd->conf->serial_number) : NULL; wps->config_methods = wps_config_methods_str2bin(hapd->conf->config_methods); +#ifdef CONFIG_WPS2 + if ((wps->config_methods & + (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | + WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { + wpa_printf(MSG_INFO, "WPS: Converting display to " + "virtual_display for WPS 2.0 compliance"); + wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY; + } + if ((wps->config_methods & + (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | + WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { + wpa_printf(MSG_INFO, "WPS: Converting push_button to " + "virtual_push_button for WPS 2.0 compliance"); + wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; + } +#endif /* CONFIG_WPS2 */ if (hapd->conf->device_type && wps_dev_type_str2bin(hapd->conf->device_type, wps->dev.pri_dev_type) < 0) { @@ -596,6 +802,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, cfg.set_ie_cb = hostapd_wps_set_ie_cb; cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; cfg.reg_success_cb = hostapd_wps_reg_success_cb; + cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; cfg.cb_ctx = hapd; cfg.skip_cred_build = conf->skip_cred_build; cfg.extra_cred = conf->extra_cred; @@ -604,10 +811,13 @@ int hostapd_init_wps(struct hostapd_data *hapd, conf->skip_cred_build; if (conf->ssid.security_policy == SECURITY_STATIC_WEP) cfg.static_wep_only = 1; + cfg.dualband = interface_count(hapd->iface) > 1; + if (cfg.dualband) + wpa_printf(MSG_DEBUG, "WPS: Dualband AP"); wps->registrar = wps_registrar_init(wps, &cfg); if (wps->registrar == NULL) { - printf("Failed to initialize WPS Registrar\n"); + wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar"); os_free(wps->network_key); os_free(wps); return -1; @@ -639,6 +849,8 @@ int hostapd_init_wps(struct hostapd_data *hapd, void hostapd_deinit_wps(struct hostapd_data *hapd) { + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); if (hapd->wps == NULL) return; #ifdef CONFIG_WPS_UPNP @@ -658,32 +870,92 @@ void hostapd_deinit_wps(struct hostapd_data *hapd) } -int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, - const char *pin, int timeout) +void hostapd_update_wps(struct hostapd_data *hapd) { - u8 u[UUID_LEN]; - int any = 0; + if (hapd->wps == NULL) + return; + +#ifdef CONFIG_WPS_UPNP + hapd->wps->friendly_name = hapd->conf->friendly_name; + hapd->wps->manufacturer_url = hapd->conf->manufacturer_url; + hapd->wps->model_description = hapd->conf->model_description; + hapd->wps->model_url = hapd->conf->model_url; + hapd->wps->upc = hapd->conf->upc; +#endif /* CONFIG_WPS_UPNP */ + + if (hapd->conf->wps_state) + wps_registrar_update_ie(hapd->wps->registrar); + else + hostapd_deinit_wps(hapd); +} + + +struct wps_add_pin_data { + const u8 *addr; + const u8 *uuid; + const u8 *pin; + size_t pin_len; + int timeout; + int added; +}; + + +static int wps_add_pin(struct hostapd_data *hapd, void *ctx) +{ + struct wps_add_pin_data *data = ctx; + int ret; if (hapd->wps == NULL) - return -1; + return 0; + ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr, + data->uuid, data->pin, data->pin_len, + data->timeout); + if (ret == 0) + data->added++; + return ret; +} + + +int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, + const char *uuid, const char *pin, int timeout) +{ + u8 u[UUID_LEN]; + struct wps_add_pin_data data; + + data.addr = addr; + data.uuid = u; + data.pin = (const u8 *) pin; + data.pin_len = os_strlen(pin); + data.timeout = timeout; + data.added = 0; + if (os_strcmp(uuid, "any") == 0) - any = 1; - else if (uuid_str2bin(uuid, u)) + data.uuid = NULL; + else { + if (uuid_str2bin(uuid, u)) + return -1; + data.uuid = u; + } + if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0) return -1; - return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u, - (const u8 *) pin, os_strlen(pin), - timeout); + return data.added ? 0 : -1; } -int hostapd_wps_button_pushed(struct hostapd_data *hapd) +static int wps_button_pushed(struct hostapd_data *hapd, void *ctx) { if (hapd->wps == NULL) - return -1; + return 0; return wps_registrar_button_pushed(hapd->wps->registrar); } +int hostapd_wps_button_pushed(struct hostapd_data *hapd) +{ + return hostapd_wps_for_each(hapd, wps_button_pushed, NULL); +} + + #ifdef CONFIG_WPS_OOB int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, char *path, char *method, char *name) @@ -721,7 +993,7 @@ int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E || wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) && - hostapd_wps_add_pin(hapd, "any", + hostapd_wps_add_pin(hapd, NULL, "any", wpabuf_head(wps->oob_conf.dev_password), 0) < 0) goto error; @@ -738,31 +1010,59 @@ error: #endif /* CONFIG_WPS_OOB */ -static void hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, - const u8 *ie, size_t ie_len) +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, + const u8 *ie, size_t ie_len) { struct hostapd_data *hapd = ctx; struct wpabuf *wps_ie; + struct ieee802_11_elems elems; if (hapd->wps == NULL) - return; + return 0; + + if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { + wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " + MACSTR, MAC2STR(addr)); + return 0; + } + + if (elems.ssid && elems.ssid_len > 0 && + (elems.ssid_len != hapd->conf->ssid.ssid_len || + os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != + 0)) + return 0; /* Not for us */ wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); if (wps_ie == NULL) - return; + return 0; + if (wps_validate_probe_req(wps_ie, addr) < 0) { + wpabuf_free(wps_ie); + return 0; + } if (wpabuf_len(wps_ie) > 0) { - wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie); + int p2p_wildcard = 0; +#ifdef CONFIG_P2P + if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN && + os_memcmp(elems.ssid, P2P_WILDCARD_SSID, + P2P_WILDCARD_SSID_LEN) == 0) + p2p_wildcard = 1; +#endif /* CONFIG_P2P */ + wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie, + p2p_wildcard); #ifdef CONFIG_WPS_UPNP /* FIX: what exactly should be included in the WLANEvent? * WPS attributes? Full ProbeReq frame? */ - upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr, - UPNP_WPS_WLANEVENT_TYPE_PROBE, - wps_ie); + if (!p2p_wildcard) + upnp_wps_device_send_wlan_event( + hapd->wps_upnp, addr, + UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie); #endif /* CONFIG_WPS_UPNP */ } wpabuf_free(wps_ie); + + return 0; } @@ -793,6 +1093,7 @@ static int hostapd_rx_req_put_wlan_response( */ sta = ap_get_sta(hapd, mac_addr); +#ifndef CONFIG_WPS_STRICT if (!sta) { /* * Workaround - Intel wsccmd uses bogus NewWLANEventMAC: @@ -806,6 +1107,7 @@ static int hostapd_rx_req_put_wlan_response( break; } } +#endif /* CONFIG_WPS_STRICT */ if (!sta) { wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); @@ -868,5 +1170,103 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, char *buf, size_t buflen) { + if (hapd->wps == NULL) + return 0; return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); } + + +static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); + hostapd_wps_ap_pin_disable(hapd); +} + + +static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) +{ + wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); + hapd->ap_pin_failures = 0; + hapd->conf->ap_setup_locked = 0; + if (hapd->wps->ap_setup_locked) { + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); + hapd->wps->ap_setup_locked = 0; + wps_registrar_update_ie(hapd->wps->registrar); + } + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + if (timeout > 0) + eloop_register_timeout(timeout, 0, + hostapd_wps_ap_pin_timeout, hapd, NULL); +} + + +static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx) +{ + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = NULL; +#ifdef CONFIG_WPS_UPNP + upnp_wps_set_ap_pin(hapd->wps_upnp, NULL); +#endif /* CONFIG_WPS_UPNP */ + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + return 0; +} + + +void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); + hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL); +} + + +struct wps_ap_pin_data { + char pin_txt[9]; + int timeout; +}; + + +static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) +{ + struct wps_ap_pin_data *data = ctx; + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = os_strdup(data->pin_txt); +#ifdef CONFIG_WPS_UPNP + upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt); +#endif /* CONFIG_WPS_UPNP */ + hostapd_wps_ap_pin_enable(hapd, data->timeout); + return 0; +} + + +const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) +{ + unsigned int pin; + struct wps_ap_pin_data data; + + pin = wps_generate_pin(); + os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin); + data.timeout = timeout; + hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); + return hapd->conf->ap_pin; +} + + +const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) +{ + return hapd->conf->ap_pin; +} + + +int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, + int timeout) +{ + struct wps_ap_pin_data data; + int ret; + + ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin); + if (ret < 0 || ret >= (int) sizeof(data.pin_txt)) + return -1; + data.timeout = timeout; + return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); +}