1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
3e5b75505Sopenharmony_ci * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "utils/includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#ifdef CONFIG_RSN_PREAUTH
12e5b75505Sopenharmony_ci
13e5b75505Sopenharmony_ci#include "utils/common.h"
14e5b75505Sopenharmony_ci#include "utils/eloop.h"
15e5b75505Sopenharmony_ci#include "l2_packet/l2_packet.h"
16e5b75505Sopenharmony_ci#include "common/wpa_common.h"
17e5b75505Sopenharmony_ci#include "eapol_auth/eapol_auth_sm.h"
18e5b75505Sopenharmony_ci#include "eapol_auth/eapol_auth_sm_i.h"
19e5b75505Sopenharmony_ci#include "hostapd.h"
20e5b75505Sopenharmony_ci#include "ap_config.h"
21e5b75505Sopenharmony_ci#include "ieee802_1x.h"
22e5b75505Sopenharmony_ci#include "sta_info.h"
23e5b75505Sopenharmony_ci#include "wpa_auth.h"
24e5b75505Sopenharmony_ci#include "preauth_auth.h"
25e5b75505Sopenharmony_ci
26e5b75505Sopenharmony_ci#ifndef ETH_P_PREAUTH
27e5b75505Sopenharmony_ci#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
28e5b75505Sopenharmony_ci#endif /* ETH_P_PREAUTH */
29e5b75505Sopenharmony_ci
30e5b75505Sopenharmony_cistatic const int dot11RSNAConfigPMKLifetime = 43200;
31e5b75505Sopenharmony_ci
32e5b75505Sopenharmony_cistruct rsn_preauth_interface {
33e5b75505Sopenharmony_ci	struct rsn_preauth_interface *next;
34e5b75505Sopenharmony_ci	struct hostapd_data *hapd;
35e5b75505Sopenharmony_ci	struct l2_packet_data *l2;
36e5b75505Sopenharmony_ci	char *ifname;
37e5b75505Sopenharmony_ci	int ifindex;
38e5b75505Sopenharmony_ci};
39e5b75505Sopenharmony_ci
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_cistatic void rsn_preauth_receive(void *ctx, const u8 *src_addr,
42e5b75505Sopenharmony_ci				const u8 *buf, size_t len)
43e5b75505Sopenharmony_ci{
44e5b75505Sopenharmony_ci	struct rsn_preauth_interface *piface = ctx;
45e5b75505Sopenharmony_ci	struct hostapd_data *hapd = piface->hapd;
46e5b75505Sopenharmony_ci	struct ieee802_1x_hdr *hdr;
47e5b75505Sopenharmony_ci	struct sta_info *sta;
48e5b75505Sopenharmony_ci	struct l2_ethhdr *ethhdr;
49e5b75505Sopenharmony_ci
50e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
51e5b75505Sopenharmony_ci		   "from interface '%s'", piface->ifname);
52e5b75505Sopenharmony_ci	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
53e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
54e5b75505Sopenharmony_ci			   "(len=%lu)", (unsigned long) len);
55e5b75505Sopenharmony_ci		return;
56e5b75505Sopenharmony_ci	}
57e5b75505Sopenharmony_ci
58e5b75505Sopenharmony_ci	ethhdr = (struct l2_ethhdr *) buf;
59e5b75505Sopenharmony_ci	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
60e5b75505Sopenharmony_ci
61e5b75505Sopenharmony_ci	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
62e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
63e5b75505Sopenharmony_ci			   MACSTR, MAC2STR(ethhdr->h_dest));
64e5b75505Sopenharmony_ci		return;
65e5b75505Sopenharmony_ci	}
66e5b75505Sopenharmony_ci
67e5b75505Sopenharmony_ci	sta = ap_get_sta(hapd, ethhdr->h_source);
68e5b75505Sopenharmony_ci	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
69e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
70e5b75505Sopenharmony_ci			   "STA " MACSTR, MAC2STR(sta->addr));
71e5b75505Sopenharmony_ci		return;
72e5b75505Sopenharmony_ci	}
73e5b75505Sopenharmony_ci	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
74e5b75505Sopenharmony_ci		sta = ap_sta_add(hapd, ethhdr->h_source);
75e5b75505Sopenharmony_ci		if (sta == NULL)
76e5b75505Sopenharmony_ci			return;
77e5b75505Sopenharmony_ci		sta->flags = WLAN_STA_PREAUTH;
78e5b75505Sopenharmony_ci
79e5b75505Sopenharmony_ci		ieee802_1x_new_station(hapd, sta);
80e5b75505Sopenharmony_ci		if (sta->eapol_sm == NULL) {
81e5b75505Sopenharmony_ci			ap_free_sta(hapd, sta);
82e5b75505Sopenharmony_ci			sta = NULL;
83e5b75505Sopenharmony_ci		} else {
84e5b75505Sopenharmony_ci			sta->eapol_sm->radius_identifier = -1;
85e5b75505Sopenharmony_ci			sta->eapol_sm->portValid = TRUE;
86e5b75505Sopenharmony_ci			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
87e5b75505Sopenharmony_ci		}
88e5b75505Sopenharmony_ci	}
89e5b75505Sopenharmony_ci	if (sta == NULL)
90e5b75505Sopenharmony_ci		return;
91e5b75505Sopenharmony_ci	sta->preauth_iface = piface;
92e5b75505Sopenharmony_ci	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
93e5b75505Sopenharmony_ci			   len - sizeof(*ethhdr));
94e5b75505Sopenharmony_ci}
95e5b75505Sopenharmony_ci
96e5b75505Sopenharmony_ci
97e5b75505Sopenharmony_cistatic int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
98e5b75505Sopenharmony_ci{
99e5b75505Sopenharmony_ci	struct rsn_preauth_interface *piface;
100e5b75505Sopenharmony_ci
101e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
102e5b75505Sopenharmony_ci
103e5b75505Sopenharmony_ci	piface = os_zalloc(sizeof(*piface));
104e5b75505Sopenharmony_ci	if (piface == NULL)
105e5b75505Sopenharmony_ci		return -1;
106e5b75505Sopenharmony_ci	piface->hapd = hapd;
107e5b75505Sopenharmony_ci
108e5b75505Sopenharmony_ci	piface->ifname = os_strdup(ifname);
109e5b75505Sopenharmony_ci	if (piface->ifname == NULL) {
110e5b75505Sopenharmony_ci		goto fail1;
111e5b75505Sopenharmony_ci	}
112e5b75505Sopenharmony_ci
113e5b75505Sopenharmony_ci	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
114e5b75505Sopenharmony_ci				    rsn_preauth_receive, piface, 1);
115e5b75505Sopenharmony_ci	if (piface->l2 == NULL) {
116e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
117e5b75505Sopenharmony_ci			   "to ETH_P_PREAUTH");
118e5b75505Sopenharmony_ci		goto fail2;
119e5b75505Sopenharmony_ci	}
120e5b75505Sopenharmony_ci
121e5b75505Sopenharmony_ci	piface->next = hapd->preauth_iface;
122e5b75505Sopenharmony_ci	hapd->preauth_iface = piface;
123e5b75505Sopenharmony_ci	return 0;
124e5b75505Sopenharmony_ci
125e5b75505Sopenharmony_cifail2:
126e5b75505Sopenharmony_ci	os_free(piface->ifname);
127e5b75505Sopenharmony_cifail1:
128e5b75505Sopenharmony_ci	os_free(piface);
129e5b75505Sopenharmony_ci	return -1;
130e5b75505Sopenharmony_ci}
131e5b75505Sopenharmony_ci
132e5b75505Sopenharmony_ci
133e5b75505Sopenharmony_civoid rsn_preauth_iface_deinit(struct hostapd_data *hapd)
134e5b75505Sopenharmony_ci{
135e5b75505Sopenharmony_ci	struct rsn_preauth_interface *piface, *prev;
136e5b75505Sopenharmony_ci
137e5b75505Sopenharmony_ci	piface = hapd->preauth_iface;
138e5b75505Sopenharmony_ci	hapd->preauth_iface = NULL;
139e5b75505Sopenharmony_ci	while (piface) {
140e5b75505Sopenharmony_ci		prev = piface;
141e5b75505Sopenharmony_ci		piface = piface->next;
142e5b75505Sopenharmony_ci		l2_packet_deinit(prev->l2);
143e5b75505Sopenharmony_ci		os_free(prev->ifname);
144e5b75505Sopenharmony_ci		os_free(prev);
145e5b75505Sopenharmony_ci	}
146e5b75505Sopenharmony_ci}
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_ci
149e5b75505Sopenharmony_ciint rsn_preauth_iface_init(struct hostapd_data *hapd)
150e5b75505Sopenharmony_ci{
151e5b75505Sopenharmony_ci	char *tmp, *start, *end;
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_ci	if (hapd->conf->rsn_preauth_interfaces == NULL)
154e5b75505Sopenharmony_ci		return 0;
155e5b75505Sopenharmony_ci
156e5b75505Sopenharmony_ci	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
157e5b75505Sopenharmony_ci	if (tmp == NULL)
158e5b75505Sopenharmony_ci		return -1;
159e5b75505Sopenharmony_ci	start = tmp;
160e5b75505Sopenharmony_ci	for (;;) {
161e5b75505Sopenharmony_ci		while (*start == ' ')
162e5b75505Sopenharmony_ci			start++;
163e5b75505Sopenharmony_ci		if (*start == '\0')
164e5b75505Sopenharmony_ci			break;
165e5b75505Sopenharmony_ci		end = os_strchr(start, ' ');
166e5b75505Sopenharmony_ci		if (end)
167e5b75505Sopenharmony_ci			*end = '\0';
168e5b75505Sopenharmony_ci
169e5b75505Sopenharmony_ci		if (rsn_preauth_iface_add(hapd, start)) {
170e5b75505Sopenharmony_ci			rsn_preauth_iface_deinit(hapd);
171e5b75505Sopenharmony_ci			os_free(tmp);
172e5b75505Sopenharmony_ci			return -1;
173e5b75505Sopenharmony_ci		}
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_ci		if (end)
176e5b75505Sopenharmony_ci			start = end + 1;
177e5b75505Sopenharmony_ci		else
178e5b75505Sopenharmony_ci			break;
179e5b75505Sopenharmony_ci	}
180e5b75505Sopenharmony_ci	os_free(tmp);
181e5b75505Sopenharmony_ci	return 0;
182e5b75505Sopenharmony_ci}
183e5b75505Sopenharmony_ci
184e5b75505Sopenharmony_ci
185e5b75505Sopenharmony_cistatic void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
186e5b75505Sopenharmony_ci{
187e5b75505Sopenharmony_ci	struct hostapd_data *hapd = eloop_ctx;
188e5b75505Sopenharmony_ci	struct sta_info *sta = timeout_ctx;
189e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
190e5b75505Sopenharmony_ci		   MACSTR, MAC2STR(sta->addr));
191e5b75505Sopenharmony_ci	ap_free_sta(hapd, sta);
192e5b75505Sopenharmony_ci}
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_ci
195e5b75505Sopenharmony_civoid rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
196e5b75505Sopenharmony_ci			  int success)
197e5b75505Sopenharmony_ci{
198e5b75505Sopenharmony_ci	const u8 *key;
199e5b75505Sopenharmony_ci	size_t len;
200e5b75505Sopenharmony_ci	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
201e5b75505Sopenharmony_ci		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
202e5b75505Sopenharmony_ci		       success ? "succeeded" : "failed");
203e5b75505Sopenharmony_ci
204e5b75505Sopenharmony_ci	key = ieee802_1x_get_key(sta->eapol_sm, &len);
205e5b75505Sopenharmony_ci	if (len > PMK_LEN)
206e5b75505Sopenharmony_ci		len = PMK_LEN;
207e5b75505Sopenharmony_ci	if (success && key) {
208e5b75505Sopenharmony_ci		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
209e5b75505Sopenharmony_ci					       sta->addr,
210e5b75505Sopenharmony_ci					       dot11RSNAConfigPMKLifetime,
211e5b75505Sopenharmony_ci					       sta->eapol_sm) == 0) {
212e5b75505Sopenharmony_ci			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
213e5b75505Sopenharmony_ci				       HOSTAPD_LEVEL_DEBUG,
214e5b75505Sopenharmony_ci				       "added PMKSA cache entry (pre-auth)");
215e5b75505Sopenharmony_ci		} else {
216e5b75505Sopenharmony_ci			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
217e5b75505Sopenharmony_ci				       HOSTAPD_LEVEL_DEBUG,
218e5b75505Sopenharmony_ci				       "failed to add PMKSA cache entry "
219e5b75505Sopenharmony_ci				       "(pre-auth)");
220e5b75505Sopenharmony_ci		}
221e5b75505Sopenharmony_ci	}
222e5b75505Sopenharmony_ci
223e5b75505Sopenharmony_ci	/*
224e5b75505Sopenharmony_ci	 * Finish STA entry removal from timeout in order to avoid freeing
225e5b75505Sopenharmony_ci	 * STA data before the caller has finished processing.
226e5b75505Sopenharmony_ci	 */
227e5b75505Sopenharmony_ci	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
228e5b75505Sopenharmony_ci}
229e5b75505Sopenharmony_ci
230e5b75505Sopenharmony_ci
231e5b75505Sopenharmony_civoid rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
232e5b75505Sopenharmony_ci		      u8 *buf, size_t len)
233e5b75505Sopenharmony_ci{
234e5b75505Sopenharmony_ci	struct rsn_preauth_interface *piface;
235e5b75505Sopenharmony_ci	struct l2_ethhdr *ethhdr;
236e5b75505Sopenharmony_ci
237e5b75505Sopenharmony_ci	piface = hapd->preauth_iface;
238e5b75505Sopenharmony_ci	while (piface) {
239e5b75505Sopenharmony_ci		if (piface == sta->preauth_iface)
240e5b75505Sopenharmony_ci			break;
241e5b75505Sopenharmony_ci		piface = piface->next;
242e5b75505Sopenharmony_ci	}
243e5b75505Sopenharmony_ci
244e5b75505Sopenharmony_ci	if (piface == NULL) {
245e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
246e5b75505Sopenharmony_ci			   "interface for " MACSTR, MAC2STR(sta->addr));
247e5b75505Sopenharmony_ci		return;
248e5b75505Sopenharmony_ci	}
249e5b75505Sopenharmony_ci
250e5b75505Sopenharmony_ci	ethhdr = os_malloc(sizeof(*ethhdr) + len);
251e5b75505Sopenharmony_ci	if (ethhdr == NULL)
252e5b75505Sopenharmony_ci		return;
253e5b75505Sopenharmony_ci
254e5b75505Sopenharmony_ci	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
255e5b75505Sopenharmony_ci	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
256e5b75505Sopenharmony_ci	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
257e5b75505Sopenharmony_ci	os_memcpy(ethhdr + 1, buf, len);
258e5b75505Sopenharmony_ci
259e5b75505Sopenharmony_ci	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
260e5b75505Sopenharmony_ci			   sizeof(*ethhdr) + len) < 0) {
261e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
262e5b75505Sopenharmony_ci			   "l2_packet_send\n");
263e5b75505Sopenharmony_ci	}
264e5b75505Sopenharmony_ci	os_free(ethhdr);
265e5b75505Sopenharmony_ci}
266e5b75505Sopenharmony_ci
267e5b75505Sopenharmony_ci
268e5b75505Sopenharmony_civoid rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
269e5b75505Sopenharmony_ci{
270e5b75505Sopenharmony_ci	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
271e5b75505Sopenharmony_ci}
272e5b75505Sopenharmony_ci
273e5b75505Sopenharmony_ci#endif /* CONFIG_RSN_PREAUTH */
274