1214501Srpaulo/*
2214501Srpaulo * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
3214501Srpaulo * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "utils/includes.h"
10214501Srpaulo
11214501Srpaulo#ifdef CONFIG_RSN_PREAUTH
12214501Srpaulo
13214501Srpaulo#include "utils/common.h"
14214501Srpaulo#include "utils/eloop.h"
15214501Srpaulo#include "l2_packet/l2_packet.h"
16214501Srpaulo#include "common/wpa_common.h"
17214501Srpaulo#include "eapol_auth/eapol_auth_sm.h"
18214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h"
19214501Srpaulo#include "hostapd.h"
20214501Srpaulo#include "ap_config.h"
21214501Srpaulo#include "ieee802_1x.h"
22214501Srpaulo#include "sta_info.h"
23214501Srpaulo#include "wpa_auth.h"
24214501Srpaulo#include "preauth_auth.h"
25214501Srpaulo
26214501Srpaulo#ifndef ETH_P_PREAUTH
27214501Srpaulo#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
28214501Srpaulo#endif /* ETH_P_PREAUTH */
29214501Srpaulo
30214501Srpaulostatic const int dot11RSNAConfigPMKLifetime = 43200;
31214501Srpaulo
32214501Srpaulostruct rsn_preauth_interface {
33214501Srpaulo	struct rsn_preauth_interface *next;
34214501Srpaulo	struct hostapd_data *hapd;
35214501Srpaulo	struct l2_packet_data *l2;
36214501Srpaulo	char *ifname;
37214501Srpaulo	int ifindex;
38214501Srpaulo};
39214501Srpaulo
40214501Srpaulo
41214501Srpaulostatic void rsn_preauth_receive(void *ctx, const u8 *src_addr,
42214501Srpaulo				const u8 *buf, size_t len)
43214501Srpaulo{
44214501Srpaulo	struct rsn_preauth_interface *piface = ctx;
45214501Srpaulo	struct hostapd_data *hapd = piface->hapd;
46214501Srpaulo	struct ieee802_1x_hdr *hdr;
47214501Srpaulo	struct sta_info *sta;
48214501Srpaulo	struct l2_ethhdr *ethhdr;
49214501Srpaulo
50214501Srpaulo	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
51214501Srpaulo		   "from interface '%s'", piface->ifname);
52214501Srpaulo	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
53214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
54214501Srpaulo			   "(len=%lu)", (unsigned long) len);
55214501Srpaulo		return;
56214501Srpaulo	}
57214501Srpaulo
58214501Srpaulo	ethhdr = (struct l2_ethhdr *) buf;
59214501Srpaulo	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
60214501Srpaulo
61214501Srpaulo	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
62214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
63214501Srpaulo			   MACSTR, MAC2STR(ethhdr->h_dest));
64214501Srpaulo		return;
65214501Srpaulo	}
66214501Srpaulo
67214501Srpaulo	sta = ap_get_sta(hapd, ethhdr->h_source);
68214501Srpaulo	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
69214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
70214501Srpaulo			   "STA " MACSTR, MAC2STR(sta->addr));
71214501Srpaulo		return;
72214501Srpaulo	}
73214501Srpaulo	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
74214501Srpaulo		sta = ap_sta_add(hapd, ethhdr->h_source);
75214501Srpaulo		if (sta == NULL)
76214501Srpaulo			return;
77214501Srpaulo		sta->flags = WLAN_STA_PREAUTH;
78214501Srpaulo
79214501Srpaulo		ieee802_1x_new_station(hapd, sta);
80214501Srpaulo		if (sta->eapol_sm == NULL) {
81214501Srpaulo			ap_free_sta(hapd, sta);
82214501Srpaulo			sta = NULL;
83214501Srpaulo		} else {
84214501Srpaulo			sta->eapol_sm->radius_identifier = -1;
85214501Srpaulo			sta->eapol_sm->portValid = TRUE;
86214501Srpaulo			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
87214501Srpaulo		}
88214501Srpaulo	}
89214501Srpaulo	if (sta == NULL)
90214501Srpaulo		return;
91214501Srpaulo	sta->preauth_iface = piface;
92214501Srpaulo	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
93214501Srpaulo			   len - sizeof(*ethhdr));
94214501Srpaulo}
95214501Srpaulo
96214501Srpaulo
97214501Srpaulostatic int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
98214501Srpaulo{
99214501Srpaulo	struct rsn_preauth_interface *piface;
100214501Srpaulo
101214501Srpaulo	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
102214501Srpaulo
103214501Srpaulo	piface = os_zalloc(sizeof(*piface));
104214501Srpaulo	if (piface == NULL)
105214501Srpaulo		return -1;
106214501Srpaulo	piface->hapd = hapd;
107214501Srpaulo
108214501Srpaulo	piface->ifname = os_strdup(ifname);
109214501Srpaulo	if (piface->ifname == NULL) {
110214501Srpaulo		goto fail1;
111214501Srpaulo	}
112214501Srpaulo
113214501Srpaulo	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
114214501Srpaulo				    rsn_preauth_receive, piface, 1);
115214501Srpaulo	if (piface->l2 == NULL) {
116214501Srpaulo		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
117214501Srpaulo			   "to ETH_P_PREAUTH");
118214501Srpaulo		goto fail2;
119214501Srpaulo	}
120214501Srpaulo
121214501Srpaulo	piface->next = hapd->preauth_iface;
122214501Srpaulo	hapd->preauth_iface = piface;
123214501Srpaulo	return 0;
124214501Srpaulo
125214501Srpaulofail2:
126214501Srpaulo	os_free(piface->ifname);
127214501Srpaulofail1:
128214501Srpaulo	os_free(piface);
129214501Srpaulo	return -1;
130214501Srpaulo}
131214501Srpaulo
132214501Srpaulo
133214501Srpaulovoid rsn_preauth_iface_deinit(struct hostapd_data *hapd)
134214501Srpaulo{
135214501Srpaulo	struct rsn_preauth_interface *piface, *prev;
136214501Srpaulo
137214501Srpaulo	piface = hapd->preauth_iface;
138214501Srpaulo	hapd->preauth_iface = NULL;
139214501Srpaulo	while (piface) {
140214501Srpaulo		prev = piface;
141214501Srpaulo		piface = piface->next;
142214501Srpaulo		l2_packet_deinit(prev->l2);
143214501Srpaulo		os_free(prev->ifname);
144214501Srpaulo		os_free(prev);
145214501Srpaulo	}
146214501Srpaulo}
147214501Srpaulo
148214501Srpaulo
149214501Srpauloint rsn_preauth_iface_init(struct hostapd_data *hapd)
150214501Srpaulo{
151214501Srpaulo	char *tmp, *start, *end;
152214501Srpaulo
153214501Srpaulo	if (hapd->conf->rsn_preauth_interfaces == NULL)
154214501Srpaulo		return 0;
155214501Srpaulo
156214501Srpaulo	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
157214501Srpaulo	if (tmp == NULL)
158214501Srpaulo		return -1;
159214501Srpaulo	start = tmp;
160214501Srpaulo	for (;;) {
161214501Srpaulo		while (*start == ' ')
162214501Srpaulo			start++;
163214501Srpaulo		if (*start == '\0')
164214501Srpaulo			break;
165214501Srpaulo		end = os_strchr(start, ' ');
166214501Srpaulo		if (end)
167214501Srpaulo			*end = '\0';
168214501Srpaulo
169214501Srpaulo		if (rsn_preauth_iface_add(hapd, start)) {
170214501Srpaulo			rsn_preauth_iface_deinit(hapd);
171214501Srpaulo			os_free(tmp);
172214501Srpaulo			return -1;
173214501Srpaulo		}
174214501Srpaulo
175214501Srpaulo		if (end)
176214501Srpaulo			start = end + 1;
177214501Srpaulo		else
178214501Srpaulo			break;
179214501Srpaulo	}
180214501Srpaulo	os_free(tmp);
181214501Srpaulo	return 0;
182214501Srpaulo}
183214501Srpaulo
184214501Srpaulo
185214501Srpaulostatic void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
186214501Srpaulo{
187214501Srpaulo	struct hostapd_data *hapd = eloop_ctx;
188214501Srpaulo	struct sta_info *sta = timeout_ctx;
189214501Srpaulo	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
190214501Srpaulo		   MACSTR, MAC2STR(sta->addr));
191214501Srpaulo	ap_free_sta(hapd, sta);
192214501Srpaulo}
193214501Srpaulo
194214501Srpaulo
195214501Srpaulovoid rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
196214501Srpaulo			  int success)
197214501Srpaulo{
198214501Srpaulo	const u8 *key;
199214501Srpaulo	size_t len;
200214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
201214501Srpaulo		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
202214501Srpaulo		       success ? "succeeded" : "failed");
203214501Srpaulo
204214501Srpaulo	key = ieee802_1x_get_key(sta->eapol_sm, &len);
205214501Srpaulo	if (len > PMK_LEN)
206214501Srpaulo		len = PMK_LEN;
207214501Srpaulo	if (success && key) {
208214501Srpaulo		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
209214501Srpaulo					       sta->addr,
210214501Srpaulo					       dot11RSNAConfigPMKLifetime,
211214501Srpaulo					       sta->eapol_sm) == 0) {
212214501Srpaulo			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
213214501Srpaulo				       HOSTAPD_LEVEL_DEBUG,
214214501Srpaulo				       "added PMKSA cache entry (pre-auth)");
215214501Srpaulo		} else {
216214501Srpaulo			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
217214501Srpaulo				       HOSTAPD_LEVEL_DEBUG,
218214501Srpaulo				       "failed to add PMKSA cache entry "
219214501Srpaulo				       "(pre-auth)");
220214501Srpaulo		}
221214501Srpaulo	}
222214501Srpaulo
223214501Srpaulo	/*
224214501Srpaulo	 * Finish STA entry removal from timeout in order to avoid freeing
225214501Srpaulo	 * STA data before the caller has finished processing.
226214501Srpaulo	 */
227214501Srpaulo	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
228214501Srpaulo}
229214501Srpaulo
230214501Srpaulo
231214501Srpaulovoid rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
232214501Srpaulo		      u8 *buf, size_t len)
233214501Srpaulo{
234214501Srpaulo	struct rsn_preauth_interface *piface;
235214501Srpaulo	struct l2_ethhdr *ethhdr;
236214501Srpaulo
237214501Srpaulo	piface = hapd->preauth_iface;
238214501Srpaulo	while (piface) {
239214501Srpaulo		if (piface == sta->preauth_iface)
240214501Srpaulo			break;
241214501Srpaulo		piface = piface->next;
242214501Srpaulo	}
243214501Srpaulo
244214501Srpaulo	if (piface == NULL) {
245214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
246214501Srpaulo			   "interface for " MACSTR, MAC2STR(sta->addr));
247214501Srpaulo		return;
248214501Srpaulo	}
249214501Srpaulo
250214501Srpaulo	ethhdr = os_malloc(sizeof(*ethhdr) + len);
251214501Srpaulo	if (ethhdr == NULL)
252214501Srpaulo		return;
253214501Srpaulo
254214501Srpaulo	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
255214501Srpaulo	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
256214501Srpaulo	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
257214501Srpaulo	os_memcpy(ethhdr + 1, buf, len);
258214501Srpaulo
259214501Srpaulo	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
260214501Srpaulo			   sizeof(*ethhdr) + len) < 0) {
261214501Srpaulo		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
262214501Srpaulo			   "l2_packet_send\n");
263214501Srpaulo	}
264214501Srpaulo	os_free(ethhdr);
265214501Srpaulo}
266214501Srpaulo
267214501Srpaulo
268214501Srpaulovoid rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
269214501Srpaulo{
270214501Srpaulo	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
271214501Srpaulo}
272214501Srpaulo
273214501Srpaulo#endif /* CONFIG_RSN_PREAUTH */
274