18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_supplicant - IBSS RSN
3b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
12b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt#include "common/wpa_ctrl.h"
1392c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt#include "utils/eloop.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "l2_packet/l2_packet.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rsn_supp/wpa.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rsn_supp/wpa_ie.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap/wpa_auth.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_supplicant_i.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver_i.h"
20c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt#include "common/ieee802_11_defs.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ibss_rsn.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2492c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidtstatic void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx);
2592c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt
2692c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt
27c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
28c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt						const u8 *addr)
29c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
30c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct ibss_rsn_peer *peer;
31c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
32c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	for (peer = ibss_rsn->peers; peer; peer = peer->next)
33c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0)
34c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			break;
35c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return peer;
36c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
37c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
38c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ibss_rsn_free(struct ibss_rsn_peer *peer)
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4192c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_auth_sta_deinit(peer->auth);
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_deinit(peer->supp);
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(peer);
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void supp_set_state(void *ctx, enum wpa_states state)
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer = ctx;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	peer->supp_state = state;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wpa_states supp_get_state(void *ctx)
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer = ctx;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return peer->supp_state;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   size_t len)
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer = ctx;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "len=%lu)",
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(dest), proto, (unsigned long) len);
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->l2)
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     u16 data_len, size_t *msg_len, void **data_pos)
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee802_1x_hdr *hdr;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, type, data_len);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*msg_len = sizeof(*hdr) + data_len;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = os_malloc(*msg_len);
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr == NULL)
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->version = 2;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->type = type;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->length = host_to_be16(data_len);
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data)
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(hdr + 1, data, data_len);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(hdr + 1, 0, data_len);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data_pos)
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*data_pos = hdr + 1;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (u8 *) hdr;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int supp_get_beacon_ie(void *ctx)
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer = ctx;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: get correct RSN IE */
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_sm_set_ap_rsn_ie(peer->supp,
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    (u8 *) "\x30\x14\x01\x00"
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "\x00\x0f\xac\x04"
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "\x01\x00\x00\x0f\xac\x04"
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "\x01\x00\x00\x0f\xac\x02"
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "\x00\x00", 22);
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
123b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
124b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
125b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
126b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
127b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if ((peer->authentication_status &
128b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	     (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) !=
129b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	    (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH))
130b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
131b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (peer->authentication_status & IBSS_RSN_REPORTED_PTK)
132b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
133b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	peer->authentication_status |= IBSS_RSN_REPORTED_PTK;
134b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR,
135b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		MAC2STR(peer->addr));
136b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
137b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
138b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int supp_set_key(void *ctx, enum wpa_alg alg,
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const u8 *addr, int key_idx, int set_tx,
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const u8 *seq, size_t seq_len,
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const u8 *key, size_t key_len)
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer = ctx;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "set_tx=%d)",
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, alg, MAC2STR(addr), key_idx, set_tx);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key_idx == 0) {
153b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP;
154b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		ibss_check_rsn_completed(peer);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * In IBSS RSN, the pairwise key from the 4-way handshake
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * initiated by the peer with highest MAC address is used.
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr,
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      ETH_ALEN) > 0) {
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK");
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_broadcast_ether_addr(addr))
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		addr = peer->addr;
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       set_tx, seq, seq_len, key, key_len);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * supp_get_network_ctx(void *ctx)
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer = ctx;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int supp_mlme_setprotection(void *ctx, const u8 *addr,
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   int protection_type, int key_type)
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "key_type=%d)",
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(addr), protection_type, key_type);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void supp_cancel_auth_timeout(void *ctx)
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void supp_deauthenticate(void * ctx, int reason_code)
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      const u8 *psk)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ctx == NULL)
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->ctx = peer;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->msg_ctx = peer->ibss_rsn->wpa_s;
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->set_state = supp_set_state;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->get_state = supp_get_state;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->ether_send = supp_ether_send;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->get_beacon_ie = supp_get_beacon_ie;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->alloc_eapol = supp_alloc_eapol;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->set_key = supp_set_key;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->get_network_ctx = supp_get_network_ctx;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->mlme_setprotection = supp_mlme_setprotection;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ctx->deauthenticate = supp_deauthenticate;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	peer->supp = wpa_sm_init(ctx);
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (peer->supp == NULL) {
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_own_addr(peer->supp, own_addr);
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1);
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_set_pmk(peer->supp, psk, PMK_LEN);
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	peer->supp_ie_len = sizeof(peer->supp_ie);
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    &peer->supp_ie_len) < 0) {
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " failed");
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_sm_notify_assoc(peer->supp, peer->addr);
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void auth_logger(void *ctx, const u8 *addr, logger_level level,
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const char *txt)
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(addr), txt);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
260391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidtstatic const u8 * auth_get_psk(void *ctx, const u8 *addr,
261391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt			       const u8 *p2p_dev_addr, const u8 *prev_psk)
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn *ibss_rsn = ctx;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(addr), prev_psk);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (prev_psk)
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ibss_rsn->psk;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   size_t data_len, int encrypt)
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn *ibss_rsn = ctx;
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "encrypt=%d)",
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->l2)
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      data_len);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const u8 *addr, int idx, u8 *key, size_t key_len)
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn *ibss_rsn = ctx;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 seq[6];
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(seq, 0, sizeof(seq));
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr) {
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " key_idx=%d)",
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, alg, MAC2STR(addr), idx);
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, alg, idx);
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (idx == 0) {
309b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		if (addr) {
310b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			struct ibss_rsn_peer *peer;
311b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			peer = ibss_rsn_get_peer(ibss_rsn, addr);
312b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			if (peer) {
313b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt				peer->authentication_status |=
314b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt					IBSS_RSN_SET_PTK_AUTH;
315b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt				ibss_check_rsn_completed(peer);
316b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			}
317b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		}
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * In IBSS RSN, the pairwise key from the 4-way handshake
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * initiated by the peer with highest MAC address is used.
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (addr == NULL ||
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) {
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK");
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       1, seq, 6, key, key_len);
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason)
33534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
33634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct ibss_rsn *ibss_rsn = ctx;
33734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason);
33834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
33934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
34034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  void *ctx),
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     void *cb_ctx)
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn *ibss_rsn = ctx;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "AUTH: for_each_sta");
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (peer = ibss_rsn->peers; peer; peer = peer->next) {
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (peer->auth && cb(peer->auth, cb_ctx))
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
359c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn,
360c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				    struct ibss_rsn_peer *peer, int authorized)
361c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
362c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	int res;
363c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
364c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (authorized) {
365c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr,
366c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					    WPA_STA_AUTHORIZED,
367c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					    WPA_STA_AUTHORIZED, ~0);
368c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port",
369c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   MAC2STR(peer->addr));
370c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	} else {
371c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr,
372c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					    0, 0, ~WPA_STA_AUTHORIZED);
373c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port",
374c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   MAC2STR(peer->addr));
375c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
376c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
377c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (res && errno != ENOENT) {
378c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags "
379c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   "for kernel driver (errno=%d)",
380c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   MAC2STR(peer->addr), errno);
381c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
382c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
383c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
384c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
385c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtstatic void auth_set_eapol(void *ctx, const u8 *addr,
386c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				       wpa_eapol_variable var, int value)
387c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{
388c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct ibss_rsn *ibss_rsn = ctx;
389c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr);
390c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
391c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (peer == NULL)
392c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return;
393c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
394c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	switch (var) {
395c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	case WPA_EAPOL_authorized:
396c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		ibss_set_sta_authorized(ibss_rsn, peer, value);
397c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		break;
398c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	default:
399c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		/* do not handle any other event */
400c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var);
401c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		break;
402c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
403c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
404c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
405c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *own_addr)
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_auth_config conf;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_auth_callbacks cb;
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&conf, 0, sizeof(conf));
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.wpa = 2;
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.wpa_pairwise = WPA_CIPHER_CCMP;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.rsn_pairwise = WPA_CIPHER_CCMP;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.wpa_group = WPA_CIPHER_CCMP;
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.eapol_version = 2;
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.wpa_group_rekey = 600;
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&cb, 0, sizeof(cb));
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb.ctx = ibss_rsn;
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb.logger = auth_logger;
426c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	cb.set_eapol = auth_set_eapol;
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb.send_eapol = auth_send_eapol;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb.get_psk = auth_get_psk;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb.set_key = auth_set_key;
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb.for_each_sta = auth_for_each_sta;
43134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	cb.disconnect = ibss_rsn_disconnect;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn->auth_group == NULL) {
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_init_keys(ibss_rsn->auth_group);
4401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct ibss_rsn_peer *peer)
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
448391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt	peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr, NULL);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (peer->auth == NULL) {
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: get peer RSN IE with Probe Request */
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth,
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				(u8 *) "\x30\x14\x01\x00"
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"\x00\x0f\xac\x04"
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"\x01\x00\x00\x0f\xac\x04"
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"\x01\x00\x00\x0f\xac\x02"
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"\x00\x00", 22, NULL, 0) !=
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WPA_IE_OK) {
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_auth_sm_event(peer->auth, WPA_ASSOC))
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth))
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
476c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtstatic int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
478c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	struct ieee80211_mgmt auth;
479c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
480c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
482c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (wpa_s->driver->send_frame == NULL)
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
485c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	os_memset(&auth, 0, sizeof(auth));
486c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
487c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
488c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt					  WLAN_FC_STYPE_AUTH);
489c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	os_memcpy(auth.da, da, ETH_ALEN);
490c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN);
491c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN);
492c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
493c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN);
494c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	auth.u.auth.auth_transaction = host_to_le16(seq);
495c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
496c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
497c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
498c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		   seq, MAC2STR(da));
499c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
500c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
501c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt					 auth_length, 0);
502c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt}
503c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
504c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
505c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtstatic int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer)
506c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt{
507c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	return peer->authentication_status &
508c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	       (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US);
509c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt}
510c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
511c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
512c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtstatic struct ibss_rsn_peer *
513c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr)
514c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt{
515c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	struct ibss_rsn_peer *peer;
516c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (ibss_rsn == NULL)
517c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return NULL;
518c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
519c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer = ibss_rsn_get_peer(ibss_rsn, addr);
520c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (peer) {
521c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR
522c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   " already running", MAC2STR(addr));
523c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return peer;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
526c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR,
527c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		   MAC2STR(addr));
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	peer = os_zalloc(sizeof(*peer));
530c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (peer == NULL) {
531c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory.");
532c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return NULL;
533c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	}
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	peer->ibss_rsn = ibss_rsn;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(peer->addr, addr, ETH_ALEN);
537c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
539c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr,
540c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			       ibss_rsn->psk) < 0) {
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ibss_rsn_free(peer);
542c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return NULL;
543c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	}
544c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
545c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer->next = ibss_rsn->peers;
546c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	ibss_rsn->peers = peer;
547c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
548c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	return peer;
549c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt}
550c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
551c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
55292c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidtstatic void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx)
55392c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt{
55492c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	struct ibss_rsn_peer *peer = eloop_ctx;
55592c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt
55692c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	/*
55792c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	 * Assume peer does not support Authentication exchange or the frame was
55892c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	 * lost somewhere - start EAPOL Authenticator.
55992c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	 */
56092c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	wpa_printf(MSG_DEBUG,
56192c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		   "RSN: Timeout on waiting Authentication frame response from "
56292c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		   MACSTR " - start authenticator", MAC2STR(peer->addr));
56392c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt
56492c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
56592c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	ibss_rsn_auth_init(peer->ibss_rsn, peer);
56692c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt}
56792c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt
56892c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt
569c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtint ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
570c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt{
571c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	struct ibss_rsn_peer *peer;
572c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	int res;
573c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
574c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	/* if the peer already exists, exit immediately */
575c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer = ibss_rsn_get_peer(ibss_rsn, addr);
576c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (peer)
577c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return 0;
578c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
579c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer = ibss_rsn_peer_init(ibss_rsn, addr);
580c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (peer == NULL)
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
582c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
583c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	/* Open Authentication: send first Authentication frame */
584c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	res = ibss_rsn_send_auth(ibss_rsn, addr, 1);
585c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (res) {
586c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		/*
587c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * The driver may not support Authentication frame exchange in
588c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * IBSS. Ignore authentication and go through EAPOL exchange.
589c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 */
590c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
591c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return ibss_rsn_auth_init(ibss_rsn, peer);
59292c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt	} else {
59392c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		os_get_time(&peer->own_auth_tx);
59492c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL);
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
597c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	return 0;
598c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt}
599c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
600c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
601c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtstatic int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn,
602c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				       struct ibss_rsn_peer *peer, int reason)
603c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt{
604c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	int already_started;
605c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
606c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (ibss_rsn == NULL || peer == NULL)
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
608c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
609c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	already_started = ibss_rsn_is_auth_started(peer);
610c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer->authentication_status |= reason;
611c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
612c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (already_started) {
613c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already "
614c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   "started for peer " MACSTR, MAC2STR(peer->addr));
615c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return 0;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
619c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		   "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
621c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	return ibss_rsn_auth_init(ibss_rsn, peer);
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer, *prev;
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn == NULL)
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (peermac == NULL) {
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* remove all peers */
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__);
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		peer = ibss_rsn->peers;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (peer) {
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			prev = peer;
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			peer = peer->next;
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ibss_rsn_free(prev);
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ibss_rsn->peers = peer;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* remove specific peer */
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR,
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, MAC2STR(peermac));
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (prev = NULL, peer = ibss_rsn->peers; peer != NULL;
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     prev = peer, peer = peer->next) {
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) {
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (prev == NULL)
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					ibss_rsn->peers = peer->next;
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				else
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					prev->next = peer->next;
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ibss_rsn_free(peer);
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "%s: Successfully "
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "removed a specific peer",
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   __func__);
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn *ibss_rsn;
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ibss_rsn = os_zalloc(sizeof(*ibss_rsn));
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn == NULL)
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ibss_rsn->wpa_s = wpa_s;
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ibss_rsn_deinit(ibss_rsn);
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ibss_rsn;
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ibss_rsn_deinit(struct ibss_rsn *ibss_rsn)
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer, *prev;
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn == NULL)
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	peer = ibss_rsn->peers;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (peer) {
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = peer;
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		peer = peer->next;
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ibss_rsn_free(prev);
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_deinit(ibss_rsn->auth_group);
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ibss_rsn);
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len)
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee802_1x_hdr *hdr;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct wpa_eapol_key *key;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 key_info;
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t plen;
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: Support other EAPOL packets than just EAPOL-Key */
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < sizeof(*hdr) + sizeof(*key))
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct ieee802_1x_hdr *) buf;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key = (const struct wpa_eapol_key *) (hdr + 1);
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = be_to_host16(hdr->length);
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->version < EAPOL_VERSION) {
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: backwards compatibility */
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, "
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"not a Key frame", hdr->type);
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu "
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "invalid (frame size %lu)",
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) plen, (unsigned long) len);
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key->type != EAPOL_KEY_TYPE_RSN) {
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, "
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "discarded", key->type);
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key_info = WPA_GET_BE16(key->key_info);
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return !!(key_info & WPA_KEY_INFO_ACK);
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct ibss_rsn_peer *peer,
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const u8 *buf, size_t len)
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int supp;
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *tmp;
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	supp = ibss_rsn_eapol_dst_supp(buf, len);
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (supp < 0)
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp = os_malloc(len);
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tmp == NULL)
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(tmp, buf, len);
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (supp) {
762c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
763c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
764c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   MACSTR, MAC2STR(peer->addr));
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
767c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		if (ibss_rsn_is_auth_started(peer) == 0) {
768c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
769c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				   "Authenticator dropped as " MACSTR " is not "
770c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				   "authenticated", MAC2STR(peer->addr));
771c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			os_free(tmp);
772c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			return -1;
773c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		}
774c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
775c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator "
776c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   "from "MACSTR, MAC2STR(peer->addr));
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(tmp);
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 1;
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *buf, size_t len)
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ibss_rsn_peer *peer;
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn == NULL)
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
793c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	peer = ibss_rsn_get_peer(ibss_rsn, src_addr);
794c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (peer)
795c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len);
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn_eapol_dst_supp(buf, len) > 0) {
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Create new IBSS peer based on an EAPOL message from the peer
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Authenticator.
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
802c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		peer = ibss_rsn_peer_init(ibss_rsn, src_addr);
803c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		if (peer == NULL)
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
805c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
806c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		/* assume the peer is authenticated already */
807c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer "
808c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   MACSTR, MAC2STR(src_addr));
809c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		ibss_rsn_peer_authenticated(ibss_rsn, peer,
810c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt					    IBSS_RSN_AUTH_EAPOL_BY_US);
811c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 buf, len);
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ibss_rsn == NULL)
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
825c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
826c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
827c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtstatic void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
828c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt					struct ibss_rsn_peer *peer,
829c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt					const u8* addr)
830c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt{
831c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR,
832c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		   MAC2STR(addr));
833c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
834c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (peer &&
835c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	    peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
83692c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		if (peer->own_auth_tx.sec) {
83792c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt			struct os_time now, diff;
83892c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt			os_get_time(&now);
83992c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt			os_time_sub(&now, &peer->own_auth_tx, &diff);
84092c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt			if (diff.sec == 0 && diff.usec < 500000) {
84192c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt				wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX",
84292c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt					   (int) diff.usec);
84392c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt				goto skip_reinit;
84492c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt			}
84592c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		}
846c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		/*
847c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * A peer sent us an Authentication frame even though it already
848c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * started an EAPOL session. We should reinit state machines
849c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * here, but it's much more complicated than just deleting and
850c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * recreating the state machine
851c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 */
852c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station "
853c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   MACSTR, MAC2STR(addr));
854c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
855c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		ibss_rsn_stop(ibss_rsn, addr);
856c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		peer = NULL;
857c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	}
858c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
859c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (!peer) {
860c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		peer = ibss_rsn_peer_init(ibss_rsn, addr);
861c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		if (!peer)
862c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			return;
863c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
864c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR,
865c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   MAC2STR(addr));
866c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	}
867c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
86892c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidtskip_reinit:
869c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	/* reply with an Authentication frame now, before sending an EAPOL */
870c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	ibss_rsn_send_auth(ibss_rsn, addr, 2);
871c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	/* no need to start another AUTH challenge in the other way.. */
872c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US);
873c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt}
874c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
875c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
876c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtvoid ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
877c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			  size_t len)
878c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt{
879c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	const struct ieee80211_mgmt *header;
880c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	struct ibss_rsn_peer *peer;
881c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	size_t auth_length;
882c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
883c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	header = (const struct ieee80211_mgmt *) auth_frame;
884c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
885c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
886c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (ibss_rsn == NULL || len < auth_length)
887c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return;
888c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
889c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN ||
890c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	    le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS)
891c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		return;
892c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
893c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	peer = ibss_rsn_get_peer(ibss_rsn, header->sa);
894c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
895c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	switch (le_to_host16(header->u.auth.auth_transaction)) {
896c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	case 1:
897c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa);
898c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		break;
899c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	case 2:
900c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from "
901c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   MACSTR, MAC2STR(header->sa));
902c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		if (!peer) {
903c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from "
904c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				   "unknown STA " MACSTR, MAC2STR(header->sa));
905c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			break;
906c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		}
907c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
908c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		/* authentication has been completed */
90992c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
91092c368d56f46a4e648b441085707c1381b5e5f63Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR,
911c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			   MAC2STR(header->sa));
912c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		ibss_rsn_peer_authenticated(ibss_rsn, peer,
913c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt					    IBSS_RSN_AUTH_BY_US);
914c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		break;
915c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	}
916c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt}
917