18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd - PMKSA cache for IEEE 802.11i RSN
340b07208ef4402da20a7f666835a62f6ec098e16Dmitry Shmidt * Copyright (c) 2004-2008, 2012-2015, 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 "utils/includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eapol_auth/eapol_auth_sm.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eapol_auth/eapol_auth_sm_i.h"
15432d603c922e970f55866c63212d29c997438977Dmitry Shmidt#include "radius/radius_das.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sta_info.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "pmksa_cache_auth.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const int pmksa_cache_max_entries = 1024;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const int dot11RSNAConfigPMKLifetime = 43200;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache {
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PMKID_HASH_SIZE 128
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *pmksa;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int pmksa_count;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *ctx;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	os_free(entry->vlan_desc);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(entry->identity);
4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(entry->cui);
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_free_class(&entry->radius_class);
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
479ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	bin_clear_free(entry, sizeof(*entry));
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidtvoid pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
52f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt			    struct rsn_pmksa_cache_entry *entry)
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *pos, *prev;
559ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	unsigned int hash;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa->pmksa_count--;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa->free_cb(entry, pmksa->ctx);
599ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
609ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	/* unlink from hash list */
619ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	hash = PMKID_HASH(entry->pmkid);
629ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	pos = pmksa->pmkid[hash];
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos) {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == entry) {
669ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			if (prev != NULL)
679ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				prev->hnext = entry->hnext;
689ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			else
699ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				pmksa->pmkid[hash] = entry->hnext;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pos;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = pos->hnext;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
769ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	/* unlink from entry list */
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = pmksa->pmksa;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos) {
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == entry) {
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev != NULL)
829ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				prev->next = entry->next;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
849ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				pmksa->pmksa = entry->next;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pos;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = pos->next;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
909ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_pmksa_cache_free_entry(entry);
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt/**
96e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * pmksa_cache_auth_flush - Flush all PMKSA cache entries
97e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
98e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt */
99e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidtvoid pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
100e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt{
101e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	while (pmksa->pmksa) {
102e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
103e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt			   MACSTR, MAC2STR(pmksa->pmksa->spa));
104e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
105e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	}
106e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt}
107e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
108e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache *pmksa = eloop_ctx;
112fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct os_reltime now;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
114fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&now);
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
117d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   MACSTR, MAC2STR(pmksa->pmksa->spa));
118d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa_cache_set_expiration(pmksa);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sec;
128fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct os_reltime now;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pmksa->pmksa == NULL)
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
133fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&now);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sec = pmksa->pmksa->expiration - now.sec;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sec < 0)
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sec = 0;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					struct eapol_state_machine *eapol)
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	struct vlan_description *vlan_desc;
14557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eapol == NULL)
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eapol->identity) {
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry->identity = os_malloc(eapol->identity_len);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (entry->identity) {
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			entry->identity_len = eapol->identity_len;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(entry->identity, eapol->identity,
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  eapol->identity_len);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (eapol->radius_cui)
15904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		entry->cui = wpabuf_dup(eapol->radius_cui);
16004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_copy_class(&entry->radius_class, &eapol->radius_class);
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->eap_type_authsrv = eapol->eap_type_authsrv;
16657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
16757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
16857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	if (vlan_desc && vlan_desc->notempty) {
16957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
17057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (entry->vlan_desc)
17157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			*entry->vlan_desc = *vlan_desc;
17257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	} else {
17357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		entry->vlan_desc = NULL;
17457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	}
175fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
176b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	entry->acct_multi_session_id = eapol->acct_multi_session_id;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtvoid pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
18157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			       struct rsn_pmksa_cache_entry *entry,
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       struct eapol_state_machine *eapol)
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (entry == NULL || eapol == NULL)
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (entry->identity) {
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(eapol->identity);
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol->identity = os_malloc(entry->identity_len);
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (eapol->identity) {
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eapol->identity_len = entry->identity_len;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(eapol->identity, entry->identity,
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  entry->identity_len);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  eapol->identity, eapol->identity_len);
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (entry->cui) {
20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(eapol->radius_cui);
20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		eapol->radius_cui = wpabuf_dup(entry->cui);
20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_free_class(&eapol->radius_class);
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_copy_class(&eapol->radius_class, &entry->radius_class);
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eapol->radius_class.attr) {
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "PMKSA", (unsigned long) eapol->radius_class.count);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol->eap_type_authsrv = entry->eap_type_authsrv;
214e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#ifndef CONFIG_NO_VLAN
215e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
216e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#endif /* CONFIG_NO_VLAN */
217fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
218b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	eapol->acct_multi_session_id = entry->acct_multi_session_id;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct rsn_pmksa_cache_entry *entry)
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *pos, *prev;
2269ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	int hash;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Add the new entry; order by expiration time */
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = pmksa->pmksa;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos) {
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos->expiration > entry->expiration)
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pos;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = pos->next;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (prev == NULL) {
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry->next = pmksa->pmksa;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pmksa->pmksa = entry;
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry->next = prev->next;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev->next = entry;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2449ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
2459ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	hash = PMKID_HASH(entry->pmkid);
2469ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	entry->hnext = pmksa->pmkid[hash];
2479ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	pmksa->pmkid[hash] = entry;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa->pmksa_count++;
250a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (prev == NULL)
251a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pmksa_cache_set_expiration(pmksa);
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(entry->spa));
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_auth_add - Add a PMKSA cache entry
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk: The new pairwise master key
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
26357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * @pmkid: Calculated PMKID
264fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * @kck: Key confirmation key or %NULL if not yet derived
265fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * @kck_len: KCK length in bytes
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @spa: Supplicant address
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @session_timeout: Session timeout
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @eapol: Pointer to EAPOL state machine data
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @akmp: WPA_KEY_MGMT_* used in key derivation
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to the added PMKSA cache entry or %NULL on error
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * cache. If an old entry is already in the cache for the same Supplicant,
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this entry will be replaced with the new entry. PMKID will be calculated
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the PMK.
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry *
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
28057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		     const u8 *pmk, size_t pmk_len, const u8 *pmkid,
281fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		     const u8 *kck, size_t kck_len,
282fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		     const u8 *aa, const u8 *spa, int session_timeout,
283fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		     struct eapol_state_machine *eapol, int akmp)
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
285092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	struct rsn_pmksa_cache_entry *entry;
286092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
287092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len,
288092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart					      aa, spa, session_timeout, eapol,
289092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart					      akmp);
290092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
291092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	if (pmksa_cache_auth_add_entry(pmksa, entry) < 0)
292092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		return NULL;
293092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
294092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	return entry;
295092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart}
296092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
297092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
298092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart/**
299092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * pmksa_cache_auth_create_entry - Create a PMKSA cache entry
300092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @pmk: The new pairwise master key
301092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
302092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @pmkid: Calculated PMKID
303092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @kck: Key confirmation key or %NULL if not yet derived
304092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @kck_len: KCK length in bytes
305092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @aa: Authenticator address
306092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @spa: Supplicant address
307092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @session_timeout: Session timeout
308092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @eapol: Pointer to EAPOL state machine data
309092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @akmp: WPA_KEY_MGMT_* used in key derivation
310092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * Returns: Pointer to the added PMKSA cache entry or %NULL on error
311092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart *
312092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * This function creates a PMKSA entry.
313092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart */
314092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartstruct rsn_pmksa_cache_entry *
315092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartpmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
316092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			      const u8 *kck, size_t kck_len, const u8 *aa,
317092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			      const u8 *spa, int session_timeout,
318092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			      struct eapol_state_machine *eapol, int akmp)
319092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart{
320092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	struct rsn_pmksa_cache_entry *entry;
321fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct os_reltime now;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
323d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (pmk_len > PMK_LEN_MAX)
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
326fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (wpa_key_mgmt_suite_b(akmp) && !kck)
327fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return NULL;
328fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry = os_zalloc(sizeof(*entry));
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (entry == NULL)
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(entry->pmk, pmk, pmk_len);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->pmk_len = pmk_len;
33457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	if (pmkid)
33557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
33657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
33740b07208ef4402da20a7f666835a62f6ec098e16Dmitry Shmidt		rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
33840b07208ef4402da20a7f666835a62f6ec098e16Dmitry Shmidt	else if (wpa_key_mgmt_suite_b(akmp))
339fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
340fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	else
341d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
342fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&now);
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->expiration = now.sec;
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (session_timeout > 0)
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry->expiration += session_timeout;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry->expiration += dot11RSNAConfigPMKLifetime;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->akmp = akmp;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(entry->spa, spa, ETH_ALEN);
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa_cache_from_eapol_data(entry, eapol);
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
352092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	return entry;
353092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart}
354092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
355092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
356092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart/**
357092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * pmksa_cache_auth_add_entry - Add a PMKSA cache entry
358092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
359092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @entry: Pointer to PMKSA cache entry
360092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart *
361092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * This function adds PMKSA cache entry to the PMKSA cache. If an old entry is
362092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * already in the cache for the same Supplicant, this entry will be replaced
363092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * with the new entry. PMKID will be calculated based on the PMK.
364092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart */
365092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartint pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
366092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			       struct rsn_pmksa_cache_entry *entry)
367092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart{
368092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	struct rsn_pmksa_cache_entry *pos;
369092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
370092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	if (entry == NULL)
371092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		return -1;
372092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Replace an old entry for the same STA (if found) with the new entry
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
375092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	pos = pmksa_cache_auth_get(pmksa, entry->spa, NULL);
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos)
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pmksa_cache_free_entry(pmksa, pos);
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Remove the oldest entry to make room for the new entry */
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "entry (for " MACSTR ") to make room for new one",
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(pmksa->pmksa->spa));
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa_cache_link_entry(pmksa, entry);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
389092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	return 0;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry *
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    const struct rsn_pmksa_cache_entry *old_entry,
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    const u8 *aa, const u8 *pmkid)
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *entry;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry = os_zalloc(sizeof(*entry));
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (entry == NULL)
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->pmk_len = old_entry->pmk_len;
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->expiration = old_entry->expiration;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->akmp = old_entry->akmp;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->opportunistic = 1;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (old_entry->identity) {
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry->identity = os_malloc(old_entry->identity_len);
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (entry->identity) {
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			entry->identity_len = old_entry->identity_len;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(entry->identity, old_entry->identity,
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  old_entry->identity_len);
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (old_entry->cui)
41904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		entry->cui = wpabuf_dup(old_entry->cui);
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_copy_class(&entry->radius_class, &old_entry->radius_class);
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->eap_type_authsrv = old_entry->eap_type_authsrv;
42457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	if (old_entry->vlan_desc) {
42557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
42657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (entry->vlan_desc)
42757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			*entry->vlan_desc = *old_entry->vlan_desc;
42857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	} else {
42957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		entry->vlan_desc = NULL;
43057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	}
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry->opportunistic = 1;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa_cache_link_entry(pmksa, entry);
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return entry;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_auth_deinit - Free all entries in PMKSA cache
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *entry, *prev;
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pmksa == NULL)
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry = pmksa->pmksa;
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (entry) {
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = entry;
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry = entry->next;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		_pmksa_cache_free_entry(prev);
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
4589ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	pmksa->pmksa_count = 0;
4599ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	pmksa->pmksa = NULL;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < PMKID_HASH_SIZE; i++)
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pmksa->pmkid[i] = NULL;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(pmksa);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_auth_get - Fetch a PMKSA cache entry
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @spa: Supplicant address or %NULL to match any
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmkid: PMKID or %NULL to match any
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry *
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     const u8 *spa, const u8 *pmkid)
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *entry;
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4799ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	if (pmkid) {
4809ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
4819ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		     entry = entry->hnext) {
4829ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			if ((spa == NULL ||
4839ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			     os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
4849ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			    os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
4859ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				return entry;
4869ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		}
4879ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	} else {
4889ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		for (entry = pmksa->pmksa; entry; entry = entry->next) {
4899ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			if (spa == NULL ||
4909ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			    os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
4919ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				return entry;
4929ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		}
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4949ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @spa: Supplicant address
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmkid: PMKID
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pmkid)
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache_entry *entry;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 new_pmkid[PMKID_LEN];
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5169ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	for (entry = pmksa->pmksa; entry; entry = entry->next) {
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
520d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			  entry->akmp);
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return entry;
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_auth_init - Initialize PMKSA cache
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @free_cb: Callback function to be called when a PMKSA cache entry is freed
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ctx: Context pointer for free_cb function
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to PMKSA cache data or %NULL on failure
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache *
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      void *ctx), void *ctx)
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rsn_pmksa_cache *pmksa;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pmksa = os_zalloc(sizeof(*pmksa));
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pmksa) {
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pmksa->free_cb = free_cb;
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pmksa->ctx = ctx;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pmksa;
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
548432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
549432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
550432d603c922e970f55866c63212d29c997438977Dmitry Shmidtstatic int das_attr_match(struct rsn_pmksa_cache_entry *entry,
551432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			  struct radius_das_attrs *attr)
552432d603c922e970f55866c63212d29c997438977Dmitry Shmidt{
553432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	int match = 0;
554432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
555432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	if (attr->sta_addr) {
556432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
557432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			return 0;
558432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		match++;
559432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	}
560432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
561432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	if (attr->acct_multi_session_id) {
562432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		char buf[20];
563432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
564b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (attr->acct_multi_session_id_len != 16)
565432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			return 0;
56657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		os_snprintf(buf, sizeof(buf), "%016llX",
56757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			    (unsigned long long) entry->acct_multi_session_id);
568b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
569432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			return 0;
570432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		match++;
571432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	}
572432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
573432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	if (attr->cui) {
574432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		if (!entry->cui ||
575432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		    attr->cui_len != wpabuf_len(entry->cui) ||
576432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		    os_memcmp(attr->cui, wpabuf_head(entry->cui),
577432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			      attr->cui_len) != 0)
578432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			return 0;
579432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		match++;
580432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	}
581432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
582432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	if (attr->user_name) {
583432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		if (!entry->identity ||
584432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		    attr->user_name_len != entry->identity_len ||
585432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		    os_memcmp(attr->user_name, entry->identity,
586432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			      attr->user_name_len) != 0)
587432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			return 0;
588432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		match++;
589432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	}
590432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
591432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	return match;
592432d603c922e970f55866c63212d29c997438977Dmitry Shmidt}
593432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
594432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
595432d603c922e970f55866c63212d29c997438977Dmitry Shmidtint pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
596432d603c922e970f55866c63212d29c997438977Dmitry Shmidt					   struct radius_das_attrs *attr)
597432d603c922e970f55866c63212d29c997438977Dmitry Shmidt{
598432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	int found = 0;
599432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	struct rsn_pmksa_cache_entry *entry, *prev;
600432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
601432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	if (attr->acct_session_id)
602432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		return -1;
603432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
604432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	entry = pmksa->pmksa;
605432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	while (entry) {
606432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		if (das_attr_match(entry, attr)) {
607432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			found++;
608432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			prev = entry;
609432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			entry = entry->next;
610432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			pmksa_cache_free_entry(pmksa, prev);
611432d603c922e970f55866c63212d29c997438977Dmitry Shmidt			continue;
612432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		}
613432d603c922e970f55866c63212d29c997438977Dmitry Shmidt		entry = entry->next;
614432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	}
615432d603c922e970f55866c63212d29c997438977Dmitry Shmidt
616432d603c922e970f55866c63212d29c997438977Dmitry Shmidt	return found ? 0 : -1;
617432d603c922e970f55866c63212d29c997438977Dmitry Shmidt}
618e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
619e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
620e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt/**
621e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
622e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
623e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * @buf: Buffer for the list
624e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * @len: Length of the buffer
625e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * Returns: Number of bytes written to buffer
626e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt *
627e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * This function is used to generate a text format representation of the
628e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * current PMKSA cache contents for the ctrl_iface PMKSA command.
629e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt */
630e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidtint pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
631e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt{
632e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	int i, ret;
633e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	char *pos = buf;
634e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	struct rsn_pmksa_cache_entry *entry;
635e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	struct os_reltime now;
636e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
637e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	os_get_reltime(&now);
638e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	ret = os_snprintf(pos, buf + len - pos,
639e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt			  "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
640e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	if (os_snprintf_error(buf + len - pos, ret))
641e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		return pos - buf;
642e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	pos += ret;
643e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	i = 0;
644e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	entry = pmksa->pmksa;
645e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	while (entry) {
646e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
647e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt				  i, MAC2STR(entry->spa));
648e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		if (os_snprintf_error(buf + len - pos, ret))
649e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt			return pos - buf;
650e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		pos += ret;
651e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
652e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt					PMKID_LEN);
653e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
654e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt				  (int) (entry->expiration - now.sec),
655e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt				  entry->opportunistic);
656e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		if (os_snprintf_error(buf + len - pos, ret))
657e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt			return pos - buf;
658e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		pos += ret;
659e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		entry = entry->next;
660e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	}
661e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	return pos - buf;
662e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt}
663092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
664092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
665092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
666092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart#ifdef CONFIG_MESH
667092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
668092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart/**
669092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * pmksa_cache_auth_list_mesh - Dump text list of entries in PMKSA cache
670092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
671092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @addr: MAC address of the peer (NULL means any)
672092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @buf: Buffer for the list
673092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * @len: Length of the buffer
674092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * Returns: Number of bytes written to buffer
675092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart *
676092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * This function is used to generate a text format representation of the
677092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * current PMKSA cache contents for the ctrl_iface PMKSA_GET command to store
678092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * in external storage.
679092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart */
680092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartint pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
681092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			       char *buf, size_t len)
682092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart{
683092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	int ret;
684092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	char *pos, *end;
685092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	struct rsn_pmksa_cache_entry *entry;
686092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	struct os_reltime now;
687092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
688092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	pos = buf;
689092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	end = buf + len;
690092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	os_get_reltime(&now);
691092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
692092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
693092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	/*
694092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	 * Entry format:
695092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	 * <BSSID> <PMKID> <PMK> <expiration in seconds>
696092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	 */
697092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	for (entry = pmksa->pmksa; entry; entry = entry->next) {
698092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
699092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			continue;
700092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
701092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		ret = os_snprintf(pos, end - pos, MACSTR " ",
702092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart				  MAC2STR(entry->spa));
703092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		if (os_snprintf_error(end - pos, ret))
704092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			return 0;
705092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		pos += ret;
706092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
707092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		pos += wpa_snprintf_hex(pos, end - pos, entry->pmkid,
708092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart					PMKID_LEN);
709092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
710092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		ret = os_snprintf(pos, end - pos, " ");
711092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		if (os_snprintf_error(end - pos, ret))
712092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			return 0;
713092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		pos += ret;
714092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
715092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		pos += wpa_snprintf_hex(pos, end - pos, entry->pmk,
716092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart					entry->pmk_len);
717092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
718092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		ret = os_snprintf(pos, end - pos, " %d\n",
719092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart				  (int) (entry->expiration - now.sec));
720092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		if (os_snprintf_error(end - pos, ret))
721092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart			return 0;
722092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart		pos += ret;
723092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	}
724092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
725092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart	return pos - buf;
726092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart}
727092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
728092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart#endif /* CONFIG_MESH */
729092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
730