ap.c revision 04949598a23f501be6eec21697465fd46a28840a
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - Basic AP mode support routines
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009, Atheros Communications
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/uuid.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/wpa_ctrl.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/hostapd.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/ap_config.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/ap_drv_ops.h"
201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef NEED_AP_MLME
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/ieee802_11.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* NEED_AP_MLME */
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/beacon.h"
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/ieee802_1x.h"
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/wps_hostapd.h"
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/ctrl_iface_ap.h"
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps/wps.h"
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "config_ssid.h"
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "config.h"
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_supplicant_i.h"
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver_i.h"
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p_supplicant.h"
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap.h"
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/sta_info.h"
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "notify.h"
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct wpa_ssid *ssid,
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct hostapd_config *conf)
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_bss_config *bss = &conf->bss[0];
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int pairwise;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->driver = wpa_s->driver;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->frequency == 0) {
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* default channel 11 */
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->channel = 11;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->channel = (ssid->frequency - 2407) / 5;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->channel = (ssid->frequency - 5000) / 5;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ssid->frequency);
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	/* TODO: enable HT40 if driver supports it;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * drop to 11b if driver does not support 11g */
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt#ifdef CONFIG_IEEE80211N
76c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	/*
771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Enable HT20 if the driver supports it, by setting conf->ieee80211n
781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * and a mask of allowed capabilities within conf->ht_capab.
79c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	 * Using default config settings for: conf->ht_op_mode_fixed,
801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * conf->secondary_channel, conf->require_ht
81c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	 */
821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_s->hw.modes) {
83c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		struct hostapd_hw_modes *mode = NULL;
8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		int i, no_ht = 0;
851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		for (i = 0; i < wpa_s->hw.num_modes; i++) {
861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				mode = &wpa_s->hw.modes[i];
88c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt				break;
89c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			}
90c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		}
9104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
9204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_HT_OVERRIDES
9304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (ssid->disable_ht) {
9404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			conf->ieee80211n = 0;
9504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			conf->ht_capab = 0;
9604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			no_ht = 1;
9704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
9804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_HT_OVERRIDES */
9904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
10004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (!no_ht && mode && mode->ht_capab) {
101c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			conf->ieee80211n = 1;
1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/*
1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * white-list capabilities that won't cause issues
1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * to connecting stations, while leaving the current
1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * capabilities intact (currently disabled SMPS).
1071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 */
1081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			conf->ht_capab |= mode->ht_capab &
1091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				(HT_CAP_INFO_GREEN_FIELD |
1101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 HT_CAP_INFO_SHORT_GI20MHZ |
1111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 HT_CAP_INFO_SHORT_GI40MHZ |
1121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 HT_CAP_INFO_RX_STBC_MASK |
1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 HT_CAP_INFO_MAX_AMSDU_SIZE);
1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
115c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
116c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt#endif /* CONFIG_IEEE80211N */
117c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Remove 802.11b rates from supported and basic rate sets */
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int *list = os_malloc(4 * sizeof(int));
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (list) {
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[0] = 60;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[1] = 120;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[2] = 240;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[3] = -1;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->basic_rates = list;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		list = os_malloc(9 * sizeof(int));
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (list) {
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[0] = 60;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[1] = 90;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[2] = 120;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[3] = 180;
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[4] = 240;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[5] = 360;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[6] = 480;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[7] = 540;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			list[8] = -1;
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->supported_rates = list;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->isolate = !wpa_s->conf->p2p_intra_bss;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->ssid_len == 0) {
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->ssid.ssid[ssid->ssid_len] = '\0';
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->ssid.ssid_len = ssid->ssid_len;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->ssid.ssid_set = 1;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid;
15804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ssid->auth_alg)
1601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->auth_algs = ssid->auth_alg;
1611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->wpa = ssid->proto;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->wpa_key_mgmt = ssid->key_mgmt;
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->wpa_pairwise = ssid->pairwise_cipher;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->passphrase) {
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (ssid->psk_set) {
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(bss->ssid.wpa_psk);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss->ssid.wpa_psk == NULL)
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.wpa_psk->group = 1;
1751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		struct hostapd_wep_keys *wep = &bss->ssid.wep;
1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		int i;
1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		for (i = 0; i < NUM_WEP_KEYS; i++) {
1801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (ssid->wep_key_len[i] == 0)
1811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				continue;
1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wep->key[i] = os_malloc(ssid->wep_key_len[i]);
1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wep->key[i] == NULL)
1841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
1851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memcpy(wep->key[i], ssid->wep_key[i],
1861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  ssid->wep_key_len[i]);
1871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wep->len[i] = ssid->wep_key_len[i];
1881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
1891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wep->idx = ssid->wep_tx_keyidx;
1901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wep->keys_set = 1;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (ssid->ap_max_inactivity)
19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		bss->ap_max_inactivity = ssid->ap_max_inactivity;
19504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (ssid->dtim_period)
19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		bss->dtim_period = ssid->dtim_period;
19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Select group cipher based on the enabled pairwise cipher suites */
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pairwise = 0;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->wpa & 1)
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pairwise |= bss->wpa_pairwise;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->wpa & 2) {
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss->rsn_pairwise == 0)
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			bss->rsn_pairwise = bss->wpa_pairwise;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pairwise |= bss->rsn_pairwise;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pairwise & WPA_CIPHER_TKIP)
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->wpa_group = WPA_CIPHER_TKIP;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->wpa_group = WPA_CIPHER_CCMP;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->wpa && bss->ieee802_1x)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.security_policy = SECURITY_WPA;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (bss->wpa)
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.security_policy = SECURITY_WPA_PSK;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (bss->ieee802_1x) {
2181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		int cipher = WPA_CIPHER_NONE;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.wep.default_len = bss->default_wep_key_len;
2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (bss->default_wep_key_len)
2221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			cipher = bss->default_wep_key_len >= 13 ?
2231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->wpa_group = cipher;
2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->wpa_pairwise = cipher;
2261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->rsn_pairwise = cipher;
2271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (bss->ssid.wep.keys_set) {
2281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		int cipher = WPA_CIPHER_WEP40;
2291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (bss->ssid.wep.len[0] >= 13)
2301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			cipher = WPA_CIPHER_WEP104;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.security_policy = SECURITY_STATIC_WEP;
2321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->wpa_group = cipher;
2331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->wpa_pairwise = cipher;
2341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->rsn_pairwise = cipher;
2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->ssid.security_policy = SECURITY_PLAINTEXT;
2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->wpa_group = WPA_CIPHER_NONE;
2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->wpa_pairwise = WPA_CIPHER_NONE;
2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bss->rsn_pairwise = WPA_CIPHER_NONE;
2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Enable WPS by default for open and WPA/WPA2-Personal network, but
2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * require user interaction to actually use it. Only the internal
2461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Registrar is supported.
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    bss->ssid.security_policy != SECURITY_PLAINTEXT)
2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto no_wps;
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_WPS2
2521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
2531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto no_wps; /* WPS2 does not allow WPA/TKIP-only
2551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      * configuration */
2561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_WPS2 */
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->eap_server = 1;
25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!ssid->ignore_broadcast_ssid)
26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		bss->wps_state = 2;
26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->ap_setup_locked = 2;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->config_methods)
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->config_methods = os_strdup(wpa_s->conf->config_methods);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bss->device_type, wpa_s->conf->device_type,
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  WPS_DEV_TYPE_LEN);
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->device_name) {
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->device_name = os_strdup(wpa_s->conf->device_name);
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->friendly_name = os_strdup(wpa_s->conf->device_name);
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->manufacturer)
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->manufacturer = os_strdup(wpa_s->conf->manufacturer);
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->model_name)
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->model_name = os_strdup(wpa_s->conf->model_name);
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->model_number)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->model_number = os_strdup(wpa_s->conf->model_number);
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->serial_number)
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->serial_number = os_strdup(wpa_s->conf->serial_number);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_nil_uuid(wpa_s->conf->uuid))
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(bss->uuid, wpa_s->wps->uuid, WPS_UUID_LEN);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
28404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtno_wps:
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->max_stations &&
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_s->max_stations < wpa_s->conf->max_num_sta)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->max_num_sta = wpa_s->max_stations;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->max_num_sta = wpa_s->conf->max_num_sta;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t hdr_len;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) buf;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr_len > len)
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   mgmt->u.action.category,
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   &mgmt->u.action.u.vs_public_action.action,
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   len - hdr_len, freq);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_wps_event_cb(void *ctx, enum wps_event event,
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    union wps_event_data *data)
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (event == WPS_EV_FAIL) {
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_event_fail *fail = &data->fail;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (wpa_s->parent && wpa_s->parent != wpa_s &&
32975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		    wpa_s == wpa_s->global->p2p_group_formation) {
33075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			/*
33175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			 * src/ap/wps_hostapd.c has already sent this on the
33275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			 * main interface, so only send on the parent interface
33375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			 * here if needed.
33475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			 */
33575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
33675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				"msg=%d config_error=%d",
33775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				fail->msg, fail->config_error);
33875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
33975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpas_p2p_wps_failed(wpa_s, fail);
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 int authorized, const u8 *p2p_dev_addr)
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr);
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t hdr_len;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) buf;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr_len > len)
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   mgmt->u.action.category,
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   &mgmt->u.action.u.vs_public_action.action,
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   len - hdr_len, freq);
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
37304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   const u8 *bssid, const u8 *ie, size_t ie_len,
37404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   int ssi_signal)
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
37804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
37904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				     ssi_signal);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_P2P */
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *uuid_e)
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_p2p_wps_success(wpa_s, mac_addr, 1);
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpas_ap_configured_cb(void *ctx)
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_configured_cb)
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					wpa_s->ap_configured_cb_data);
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     struct wpa_ssid *ssid)
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_associate_params params;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_iface *hapd_iface;
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_config *conf;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->ssid == NULL || ssid->ssid_len == 0) {
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_ap_deinit(wpa_s);
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')",
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&params, 0, sizeof(params));
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.ssid = ssid->ssid;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.ssid_len = ssid->ssid_len;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (ssid->mode) {
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPAS_MODE_INFRA:
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.mode = IEEE80211_MODE_INFRA;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPAS_MODE_IBSS:
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.mode = IEEE80211_MODE_IBSS;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPAS_MODE_AP:
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPAS_MODE_P2P_GO:
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPAS_MODE_P2P_GROUP_FORMATION:
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.mode = IEEE80211_MODE_AP;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.freq = ssid->frequency;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.wpa_proto = ssid->proto;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else {
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "cipher.");
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params.group_suite = params.pairwise_suite;
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->mode == WPAS_MODE_P2P_GO ||
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.p2p = 1;
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->parent->set_ap_uapsd)
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.uapsd = wpa_s->parent->ap_uapsd;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params.uapsd = -1;
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_drv_associate(wpa_s, &params) < 0) {
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd_iface == NULL)
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd_iface->owner = wpa_s;
4851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	hapd_iface->drv_flags = wpa_s->drv_flags;
4861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf == NULL) {
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_ap_deinit(wpa_s);
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params.uapsd > 0) {
4951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		conf->bss->wmm_enabled = 1;
4961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		conf->bss->wmm_uapsd = 1;
4971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to create AP configuration");
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_ap_deinit(wpa_s);
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->mode == WPAS_MODE_P2P_GO)
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			P2P_GROUP_FORMATION;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd_iface->num_bss = conf->num_bss;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd_iface->bss = os_zalloc(conf->num_bss *
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    sizeof(struct hostapd_data *));
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd_iface->bss == NULL) {
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_ap_deinit(wpa_s);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < conf->num_bss; i++) {
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i] =
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hostapd_alloc_bss_data(hapd_iface, conf,
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       &conf->bss[i]);
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (hapd_iface->bss[i] == NULL) {
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_supplicant_ap_deinit(wpa_s);
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->msg_ctx = wpa_s;
531497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt		hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->vendor_action_cb_ctx = wpa_s;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hostapd_register_probereq_cb(hapd_iface->bss[i],
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     ap_probe_req_rx, wpa_s);
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s;
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->wps_event_cb = ap_wps_event_cb;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->wps_event_cb_ctx = wpa_s;
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
54604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
54704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt								    ssid);
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd_iface->bss[0]->driver = wpa_s->driver;
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->current_ssid = ssid;
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->assoc_freq = ssid->frequency;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hostapd_setup_interface(wpa_s->ap_iface)) {
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_ap_deinit(wpa_s);
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->current_ssid = NULL;
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->assoc_freq = 0;
582c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	wpa_s->reassociated_connection = 0;
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface->bss)
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_s->ap_iface->bss[0]->p2p_group = NULL;
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_p2p_group_deinit(wpa_s);
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_interface_deinit(wpa_s->ap_iface);
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_interface_free(wpa_s->ap_iface);
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_s->ap_iface = NULL;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_drv_deinit_ap(wpa_s);
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_tx_status(void *ctx, const u8 *addr,
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  const u8 *buf, size_t len, int ack)
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef NEED_AP_MLME
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_tx_status(wpa_s->ap_iface->bss[0], addr, buf, len, ack);
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* NEED_AP_MLME */
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid ap_eapol_tx_status(void *ctx, const u8 *dst,
6061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			const u8 *data, size_t len, int ack)
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef NEED_AP_MLME
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
6101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
6111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* NEED_AP_MLME */
6121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid ap_client_poll_ok(void *ctx, const u8 *addr)
6161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef NEED_AP_MLME
6181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
6191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_s->ap_iface)
6201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr);
6211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* NEED_AP_MLME */
6221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds)
6261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef NEED_AP_MLME
6281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
6291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], addr, wds);
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* NEED_AP_MLME */
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt)
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef NEED_AP_MLME
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_frame_info fi;
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&fi, 0, sizeof(fi));
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fi.datarate = rx_mgmt->datarate;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fi.ssi_signal = rx_mgmt->ssi_signal;
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ieee802_11_mgmt(wpa_s->ap_iface->bss[0], rx_mgmt->frame,
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rx_mgmt->frame_len, &fi);
6441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* NEED_AP_MLME */
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok)
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef NEED_AP_MLME
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ieee802_11_mgmt_cb(wpa_s->ap_iface->bss[0], buf, len, stype, ok);
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* NEED_AP_MLME */
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *src_addr, const u8 *buf, size_t len)
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len);
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *p2p_dev_addr)
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_s->ap_iface)
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0],
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 p2p_dev_addr);
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg;
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int reg_sel = 0, wps_sta = 0;
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps)
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg = wpa_s->ap_iface->bss[0]->wps->registrar;
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg_sel = wps_registrar_wps_cancel(reg);
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
68704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  ap_sta_wps_cancel, NULL);
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!reg_sel && !wps_sta) {
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "time");
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * There are 2 cases to return wps cancel as success:
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 1. When wps cancel was initiated but no connection has been
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *    established with client yet.
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 2. Client is in the middle of exchanging WPS messages.
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const char *pin, char *buf, size_t buflen)
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret, ret_len = 0;
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_s->ap_iface)
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pin == NULL) {
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		unsigned int rpin = wps_generate_pin();
7161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret_len = os_snprintf(buf, buflen, "%08d", rpin);
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin = buf;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret_len = os_snprintf(buf, buflen, "%s", pin);
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  0);
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret_len;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = eloop_data;
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_wps_ap_pin_disable(wpa_s);
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpas_wps_ap_pin_enable(struct wpa_supplicant *wpa_s, int timeout)
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->ap_pin_failures = 0;
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (timeout > 0)
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(timeout, 0,
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       wpas_wps_ap_pin_timeout, wpa_s, NULL);
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s)
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hapd->conf->ap_pin);
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->conf->ap_pin = NULL;
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int pin;
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char pin_txt[9];
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pin = wps_generate_pin();
7771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hapd->conf->ap_pin);
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->conf->ap_pin = os_strdup(pin_txt);
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->ap_pin == NULL)
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_wps_ap_pin_enable(wpa_s, timeout);
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hapd->conf->ap_pin;
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s)
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hapd->conf->ap_pin;
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int timeout)
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char pin_txt[9];
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || ret >= (int) sizeof(pin_txt))
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hapd->conf->ap_pin);
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->conf->ap_pin = os_strdup(pin_txt);
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->ap_pin == NULL)
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpas_wps_ap_pin_enable(wpa_s, timeout);
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Registrar failed to prove its knowledge of the AP PIN. Disable AP
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PIN if this happens multiple times to slow down brute force attacks.
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->ap_pin_failures++;
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   hapd->ap_pin_failures);
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->ap_pin_failures < 3)
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN");
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->ap_pin_failures = 0;
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hapd->conf->ap_pin);
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->conf->ap_pin = NULL;
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    char *buf, size_t buflen)
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0],
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    buf, buflen);
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      char *buf, size_t buflen)
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr,
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      buf, buflen);
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   char *buf, size_t buflen)
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr,
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   buf, buflen);
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
88104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   const char *txtaddr)
88204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
88304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpa_s->ap_iface == NULL)
88404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
88504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return hostapd_ctrl_iface_disassociate(wpa_s->ap_iface->bss[0],
88604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					       txtaddr);
88704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
88804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
88904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
89004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
89104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				     const char *txtaddr)
89204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
89304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wpa_s->ap_iface == NULL)
89404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
89504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return hostapd_ctrl_iface_deauthenticate(wpa_s->ap_iface->bss[0],
89604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt						 txtaddr);
89704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
89804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
89904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 size_t buflen, int verbose)
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos = buf, *end = buf + buflen;
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_bss_config *conf;
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->ap_iface == NULL)
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf = wpa_s->ap_iface->bss[0]->conf;
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf->wpa == 0)
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(pos, end - pos,
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "pairwise_cipher=%s\n"
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "group_cipher=%s\n"
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "key_mgmt=%s\n",
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wpa_cipher_txt(conf->rsn_pairwise),
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wpa_cipher_txt(conf->wpa_group),
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wpa_key_mgmt_txt(conf->wpa_key_mgmt,
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   conf->wpa));
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || ret >= end - pos)
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return pos - buf;
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ret;
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pos - buf;
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE */
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_iface *iface = wpa_s->ap_iface;
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ssid *ssid = wpa_s->current_ssid;
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ssid == NULL || wpa_s->ap_iface == NULL ||
9381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    ssid->mode == WPAS_MODE_INFRA ||
9391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    ssid->mode == WPAS_MODE_IBSS)
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid->mode == WPAS_MODE_P2P_GO)
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			P2P_GROUP_FORMATION;
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = iface->bss[0];
9511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (hapd->drv_priv == NULL)
9521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
9531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ieee802_11_set_beacons(iface);
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_set_ap_wps_ie(hapd);
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
96104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		       int offset)
96204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
96304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!wpa_s->ap_iface)
96404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
96504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
96604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_s->assoc_freq = freq;
96704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
96804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
96904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
97004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const u8 *addr)
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd;
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_bss_config *conf;
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_s->ap_iface)
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AP: Set MAC address filter: " MACSTR,
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(addr));
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AP: Clear MAC address filter");
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd = wpa_s->ap_iface->bss[0];
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf = hapd->conf;
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conf->accept_mac);
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->accept_mac = NULL;
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->num_accept_mac = 0;
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conf->deny_mac);
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->deny_mac = NULL;
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->num_deny_mac = 0;
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr == NULL) {
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conf->macaddr_acl = ACCEPT_UNLESS_DENIED;
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->macaddr_acl = DENY_UNLESS_ACCEPTED;
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->accept_mac = os_zalloc(sizeof(struct mac_acl_entry));
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf->accept_mac == NULL)
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(conf->accept_mac[0].addr, addr, ETH_ALEN);
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf->num_accept_mac = 1;
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1010