xref: /freebsd/contrib/wpa/wpa_supplicant/wpas_glue.c (revision e28a4053b110e06768631ac8401ed4a3c05e68a5)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant - Glue code to setup EAPOL and RSN modules
339beb93cSSam Leffler  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
539beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
639beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
739beb93cSSam Leffler  * published by the Free Software Foundation.
839beb93cSSam Leffler  *
939beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
1039beb93cSSam Leffler  * license.
1139beb93cSSam Leffler  *
1239beb93cSSam Leffler  * See README and COPYING for more details.
1339beb93cSSam Leffler  */
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "includes.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #include "common.h"
1839beb93cSSam Leffler #include "eapol_supp/eapol_supp_sm.h"
19*e28a4053SRui Paulo #include "rsn_supp/wpa.h"
2039beb93cSSam Leffler #include "eloop.h"
2139beb93cSSam Leffler #include "config.h"
2239beb93cSSam Leffler #include "l2_packet/l2_packet.h"
23*e28a4053SRui Paulo #include "common/wpa_common.h"
2439beb93cSSam Leffler #include "wpa_supplicant_i.h"
25*e28a4053SRui Paulo #include "driver_i.h"
26*e28a4053SRui Paulo #include "rsn_supp/pmksa_cache.h"
2739beb93cSSam Leffler #include "mlme.h"
28*e28a4053SRui Paulo #include "sme.h"
29*e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
30*e28a4053SRui Paulo #include "common/wpa_ctrl.h"
3139beb93cSSam Leffler #include "wpas_glue.h"
3239beb93cSSam Leffler #include "wps_supplicant.h"
33*e28a4053SRui Paulo #include "bss.h"
34*e28a4053SRui Paulo #include "scan.h"
3539beb93cSSam Leffler 
3639beb93cSSam Leffler 
3739beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS
3839beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
3939beb93cSSam Leffler static void wpa_supplicant_set_config_blob(void *ctx,
4039beb93cSSam Leffler 					   struct wpa_config_blob *blob)
4139beb93cSSam Leffler {
4239beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
4339beb93cSSam Leffler 	wpa_config_set_blob(wpa_s->conf, blob);
4439beb93cSSam Leffler 	if (wpa_s->conf->update_config) {
4539beb93cSSam Leffler 		int ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
4639beb93cSSam Leffler 		if (ret) {
4739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to update config after "
4839beb93cSSam Leffler 				   "blob set");
4939beb93cSSam Leffler 		}
5039beb93cSSam Leffler 	}
5139beb93cSSam Leffler }
5239beb93cSSam Leffler 
5339beb93cSSam Leffler 
5439beb93cSSam Leffler static const struct wpa_config_blob *
5539beb93cSSam Leffler wpa_supplicant_get_config_blob(void *ctx, const char *name)
5639beb93cSSam Leffler {
5739beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
5839beb93cSSam Leffler 	return wpa_config_get_blob(wpa_s->conf, name);
5939beb93cSSam Leffler }
6039beb93cSSam Leffler #endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
6139beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */
6239beb93cSSam Leffler 
6339beb93cSSam Leffler 
6439beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
6539beb93cSSam Leffler static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
6639beb93cSSam Leffler 			    const void *data, u16 data_len,
6739beb93cSSam Leffler 			    size_t *msg_len, void **data_pos)
6839beb93cSSam Leffler {
6939beb93cSSam Leffler 	struct ieee802_1x_hdr *hdr;
7039beb93cSSam Leffler 
7139beb93cSSam Leffler 	*msg_len = sizeof(*hdr) + data_len;
7239beb93cSSam Leffler 	hdr = os_malloc(*msg_len);
7339beb93cSSam Leffler 	if (hdr == NULL)
7439beb93cSSam Leffler 		return NULL;
7539beb93cSSam Leffler 
7639beb93cSSam Leffler 	hdr->version = wpa_s->conf->eapol_version;
7739beb93cSSam Leffler 	hdr->type = type;
7839beb93cSSam Leffler 	hdr->length = host_to_be16(data_len);
7939beb93cSSam Leffler 
8039beb93cSSam Leffler 	if (data)
8139beb93cSSam Leffler 		os_memcpy(hdr + 1, data, data_len);
8239beb93cSSam Leffler 	else
8339beb93cSSam Leffler 		os_memset(hdr + 1, 0, data_len);
8439beb93cSSam Leffler 
8539beb93cSSam Leffler 	if (data_pos)
8639beb93cSSam Leffler 		*data_pos = hdr + 1;
8739beb93cSSam Leffler 
8839beb93cSSam Leffler 	return (u8 *) hdr;
8939beb93cSSam Leffler }
9039beb93cSSam Leffler 
9139beb93cSSam Leffler 
9239beb93cSSam Leffler /**
9339beb93cSSam Leffler  * wpa_ether_send - Send Ethernet frame
9439beb93cSSam Leffler  * @wpa_s: Pointer to wpa_supplicant data
9539beb93cSSam Leffler  * @dest: Destination MAC address
9639beb93cSSam Leffler  * @proto: Ethertype in host byte order
9739beb93cSSam Leffler  * @buf: Frame payload starting from IEEE 802.1X header
9839beb93cSSam Leffler  * @len: Frame payload length
9939beb93cSSam Leffler  * Returns: >=0 on success, <0 on failure
10039beb93cSSam Leffler  */
10139beb93cSSam Leffler static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
10239beb93cSSam Leffler 			  u16 proto, const u8 *buf, size_t len)
10339beb93cSSam Leffler {
10439beb93cSSam Leffler 	if (wpa_s->l2) {
10539beb93cSSam Leffler 		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
10639beb93cSSam Leffler 	}
10739beb93cSSam Leffler 
10839beb93cSSam Leffler 	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
10939beb93cSSam Leffler }
11039beb93cSSam Leffler #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
11139beb93cSSam Leffler 
11239beb93cSSam Leffler 
11339beb93cSSam Leffler #ifdef IEEE8021X_EAPOL
11439beb93cSSam Leffler 
11539beb93cSSam Leffler /**
11639beb93cSSam Leffler  * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
11739beb93cSSam Leffler  * @ctx: Pointer to wpa_supplicant data (wpa_s)
11839beb93cSSam Leffler  * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
11939beb93cSSam Leffler  * @buf: EAPOL payload (after IEEE 802.1X header)
12039beb93cSSam Leffler  * @len: EAPOL payload length
12139beb93cSSam Leffler  * Returns: >=0 on success, <0 on failure
12239beb93cSSam Leffler  *
12339beb93cSSam Leffler  * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
12439beb93cSSam Leffler  * to the current Authenticator.
12539beb93cSSam Leffler  */
12639beb93cSSam Leffler static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
12739beb93cSSam Leffler 				     size_t len)
12839beb93cSSam Leffler {
12939beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
13039beb93cSSam Leffler 	u8 *msg, *dst, bssid[ETH_ALEN];
13139beb93cSSam Leffler 	size_t msglen;
13239beb93cSSam Leffler 	int res;
13339beb93cSSam Leffler 
13439beb93cSSam Leffler 	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
13539beb93cSSam Leffler 	 * extra copy here */
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
13839beb93cSSam Leffler 	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
13939beb93cSSam Leffler 		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
14039beb93cSSam Leffler 		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
14139beb93cSSam Leffler 		 * machines. */
14239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X "
14339beb93cSSam Leffler 			   "mode (type=%d len=%lu)", type,
14439beb93cSSam Leffler 			   (unsigned long) len);
14539beb93cSSam Leffler 		return -1;
14639beb93cSSam Leffler 	}
14739beb93cSSam Leffler 
14839beb93cSSam Leffler 	if (pmksa_cache_get_current(wpa_s->wpa) &&
14939beb93cSSam Leffler 	    type == IEEE802_1X_TYPE_EAPOL_START) {
15039beb93cSSam Leffler 		/* Trying to use PMKSA caching - do not send EAPOL-Start frames
15139beb93cSSam Leffler 		 * since they will trigger full EAPOL authentication. */
15239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
15339beb93cSSam Leffler 			   "EAPOL-Start");
15439beb93cSSam Leffler 		return -1;
15539beb93cSSam Leffler 	}
15639beb93cSSam Leffler 
15739beb93cSSam Leffler 	if (is_zero_ether_addr(wpa_s->bssid)) {
15839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
15939beb93cSSam Leffler 			   "EAPOL frame");
16039beb93cSSam Leffler 		if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
16139beb93cSSam Leffler 		    !is_zero_ether_addr(bssid)) {
16239beb93cSSam Leffler 			dst = bssid;
16339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
16439beb93cSSam Leffler 				   " from the driver as the EAPOL destination",
16539beb93cSSam Leffler 				   MAC2STR(dst));
16639beb93cSSam Leffler 		} else {
16739beb93cSSam Leffler 			dst = wpa_s->last_eapol_src;
16839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Using the source address of the"
16939beb93cSSam Leffler 				   " last received EAPOL frame " MACSTR " as "
17039beb93cSSam Leffler 				   "the EAPOL destination",
17139beb93cSSam Leffler 				   MAC2STR(dst));
17239beb93cSSam Leffler 		}
17339beb93cSSam Leffler 	} else {
17439beb93cSSam Leffler 		/* BSSID was already set (from (Re)Assoc event, so use it as
17539beb93cSSam Leffler 		 * the EAPOL destination. */
17639beb93cSSam Leffler 		dst = wpa_s->bssid;
17739beb93cSSam Leffler 	}
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
18039beb93cSSam Leffler 	if (msg == NULL)
18139beb93cSSam Leffler 		return -1;
18239beb93cSSam Leffler 
18339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst));
18439beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
18539beb93cSSam Leffler 	res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
18639beb93cSSam Leffler 	os_free(msg);
18739beb93cSSam Leffler 	return res;
18839beb93cSSam Leffler }
18939beb93cSSam Leffler 
19039beb93cSSam Leffler 
19139beb93cSSam Leffler /**
19239beb93cSSam Leffler  * wpa_eapol_set_wep_key - set WEP key for the driver
19339beb93cSSam Leffler  * @ctx: Pointer to wpa_supplicant data (wpa_s)
19439beb93cSSam Leffler  * @unicast: 1 = individual unicast key, 0 = broadcast key
19539beb93cSSam Leffler  * @keyidx: WEP key index (0..3)
19639beb93cSSam Leffler  * @key: Pointer to key data
19739beb93cSSam Leffler  * @keylen: Key length in bytes
19839beb93cSSam Leffler  * Returns: 0 on success or < 0 on error.
19939beb93cSSam Leffler  */
20039beb93cSSam Leffler static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
20139beb93cSSam Leffler 				 const u8 *key, size_t keylen)
20239beb93cSSam Leffler {
20339beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
20439beb93cSSam Leffler 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
20539beb93cSSam Leffler 		int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 :
20639beb93cSSam Leffler 			WPA_CIPHER_WEP104;
20739beb93cSSam Leffler 		if (unicast)
20839beb93cSSam Leffler 			wpa_s->pairwise_cipher = cipher;
20939beb93cSSam Leffler 		else
21039beb93cSSam Leffler 			wpa_s->group_cipher = cipher;
21139beb93cSSam Leffler 	}
21239beb93cSSam Leffler 	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
21339beb93cSSam Leffler 			       unicast ? wpa_s->bssid :
21439beb93cSSam Leffler 			       (u8 *) "\xff\xff\xff\xff\xff\xff",
21539beb93cSSam Leffler 			       keyidx, unicast, (u8 *) "", 0, key, keylen);
21639beb93cSSam Leffler }
21739beb93cSSam Leffler 
21839beb93cSSam Leffler 
21939beb93cSSam Leffler static void wpa_supplicant_aborted_cached(void *ctx)
22039beb93cSSam Leffler {
22139beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
22239beb93cSSam Leffler 	wpa_sm_aborted_cached(wpa_s->wpa);
22339beb93cSSam Leffler }
22439beb93cSSam Leffler 
22539beb93cSSam Leffler 
22639beb93cSSam Leffler static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
22739beb93cSSam Leffler 				    void *ctx)
22839beb93cSSam Leffler {
22939beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
23039beb93cSSam Leffler 	int res, pmk_len;
23139beb93cSSam Leffler 	u8 pmk[PMK_LEN];
23239beb93cSSam Leffler 
23339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
23439beb93cSSam Leffler 		   success ? "" : "un");
23539beb93cSSam Leffler 
23639beb93cSSam Leffler 	if (wpas_wps_eapol_cb(wpa_s) > 0)
23739beb93cSSam Leffler 		return;
23839beb93cSSam Leffler 
23939beb93cSSam Leffler 	if (!success) {
24039beb93cSSam Leffler 		/*
24139beb93cSSam Leffler 		 * Make sure we do not get stuck here waiting for long EAPOL
24239beb93cSSam Leffler 		 * timeout if the AP does not disconnect in case of
24339beb93cSSam Leffler 		 * authentication failure.
24439beb93cSSam Leffler 		 */
24539beb93cSSam Leffler 		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
24639beb93cSSam Leffler 	}
24739beb93cSSam Leffler 
248*e28a4053SRui Paulo 	if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
24939beb93cSSam Leffler 		return;
25039beb93cSSam Leffler 
25139beb93cSSam Leffler 	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
25239beb93cSSam Leffler 		return;
25339beb93cSSam Leffler 
25439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
25539beb93cSSam Leffler 		   "handshake");
25639beb93cSSam Leffler 
25739beb93cSSam Leffler 	pmk_len = PMK_LEN;
25839beb93cSSam Leffler 	res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
25939beb93cSSam Leffler 	if (res) {
26039beb93cSSam Leffler 		/*
26139beb93cSSam Leffler 		 * EAP-LEAP is an exception from other EAP methods: it
26239beb93cSSam Leffler 		 * uses only 16-byte PMK.
26339beb93cSSam Leffler 		 */
26439beb93cSSam Leffler 		res = eapol_sm_get_key(eapol, pmk, 16);
26539beb93cSSam Leffler 		pmk_len = 16;
26639beb93cSSam Leffler 	}
26739beb93cSSam Leffler 
26839beb93cSSam Leffler 	if (res) {
26939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
27039beb93cSSam Leffler 			   "machines");
27139beb93cSSam Leffler 		return;
27239beb93cSSam Leffler 	}
27339beb93cSSam Leffler 
27439beb93cSSam Leffler 	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
27539beb93cSSam Leffler 			    pmk_len)) {
27639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
27739beb93cSSam Leffler 	}
27839beb93cSSam Leffler 
27939beb93cSSam Leffler 	wpa_supplicant_cancel_scan(wpa_s);
28039beb93cSSam Leffler 	wpa_supplicant_cancel_auth_timeout(wpa_s);
28139beb93cSSam Leffler 	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
28239beb93cSSam Leffler 
28339beb93cSSam Leffler }
28439beb93cSSam Leffler 
28539beb93cSSam Leffler 
28639beb93cSSam Leffler static void wpa_supplicant_notify_eapol_done(void *ctx)
28739beb93cSSam Leffler {
28839beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
28939beb93cSSam Leffler 	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
29039beb93cSSam Leffler 	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
29139beb93cSSam Leffler 		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
29239beb93cSSam Leffler 	} else {
29339beb93cSSam Leffler 		wpa_supplicant_cancel_auth_timeout(wpa_s);
29439beb93cSSam Leffler 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
29539beb93cSSam Leffler 	}
29639beb93cSSam Leffler }
29739beb93cSSam Leffler 
29839beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */
29939beb93cSSam Leffler 
30039beb93cSSam Leffler 
30139beb93cSSam Leffler #ifndef CONFIG_NO_WPA
30239beb93cSSam Leffler 
30339beb93cSSam Leffler static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
30439beb93cSSam Leffler {
30539beb93cSSam Leffler 	int ret = 0;
306*e28a4053SRui Paulo 	struct wpa_bss *curr = NULL, *bss;
30739beb93cSSam Leffler 	struct wpa_ssid *ssid = wpa_s->current_ssid;
30839beb93cSSam Leffler 	const u8 *ie;
30939beb93cSSam Leffler 
310*e28a4053SRui Paulo 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
311*e28a4053SRui Paulo 		if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0)
31239beb93cSSam Leffler 			continue;
31339beb93cSSam Leffler 		if (ssid == NULL ||
314*e28a4053SRui Paulo 		    ((bss->ssid_len == ssid->ssid_len &&
315*e28a4053SRui Paulo 		      os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) ||
31639beb93cSSam Leffler 		     ssid->ssid_len == 0)) {
317*e28a4053SRui Paulo 			curr = bss;
31839beb93cSSam Leffler 			break;
31939beb93cSSam Leffler 		}
32039beb93cSSam Leffler 	}
32139beb93cSSam Leffler 
32239beb93cSSam Leffler 	if (curr) {
323*e28a4053SRui Paulo 		ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
32439beb93cSSam Leffler 		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
32539beb93cSSam Leffler 			ret = -1;
32639beb93cSSam Leffler 
327*e28a4053SRui Paulo 		ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
32839beb93cSSam Leffler 		if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
32939beb93cSSam Leffler 			ret = -1;
33039beb93cSSam Leffler 	} else {
33139beb93cSSam Leffler 		ret = -1;
33239beb93cSSam Leffler 	}
33339beb93cSSam Leffler 
33439beb93cSSam Leffler 	return ret;
33539beb93cSSam Leffler }
33639beb93cSSam Leffler 
33739beb93cSSam Leffler 
33839beb93cSSam Leffler static int wpa_supplicant_get_beacon_ie(void *ctx)
33939beb93cSSam Leffler {
34039beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
34139beb93cSSam Leffler 	if (wpa_get_beacon_ie(wpa_s) == 0) {
34239beb93cSSam Leffler 		return 0;
34339beb93cSSam Leffler 	}
34439beb93cSSam Leffler 
34539beb93cSSam Leffler 	/* No WPA/RSN IE found in the cached scan results. Try to get updated
34639beb93cSSam Leffler 	 * scan results from the driver. */
347*e28a4053SRui Paulo 	if (wpa_supplicant_update_scan_results(wpa_s) < 0)
34839beb93cSSam Leffler 		return -1;
34939beb93cSSam Leffler 
35039beb93cSSam Leffler 	return wpa_get_beacon_ie(wpa_s);
35139beb93cSSam Leffler }
35239beb93cSSam Leffler 
35339beb93cSSam Leffler 
35439beb93cSSam Leffler static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
35539beb93cSSam Leffler 			     const void *data, u16 data_len,
35639beb93cSSam Leffler 			     size_t *msg_len, void **data_pos)
35739beb93cSSam Leffler {
35839beb93cSSam Leffler 	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
35939beb93cSSam Leffler }
36039beb93cSSam Leffler 
36139beb93cSSam Leffler 
36239beb93cSSam Leffler static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
36339beb93cSSam Leffler 			   const u8 *buf, size_t len)
36439beb93cSSam Leffler {
36539beb93cSSam Leffler 	return wpa_ether_send(wpa_s, dest, proto, buf, len);
36639beb93cSSam Leffler }
36739beb93cSSam Leffler 
36839beb93cSSam Leffler 
36939beb93cSSam Leffler static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
37039beb93cSSam Leffler {
37139beb93cSSam Leffler 	wpa_supplicant_cancel_auth_timeout(wpa_s);
37239beb93cSSam Leffler }
37339beb93cSSam Leffler 
37439beb93cSSam Leffler 
375*e28a4053SRui Paulo static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state)
37639beb93cSSam Leffler {
37739beb93cSSam Leffler 	wpa_supplicant_set_state(wpa_s, state);
37839beb93cSSam Leffler }
37939beb93cSSam Leffler 
38039beb93cSSam Leffler 
38139beb93cSSam Leffler /**
38239beb93cSSam Leffler  * wpa_supplicant_get_state - Get the connection state
38339beb93cSSam Leffler  * @wpa_s: Pointer to wpa_supplicant data
38439beb93cSSam Leffler  * Returns: The current connection state (WPA_*)
38539beb93cSSam Leffler  */
386*e28a4053SRui Paulo static enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
38739beb93cSSam Leffler {
38839beb93cSSam Leffler 	return wpa_s->wpa_state;
38939beb93cSSam Leffler }
39039beb93cSSam Leffler 
39139beb93cSSam Leffler 
392*e28a4053SRui Paulo static enum wpa_states _wpa_supplicant_get_state(void *wpa_s)
39339beb93cSSam Leffler {
39439beb93cSSam Leffler 	return wpa_supplicant_get_state(wpa_s);
39539beb93cSSam Leffler }
39639beb93cSSam Leffler 
39739beb93cSSam Leffler 
39839beb93cSSam Leffler static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
39939beb93cSSam Leffler {
40039beb93cSSam Leffler 	wpa_supplicant_disassociate(wpa_s, reason_code);
40139beb93cSSam Leffler 	/* Schedule a scan to make sure we continue looking for networks */
4023157ba21SRui Paulo 	wpa_supplicant_req_scan(wpa_s, 5, 0);
40339beb93cSSam Leffler }
40439beb93cSSam Leffler 
40539beb93cSSam Leffler 
40639beb93cSSam Leffler static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
40739beb93cSSam Leffler {
40839beb93cSSam Leffler 	wpa_supplicant_deauthenticate(wpa_s, reason_code);
40939beb93cSSam Leffler 	/* Schedule a scan to make sure we continue looking for networks */
4103157ba21SRui Paulo 	wpa_supplicant_req_scan(wpa_s, 5, 0);
41139beb93cSSam Leffler }
41239beb93cSSam Leffler 
41339beb93cSSam Leffler 
41439beb93cSSam Leffler static void * wpa_supplicant_get_network_ctx(void *wpa_s)
41539beb93cSSam Leffler {
41639beb93cSSam Leffler 	return wpa_supplicant_get_ssid(wpa_s);
41739beb93cSSam Leffler }
41839beb93cSSam Leffler 
41939beb93cSSam Leffler 
42039beb93cSSam Leffler static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
42139beb93cSSam Leffler {
42239beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
423*e28a4053SRui Paulo 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
42439beb93cSSam Leffler 		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
42539beb93cSSam Leffler 		return 0;
42639beb93cSSam Leffler 	}
42739beb93cSSam Leffler 	return wpa_drv_get_bssid(wpa_s, bssid);
42839beb93cSSam Leffler }
42939beb93cSSam Leffler 
43039beb93cSSam Leffler 
431*e28a4053SRui Paulo static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
43239beb93cSSam Leffler 				  const u8 *addr, int key_idx, int set_tx,
43339beb93cSSam Leffler 				  const u8 *seq, size_t seq_len,
43439beb93cSSam Leffler 				  const u8 *key, size_t key_len)
43539beb93cSSam Leffler {
43639beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = _wpa_s;
43739beb93cSSam Leffler 	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
43839beb93cSSam Leffler 		/* Clear the MIC error counter when setting a new PTK. */
43939beb93cSSam Leffler 		wpa_s->mic_errors_seen = 0;
44039beb93cSSam Leffler 	}
44139beb93cSSam Leffler 	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
44239beb93cSSam Leffler 			       key, key_len);
44339beb93cSSam Leffler }
44439beb93cSSam Leffler 
44539beb93cSSam Leffler 
44639beb93cSSam Leffler static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
44739beb93cSSam Leffler 					     int protection_type,
44839beb93cSSam Leffler 					     int key_type)
44939beb93cSSam Leffler {
45039beb93cSSam Leffler 	return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type,
45139beb93cSSam Leffler 					  key_type);
45239beb93cSSam Leffler }
45339beb93cSSam Leffler 
45439beb93cSSam Leffler 
45539beb93cSSam Leffler static int wpa_supplicant_add_pmkid(void *wpa_s,
45639beb93cSSam Leffler 				    const u8 *bssid, const u8 *pmkid)
45739beb93cSSam Leffler {
45839beb93cSSam Leffler 	return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
45939beb93cSSam Leffler }
46039beb93cSSam Leffler 
46139beb93cSSam Leffler 
46239beb93cSSam Leffler static int wpa_supplicant_remove_pmkid(void *wpa_s,
46339beb93cSSam Leffler 				       const u8 *bssid, const u8 *pmkid)
46439beb93cSSam Leffler {
46539beb93cSSam Leffler 	return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
46639beb93cSSam Leffler }
46739beb93cSSam Leffler 
46839beb93cSSam Leffler 
46939beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
47039beb93cSSam Leffler static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
47139beb93cSSam Leffler 					const u8 *ies, size_t ies_len)
47239beb93cSSam Leffler {
47339beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
474*e28a4053SRui Paulo 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
47539beb93cSSam Leffler 		return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len);
476*e28a4053SRui Paulo 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
477*e28a4053SRui Paulo 		return sme_update_ft_ies(wpa_s, md, ies, ies_len);
47839beb93cSSam Leffler 	return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
47939beb93cSSam Leffler }
48039beb93cSSam Leffler 
48139beb93cSSam Leffler 
48239beb93cSSam Leffler static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
48339beb93cSSam Leffler 					 const u8 *target_ap,
48439beb93cSSam Leffler 					 const u8 *ies, size_t ies_len)
48539beb93cSSam Leffler {
48639beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
487*e28a4053SRui Paulo 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
48839beb93cSSam Leffler 		return ieee80211_sta_send_ft_action(wpa_s, action, target_ap,
48939beb93cSSam Leffler 						    ies, ies_len);
49039beb93cSSam Leffler 	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
49139beb93cSSam Leffler }
492*e28a4053SRui Paulo 
493*e28a4053SRui Paulo 
494*e28a4053SRui Paulo static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
495*e28a4053SRui Paulo {
496*e28a4053SRui Paulo 	struct wpa_supplicant *wpa_s = ctx;
497*e28a4053SRui Paulo 	struct wpa_driver_auth_params params;
498*e28a4053SRui Paulo 	struct wpa_bss *bss;
499*e28a4053SRui Paulo 
500*e28a4053SRui Paulo 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
501*e28a4053SRui Paulo 		return -1;
502*e28a4053SRui Paulo 
503*e28a4053SRui Paulo 	bss = wpa_bss_get_bssid(wpa_s, target_ap);
504*e28a4053SRui Paulo 	if (bss == NULL)
505*e28a4053SRui Paulo 		return -1;
506*e28a4053SRui Paulo 
507*e28a4053SRui Paulo 	os_memset(&params, 0, sizeof(params));
508*e28a4053SRui Paulo 	params.bssid = target_ap;
509*e28a4053SRui Paulo 	params.freq = bss->freq;
510*e28a4053SRui Paulo 	params.ssid = bss->ssid;
511*e28a4053SRui Paulo 	params.ssid_len = bss->ssid_len;
512*e28a4053SRui Paulo 	params.auth_alg = WPA_AUTH_ALG_FT;
513*e28a4053SRui Paulo 	params.local_state_change = 1;
514*e28a4053SRui Paulo 	return wpa_drv_authenticate(wpa_s, &params);
515*e28a4053SRui Paulo }
51639beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
51739beb93cSSam Leffler 
51839beb93cSSam Leffler #endif /* CONFIG_NO_WPA */
51939beb93cSSam Leffler 
52039beb93cSSam Leffler 
521*e28a4053SRui Paulo #ifdef IEEE8021X_EAPOL
52239beb93cSSam Leffler #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
52339beb93cSSam Leffler static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
52439beb93cSSam Leffler 					    const char *txt)
52539beb93cSSam Leffler {
52639beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
52739beb93cSSam Leffler 	struct wpa_ssid *ssid = wpa_s->current_ssid;
52839beb93cSSam Leffler 	char *buf;
52939beb93cSSam Leffler 	size_t buflen;
53039beb93cSSam Leffler 	int len;
53139beb93cSSam Leffler 
53239beb93cSSam Leffler 	if (ssid == NULL)
53339beb93cSSam Leffler 		return;
53439beb93cSSam Leffler 
53539beb93cSSam Leffler 	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
53639beb93cSSam Leffler 	buf = os_malloc(buflen);
53739beb93cSSam Leffler 	if (buf == NULL)
53839beb93cSSam Leffler 		return;
53939beb93cSSam Leffler 	len = os_snprintf(buf, buflen,
54039beb93cSSam Leffler 			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
54139beb93cSSam Leffler 			  field, ssid->id, txt);
54239beb93cSSam Leffler 	if (len < 0 || (size_t) len >= buflen) {
54339beb93cSSam Leffler 		os_free(buf);
54439beb93cSSam Leffler 		return;
54539beb93cSSam Leffler 	}
54639beb93cSSam Leffler 	if (ssid->ssid && buflen > len + ssid->ssid_len) {
54739beb93cSSam Leffler 		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
54839beb93cSSam Leffler 		len += ssid->ssid_len;
54939beb93cSSam Leffler 		buf[len] = '\0';
55039beb93cSSam Leffler 	}
55139beb93cSSam Leffler 	buf[buflen - 1] = '\0';
55239beb93cSSam Leffler 	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
55339beb93cSSam Leffler 	os_free(buf);
55439beb93cSSam Leffler }
55539beb93cSSam Leffler #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
55639beb93cSSam Leffler #define wpa_supplicant_eap_param_needed NULL
55739beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
55839beb93cSSam Leffler 
55939beb93cSSam Leffler 
560*e28a4053SRui Paulo static void wpa_supplicant_port_cb(void *ctx, int authorized)
561*e28a4053SRui Paulo {
562*e28a4053SRui Paulo 	struct wpa_supplicant *wpa_s = ctx;
563*e28a4053SRui Paulo #ifdef CONFIG_AP
564*e28a4053SRui Paulo 	if (wpa_s->ap_iface) {
565*e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant "
566*e28a4053SRui Paulo 			   "port status: %s",
567*e28a4053SRui Paulo 			   authorized ? "Authorized" : "Unauthorized");
568*e28a4053SRui Paulo 		return;
569*e28a4053SRui Paulo 	}
570*e28a4053SRui Paulo #endif /* CONFIG_AP */
571*e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s",
572*e28a4053SRui Paulo 		   authorized ? "Authorized" : "Unauthorized");
573*e28a4053SRui Paulo 	wpa_drv_set_supp_port(wpa_s, authorized);
574*e28a4053SRui Paulo }
575*e28a4053SRui Paulo #endif /* IEEE8021X_EAPOL */
576*e28a4053SRui Paulo 
577*e28a4053SRui Paulo 
57839beb93cSSam Leffler int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
57939beb93cSSam Leffler {
58039beb93cSSam Leffler #ifdef IEEE8021X_EAPOL
58139beb93cSSam Leffler 	struct eapol_ctx *ctx;
58239beb93cSSam Leffler 	ctx = os_zalloc(sizeof(*ctx));
58339beb93cSSam Leffler 	if (ctx == NULL) {
58439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
58539beb93cSSam Leffler 		return -1;
58639beb93cSSam Leffler 	}
58739beb93cSSam Leffler 
58839beb93cSSam Leffler 	ctx->ctx = wpa_s;
58939beb93cSSam Leffler 	ctx->msg_ctx = wpa_s;
59039beb93cSSam Leffler 	ctx->eapol_send_ctx = wpa_s;
59139beb93cSSam Leffler 	ctx->preauth = 0;
59239beb93cSSam Leffler 	ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
59339beb93cSSam Leffler 	ctx->eapol_send = wpa_supplicant_eapol_send;
59439beb93cSSam Leffler 	ctx->set_wep_key = wpa_eapol_set_wep_key;
59539beb93cSSam Leffler 	ctx->set_config_blob = wpa_supplicant_set_config_blob;
59639beb93cSSam Leffler 	ctx->get_config_blob = wpa_supplicant_get_config_blob;
59739beb93cSSam Leffler 	ctx->aborted_cached = wpa_supplicant_aborted_cached;
59839beb93cSSam Leffler 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
59939beb93cSSam Leffler 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
60039beb93cSSam Leffler 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
60139beb93cSSam Leffler 	ctx->wps = wpa_s->wps;
60239beb93cSSam Leffler 	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
603*e28a4053SRui Paulo 	ctx->port_cb = wpa_supplicant_port_cb;
60439beb93cSSam Leffler 	ctx->cb = wpa_supplicant_eapol_cb;
60539beb93cSSam Leffler 	ctx->cb_ctx = wpa_s;
60639beb93cSSam Leffler 	wpa_s->eapol = eapol_sm_init(ctx);
60739beb93cSSam Leffler 	if (wpa_s->eapol == NULL) {
60839beb93cSSam Leffler 		os_free(ctx);
60939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state "
61039beb93cSSam Leffler 			   "machines.");
61139beb93cSSam Leffler 		return -1;
61239beb93cSSam Leffler 	}
61339beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */
61439beb93cSSam Leffler 
61539beb93cSSam Leffler 	return 0;
61639beb93cSSam Leffler }
61739beb93cSSam Leffler 
61839beb93cSSam Leffler 
61939beb93cSSam Leffler int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
62039beb93cSSam Leffler {
62139beb93cSSam Leffler #ifndef CONFIG_NO_WPA
62239beb93cSSam Leffler 	struct wpa_sm_ctx *ctx;
62339beb93cSSam Leffler 	ctx = os_zalloc(sizeof(*ctx));
62439beb93cSSam Leffler 	if (ctx == NULL) {
62539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
62639beb93cSSam Leffler 		return -1;
62739beb93cSSam Leffler 	}
62839beb93cSSam Leffler 
62939beb93cSSam Leffler 	ctx->ctx = wpa_s;
630*e28a4053SRui Paulo 	ctx->msg_ctx = wpa_s;
63139beb93cSSam Leffler 	ctx->set_state = _wpa_supplicant_set_state;
63239beb93cSSam Leffler 	ctx->get_state = _wpa_supplicant_get_state;
63339beb93cSSam Leffler 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
63439beb93cSSam Leffler 	ctx->disassociate = _wpa_supplicant_disassociate;
63539beb93cSSam Leffler 	ctx->set_key = wpa_supplicant_set_key;
63639beb93cSSam Leffler 	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
63739beb93cSSam Leffler 	ctx->get_bssid = wpa_supplicant_get_bssid;
63839beb93cSSam Leffler 	ctx->ether_send = _wpa_ether_send;
63939beb93cSSam Leffler 	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
64039beb93cSSam Leffler 	ctx->alloc_eapol = _wpa_alloc_eapol;
64139beb93cSSam Leffler 	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
64239beb93cSSam Leffler 	ctx->add_pmkid = wpa_supplicant_add_pmkid;
64339beb93cSSam Leffler 	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
64439beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS
64539beb93cSSam Leffler 	ctx->set_config_blob = wpa_supplicant_set_config_blob;
64639beb93cSSam Leffler 	ctx->get_config_blob = wpa_supplicant_get_config_blob;
64739beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */
64839beb93cSSam Leffler 	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
64939beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
65039beb93cSSam Leffler 	ctx->update_ft_ies = wpa_supplicant_update_ft_ies;
65139beb93cSSam Leffler 	ctx->send_ft_action = wpa_supplicant_send_ft_action;
652*e28a4053SRui Paulo 	ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
65339beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
65439beb93cSSam Leffler 
65539beb93cSSam Leffler 	wpa_s->wpa = wpa_sm_init(ctx);
65639beb93cSSam Leffler 	if (wpa_s->wpa == NULL) {
65739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
65839beb93cSSam Leffler 			   "machine");
65939beb93cSSam Leffler 		return -1;
66039beb93cSSam Leffler 	}
66139beb93cSSam Leffler #endif /* CONFIG_NO_WPA */
66239beb93cSSam Leffler 
66339beb93cSSam Leffler 	return 0;
66439beb93cSSam Leffler }
66539beb93cSSam Leffler 
66639beb93cSSam Leffler 
66739beb93cSSam Leffler void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
66839beb93cSSam Leffler 					struct wpa_ssid *ssid)
66939beb93cSSam Leffler {
67039beb93cSSam Leffler 	struct rsn_supp_config conf;
67139beb93cSSam Leffler 	if (ssid) {
67239beb93cSSam Leffler 		os_memset(&conf, 0, sizeof(conf));
67339beb93cSSam Leffler 		conf.network_ctx = ssid;
67439beb93cSSam Leffler 		conf.peerkey_enabled = ssid->peerkey;
67539beb93cSSam Leffler 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
67639beb93cSSam Leffler #ifdef IEEE8021X_EAPOL
67739beb93cSSam Leffler 		conf.eap_workaround = ssid->eap_workaround;
67839beb93cSSam Leffler 		conf.eap_conf_ctx = &ssid->eap;
67939beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */
68039beb93cSSam Leffler 		conf.ssid = ssid->ssid;
68139beb93cSSam Leffler 		conf.ssid_len = ssid->ssid_len;
68239beb93cSSam Leffler 		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
68339beb93cSSam Leffler 	}
68439beb93cSSam Leffler 	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
68539beb93cSSam Leffler }
686