xref: /freebsd/contrib/wpa/wpa_supplicant/wpas_glue.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
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"
1939beb93cSSam Leffler #include "wpa.h"
2039beb93cSSam Leffler #include "eloop.h"
2139beb93cSSam Leffler #include "config.h"
2239beb93cSSam Leffler #include "l2_packet/l2_packet.h"
2339beb93cSSam Leffler #include "wpa_common.h"
2439beb93cSSam Leffler #include "wpa_supplicant_i.h"
2539beb93cSSam Leffler #include "pmksa_cache.h"
2639beb93cSSam Leffler #include "mlme.h"
2739beb93cSSam Leffler #include "ieee802_11_defs.h"
2839beb93cSSam Leffler #include "wpa_ctrl.h"
2939beb93cSSam Leffler #include "wpas_glue.h"
3039beb93cSSam Leffler #include "wps_supplicant.h"
3139beb93cSSam Leffler 
3239beb93cSSam Leffler 
3339beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS
3439beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
3539beb93cSSam Leffler static void wpa_supplicant_set_config_blob(void *ctx,
3639beb93cSSam Leffler 					   struct wpa_config_blob *blob)
3739beb93cSSam Leffler {
3839beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
3939beb93cSSam Leffler 	wpa_config_set_blob(wpa_s->conf, blob);
4039beb93cSSam Leffler 	if (wpa_s->conf->update_config) {
4139beb93cSSam Leffler 		int ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
4239beb93cSSam Leffler 		if (ret) {
4339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to update config after "
4439beb93cSSam Leffler 				   "blob set");
4539beb93cSSam Leffler 		}
4639beb93cSSam Leffler 	}
4739beb93cSSam Leffler }
4839beb93cSSam Leffler 
4939beb93cSSam Leffler 
5039beb93cSSam Leffler static const struct wpa_config_blob *
5139beb93cSSam Leffler wpa_supplicant_get_config_blob(void *ctx, const char *name)
5239beb93cSSam Leffler {
5339beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
5439beb93cSSam Leffler 	return wpa_config_get_blob(wpa_s->conf, name);
5539beb93cSSam Leffler }
5639beb93cSSam Leffler #endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
5739beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */
5839beb93cSSam Leffler 
5939beb93cSSam Leffler 
6039beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
6139beb93cSSam Leffler static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
6239beb93cSSam Leffler 			    const void *data, u16 data_len,
6339beb93cSSam Leffler 			    size_t *msg_len, void **data_pos)
6439beb93cSSam Leffler {
6539beb93cSSam Leffler 	struct ieee802_1x_hdr *hdr;
6639beb93cSSam Leffler 
6739beb93cSSam Leffler 	*msg_len = sizeof(*hdr) + data_len;
6839beb93cSSam Leffler 	hdr = os_malloc(*msg_len);
6939beb93cSSam Leffler 	if (hdr == NULL)
7039beb93cSSam Leffler 		return NULL;
7139beb93cSSam Leffler 
7239beb93cSSam Leffler 	hdr->version = wpa_s->conf->eapol_version;
7339beb93cSSam Leffler 	hdr->type = type;
7439beb93cSSam Leffler 	hdr->length = host_to_be16(data_len);
7539beb93cSSam Leffler 
7639beb93cSSam Leffler 	if (data)
7739beb93cSSam Leffler 		os_memcpy(hdr + 1, data, data_len);
7839beb93cSSam Leffler 	else
7939beb93cSSam Leffler 		os_memset(hdr + 1, 0, data_len);
8039beb93cSSam Leffler 
8139beb93cSSam Leffler 	if (data_pos)
8239beb93cSSam Leffler 		*data_pos = hdr + 1;
8339beb93cSSam Leffler 
8439beb93cSSam Leffler 	return (u8 *) hdr;
8539beb93cSSam Leffler }
8639beb93cSSam Leffler 
8739beb93cSSam Leffler 
8839beb93cSSam Leffler /**
8939beb93cSSam Leffler  * wpa_ether_send - Send Ethernet frame
9039beb93cSSam Leffler  * @wpa_s: Pointer to wpa_supplicant data
9139beb93cSSam Leffler  * @dest: Destination MAC address
9239beb93cSSam Leffler  * @proto: Ethertype in host byte order
9339beb93cSSam Leffler  * @buf: Frame payload starting from IEEE 802.1X header
9439beb93cSSam Leffler  * @len: Frame payload length
9539beb93cSSam Leffler  * Returns: >=0 on success, <0 on failure
9639beb93cSSam Leffler  */
9739beb93cSSam Leffler static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
9839beb93cSSam Leffler 			  u16 proto, const u8 *buf, size_t len)
9939beb93cSSam Leffler {
10039beb93cSSam Leffler 	if (wpa_s->l2) {
10139beb93cSSam Leffler 		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
10239beb93cSSam Leffler 	}
10339beb93cSSam Leffler 
10439beb93cSSam Leffler 	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
10539beb93cSSam Leffler }
10639beb93cSSam Leffler #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
10739beb93cSSam Leffler 
10839beb93cSSam Leffler 
10939beb93cSSam Leffler #ifdef IEEE8021X_EAPOL
11039beb93cSSam Leffler 
11139beb93cSSam Leffler /**
11239beb93cSSam Leffler  * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
11339beb93cSSam Leffler  * @ctx: Pointer to wpa_supplicant data (wpa_s)
11439beb93cSSam Leffler  * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
11539beb93cSSam Leffler  * @buf: EAPOL payload (after IEEE 802.1X header)
11639beb93cSSam Leffler  * @len: EAPOL payload length
11739beb93cSSam Leffler  * Returns: >=0 on success, <0 on failure
11839beb93cSSam Leffler  *
11939beb93cSSam Leffler  * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
12039beb93cSSam Leffler  * to the current Authenticator.
12139beb93cSSam Leffler  */
12239beb93cSSam Leffler static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
12339beb93cSSam Leffler 				     size_t len)
12439beb93cSSam Leffler {
12539beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
12639beb93cSSam Leffler 	u8 *msg, *dst, bssid[ETH_ALEN];
12739beb93cSSam Leffler 	size_t msglen;
12839beb93cSSam Leffler 	int res;
12939beb93cSSam Leffler 
13039beb93cSSam Leffler 	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
13139beb93cSSam Leffler 	 * extra copy here */
13239beb93cSSam Leffler 
13339beb93cSSam Leffler 	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
13439beb93cSSam Leffler 	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
13539beb93cSSam Leffler 		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
13639beb93cSSam Leffler 		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
13739beb93cSSam Leffler 		 * machines. */
13839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X "
13939beb93cSSam Leffler 			   "mode (type=%d len=%lu)", type,
14039beb93cSSam Leffler 			   (unsigned long) len);
14139beb93cSSam Leffler 		return -1;
14239beb93cSSam Leffler 	}
14339beb93cSSam Leffler 
14439beb93cSSam Leffler 	if (pmksa_cache_get_current(wpa_s->wpa) &&
14539beb93cSSam Leffler 	    type == IEEE802_1X_TYPE_EAPOL_START) {
14639beb93cSSam Leffler 		/* Trying to use PMKSA caching - do not send EAPOL-Start frames
14739beb93cSSam Leffler 		 * since they will trigger full EAPOL authentication. */
14839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
14939beb93cSSam Leffler 			   "EAPOL-Start");
15039beb93cSSam Leffler 		return -1;
15139beb93cSSam Leffler 	}
15239beb93cSSam Leffler 
15339beb93cSSam Leffler 	if (is_zero_ether_addr(wpa_s->bssid)) {
15439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
15539beb93cSSam Leffler 			   "EAPOL frame");
15639beb93cSSam Leffler 		if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
15739beb93cSSam Leffler 		    !is_zero_ether_addr(bssid)) {
15839beb93cSSam Leffler 			dst = bssid;
15939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
16039beb93cSSam Leffler 				   " from the driver as the EAPOL destination",
16139beb93cSSam Leffler 				   MAC2STR(dst));
16239beb93cSSam Leffler 		} else {
16339beb93cSSam Leffler 			dst = wpa_s->last_eapol_src;
16439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Using the source address of the"
16539beb93cSSam Leffler 				   " last received EAPOL frame " MACSTR " as "
16639beb93cSSam Leffler 				   "the EAPOL destination",
16739beb93cSSam Leffler 				   MAC2STR(dst));
16839beb93cSSam Leffler 		}
16939beb93cSSam Leffler 	} else {
17039beb93cSSam Leffler 		/* BSSID was already set (from (Re)Assoc event, so use it as
17139beb93cSSam Leffler 		 * the EAPOL destination. */
17239beb93cSSam Leffler 		dst = wpa_s->bssid;
17339beb93cSSam Leffler 	}
17439beb93cSSam Leffler 
17539beb93cSSam Leffler 	msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
17639beb93cSSam Leffler 	if (msg == NULL)
17739beb93cSSam Leffler 		return -1;
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst));
18039beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
18139beb93cSSam Leffler 	res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
18239beb93cSSam Leffler 	os_free(msg);
18339beb93cSSam Leffler 	return res;
18439beb93cSSam Leffler }
18539beb93cSSam Leffler 
18639beb93cSSam Leffler 
18739beb93cSSam Leffler /**
18839beb93cSSam Leffler  * wpa_eapol_set_wep_key - set WEP key for the driver
18939beb93cSSam Leffler  * @ctx: Pointer to wpa_supplicant data (wpa_s)
19039beb93cSSam Leffler  * @unicast: 1 = individual unicast key, 0 = broadcast key
19139beb93cSSam Leffler  * @keyidx: WEP key index (0..3)
19239beb93cSSam Leffler  * @key: Pointer to key data
19339beb93cSSam Leffler  * @keylen: Key length in bytes
19439beb93cSSam Leffler  * Returns: 0 on success or < 0 on error.
19539beb93cSSam Leffler  */
19639beb93cSSam Leffler static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
19739beb93cSSam Leffler 				 const u8 *key, size_t keylen)
19839beb93cSSam Leffler {
19939beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
20039beb93cSSam Leffler 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
20139beb93cSSam Leffler 		int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 :
20239beb93cSSam Leffler 			WPA_CIPHER_WEP104;
20339beb93cSSam Leffler 		if (unicast)
20439beb93cSSam Leffler 			wpa_s->pairwise_cipher = cipher;
20539beb93cSSam Leffler 		else
20639beb93cSSam Leffler 			wpa_s->group_cipher = cipher;
20739beb93cSSam Leffler 	}
20839beb93cSSam Leffler 	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
20939beb93cSSam Leffler 			       unicast ? wpa_s->bssid :
21039beb93cSSam Leffler 			       (u8 *) "\xff\xff\xff\xff\xff\xff",
21139beb93cSSam Leffler 			       keyidx, unicast, (u8 *) "", 0, key, keylen);
21239beb93cSSam Leffler }
21339beb93cSSam Leffler 
21439beb93cSSam Leffler 
21539beb93cSSam Leffler static void wpa_supplicant_aborted_cached(void *ctx)
21639beb93cSSam Leffler {
21739beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
21839beb93cSSam Leffler 	wpa_sm_aborted_cached(wpa_s->wpa);
21939beb93cSSam Leffler }
22039beb93cSSam Leffler 
22139beb93cSSam Leffler 
22239beb93cSSam Leffler static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
22339beb93cSSam Leffler 				    void *ctx)
22439beb93cSSam Leffler {
22539beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
22639beb93cSSam Leffler 	int res, pmk_len;
22739beb93cSSam Leffler 	u8 pmk[PMK_LEN];
22839beb93cSSam Leffler 
22939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
23039beb93cSSam Leffler 		   success ? "" : "un");
23139beb93cSSam Leffler 
23239beb93cSSam Leffler 	if (wpas_wps_eapol_cb(wpa_s) > 0)
23339beb93cSSam Leffler 		return;
23439beb93cSSam Leffler 
23539beb93cSSam Leffler 	if (!success) {
23639beb93cSSam Leffler 		/*
23739beb93cSSam Leffler 		 * Make sure we do not get stuck here waiting for long EAPOL
23839beb93cSSam Leffler 		 * timeout if the AP does not disconnect in case of
23939beb93cSSam Leffler 		 * authentication failure.
24039beb93cSSam Leffler 		 */
24139beb93cSSam Leffler 		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
24239beb93cSSam Leffler 	}
24339beb93cSSam Leffler 
24439beb93cSSam Leffler 	if (!success || !wpa_s->driver_4way_handshake)
24539beb93cSSam Leffler 		return;
24639beb93cSSam Leffler 
24739beb93cSSam Leffler 	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
24839beb93cSSam Leffler 		return;
24939beb93cSSam Leffler 
25039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
25139beb93cSSam Leffler 		   "handshake");
25239beb93cSSam Leffler 
25339beb93cSSam Leffler 	pmk_len = PMK_LEN;
25439beb93cSSam Leffler 	res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
25539beb93cSSam Leffler 	if (res) {
25639beb93cSSam Leffler 		/*
25739beb93cSSam Leffler 		 * EAP-LEAP is an exception from other EAP methods: it
25839beb93cSSam Leffler 		 * uses only 16-byte PMK.
25939beb93cSSam Leffler 		 */
26039beb93cSSam Leffler 		res = eapol_sm_get_key(eapol, pmk, 16);
26139beb93cSSam Leffler 		pmk_len = 16;
26239beb93cSSam Leffler 	}
26339beb93cSSam Leffler 
26439beb93cSSam Leffler 	if (res) {
26539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
26639beb93cSSam Leffler 			   "machines");
26739beb93cSSam Leffler 		return;
26839beb93cSSam Leffler 	}
26939beb93cSSam Leffler 
27039beb93cSSam Leffler 	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
27139beb93cSSam Leffler 			    pmk_len)) {
27239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
27339beb93cSSam Leffler 	}
27439beb93cSSam Leffler 
27539beb93cSSam Leffler 	wpa_supplicant_cancel_scan(wpa_s);
27639beb93cSSam Leffler 	wpa_supplicant_cancel_auth_timeout(wpa_s);
27739beb93cSSam Leffler 	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
27839beb93cSSam Leffler 
27939beb93cSSam Leffler }
28039beb93cSSam Leffler 
28139beb93cSSam Leffler 
28239beb93cSSam Leffler static void wpa_supplicant_notify_eapol_done(void *ctx)
28339beb93cSSam Leffler {
28439beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
28539beb93cSSam Leffler 	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
28639beb93cSSam Leffler 	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
28739beb93cSSam Leffler 		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
28839beb93cSSam Leffler 	} else {
28939beb93cSSam Leffler 		wpa_supplicant_cancel_auth_timeout(wpa_s);
29039beb93cSSam Leffler 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
29139beb93cSSam Leffler 	}
29239beb93cSSam Leffler }
29339beb93cSSam Leffler 
29439beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */
29539beb93cSSam Leffler 
29639beb93cSSam Leffler 
29739beb93cSSam Leffler #ifndef CONFIG_NO_WPA
29839beb93cSSam Leffler 
29939beb93cSSam Leffler static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
30039beb93cSSam Leffler {
30139beb93cSSam Leffler 	size_t i;
30239beb93cSSam Leffler 	int ret = 0;
30339beb93cSSam Leffler 	struct wpa_scan_res *curr = NULL;
30439beb93cSSam Leffler 	struct wpa_ssid *ssid = wpa_s->current_ssid;
30539beb93cSSam Leffler 	const u8 *ie;
30639beb93cSSam Leffler 
30739beb93cSSam Leffler 	if (wpa_s->scan_res == NULL)
30839beb93cSSam Leffler 		return -1;
30939beb93cSSam Leffler 
31039beb93cSSam Leffler 	for (i = 0; i < wpa_s->scan_res->num; i++) {
31139beb93cSSam Leffler 		struct wpa_scan_res *r = wpa_s->scan_res->res[i];
31239beb93cSSam Leffler 		if (os_memcmp(r->bssid, wpa_s->bssid, ETH_ALEN) != 0)
31339beb93cSSam Leffler 			continue;
31439beb93cSSam Leffler 		ie = wpa_scan_get_ie(r, WLAN_EID_SSID);
31539beb93cSSam Leffler 		if (ssid == NULL ||
31639beb93cSSam Leffler 		    ((ie && ie[1] == ssid->ssid_len &&
31739beb93cSSam Leffler 		      os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) == 0) ||
31839beb93cSSam Leffler 		     ssid->ssid_len == 0)) {
31939beb93cSSam Leffler 			curr = r;
32039beb93cSSam Leffler 			break;
32139beb93cSSam Leffler 		}
32239beb93cSSam Leffler 	}
32339beb93cSSam Leffler 
32439beb93cSSam Leffler 	if (curr) {
32539beb93cSSam Leffler 		ie = wpa_scan_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
32639beb93cSSam Leffler 		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
32739beb93cSSam Leffler 			ret = -1;
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 		ie = wpa_scan_get_ie(curr, WLAN_EID_RSN);
33039beb93cSSam Leffler 		if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
33139beb93cSSam Leffler 			ret = -1;
33239beb93cSSam Leffler 	} else {
33339beb93cSSam Leffler 		ret = -1;
33439beb93cSSam Leffler 	}
33539beb93cSSam Leffler 
33639beb93cSSam Leffler 	return ret;
33739beb93cSSam Leffler }
33839beb93cSSam Leffler 
33939beb93cSSam Leffler 
34039beb93cSSam Leffler static int wpa_supplicant_get_beacon_ie(void *ctx)
34139beb93cSSam Leffler {
34239beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
34339beb93cSSam Leffler 	if (wpa_get_beacon_ie(wpa_s) == 0) {
34439beb93cSSam Leffler 		return 0;
34539beb93cSSam Leffler 	}
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 	/* No WPA/RSN IE found in the cached scan results. Try to get updated
34839beb93cSSam Leffler 	 * scan results from the driver. */
34939beb93cSSam Leffler 	if (wpa_supplicant_get_scan_results(wpa_s) < 0) {
35039beb93cSSam Leffler 		return -1;
35139beb93cSSam Leffler 	}
35239beb93cSSam Leffler 
35339beb93cSSam Leffler 	return wpa_get_beacon_ie(wpa_s);
35439beb93cSSam Leffler }
35539beb93cSSam Leffler 
35639beb93cSSam Leffler 
35739beb93cSSam Leffler static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
35839beb93cSSam Leffler 			     const void *data, u16 data_len,
35939beb93cSSam Leffler 			     size_t *msg_len, void **data_pos)
36039beb93cSSam Leffler {
36139beb93cSSam Leffler 	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
36239beb93cSSam Leffler }
36339beb93cSSam Leffler 
36439beb93cSSam Leffler 
36539beb93cSSam Leffler static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
36639beb93cSSam Leffler 			   const u8 *buf, size_t len)
36739beb93cSSam Leffler {
36839beb93cSSam Leffler 	return wpa_ether_send(wpa_s, dest, proto, buf, len);
36939beb93cSSam Leffler }
37039beb93cSSam Leffler 
37139beb93cSSam Leffler 
37239beb93cSSam Leffler static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
37339beb93cSSam Leffler {
37439beb93cSSam Leffler 	wpa_supplicant_cancel_auth_timeout(wpa_s);
37539beb93cSSam Leffler }
37639beb93cSSam Leffler 
37739beb93cSSam Leffler 
37839beb93cSSam Leffler static void _wpa_supplicant_set_state(void *wpa_s, wpa_states state)
37939beb93cSSam Leffler {
38039beb93cSSam Leffler 	wpa_supplicant_set_state(wpa_s, state);
38139beb93cSSam Leffler }
38239beb93cSSam Leffler 
38339beb93cSSam Leffler 
38439beb93cSSam Leffler /**
38539beb93cSSam Leffler  * wpa_supplicant_get_state - Get the connection state
38639beb93cSSam Leffler  * @wpa_s: Pointer to wpa_supplicant data
38739beb93cSSam Leffler  * Returns: The current connection state (WPA_*)
38839beb93cSSam Leffler  */
38939beb93cSSam Leffler static wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
39039beb93cSSam Leffler {
39139beb93cSSam Leffler 	return wpa_s->wpa_state;
39239beb93cSSam Leffler }
39339beb93cSSam Leffler 
39439beb93cSSam Leffler 
39539beb93cSSam Leffler static wpa_states _wpa_supplicant_get_state(void *wpa_s)
39639beb93cSSam Leffler {
39739beb93cSSam Leffler 	return wpa_supplicant_get_state(wpa_s);
39839beb93cSSam Leffler }
39939beb93cSSam Leffler 
40039beb93cSSam Leffler 
40139beb93cSSam Leffler static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
40239beb93cSSam Leffler {
40339beb93cSSam Leffler 	wpa_supplicant_disassociate(wpa_s, reason_code);
40439beb93cSSam Leffler 	/* Schedule a scan to make sure we continue looking for networks */
40539beb93cSSam Leffler 	wpa_supplicant_req_scan(wpa_s, 0, 0);
40639beb93cSSam Leffler }
40739beb93cSSam Leffler 
40839beb93cSSam Leffler 
40939beb93cSSam Leffler static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
41039beb93cSSam Leffler {
41139beb93cSSam Leffler 	wpa_supplicant_deauthenticate(wpa_s, reason_code);
41239beb93cSSam Leffler 	/* Schedule a scan to make sure we continue looking for networks */
41339beb93cSSam Leffler 	wpa_supplicant_req_scan(wpa_s, 0, 0);
41439beb93cSSam Leffler }
41539beb93cSSam Leffler 
41639beb93cSSam Leffler 
41739beb93cSSam Leffler static void * wpa_supplicant_get_network_ctx(void *wpa_s)
41839beb93cSSam Leffler {
41939beb93cSSam Leffler 	return wpa_supplicant_get_ssid(wpa_s);
42039beb93cSSam Leffler }
42139beb93cSSam Leffler 
42239beb93cSSam Leffler 
42339beb93cSSam Leffler static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
42439beb93cSSam Leffler {
42539beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
42639beb93cSSam Leffler 	if (wpa_s->use_client_mlme) {
42739beb93cSSam Leffler 		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
42839beb93cSSam Leffler 		return 0;
42939beb93cSSam Leffler 	}
43039beb93cSSam Leffler 	return wpa_drv_get_bssid(wpa_s, bssid);
43139beb93cSSam Leffler }
43239beb93cSSam Leffler 
43339beb93cSSam Leffler 
43439beb93cSSam Leffler static int wpa_supplicant_set_key(void *_wpa_s, wpa_alg alg,
43539beb93cSSam Leffler 				  const u8 *addr, int key_idx, int set_tx,
43639beb93cSSam Leffler 				  const u8 *seq, size_t seq_len,
43739beb93cSSam Leffler 				  const u8 *key, size_t key_len)
43839beb93cSSam Leffler {
43939beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = _wpa_s;
44039beb93cSSam Leffler 	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
44139beb93cSSam Leffler 		/* Clear the MIC error counter when setting a new PTK. */
44239beb93cSSam Leffler 		wpa_s->mic_errors_seen = 0;
44339beb93cSSam Leffler 	}
44439beb93cSSam Leffler 	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
44539beb93cSSam Leffler 			       key, key_len);
44639beb93cSSam Leffler }
44739beb93cSSam Leffler 
44839beb93cSSam Leffler 
44939beb93cSSam Leffler static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
45039beb93cSSam Leffler 					     int protection_type,
45139beb93cSSam Leffler 					     int key_type)
45239beb93cSSam Leffler {
45339beb93cSSam Leffler 	return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type,
45439beb93cSSam Leffler 					  key_type);
45539beb93cSSam Leffler }
45639beb93cSSam Leffler 
45739beb93cSSam Leffler 
45839beb93cSSam Leffler static int wpa_supplicant_add_pmkid(void *wpa_s,
45939beb93cSSam Leffler 				    const u8 *bssid, const u8 *pmkid)
46039beb93cSSam Leffler {
46139beb93cSSam Leffler 	return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
46239beb93cSSam Leffler }
46339beb93cSSam Leffler 
46439beb93cSSam Leffler 
46539beb93cSSam Leffler static int wpa_supplicant_remove_pmkid(void *wpa_s,
46639beb93cSSam Leffler 				       const u8 *bssid, const u8 *pmkid)
46739beb93cSSam Leffler {
46839beb93cSSam Leffler 	return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
46939beb93cSSam Leffler }
47039beb93cSSam Leffler 
47139beb93cSSam Leffler 
47239beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
47339beb93cSSam Leffler static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
47439beb93cSSam Leffler 					const u8 *ies, size_t ies_len)
47539beb93cSSam Leffler {
47639beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
47739beb93cSSam Leffler 	if (wpa_s->use_client_mlme)
47839beb93cSSam Leffler 		return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len);
47939beb93cSSam Leffler 	return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
48039beb93cSSam Leffler }
48139beb93cSSam Leffler 
48239beb93cSSam Leffler 
48339beb93cSSam Leffler static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
48439beb93cSSam Leffler 					 const u8 *target_ap,
48539beb93cSSam Leffler 					 const u8 *ies, size_t ies_len)
48639beb93cSSam Leffler {
48739beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
48839beb93cSSam Leffler 	if (wpa_s->use_client_mlme)
48939beb93cSSam Leffler 		return ieee80211_sta_send_ft_action(wpa_s, action, target_ap,
49039beb93cSSam Leffler 						    ies, ies_len);
49139beb93cSSam Leffler 	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
49239beb93cSSam Leffler }
49339beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
49439beb93cSSam Leffler 
49539beb93cSSam Leffler #endif /* CONFIG_NO_WPA */
49639beb93cSSam Leffler 
49739beb93cSSam Leffler 
49839beb93cSSam Leffler #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
49939beb93cSSam Leffler static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
50039beb93cSSam Leffler 					    const char *txt)
50139beb93cSSam Leffler {
50239beb93cSSam Leffler 	struct wpa_supplicant *wpa_s = ctx;
50339beb93cSSam Leffler 	struct wpa_ssid *ssid = wpa_s->current_ssid;
50439beb93cSSam Leffler 	char *buf;
50539beb93cSSam Leffler 	size_t buflen;
50639beb93cSSam Leffler 	int len;
50739beb93cSSam Leffler 
50839beb93cSSam Leffler 	if (ssid == NULL)
50939beb93cSSam Leffler 		return;
51039beb93cSSam Leffler 
51139beb93cSSam Leffler 	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
51239beb93cSSam Leffler 	buf = os_malloc(buflen);
51339beb93cSSam Leffler 	if (buf == NULL)
51439beb93cSSam Leffler 		return;
51539beb93cSSam Leffler 	len = os_snprintf(buf, buflen,
51639beb93cSSam Leffler 			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
51739beb93cSSam Leffler 			  field, ssid->id, txt);
51839beb93cSSam Leffler 	if (len < 0 || (size_t) len >= buflen) {
51939beb93cSSam Leffler 		os_free(buf);
52039beb93cSSam Leffler 		return;
52139beb93cSSam Leffler 	}
52239beb93cSSam Leffler 	if (ssid->ssid && buflen > len + ssid->ssid_len) {
52339beb93cSSam Leffler 		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
52439beb93cSSam Leffler 		len += ssid->ssid_len;
52539beb93cSSam Leffler 		buf[len] = '\0';
52639beb93cSSam Leffler 	}
52739beb93cSSam Leffler 	buf[buflen - 1] = '\0';
52839beb93cSSam Leffler 	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
52939beb93cSSam Leffler 	os_free(buf);
53039beb93cSSam Leffler }
53139beb93cSSam Leffler #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
53239beb93cSSam Leffler #define wpa_supplicant_eap_param_needed NULL
53339beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
53439beb93cSSam Leffler 
53539beb93cSSam Leffler 
53639beb93cSSam Leffler int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
53739beb93cSSam Leffler {
53839beb93cSSam Leffler #ifdef IEEE8021X_EAPOL
53939beb93cSSam Leffler 	struct eapol_ctx *ctx;
54039beb93cSSam Leffler 	ctx = os_zalloc(sizeof(*ctx));
54139beb93cSSam Leffler 	if (ctx == NULL) {
54239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
54339beb93cSSam Leffler 		return -1;
54439beb93cSSam Leffler 	}
54539beb93cSSam Leffler 
54639beb93cSSam Leffler 	ctx->ctx = wpa_s;
54739beb93cSSam Leffler 	ctx->msg_ctx = wpa_s;
54839beb93cSSam Leffler 	ctx->eapol_send_ctx = wpa_s;
54939beb93cSSam Leffler 	ctx->preauth = 0;
55039beb93cSSam Leffler 	ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
55139beb93cSSam Leffler 	ctx->eapol_send = wpa_supplicant_eapol_send;
55239beb93cSSam Leffler 	ctx->set_wep_key = wpa_eapol_set_wep_key;
55339beb93cSSam Leffler 	ctx->set_config_blob = wpa_supplicant_set_config_blob;
55439beb93cSSam Leffler 	ctx->get_config_blob = wpa_supplicant_get_config_blob;
55539beb93cSSam Leffler 	ctx->aborted_cached = wpa_supplicant_aborted_cached;
55639beb93cSSam Leffler #ifdef EAP_TLS_OPENSSL
55739beb93cSSam Leffler 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
55839beb93cSSam Leffler 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
55939beb93cSSam Leffler 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
56039beb93cSSam Leffler #endif /* EAP_TLS_OPENSSL */
56139beb93cSSam Leffler 	ctx->wps = wpa_s->wps;
56239beb93cSSam Leffler 	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
56339beb93cSSam Leffler 	ctx->cb = wpa_supplicant_eapol_cb;
56439beb93cSSam Leffler 	ctx->cb_ctx = wpa_s;
56539beb93cSSam Leffler 	wpa_s->eapol = eapol_sm_init(ctx);
56639beb93cSSam Leffler 	if (wpa_s->eapol == NULL) {
56739beb93cSSam Leffler 		os_free(ctx);
56839beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state "
56939beb93cSSam Leffler 			   "machines.");
57039beb93cSSam Leffler 		return -1;
57139beb93cSSam Leffler 	}
57239beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 	return 0;
57539beb93cSSam Leffler }
57639beb93cSSam Leffler 
57739beb93cSSam Leffler 
57839beb93cSSam Leffler int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
57939beb93cSSam Leffler {
58039beb93cSSam Leffler #ifndef CONFIG_NO_WPA
58139beb93cSSam Leffler 	struct wpa_sm_ctx *ctx;
58239beb93cSSam Leffler 	ctx = os_zalloc(sizeof(*ctx));
58339beb93cSSam Leffler 	if (ctx == NULL) {
58439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
58539beb93cSSam Leffler 		return -1;
58639beb93cSSam Leffler 	}
58739beb93cSSam Leffler 
58839beb93cSSam Leffler 	ctx->ctx = wpa_s;
58939beb93cSSam Leffler 	ctx->set_state = _wpa_supplicant_set_state;
59039beb93cSSam Leffler 	ctx->get_state = _wpa_supplicant_get_state;
59139beb93cSSam Leffler 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
59239beb93cSSam Leffler 	ctx->disassociate = _wpa_supplicant_disassociate;
59339beb93cSSam Leffler 	ctx->set_key = wpa_supplicant_set_key;
59439beb93cSSam Leffler 	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
59539beb93cSSam Leffler 	ctx->get_bssid = wpa_supplicant_get_bssid;
59639beb93cSSam Leffler 	ctx->ether_send = _wpa_ether_send;
59739beb93cSSam Leffler 	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
59839beb93cSSam Leffler 	ctx->alloc_eapol = _wpa_alloc_eapol;
59939beb93cSSam Leffler 	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
60039beb93cSSam Leffler 	ctx->add_pmkid = wpa_supplicant_add_pmkid;
60139beb93cSSam Leffler 	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
60239beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS
60339beb93cSSam Leffler 	ctx->set_config_blob = wpa_supplicant_set_config_blob;
60439beb93cSSam Leffler 	ctx->get_config_blob = wpa_supplicant_get_config_blob;
60539beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */
60639beb93cSSam Leffler 	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
60739beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
60839beb93cSSam Leffler 	ctx->update_ft_ies = wpa_supplicant_update_ft_ies;
60939beb93cSSam Leffler 	ctx->send_ft_action = wpa_supplicant_send_ft_action;
61039beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
61139beb93cSSam Leffler 
61239beb93cSSam Leffler 	wpa_s->wpa = wpa_sm_init(ctx);
61339beb93cSSam Leffler 	if (wpa_s->wpa == NULL) {
61439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
61539beb93cSSam Leffler 			   "machine");
61639beb93cSSam Leffler 		return -1;
61739beb93cSSam Leffler 	}
61839beb93cSSam Leffler #endif /* CONFIG_NO_WPA */
61939beb93cSSam Leffler 
62039beb93cSSam Leffler 	return 0;
62139beb93cSSam Leffler }
62239beb93cSSam Leffler 
62339beb93cSSam Leffler 
62439beb93cSSam Leffler void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
62539beb93cSSam Leffler 					struct wpa_ssid *ssid)
62639beb93cSSam Leffler {
62739beb93cSSam Leffler 	struct rsn_supp_config conf;
62839beb93cSSam Leffler 	if (ssid) {
62939beb93cSSam Leffler 		os_memset(&conf, 0, sizeof(conf));
63039beb93cSSam Leffler 		conf.network_ctx = ssid;
63139beb93cSSam Leffler 		conf.peerkey_enabled = ssid->peerkey;
63239beb93cSSam Leffler 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
63339beb93cSSam Leffler #ifdef IEEE8021X_EAPOL
63439beb93cSSam Leffler 		conf.eap_workaround = ssid->eap_workaround;
63539beb93cSSam Leffler 		conf.eap_conf_ctx = &ssid->eap;
63639beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */
63739beb93cSSam Leffler 		conf.ssid = ssid->ssid;
63839beb93cSSam Leffler 		conf.ssid_len = ssid->ssid_len;
63939beb93cSSam Leffler 		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
64039beb93cSSam Leffler 	}
64139beb93cSSam Leffler 	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
64239beb93cSSam Leffler }
643