1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * hostapd / RADIUS authentication server
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include <net/if.h>
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "radius.h"
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eloop.h"
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "defs.h"
22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_server/eap.h"
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "radius_server.h"
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_SESSION_TIMEOUT 60
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_MAX_SESSION 100
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_MAX_MSG_LEN 3000
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct eapol_callbacks radius_server_eapol_cb;
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_client;
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_server_data;
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_server_counters {
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 access_requests;
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 invalid_requests;
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 dup_access_requests;
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 access_accepts;
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 access_rejects;
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 access_challenges;
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 malformed_access_requests;
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 bad_authenticators;
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 packets_dropped;
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 unknown_types;
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_session {
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *next;
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *client;
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *server;
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int sess_id;
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sm *eap;
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_eapol_interface *eap_if;
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *last_msg;
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *last_from_addr;
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int last_from_port;
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct sockaddr_storage last_from;
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	socklen_t last_fromlen;
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 last_identifier;
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *last_reply;
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 last_authenticator[16];
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_client {
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *next;
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct in_addr addr;
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct in_addr mask;
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct in6_addr addr6;
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct in6_addr mask6;
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *shared_secret;
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int shared_secret_len;
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sessions;
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_counters counters;
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_server_data {
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int auth_sock;
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *clients;
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int next_sess_id;
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	void *conf_ctx;
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int num_sess;
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	void *eap_sim_db_priv;
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	void *ssl_ctx;
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *pac_opaque_encr_key;
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *eap_fast_a_id;
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t eap_fast_a_id_len;
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *eap_fast_a_id_info;
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int eap_fast_prov;
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int pac_key_lifetime;
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int pac_key_refresh_time;
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int eap_sim_aka_result_ind;
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int tnc;
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wps_context *wps;
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ipv6;
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct os_time start_time;
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_counters counters;
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    int phase2, struct eap_user *user);
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *eap_req_id_text;
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t eap_req_id_text_len;
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtextern int wpa_debug_level;
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_DEBUG(args...) \
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtwpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_ERROR(args...) \
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtwpa_printf(MSG_ERROR, "RADIUS SRV: " args)
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_DUMP(args...) \
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtwpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RADIUS_DUMP_ASCII(args...) \
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtwpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
120dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidtstatic void radius_server_session_remove_timeout(void *eloop_ctx,
121dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt						 void *timeout_ctx);
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_client *
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 int ipv6)
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *client = data->clients;
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (client) {
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ipv6) {
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			struct in6_addr *addr6;
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			int i;
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			addr6 = (struct in6_addr *) addr;
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			for (i = 0; i < 16; i++) {
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				if ((addr6->s6_addr[i] &
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     client->mask6.s6_addr[i]) !=
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    (client->addr6.s6_addr[i] &
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     client->mask6.s6_addr[i])) {
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					i = 17;
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					break;
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				}
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (i == 16) {
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				break;
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    (addr->s_addr & client->mask.s_addr)) {
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client = client->next;
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return client;
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_session *
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_get_session(struct radius_client *client, unsigned int sess_id)
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess = client->sessions;
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (sess) {
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess->sess_id == sess_id) {
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess = sess->next;
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return sess;
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_session_free(struct radius_server_data *data,
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       struct radius_session *sess)
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eloop_cancel_timeout(radius_server_session_timeout, data, sess);
183dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_server_sm_deinit(sess->eap);
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->last_msg) {
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_free(sess->last_msg);
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(sess->last_msg);
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(sess->last_from_addr);
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->last_reply) {
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_free(sess->last_reply);
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(sess->last_reply);
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(sess);
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_sess--;
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_session_remove(struct radius_server_data *data,
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					 struct radius_session *sess)
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *client = sess->client;
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *session, *prev;
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prev = NULL;
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	session = client->sessions;
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (session) {
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (session == sess) {
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (prev == NULL) {
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				client->sessions = sess->next;
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			} else {
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				prev->next = sess->next;
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			radius_server_session_free(data, sess);
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prev = session;
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		session = session->next;
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_session_remove_timeout(void *eloop_ctx,
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 void *timeout_ctx)
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *data = eloop_ctx;
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess = timeout_ctx;
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	radius_server_session_remove(data, sess);
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *data = eloop_ctx;
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess = timeout_ctx;
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	radius_server_session_remove(data, sess);
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_session *
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_new_session(struct radius_server_data *data,
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  struct radius_client *client)
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess;
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->num_sess >= RADIUS_MAX_SESSION) {
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Maximum number of existing session - no room "
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     "for a new session");
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess = os_zalloc(sizeof(*sess));
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess == NULL)
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->server = data;
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->client = client;
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->sess_id = data->next_sess_id++;
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->next = client->sessions;
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	client->sessions = sess;
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       radius_server_session_timeout, data, sess);
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_sess++;
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return sess;
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_session *
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_get_new_session(struct radius_server_data *data,
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      struct radius_client *client,
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      struct radius_msg *msg)
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *user;
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t user_len;
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int res;
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess;
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_config eap_conf;
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DEBUG("Creating a new session");
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	user = os_malloc(256);
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (user == NULL) {
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (res < 0 || res > 256) {
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Could not get User-Name");
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(user);
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	user_len = res;
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DUMP_ASCII("User-Name", user, user_len);
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(user);
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (res == 0) {
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Matching user entry found");
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess = radius_server_new_session(data, client);
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess == NULL) {
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			RADIUS_DEBUG("Failed to create a new session");
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("User-Name not found from user database");
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(&eap_conf, 0, sizeof(eap_conf));
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.ssl_ctx = data->ssl_ctx;
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.backend_auth = TRUE;
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_server = 1;
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_fast_a_id = data->eap_fast_a_id;
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_fast_prov = data->eap_fast_prov;
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.pac_key_lifetime = data->pac_key_lifetime;
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.tnc = data->tnc;
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_conf.wps = data->wps;
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       &eap_conf);
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->eap == NULL) {
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to initialize EAP state machine for the "
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     "new session");
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_session_free(data, sess);
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->eap_if = eap_get_interface(sess->eap);
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->eap_if->eapRestart = TRUE;
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->eap_if->portEnabled = TRUE;
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return sess;
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_msg *
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_encapsulate_eap(struct radius_server_data *data,
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      struct radius_client *client,
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      struct radius_session *sess,
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      struct radius_msg *request)
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *msg;
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int code;
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int sess_id;
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->eap_if->eapFail) {
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->eap_if->eapFail = FALSE;
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		code = RADIUS_CODE_ACCESS_REJECT;
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (sess->eap_if->eapSuccess) {
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->eap_if->eapSuccess = FALSE;
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		code = RADIUS_CODE_ACCESS_ACCEPT;
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->eap_if->eapReq = FALSE;
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		code = RADIUS_CODE_ACCESS_CHALLENGE;
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = radius_msg_new(code, request->hdr->identifier);
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL) {
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to allocate reply message");
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess_id = htonl(sess->sess_id);
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 (u8 *) &sess_id, sizeof(sess_id))) {
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to add State attribute");
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->eap_if->eapReqData &&
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpabuf_len(sess->eap_if->eapReqData))) {
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to add EAP-Message attribute");
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		int len;
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess->eap_if->eapKeyDataLen > 64) {
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			len = 32;
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			len = sess->eap_if->eapKeyDataLen / 2;
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator,
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					      (u8 *) client->shared_secret,
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					      client->shared_secret_len,
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					      sess->eap_if->eapKeyData + len,
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					      len, sess->eap_if->eapKeyData,
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					      len)) {
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			RADIUS_DEBUG("Failed to add MPPE key attributes");
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_free(msg);
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(msg);
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  client->shared_secret_len,
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  request->hdr->authenticator) < 0) {
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return msg;
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int radius_server_reject(struct radius_server_data *data,
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				struct radius_client *client,
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				struct radius_msg *request,
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				struct sockaddr *from, socklen_t fromlen,
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				const char *from_addr, int from_port)
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *msg;
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret = 0;
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_hdr eapfail;
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DEBUG("Reject invalid request from %s:%d",
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		     from_addr, from_port);
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT,
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     request->hdr->identifier);
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL) {
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(&eapfail, 0, sizeof(eapfail));
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eapfail.code = EAP_CODE_FAILURE;
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eapfail.identifier = 0;
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eapfail.length = host_to_be16(sizeof(eapfail));
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to add EAP-Message attribute");
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_free(msg);
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(msg);
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  client->shared_secret_len,
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  request->hdr->authenticator) < 0) {
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (wpa_debug_level <= MSG_MSGDUMP) {
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_dump(msg);
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->counters.access_rejects++;
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	client->counters.access_rejects++;
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0,
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   (struct sockaddr *) from, sizeof(*from)) < 0) {
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		perror("sendto[RADIUS SRV]");
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret = -1;
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	radius_msg_free(msg);
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(msg);
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int radius_server_request(struct radius_server_data *data,
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 struct radius_msg *msg,
483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 struct sockaddr *from, socklen_t fromlen,
484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 struct radius_client *client,
485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 const char *from_addr, int from_port,
486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 struct radius_session *force_sess)
487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *eap = NULL;
489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t eap_len;
490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int res, state_included = 0;
491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 statebuf[4];
492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int state;
493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess;
494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *reply;
495dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	int is_complete = 0;
496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (force_sess)
498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess = force_sess;
499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else {
500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  sizeof(statebuf));
502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		state_included = res >= 0;
503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (res == sizeof(statebuf)) {
504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			state = WPA_GET_BE32(statebuf);
505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			sess = radius_server_get_session(client, state);
506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			sess = NULL;
508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess) {
512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (state_included) {
514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("State attribute included but no session found");
515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_reject(data, client, msg, from, fromlen,
516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     from_addr, from_port);
517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess = radius_server_get_new_session(data, client, msg);
520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess == NULL) {
521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			RADIUS_DEBUG("Could not create a new session");
522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			radius_server_reject(data, client, msg, from, fromlen,
523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     from_addr, from_port);
524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->last_from_port == from_port &&
529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    sess->last_identifier == msg->hdr->identifier &&
530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) ==
531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    0) {
532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Duplicate message from %s", from_addr);
533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.dup_access_requests++;
534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.dup_access_requests++;
535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess->last_reply) {
537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			res = sendto(data->auth_sock, sess->last_reply->buf,
538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     sess->last_reply->buf_used, 0,
539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     (struct sockaddr *) from, fromlen);
540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (res < 0) {
541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				perror("sendto[RADIUS SRV]");
542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return 0;
544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("No previous reply available for duplicate "
547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     "message");
548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = radius_msg_get_eap(msg, &eap_len);
552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap == NULL) {
553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     from_addr);
555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.packets_dropped++;
556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.packets_dropped++;
557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DUMP("Received EAP data", eap, eap_len);
561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * RFC3579 Sect. 2.6.2.
564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Include EAP-Response/Nak with no preferred method if
565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * code == request.
566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * If code is not 1-4, discard the packet silently.
567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Or is this already done by the EAP state machine? */
568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(sess->eap_if->eapRespData);
570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len);
571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess->eap_if->eapRespData == NULL)
572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(eap);
573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = NULL;
574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->eap_if->eapResp = TRUE;
575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_server_sm_step(sess->eap);
576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	     sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DUMP("EAP data from the state machine",
580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    wpabuf_head(sess->eap_if->eapReqData),
581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    wpabuf_len(sess->eap_if->eapReqData));
582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (sess->eap_if->eapFail) {
583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     "set");
585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (eap_sm_method_pending(sess->eap)) {
586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess->last_msg) {
587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			radius_msg_free(sess->last_msg);
588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_free(sess->last_msg);
589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_msg = msg;
591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_from_port = from_port;
592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(sess->last_from_addr);
593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_from_addr = os_strdup(from_addr);
594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_fromlen = fromlen;
595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(&sess->last_from, from, fromlen);
596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -2;
597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("No EAP data from the state machine - ignore this"
599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     " Access-Request silently (assuming it was a "
600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     "duplicate)");
601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.packets_dropped++;
602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.packets_dropped++;
603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
606dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
607dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		is_complete = 1;
608dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt
609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	reply = radius_server_encapsulate_eap(data, client, sess, msg);
610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (reply) {
612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (wpa_debug_level <= MSG_MSGDUMP) {
614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			radius_msg_dump(reply);
615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		switch (reply->hdr->code) {
618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case RADIUS_CODE_ACCESS_ACCEPT:
619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->counters.access_accepts++;
620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			client->counters.access_accepts++;
621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case RADIUS_CODE_ACCESS_REJECT:
623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->counters.access_rejects++;
624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			client->counters.access_rejects++;
625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case RADIUS_CODE_ACCESS_CHALLENGE:
627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->counters.access_challenges++;
628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			client->counters.access_challenges++;
629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     (struct sockaddr *) from, fromlen);
633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (res < 0) {
634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			perror("sendto[RADIUS SRV]");
635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess->last_reply) {
637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			radius_msg_free(sess->last_reply);
638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_free(sess->last_reply);
639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_reply = reply;
641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_from_port = from_port;
642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sess->last_identifier = msg->hdr->identifier;
643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(sess->last_authenticator, msg->hdr->authenticator,
644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  16);
645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.packets_dropped++;
647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.packets_dropped++;
648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
650dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	if (is_complete) {
651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Removing completed session 0x%x after timeout",
652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     sess->sess_id);
653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eloop_cancel_timeout(radius_server_session_remove_timeout,
654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     data, sess);
655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eloop_register_timeout(10, 0,
656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       radius_server_session_remove_timeout,
657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       data, sess);
658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_receive_auth(int sock, void *eloop_ctx,
665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       void *sock_ctx)
666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *data = eloop_ctx;
668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *buf = NULL;
669dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	union {
670dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		struct sockaddr_storage ss;
671dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		struct sockaddr_in sin;
672dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt#ifdef CONFIG_IPV6
673dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		struct sockaddr_in6 sin6;
674dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt#endif /* CONFIG_IPV6 */
675dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	} from;
676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	socklen_t fromlen;
677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int len;
678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *client = NULL;
679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *msg = NULL;
680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char abuf[50];
681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int from_port = 0;
682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(RADIUS_MAX_MSG_LEN);
684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL) {
685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	fromlen = sizeof(from);
689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
690dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		       (struct sockaddr *) &from.ss, &fromlen);
691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (len < 0) {
692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		perror("recvfrom[radius_server]");
693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->ipv6) {
698dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
699dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt			      sizeof(abuf)) == NULL)
700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			abuf[0] = '\0';
701dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		from_port = ntohs(from.sin6.sin6_port);
702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Received %d bytes from %s:%d",
703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     len, abuf, from_port);
704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client = radius_server_get_client(data,
706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						  (struct in_addr *)
707dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt						  &from.sin6.sin6_addr, 1);
708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!data->ipv6) {
712dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
713dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		from_port = ntohs(from.sin.sin_port);
714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Received %d bytes from %s:%d",
715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     len, abuf, from_port);
716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
717dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		client = radius_server_get_client(data, &from.sin.sin_addr, 0);
718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	RADIUS_DUMP("Received data", buf, len);
721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (client == NULL) {
723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.invalid_requests++;
725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = radius_msg_parse(buf, len);
729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL) {
730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.malformed_access_requests++;
732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.malformed_access_requests++;
733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = NULL;
738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (wpa_debug_level <= MSG_MSGDUMP) {
740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_dump(msg);
741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) {
744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code);
745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.unknown_types++;
746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.unknown_types++;
747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->counters.access_requests++;
751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	client->counters.access_requests++;
752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       client->shared_secret_len, NULL)) {
755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->counters.bad_authenticators++;
757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client->counters.bad_authenticators++;
758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_server_request(data, msg, (struct sockaddr *) &from,
762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  fromlen, client, abuf, from_port, NULL) ==
763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    -2)
764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return; /* msg was stored with the session */
765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtfail:
767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg) {
768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_msg_free(msg);
769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(msg);
770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
775dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidtstatic int radius_server_disable_pmtu_discovery(int s)
776dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt{
777dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	int r = -1;
778dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
779dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
780dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	int action = IP_PMTUDISC_DONT;
781dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
782dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		       sizeof(action));
783dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	if (r == -1)
784dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
785dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt			   "%s", strerror(errno));
786dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt#endif
787dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	return r;
788dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt}
789dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt
790dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt
791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int radius_server_open_socket(int port)
792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int s;
794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct sockaddr_in addr;
795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	s = socket(PF_INET, SOCK_DGRAM, 0);
797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (s < 0) {
798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		perror("socket");
799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
802dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt	radius_server_disable_pmtu_discovery(s);
803dde787cc314cd04caa4ea5f031cc8a02495ca513Dmitry Shmidt
804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(&addr, 0, sizeof(addr));
805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr.sin_family = AF_INET;
806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr.sin_port = htons(port);
807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		perror("bind");
809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		close(s);
810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return s;
814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int radius_server_open_socket6(int port)
819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int s;
821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct sockaddr_in6 addr;
822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	s = socket(PF_INET6, SOCK_DGRAM, 0);
824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (s < 0) {
825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		perror("socket[IPv6]");
826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(&addr, 0, sizeof(addr));
830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr.sin6_family = AF_INET6;
831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr.sin6_port = htons(port);
833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		perror("bind");
835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		close(s);
836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return s;
840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_free_sessions(struct radius_server_data *data,
845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					struct radius_session *sessions)
846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *session, *prev;
848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	session = sessions;
850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (session) {
851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prev = session;
852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		session = session->next;
853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_session_free(data, prev);
854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void radius_server_free_clients(struct radius_server_data *data,
859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       struct radius_client *clients)
860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *client, *prev;
862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	client = clients;
864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (client) {
865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prev = client;
866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		client = client->next;
867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_free_sessions(data, prev->sessions);
869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(prev->shared_secret);
870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(prev);
871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct radius_client *
876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_read_clients(const char *client_file, int ipv6)
877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
878526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	FILE *f;
879526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const int buf_size = 1024;
880526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *buf, *pos;
881526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *clients, *tail, *entry;
882526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int line = 0, mask, failed = 0, i;
883526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct in_addr addr;
884526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
885526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct in6_addr addr6;
886526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
887526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int val;
888526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
889526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	f = fopen(client_file, "r");
890526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (f == NULL) {
891526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_ERROR("Could not open client file '%s'", client_file);
892526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
893526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
894526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
895526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(buf_size);
896526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL) {
897526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		fclose(f);
898526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
899526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
900526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
901526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	clients = tail = NULL;
902526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (fgets(buf, buf_size, f)) {
903526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Configuration file format:
904526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * 192.168.1.0/24 secret
905526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * 192.168.1.2 secret
906526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * fe80::211:22ff:fe33:4455/64 secretipv6
907526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 */
908526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		line++;
909526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		buf[buf_size - 1] = '\0';
910526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = buf;
911526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		while (*pos != '\0' && *pos != '\n')
912526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
913526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*pos == '\n')
914526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*pos = '\0';
915526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*buf == '\0' || *buf == '#')
916526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			continue;
917526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
918526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = buf;
919526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
920526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
921526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       (*pos >= 'A' && *pos <= 'F')) {
922526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
923526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
924526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
925526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*pos == '\0') {
926526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			failed = 1;
927526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
928526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
929526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
930526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*pos == '/') {
931526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			char *end;
932526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*pos++ = '\0';
933526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			mask = strtol(pos, &end, 10);
934526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if ((pos == end) ||
935526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    (mask < 0 || mask > (ipv6 ? 128 : 32))) {
936526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				failed = 1;
937526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				break;
938526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
939526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos = end;
940526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
941526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			mask = ipv6 ? 128 : 32;
942526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*pos++ = '\0';
943526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
944526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
945526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!ipv6 && inet_aton(buf, &addr) == 0) {
946526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			failed = 1;
947526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
948526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
949526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
950526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
951526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (inet_pton(AF_INET, buf, &addr) <= 0) {
952526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				failed = 1;
953526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				break;
954526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
955526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			/* Convert IPv4 address to IPv6 */
956526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (mask <= 32)
957526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				mask += (128 - 32);
958526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memset(addr6.s6_addr, 0, 10);
959526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			addr6.s6_addr[10] = 0xff;
960526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			addr6.s6_addr[11] = 0xff;
961526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr,
962526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  4);
963526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
964526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
965526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
966526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		while (*pos == ' ' || *pos == '\t') {
967526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
968526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
969526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
970526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (*pos == '\0') {
971526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			failed = 1;
972526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
973526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
974526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
975526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		entry = os_zalloc(sizeof(*entry));
976526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (entry == NULL) {
977526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			failed = 1;
978526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
979526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
980526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		entry->shared_secret = os_strdup(pos);
981526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (entry->shared_secret == NULL) {
982526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			failed = 1;
983526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_free(entry);
984526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
985526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
986526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		entry->shared_secret_len = os_strlen(entry->shared_secret);
987526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		entry->addr.s_addr = addr.s_addr;
988526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!ipv6) {
989526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			val = 0;
990526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			for (i = 0; i < mask; i++)
991526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				val |= 1 << (31 - i);
992526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			entry->mask.s_addr = htonl(val);
993526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
994526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
995526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ipv6) {
996526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			int offset = mask / 8;
997526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
998526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
999526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memset(entry->mask6.s6_addr, 0xff, offset);
1000526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			val = 0;
1001526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			for (i = 0; i < (mask % 8); i++)
1002526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				val |= 1 << (7 - i);
1003526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (offset < 16)
1004526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				entry->mask6.s6_addr[offset] = val;
1005526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1006526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
1007526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1008526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (tail == NULL) {
1009526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			clients = tail = entry;
1010526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
1011526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			tail->next = entry;
1012526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			tail = entry;
1013526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1014526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1015526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1016526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (failed) {
1017526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
1018526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_free_clients(NULL, clients);
1019526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		clients = NULL;
1020526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1021526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1022526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
1023526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	fclose(f);
1024526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1025526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return clients;
1026526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1027526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1028526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1029526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct radius_server_data *
1030526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtradius_server_init(struct radius_server_conf *conf)
1031526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1032526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *data;
1033526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1034526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifndef CONFIG_IPV6
1035526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->ipv6) {
1036526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		fprintf(stderr, "RADIUS server compiled without IPv6 "
1037526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			"support.\n");
1038526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1039526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1040526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
1041526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1042526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data = os_zalloc(sizeof(*data));
1043526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
1044526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1045526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1046526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_get_time(&data->start_time);
1047526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->conf_ctx = conf->conf_ctx;
1048526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->eap_sim_db_priv = conf->eap_sim_db_priv;
1049526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->ssl_ctx = conf->ssl_ctx;
1050526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->ipv6 = conf->ipv6;
1051526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->pac_opaque_encr_key) {
1052526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->pac_opaque_encr_key = os_malloc(16);
1053526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key,
1054526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  16);
1055526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1056526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->eap_fast_a_id) {
1057526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
1058526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->eap_fast_a_id) {
1059526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
1060526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  conf->eap_fast_a_id_len);
1061526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
1062526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1063526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1064526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->eap_fast_a_id_info)
1065526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
1066526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->eap_fast_prov = conf->eap_fast_prov;
1067526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->pac_key_lifetime = conf->pac_key_lifetime;
1068526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->pac_key_refresh_time = conf->pac_key_refresh_time;
1069526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->get_eap_user = conf->get_eap_user;
1070526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
1071526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->tnc = conf->tnc;
1072526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->wps = conf->wps;
1073526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->eap_req_id_text) {
1074526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
1075526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->eap_req_id_text) {
1076526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
1077526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  conf->eap_req_id_text_len);
1078526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->eap_req_id_text_len = conf->eap_req_id_text_len;
1079526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1080526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1081526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1082526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->clients = radius_server_read_clients(conf->client_file,
1083526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   conf->ipv6);
1084526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->clients == NULL) {
1085526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		printf("No RADIUS clients configured.\n");
1086526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_deinit(data);
1087526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1088526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1089526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1090526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
1091526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (conf->ipv6)
1092526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->auth_sock = radius_server_open_socket6(conf->auth_port);
1093526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else
1094526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
1095526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->auth_sock = radius_server_open_socket(conf->auth_port);
1096526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->auth_sock < 0) {
1097526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		printf("Failed to open UDP socket for RADIUS authentication "
1098526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       "server\n");
1099526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_deinit(data);
1100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eloop_register_read_sock(data->auth_sock,
1103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     radius_server_receive_auth,
1104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     data, NULL)) {
1105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		radius_server_deinit(data);
1106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data;
1110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_server_deinit(struct radius_server_data *data)
1114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
1116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
1117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->auth_sock >= 0) {
1119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eloop_unregister_read_sock(data->auth_sock);
1120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		close(data->auth_sock);
1121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	radius_server_free_clients(data, data->clients);
1124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->pac_opaque_encr_key);
1126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->eap_fast_a_id);
1127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->eap_fast_a_id_info);
1128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->eap_req_id_text);
1129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data);
1130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint radius_server_get_mib(struct radius_server_data *data, char *buf,
1134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  size_t buflen)
1135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret, uptime;
1137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	unsigned int idx;
1138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *end, *pos;
1139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct os_time now;
1140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *cli;
1141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* RFC 2619 - RADIUS Authentication Server MIB */
1143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL || buflen == 0)
1145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return 0;
1146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf;
1148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	end = buf + buflen;
1149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_get_time(&now);
1151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	uptime = (now.sec - data->start_time.sec) * 100 +
1152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		((now.usec - data->start_time.usec) / 10000) % 100;
1153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = os_snprintf(pos, end - pos,
1154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "RADIUS-AUTH-SERVER-MIB\n"
1155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServIdent=hostapd\n"
1156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServUpTime=%d\n"
1157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServResetTime=0\n"
1158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServConfigReset=4\n",
1159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  uptime);
1160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret < 0 || ret >= end - pos) {
1161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		*pos = '\0';
1162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return pos - buf;
1163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ret;
1165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = os_snprintf(pos, end - pos,
1167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalAccessRequests=%u\n"
1168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalInvalidRequests=%u\n"
1169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalDupAccessRequests=%u\n"
1170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalAccessAccepts=%u\n"
1171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalAccessRejects=%u\n"
1172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalAccessChallenges=%u\n"
1173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalMalformedAccessRequests=%u\n"
1174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalBadAuthenticators=%u\n"
1175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalPacketsDropped=%u\n"
1176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "radiusAuthServTotalUnknownTypes=%u\n",
1177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.access_requests,
1178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.invalid_requests,
1179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.dup_access_requests,
1180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.access_accepts,
1181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.access_rejects,
1182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.access_challenges,
1183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.malformed_access_requests,
1184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.bad_authenticators,
1185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.packets_dropped,
1186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  data->counters.unknown_types);
1187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret < 0 || ret >= end - pos) {
1188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		*pos = '\0';
1189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return pos - buf;
1190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ret;
1192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
1194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		char abuf[50], mbuf[50];
1195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IPV6
1196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->ipv6) {
1197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (inet_ntop(AF_INET6, &cli->addr6, abuf,
1198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      sizeof(abuf)) == NULL)
1199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				abuf[0] = '\0';
1200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (inet_ntop(AF_INET6, &cli->mask6, abuf,
1201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      sizeof(mbuf)) == NULL)
1202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				mbuf[0] = '\0';
1203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IPV6 */
1205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!data->ipv6) {
1206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
1207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
1208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret = os_snprintf(pos, end - pos,
1211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthClientIndex=%u\n"
1212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthClientAddress=%s/%s\n"
1213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServAccessRequests=%u\n"
1214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServDupAccessRequests=%u\n"
1215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServAccessAccepts=%u\n"
1216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServAccessRejects=%u\n"
1217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServAccessChallenges=%u\n"
1218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServMalformedAccessRequests=%u\n"
1219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServBadAuthenticators=%u\n"
1220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServPacketsDropped=%u\n"
1221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  "radiusAuthServUnknownTypes=%u\n",
1222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  idx,
1223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  abuf, mbuf,
1224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.access_requests,
1225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.dup_access_requests,
1226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.access_accepts,
1227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.access_rejects,
1228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.access_challenges,
1229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.malformed_access_requests,
1230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.bad_authenticators,
1231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.packets_dropped,
1232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  cli->counters.unknown_types);
1233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ret < 0 || ret >= end - pos) {
1234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*pos = '\0';
1235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return pos - buf;
1236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += ret;
1238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return pos - buf;
1241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int radius_server_get_eap_user(void *ctx, const u8 *identity,
1245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      size_t identity_len, int phase2,
1246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      struct eap_user *user)
1247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess = ctx;
1249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *data = sess->server;
1250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->get_eap_user(data->conf_ctx, identity, identity_len,
1252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  phase2, user);
1253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
1257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *sess = ctx;
1259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_server_data *data = sess->server;
1260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*len = data->eap_req_id_text_len;
1261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->eap_req_id_text;
1262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct eapol_callbacks radius_server_eapol_cb =
1266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	.get_eap_user = radius_server_get_eap_user,
1268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	.get_eap_req_id_text = radius_server_get_eap_req_id_text,
1269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
1270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
1273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_client *cli;
1275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_session *s, *sess = NULL;
1276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct radius_msg *msg;
1277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
1279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
1280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (cli = data->clients; cli; cli = cli->next) {
1282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (s = cli->sessions; s; s = s->next) {
1283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (s->eap == ctx && s->last_msg) {
1284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				sess = s;
1285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				break;
1286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
1287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (sess)
1288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				break;
1289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (sess)
1291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
1292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sess == NULL) {
1295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		RADIUS_DEBUG("No session matched callback ctx");
1296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
1297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = sess->last_msg;
1300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sess->last_msg = NULL;
1301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_sm_pending_cb(sess->eap);
1302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (radius_server_request(data, msg,
1303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  (struct sockaddr *) &sess->last_from,
1304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  sess->last_fromlen, cli,
1305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  sess->last_from_addr,
1306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  sess->last_from_port, sess) == -2)
1307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return; /* msg was stored with the session */
1308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	radius_msg_free(msg);
1310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(msg);
1311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1312