1/*
2 * RADIUS client
3 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "radius.h"
13#include "radius_client.h"
14#include "eloop.h"
15
16/* Defaults for RADIUS retransmit values (exponential backoff) */
17
18/**
19 * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
20 */
21#define RADIUS_CLIENT_FIRST_WAIT 3
22
23/**
24 * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
25 */
26#define RADIUS_CLIENT_MAX_WAIT 120
27
28/**
29 * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
30 *
31 * Maximum number of retransmit attempts before the entry is removed from
32 * retransmit list.
33 */
34#define RADIUS_CLIENT_MAX_RETRIES 10
35
36/**
37 * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
38 *
39 * Maximum number of entries in retransmit list (oldest entries will be
40 * removed, if this limit is exceeded).
41 */
42#define RADIUS_CLIENT_MAX_ENTRIES 30
43
44/**
45 * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
46 *
47 * The number of failed retry attempts after which the RADIUS server will be
48 * changed (if one of more backup servers are configured).
49 */
50#define RADIUS_CLIENT_NUM_FAILOVER 4
51
52
53/**
54 * struct radius_rx_handler - RADIUS client RX handler
55 *
56 * This data structure is used internally inside the RADIUS client module to
57 * store registered RX handlers. These handlers are registered by calls to
58 * radius_client_register() and unregistered when the RADIUS client is
59 * deinitialized with a call to radius_client_deinit().
60 */
61struct radius_rx_handler {
62	/**
63	 * handler - Received RADIUS message handler
64	 */
65	RadiusRxResult (*handler)(struct radius_msg *msg,
66				  struct radius_msg *req,
67				  const u8 *shared_secret,
68				  size_t shared_secret_len,
69				  void *data);
70
71	/**
72	 * data - Context data for the handler
73	 */
74	void *data;
75};
76
77
78/**
79 * struct radius_msg_list - RADIUS client message retransmit list
80 *
81 * This data structure is used internally inside the RADIUS client module to
82 * store pending RADIUS requests that may still need to be retransmitted.
83 */
84struct radius_msg_list {
85	/**
86	 * addr - STA/client address
87	 *
88	 * This is used to find RADIUS messages for the same STA.
89	 */
90	u8 addr[ETH_ALEN];
91
92	/**
93	 * msg - RADIUS message
94	 */
95	struct radius_msg *msg;
96
97	/**
98	 * msg_type - Message type
99	 */
100	RadiusType msg_type;
101
102	/**
103	 * first_try - Time of the first transmission attempt
104	 */
105	os_time_t first_try;
106
107	/**
108	 * next_try - Time for the next transmission attempt
109	 */
110	os_time_t next_try;
111
112	/**
113	 * attempts - Number of transmission attempts
114	 */
115	int attempts;
116
117	/**
118	 * next_wait - Next retransmission wait time in seconds
119	 */
120	int next_wait;
121
122	/**
123	 * last_attempt - Time of the last transmission attempt
124	 */
125	struct os_reltime last_attempt;
126
127	/**
128	 * shared_secret - Shared secret with the target RADIUS server
129	 */
130	const u8 *shared_secret;
131
132	/**
133	 * shared_secret_len - shared_secret length in octets
134	 */
135	size_t shared_secret_len;
136
137	/* TODO: server config with failover to backup server(s) */
138
139	/**
140	 * next - Next message in the list
141	 */
142	struct radius_msg_list *next;
143};
144
145
146/**
147 * struct radius_client_data - Internal RADIUS client data
148 *
149 * This data structure is used internally inside the RADIUS client module.
150 * External users allocate this by calling radius_client_init() and free it by
151 * calling radius_client_deinit(). The pointer to this opaque data is used in
152 * calls to other functions as an identifier for the RADIUS client instance.
153 */
154struct radius_client_data {
155	/**
156	 * ctx - Context pointer for hostapd_logger() callbacks
157	 */
158	void *ctx;
159
160	/**
161	 * conf - RADIUS client configuration (list of RADIUS servers to use)
162	 */
163	struct hostapd_radius_servers *conf;
164
165	/**
166	 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
167	 */
168	int auth_serv_sock;
169
170	/**
171	 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
172	 */
173	int acct_serv_sock;
174
175	/**
176	 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
177	 */
178	int auth_serv_sock6;
179
180	/**
181	 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
182	 */
183	int acct_serv_sock6;
184
185	/**
186	 * auth_sock - Currently used socket for RADIUS authentication server
187	 */
188	int auth_sock;
189
190	/**
191	 * acct_sock - Currently used socket for RADIUS accounting server
192	 */
193	int acct_sock;
194
195	/**
196	 * auth_handlers - Authentication message handlers
197	 */
198	struct radius_rx_handler *auth_handlers;
199
200	/**
201	 * num_auth_handlers - Number of handlers in auth_handlers
202	 */
203	size_t num_auth_handlers;
204
205	/**
206	 * acct_handlers - Accounting message handlers
207	 */
208	struct radius_rx_handler *acct_handlers;
209
210	/**
211	 * num_acct_handlers - Number of handlers in acct_handlers
212	 */
213	size_t num_acct_handlers;
214
215	/**
216	 * msgs - Pending outgoing RADIUS messages
217	 */
218	struct radius_msg_list *msgs;
219
220	/**
221	 * num_msgs - Number of pending messages in the msgs list
222	 */
223	size_t num_msgs;
224
225	/**
226	 * next_radius_identifier - Next RADIUS message identifier to use
227	 */
228	u8 next_radius_identifier;
229
230	/**
231	 * interim_error_cb - Interim accounting error callback
232	 */
233	void (*interim_error_cb)(const u8 *addr, void *ctx);
234
235	/**
236	 * interim_error_cb_ctx - interim_error_cb() context data
237	 */
238	void *interim_error_cb_ctx;
239};
240
241
242static int
243radius_change_server(struct radius_client_data *radius,
244		     struct hostapd_radius_server *nserv,
245		     struct hostapd_radius_server *oserv,
246		     int sock, int sock6, int auth);
247static int radius_client_init_acct(struct radius_client_data *radius);
248static int radius_client_init_auth(struct radius_client_data *radius);
249static void radius_client_auth_failover(struct radius_client_data *radius);
250static void radius_client_acct_failover(struct radius_client_data *radius);
251
252
253static void radius_client_msg_free(struct radius_msg_list *req)
254{
255	radius_msg_free(req->msg);
256	os_free(req);
257}
258
259
260/**
261 * radius_client_register - Register a RADIUS client RX handler
262 * @radius: RADIUS client context from radius_client_init()
263 * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
264 * @handler: Handler for received RADIUS messages
265 * @data: Context pointer for handler callbacks
266 * Returns: 0 on success, -1 on failure
267 *
268 * This function is used to register a handler for processing received RADIUS
269 * authentication and accounting messages. The handler() callback function will
270 * be called whenever a RADIUS message is received from the active server.
271 *
272 * There can be multiple registered RADIUS message handlers. The handlers will
273 * be called in order until one of them indicates that it has processed or
274 * queued the message.
275 */
276int radius_client_register(struct radius_client_data *radius,
277			   RadiusType msg_type,
278			   RadiusRxResult (*handler)(struct radius_msg *msg,
279						     struct radius_msg *req,
280						     const u8 *shared_secret,
281						     size_t shared_secret_len,
282						     void *data),
283			   void *data)
284{
285	struct radius_rx_handler **handlers, *newh;
286	size_t *num;
287
288	if (msg_type == RADIUS_ACCT) {
289		handlers = &radius->acct_handlers;
290		num = &radius->num_acct_handlers;
291	} else {
292		handlers = &radius->auth_handlers;
293		num = &radius->num_auth_handlers;
294	}
295
296	newh = os_realloc_array(*handlers, *num + 1,
297				sizeof(struct radius_rx_handler));
298	if (newh == NULL)
299		return -1;
300
301	newh[*num].handler = handler;
302	newh[*num].data = data;
303	(*num)++;
304	*handlers = newh;
305
306	return 0;
307}
308
309
310/**
311 * radius_client_set_interim_erro_cb - Register an interim acct error callback
312 * @radius: RADIUS client context from radius_client_init()
313 * @addr: Station address from the failed message
314 * @cb: Handler for interim accounting errors
315 * @ctx: Context pointer for handler callbacks
316 *
317 * This function is used to register a handler for processing failed
318 * transmission attempts of interim accounting update messages.
319 */
320void radius_client_set_interim_error_cb(struct radius_client_data *radius,
321					void (*cb)(const u8 *addr, void *ctx),
322					void *ctx)
323{
324	radius->interim_error_cb = cb;
325	radius->interim_error_cb_ctx = ctx;
326}
327
328
329/*
330 * Returns >0 if message queue was flushed (i.e., the message that triggered
331 * the error is not available anymore)
332 */
333static int radius_client_handle_send_error(struct radius_client_data *radius,
334					   int s, RadiusType msg_type)
335{
336#ifndef CONFIG_NATIVE_WINDOWS
337	int _errno = errno;
338	wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
339	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
340	    _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
341		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
342			       HOSTAPD_LEVEL_INFO,
343			       "Send failed - maybe interface status changed -"
344			       " try to connect again");
345		if (msg_type == RADIUS_ACCT ||
346		    msg_type == RADIUS_ACCT_INTERIM) {
347			radius_client_init_acct(radius);
348			return 0;
349		} else {
350			radius_client_init_auth(radius);
351			return 1;
352		}
353	}
354#endif /* CONFIG_NATIVE_WINDOWS */
355
356	return 0;
357}
358
359
360static int radius_client_retransmit(struct radius_client_data *radius,
361				    struct radius_msg_list *entry,
362				    os_time_t now)
363{
364	struct hostapd_radius_servers *conf = radius->conf;
365	int s;
366	struct wpabuf *buf;
367	size_t prev_num_msgs;
368	u8 *acct_delay_time;
369	size_t acct_delay_time_len;
370
371	if (entry->msg_type == RADIUS_ACCT ||
372	    entry->msg_type == RADIUS_ACCT_INTERIM) {
373		if (radius->acct_sock < 0)
374			radius_client_init_acct(radius);
375		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
376			prev_num_msgs = radius->num_msgs;
377			radius_client_acct_failover(radius);
378			if (prev_num_msgs != radius->num_msgs)
379				return 0;
380		}
381		s = radius->acct_sock;
382		if (entry->attempts == 0)
383			conf->acct_server->requests++;
384		else {
385			conf->acct_server->timeouts++;
386			conf->acct_server->retransmissions++;
387		}
388	} else {
389		if (radius->auth_sock < 0)
390			radius_client_init_auth(radius);
391		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
392			prev_num_msgs = radius->num_msgs;
393			radius_client_auth_failover(radius);
394			if (prev_num_msgs != radius->num_msgs)
395				return 0;
396		}
397		s = radius->auth_sock;
398		if (entry->attempts == 0)
399			conf->auth_server->requests++;
400		else {
401			conf->auth_server->timeouts++;
402			conf->auth_server->retransmissions++;
403		}
404	}
405
406	if (entry->msg_type == RADIUS_ACCT_INTERIM) {
407		wpa_printf(MSG_DEBUG,
408			   "RADIUS: Failed to transmit interim accounting update to "
409			   MACSTR " - drop message and request a new update",
410			   MAC2STR(entry->addr));
411		if (radius->interim_error_cb)
412			radius->interim_error_cb(entry->addr,
413						 radius->interim_error_cb_ctx);
414		return 1;
415	}
416
417	if (s < 0) {
418		wpa_printf(MSG_INFO,
419			   "RADIUS: No valid socket for retransmission");
420		return 1;
421	}
422
423	if (entry->msg_type == RADIUS_ACCT &&
424	    radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
425				    &acct_delay_time, &acct_delay_time_len,
426				    NULL) == 0 &&
427	    acct_delay_time_len == 4) {
428		struct radius_hdr *hdr;
429		u32 delay_time;
430
431		/*
432		 * Need to assign a new identifier since attribute contents
433		 * changes.
434		 */
435		hdr = radius_msg_get_hdr(entry->msg);
436		hdr->identifier = radius_client_get_id(radius);
437
438		/* Update Acct-Delay-Time to show wait time in queue */
439		delay_time = now - entry->first_try;
440		WPA_PUT_BE32(acct_delay_time, delay_time);
441
442		wpa_printf(MSG_DEBUG,
443			   "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
444			   delay_time);
445		radius_msg_finish_acct(entry->msg, entry->shared_secret,
446				       entry->shared_secret_len);
447		if (radius->conf->msg_dumps)
448			radius_msg_dump(entry->msg);
449	}
450
451	/* retransmit; remove entry if too many attempts */
452	entry->attempts++;
453	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
454		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
455		       radius_msg_get_hdr(entry->msg)->identifier);
456
457	os_get_reltime(&entry->last_attempt);
458	buf = radius_msg_get_buf(entry->msg);
459	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
460		if (radius_client_handle_send_error(radius, s, entry->msg_type)
461		    > 0)
462			return 0;
463	}
464
465	entry->next_try = now + entry->next_wait;
466	entry->next_wait *= 2;
467	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
468		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
469	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
470		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
471		return 1;
472	}
473
474	return 0;
475}
476
477
478static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
479{
480	struct radius_client_data *radius = eloop_ctx;
481	struct os_reltime now;
482	os_time_t first;
483	struct radius_msg_list *entry, *prev, *tmp;
484	int auth_failover = 0, acct_failover = 0;
485	size_t prev_num_msgs;
486	int s;
487
488	entry = radius->msgs;
489	if (!entry)
490		return;
491
492	os_get_reltime(&now);
493	first = 0;
494
495	prev = NULL;
496	while (entry) {
497		prev_num_msgs = radius->num_msgs;
498		if (now.sec >= entry->next_try &&
499		    radius_client_retransmit(radius, entry, now.sec)) {
500			if (prev)
501				prev->next = entry->next;
502			else
503				radius->msgs = entry->next;
504
505			tmp = entry;
506			entry = entry->next;
507			radius_client_msg_free(tmp);
508			radius->num_msgs--;
509			continue;
510		}
511
512		if (prev_num_msgs != radius->num_msgs) {
513			wpa_printf(MSG_DEBUG,
514				   "RADIUS: Message removed from queue - restart from beginning");
515			entry = radius->msgs;
516			prev = NULL;
517			continue;
518		}
519
520		s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
521			radius->acct_sock;
522		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
523		    (s < 0 && entry->attempts > 0)) {
524			if (entry->msg_type == RADIUS_ACCT ||
525			    entry->msg_type == RADIUS_ACCT_INTERIM)
526				acct_failover++;
527			else
528				auth_failover++;
529		}
530
531		if (first == 0 || entry->next_try < first)
532			first = entry->next_try;
533
534		prev = entry;
535		entry = entry->next;
536	}
537
538	if (radius->msgs) {
539		if (first < now.sec)
540			first = now.sec;
541		eloop_register_timeout(first - now.sec, 0,
542				       radius_client_timer, radius, NULL);
543		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
544			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
545			       "retransmit in %ld seconds",
546			       (long int) (first - now.sec));
547	}
548
549	if (auth_failover)
550		radius_client_auth_failover(radius);
551
552	if (acct_failover)
553		radius_client_acct_failover(radius);
554}
555
556
557static void radius_client_auth_failover(struct radius_client_data *radius)
558{
559	struct hostapd_radius_servers *conf = radius->conf;
560	struct hostapd_radius_server *next, *old;
561	struct radius_msg_list *entry;
562	char abuf[50];
563
564	old = conf->auth_server;
565	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
566		       HOSTAPD_LEVEL_NOTICE,
567		       "No response from Authentication server %s:%d - failover",
568		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
569		       old->port);
570
571	for (entry = radius->msgs; entry; entry = entry->next) {
572		if (entry->msg_type == RADIUS_AUTH)
573			old->timeouts++;
574	}
575
576	next = old + 1;
577	if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
578		next = conf->auth_servers;
579	conf->auth_server = next;
580	radius_change_server(radius, next, old,
581			     radius->auth_serv_sock,
582			     radius->auth_serv_sock6, 1);
583}
584
585
586static void radius_client_acct_failover(struct radius_client_data *radius)
587{
588	struct hostapd_radius_servers *conf = radius->conf;
589	struct hostapd_radius_server *next, *old;
590	struct radius_msg_list *entry;
591	char abuf[50];
592
593	old = conf->acct_server;
594	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
595		       HOSTAPD_LEVEL_NOTICE,
596		       "No response from Accounting server %s:%d - failover",
597		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
598		       old->port);
599
600	for (entry = radius->msgs; entry; entry = entry->next) {
601		if (entry->msg_type == RADIUS_ACCT ||
602		    entry->msg_type == RADIUS_ACCT_INTERIM)
603			old->timeouts++;
604	}
605
606	next = old + 1;
607	if (next > &conf->acct_servers[conf->num_acct_servers - 1])
608		next = conf->acct_servers;
609	conf->acct_server = next;
610	radius_change_server(radius, next, old,
611			     radius->acct_serv_sock,
612			     radius->acct_serv_sock6, 0);
613}
614
615
616static void radius_client_update_timeout(struct radius_client_data *radius)
617{
618	struct os_reltime now;
619	os_time_t first;
620	struct radius_msg_list *entry;
621
622	eloop_cancel_timeout(radius_client_timer, radius, NULL);
623
624	if (radius->msgs == NULL) {
625		return;
626	}
627
628	first = 0;
629	for (entry = radius->msgs; entry; entry = entry->next) {
630		if (first == 0 || entry->next_try < first)
631			first = entry->next_try;
632	}
633
634	os_get_reltime(&now);
635	if (first < now.sec)
636		first = now.sec;
637	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
638			       NULL);
639	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
640		       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
641		       " %ld seconds", (long int) (first - now.sec));
642}
643
644
645static void radius_client_list_add(struct radius_client_data *radius,
646				   struct radius_msg *msg,
647				   RadiusType msg_type,
648				   const u8 *shared_secret,
649				   size_t shared_secret_len, const u8 *addr)
650{
651	struct radius_msg_list *entry, *prev;
652
653	if (eloop_terminated()) {
654		/* No point in adding entries to retransmit queue since event
655		 * loop has already been terminated. */
656		radius_msg_free(msg);
657		return;
658	}
659
660	entry = os_zalloc(sizeof(*entry));
661	if (entry == NULL) {
662		wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
663		radius_msg_free(msg);
664		return;
665	}
666
667	if (addr)
668		os_memcpy(entry->addr, addr, ETH_ALEN);
669	entry->msg = msg;
670	entry->msg_type = msg_type;
671	entry->shared_secret = shared_secret;
672	entry->shared_secret_len = shared_secret_len;
673	os_get_reltime(&entry->last_attempt);
674	entry->first_try = entry->last_attempt.sec;
675	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
676	entry->attempts = 1;
677	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
678	entry->next = radius->msgs;
679	radius->msgs = entry;
680	radius_client_update_timeout(radius);
681
682	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
683		wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
684		prev = NULL;
685		while (entry->next) {
686			prev = entry;
687			entry = entry->next;
688		}
689		if (prev) {
690			prev->next = NULL;
691			radius_client_msg_free(entry);
692		}
693	} else
694		radius->num_msgs++;
695}
696
697
698/**
699 * radius_client_send - Send a RADIUS request
700 * @radius: RADIUS client context from radius_client_init()
701 * @msg: RADIUS message to be sent
702 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
703 * @addr: MAC address of the device related to this message or %NULL
704 * Returns: 0 on success, -1 on failure
705 *
706 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
707 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
708 * between accounting and interim accounting messages is that the interim
709 * message will not be retransmitted. Instead, a callback is used to indicate
710 * that the transmission failed for the specific station @addr so that a new
711 * interim accounting update message can be generated with up-to-date session
712 * data instead of trying to resend old information.
713 *
714 * The message is added on the retransmission queue and will be retransmitted
715 * automatically until a response is received or maximum number of retries
716 * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
717 * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
718 * automatically on transmission failure.
719 *
720 * The related device MAC address can be used to identify pending messages that
721 * can be removed with radius_client_flush_auth().
722 */
723int radius_client_send(struct radius_client_data *radius,
724		       struct radius_msg *msg, RadiusType msg_type,
725		       const u8 *addr)
726{
727	struct hostapd_radius_servers *conf = radius->conf;
728	const u8 *shared_secret;
729	size_t shared_secret_len;
730	char *name;
731	int s, res;
732	struct wpabuf *buf;
733
734	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
735		if (conf->acct_server && radius->acct_sock < 0)
736			radius_client_init_acct(radius);
737
738		if (conf->acct_server == NULL || radius->acct_sock < 0 ||
739		    conf->acct_server->shared_secret == NULL) {
740			hostapd_logger(radius->ctx, NULL,
741				       HOSTAPD_MODULE_RADIUS,
742				       HOSTAPD_LEVEL_INFO,
743				       "No accounting server configured");
744			return -1;
745		}
746		shared_secret = conf->acct_server->shared_secret;
747		shared_secret_len = conf->acct_server->shared_secret_len;
748		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
749		name = "accounting";
750		s = radius->acct_sock;
751		conf->acct_server->requests++;
752	} else {
753		if (conf->auth_server && radius->auth_sock < 0)
754			radius_client_init_auth(radius);
755
756		if (conf->auth_server == NULL || radius->auth_sock < 0 ||
757		    conf->auth_server->shared_secret == NULL) {
758			hostapd_logger(radius->ctx, NULL,
759				       HOSTAPD_MODULE_RADIUS,
760				       HOSTAPD_LEVEL_INFO,
761				       "No authentication server configured");
762			return -1;
763		}
764		shared_secret = conf->auth_server->shared_secret;
765		shared_secret_len = conf->auth_server->shared_secret_len;
766		radius_msg_finish(msg, shared_secret, shared_secret_len);
767		name = "authentication";
768		s = radius->auth_sock;
769		conf->auth_server->requests++;
770	}
771
772	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
773		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
774		       "server", name);
775	if (conf->msg_dumps)
776		radius_msg_dump(msg);
777
778	buf = radius_msg_get_buf(msg);
779	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
780	if (res < 0)
781		radius_client_handle_send_error(radius, s, msg_type);
782
783	radius_client_list_add(radius, msg, msg_type, shared_secret,
784			       shared_secret_len, addr);
785
786	return 0;
787}
788
789
790static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
791{
792	struct radius_client_data *radius = eloop_ctx;
793	struct hostapd_radius_servers *conf = radius->conf;
794	RadiusType msg_type = (RadiusType) sock_ctx;
795	int len, roundtrip;
796	unsigned char buf[3000];
797	struct radius_msg *msg;
798	struct radius_hdr *hdr;
799	struct radius_rx_handler *handlers;
800	size_t num_handlers, i;
801	struct radius_msg_list *req, *prev_req;
802	struct os_reltime now;
803	struct hostapd_radius_server *rconf;
804	int invalid_authenticator = 0;
805
806	if (msg_type == RADIUS_ACCT) {
807		handlers = radius->acct_handlers;
808		num_handlers = radius->num_acct_handlers;
809		rconf = conf->acct_server;
810	} else {
811		handlers = radius->auth_handlers;
812		num_handlers = radius->num_auth_handlers;
813		rconf = conf->auth_server;
814	}
815
816	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
817	if (len < 0) {
818		wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
819		return;
820	}
821	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
822		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
823		       "server", len);
824	if (len == sizeof(buf)) {
825		wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
826		return;
827	}
828
829	msg = radius_msg_parse(buf, len);
830	if (msg == NULL) {
831		wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
832		rconf->malformed_responses++;
833		return;
834	}
835	hdr = radius_msg_get_hdr(msg);
836
837	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
838		       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
839	if (conf->msg_dumps)
840		radius_msg_dump(msg);
841
842	switch (hdr->code) {
843	case RADIUS_CODE_ACCESS_ACCEPT:
844		rconf->access_accepts++;
845		break;
846	case RADIUS_CODE_ACCESS_REJECT:
847		rconf->access_rejects++;
848		break;
849	case RADIUS_CODE_ACCESS_CHALLENGE:
850		rconf->access_challenges++;
851		break;
852	case RADIUS_CODE_ACCOUNTING_RESPONSE:
853		rconf->responses++;
854		break;
855	}
856
857	prev_req = NULL;
858	req = radius->msgs;
859	while (req) {
860		/* TODO: also match by src addr:port of the packet when using
861		 * alternative RADIUS servers (?) */
862		if ((req->msg_type == msg_type ||
863		     (req->msg_type == RADIUS_ACCT_INTERIM &&
864		      msg_type == RADIUS_ACCT)) &&
865		    radius_msg_get_hdr(req->msg)->identifier ==
866		    hdr->identifier)
867			break;
868
869		prev_req = req;
870		req = req->next;
871	}
872
873	if (req == NULL) {
874		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
875			       HOSTAPD_LEVEL_DEBUG,
876			       "No matching RADIUS request found (type=%d "
877			       "id=%d) - dropping packet",
878			       msg_type, hdr->identifier);
879		goto fail;
880	}
881
882	os_get_reltime(&now);
883	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
884		(now.usec - req->last_attempt.usec) / 10000;
885	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
886		       HOSTAPD_LEVEL_DEBUG,
887		       "Received RADIUS packet matched with a pending "
888		       "request, round trip time %d.%02d sec",
889		       roundtrip / 100, roundtrip % 100);
890	rconf->round_trip_time = roundtrip;
891
892	/* Remove ACKed RADIUS packet from retransmit list */
893	if (prev_req)
894		prev_req->next = req->next;
895	else
896		radius->msgs = req->next;
897	radius->num_msgs--;
898
899	for (i = 0; i < num_handlers; i++) {
900		RadiusRxResult res;
901		res = handlers[i].handler(msg, req->msg, req->shared_secret,
902					  req->shared_secret_len,
903					  handlers[i].data);
904		switch (res) {
905		case RADIUS_RX_PROCESSED:
906			radius_msg_free(msg);
907			/* continue */
908		case RADIUS_RX_QUEUED:
909			radius_client_msg_free(req);
910			return;
911		case RADIUS_RX_INVALID_AUTHENTICATOR:
912			invalid_authenticator++;
913			/* continue */
914		case RADIUS_RX_UNKNOWN:
915			/* continue with next handler */
916			break;
917		}
918	}
919
920	if (invalid_authenticator)
921		rconf->bad_authenticators++;
922	else
923		rconf->unknown_types++;
924	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
925		       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
926		       "(type=%d code=%d id=%d)%s - dropping packet",
927		       msg_type, hdr->code, hdr->identifier,
928		       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
929		       "");
930	radius_client_msg_free(req);
931
932 fail:
933	radius_msg_free(msg);
934}
935
936
937/**
938 * radius_client_get_id - Get an identifier for a new RADIUS message
939 * @radius: RADIUS client context from radius_client_init()
940 * Returns: Allocated identifier
941 *
942 * This function is used to fetch a unique (among pending requests) identifier
943 * for a new RADIUS message.
944 */
945u8 radius_client_get_id(struct radius_client_data *radius)
946{
947	struct radius_msg_list *entry, *prev, *_remove;
948	u8 id = radius->next_radius_identifier++;
949
950	/* remove entries with matching id from retransmit list to avoid
951	 * using new reply from the RADIUS server with an old request */
952	entry = radius->msgs;
953	prev = NULL;
954	while (entry) {
955		if (radius_msg_get_hdr(entry->msg)->identifier == id) {
956			hostapd_logger(radius->ctx, entry->addr,
957				       HOSTAPD_MODULE_RADIUS,
958				       HOSTAPD_LEVEL_DEBUG,
959				       "Removing pending RADIUS message, "
960				       "since its id (%d) is reused", id);
961			if (prev)
962				prev->next = entry->next;
963			else
964				radius->msgs = entry->next;
965			_remove = entry;
966		} else {
967			_remove = NULL;
968			prev = entry;
969		}
970		entry = entry->next;
971
972		if (_remove)
973			radius_client_msg_free(_remove);
974	}
975
976	return id;
977}
978
979
980/**
981 * radius_client_flush - Flush all pending RADIUS client messages
982 * @radius: RADIUS client context from radius_client_init()
983 * @only_auth: Whether only authentication messages are removed
984 */
985void radius_client_flush(struct radius_client_data *radius, int only_auth)
986{
987	struct radius_msg_list *entry, *prev, *tmp;
988
989	if (!radius)
990		return;
991
992	prev = NULL;
993	entry = radius->msgs;
994
995	while (entry) {
996		if (!only_auth || entry->msg_type == RADIUS_AUTH) {
997			if (prev)
998				prev->next = entry->next;
999			else
1000				radius->msgs = entry->next;
1001
1002			tmp = entry;
1003			entry = entry->next;
1004			radius_client_msg_free(tmp);
1005			radius->num_msgs--;
1006		} else {
1007			prev = entry;
1008			entry = entry->next;
1009		}
1010	}
1011
1012	if (radius->msgs == NULL)
1013		eloop_cancel_timeout(radius_client_timer, radius, NULL);
1014}
1015
1016
1017static void radius_client_update_acct_msgs(struct radius_client_data *radius,
1018					   const u8 *shared_secret,
1019					   size_t shared_secret_len)
1020{
1021	struct radius_msg_list *entry;
1022
1023	if (!radius)
1024		return;
1025
1026	for (entry = radius->msgs; entry; entry = entry->next) {
1027		if (entry->msg_type == RADIUS_ACCT) {
1028			entry->shared_secret = shared_secret;
1029			entry->shared_secret_len = shared_secret_len;
1030			radius_msg_finish_acct(entry->msg, shared_secret,
1031					       shared_secret_len);
1032		}
1033	}
1034}
1035
1036
1037static int
1038radius_change_server(struct radius_client_data *radius,
1039		     struct hostapd_radius_server *nserv,
1040		     struct hostapd_radius_server *oserv,
1041		     int sock, int sock6, int auth)
1042{
1043	struct sockaddr_in serv, claddr;
1044#ifdef CONFIG_IPV6
1045	struct sockaddr_in6 serv6, claddr6;
1046#endif /* CONFIG_IPV6 */
1047	struct sockaddr *addr, *cl_addr;
1048	socklen_t addrlen, claddrlen;
1049	char abuf[50];
1050	int sel_sock;
1051	struct radius_msg_list *entry;
1052	struct hostapd_radius_servers *conf = radius->conf;
1053	struct sockaddr_in disconnect_addr = {
1054		.sin_family = AF_UNSPEC,
1055	};
1056
1057	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
1058		       HOSTAPD_LEVEL_INFO,
1059		       "%s server %s:%d",
1060		       auth ? "Authentication" : "Accounting",
1061		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
1062		       nserv->port);
1063
1064	if (oserv && oserv == nserv) {
1065		/* Reconnect to same server, flush */
1066		if (auth)
1067			radius_client_flush(radius, 1);
1068	}
1069
1070	if (oserv && oserv != nserv &&
1071	    (nserv->shared_secret_len != oserv->shared_secret_len ||
1072	     os_memcmp(nserv->shared_secret, oserv->shared_secret,
1073		       nserv->shared_secret_len) != 0)) {
1074		/* Pending RADIUS packets used different shared secret, so
1075		 * they need to be modified. Update accounting message
1076		 * authenticators here. Authentication messages are removed
1077		 * since they would require more changes and the new RADIUS
1078		 * server may not be prepared to receive them anyway due to
1079		 * missing state information. Client will likely retry
1080		 * authentication, so this should not be an issue. */
1081		if (auth)
1082			radius_client_flush(radius, 1);
1083		else {
1084			radius_client_update_acct_msgs(
1085				radius, nserv->shared_secret,
1086				nserv->shared_secret_len);
1087		}
1088	}
1089
1090	/* Reset retry counters for the new server */
1091	for (entry = radius->msgs; oserv && oserv != nserv && entry;
1092	     entry = entry->next) {
1093		if ((auth && entry->msg_type != RADIUS_AUTH) ||
1094		    (!auth && entry->msg_type != RADIUS_ACCT))
1095			continue;
1096		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
1097		entry->attempts = 0;
1098		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
1099	}
1100
1101	if (radius->msgs) {
1102		eloop_cancel_timeout(radius_client_timer, radius, NULL);
1103		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
1104				       radius_client_timer, radius, NULL);
1105	}
1106
1107	switch (nserv->addr.af) {
1108	case AF_INET:
1109		os_memset(&serv, 0, sizeof(serv));
1110		serv.sin_family = AF_INET;
1111		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
1112		serv.sin_port = htons(nserv->port);
1113		addr = (struct sockaddr *) &serv;
1114		addrlen = sizeof(serv);
1115		sel_sock = sock;
1116		break;
1117#ifdef CONFIG_IPV6
1118	case AF_INET6:
1119		os_memset(&serv6, 0, sizeof(serv6));
1120		serv6.sin6_family = AF_INET6;
1121		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
1122			  sizeof(struct in6_addr));
1123		serv6.sin6_port = htons(nserv->port);
1124		addr = (struct sockaddr *) &serv6;
1125		addrlen = sizeof(serv6);
1126		sel_sock = sock6;
1127		break;
1128#endif /* CONFIG_IPV6 */
1129	default:
1130		return -1;
1131	}
1132
1133	if (sel_sock < 0) {
1134		wpa_printf(MSG_INFO,
1135			   "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
1136			   nserv->addr.af, sock, sock6, auth);
1137		return -1;
1138	}
1139
1140	if (conf->force_client_addr) {
1141		switch (conf->client_addr.af) {
1142		case AF_INET:
1143			os_memset(&claddr, 0, sizeof(claddr));
1144			claddr.sin_family = AF_INET;
1145			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
1146			claddr.sin_port = htons(0);
1147			cl_addr = (struct sockaddr *) &claddr;
1148			claddrlen = sizeof(claddr);
1149			break;
1150#ifdef CONFIG_IPV6
1151		case AF_INET6:
1152			os_memset(&claddr6, 0, sizeof(claddr6));
1153			claddr6.sin6_family = AF_INET6;
1154			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
1155				  sizeof(struct in6_addr));
1156			claddr6.sin6_port = htons(0);
1157			cl_addr = (struct sockaddr *) &claddr6;
1158			claddrlen = sizeof(claddr6);
1159			break;
1160#endif /* CONFIG_IPV6 */
1161		default:
1162			return -1;
1163		}
1164
1165		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
1166			wpa_printf(MSG_INFO, "bind[radius]: %s",
1167				   strerror(errno));
1168			return -1;
1169		}
1170	}
1171
1172	/* Force a reconnect by disconnecting the socket first */
1173	if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
1174		    sizeof(disconnect_addr)) < 0)
1175		wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
1176
1177	if (connect(sel_sock, addr, addrlen) < 0) {
1178		wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
1179		return -1;
1180	}
1181
1182#ifndef CONFIG_NATIVE_WINDOWS
1183	switch (nserv->addr.af) {
1184	case AF_INET:
1185		claddrlen = sizeof(claddr);
1186		if (getsockname(sel_sock, (struct sockaddr *) &claddr,
1187				&claddrlen) == 0) {
1188			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1189				   inet_ntoa(claddr.sin_addr),
1190				   ntohs(claddr.sin_port));
1191		}
1192		break;
1193#ifdef CONFIG_IPV6
1194	case AF_INET6: {
1195		claddrlen = sizeof(claddr6);
1196		if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
1197				&claddrlen) == 0) {
1198			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1199				   inet_ntop(AF_INET6, &claddr6.sin6_addr,
1200					     abuf, sizeof(abuf)),
1201				   ntohs(claddr6.sin6_port));
1202		}
1203		break;
1204	}
1205#endif /* CONFIG_IPV6 */
1206	}
1207#endif /* CONFIG_NATIVE_WINDOWS */
1208
1209	if (auth)
1210		radius->auth_sock = sel_sock;
1211	else
1212		radius->acct_sock = sel_sock;
1213
1214	return 0;
1215}
1216
1217
1218static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1219{
1220	struct radius_client_data *radius = eloop_ctx;
1221	struct hostapd_radius_servers *conf = radius->conf;
1222	struct hostapd_radius_server *oserv;
1223
1224	if (radius->auth_sock >= 0 && conf->auth_servers &&
1225	    conf->auth_server != conf->auth_servers) {
1226		oserv = conf->auth_server;
1227		conf->auth_server = conf->auth_servers;
1228		if (radius_change_server(radius, conf->auth_server, oserv,
1229					 radius->auth_serv_sock,
1230					 radius->auth_serv_sock6, 1) < 0) {
1231			conf->auth_server = oserv;
1232			radius_change_server(radius, oserv, conf->auth_server,
1233					     radius->auth_serv_sock,
1234					     radius->auth_serv_sock6, 1);
1235		}
1236	}
1237
1238	if (radius->acct_sock >= 0 && conf->acct_servers &&
1239	    conf->acct_server != conf->acct_servers) {
1240		oserv = conf->acct_server;
1241		conf->acct_server = conf->acct_servers;
1242		if (radius_change_server(radius, conf->acct_server, oserv,
1243					 radius->acct_serv_sock,
1244					 radius->acct_serv_sock6, 0) < 0) {
1245			conf->acct_server = oserv;
1246			radius_change_server(radius, oserv, conf->acct_server,
1247					     radius->acct_serv_sock,
1248					     radius->acct_serv_sock6, 0);
1249		}
1250	}
1251
1252	if (conf->retry_primary_interval)
1253		eloop_register_timeout(conf->retry_primary_interval, 0,
1254				       radius_retry_primary_timer, radius,
1255				       NULL);
1256}
1257
1258
1259static int radius_client_disable_pmtu_discovery(int s)
1260{
1261	int r = -1;
1262#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1263	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
1264	int action = IP_PMTUDISC_DONT;
1265	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1266		       sizeof(action));
1267	if (r == -1)
1268		wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1269			   strerror(errno));
1270#endif
1271	return r;
1272}
1273
1274
1275static void radius_close_auth_sockets(struct radius_client_data *radius)
1276{
1277	radius->auth_sock = -1;
1278
1279	if (radius->auth_serv_sock >= 0) {
1280		eloop_unregister_read_sock(radius->auth_serv_sock);
1281		close(radius->auth_serv_sock);
1282		radius->auth_serv_sock = -1;
1283	}
1284#ifdef CONFIG_IPV6
1285	if (radius->auth_serv_sock6 >= 0) {
1286		eloop_unregister_read_sock(radius->auth_serv_sock6);
1287		close(radius->auth_serv_sock6);
1288		radius->auth_serv_sock6 = -1;
1289	}
1290#endif /* CONFIG_IPV6 */
1291}
1292
1293
1294static void radius_close_acct_sockets(struct radius_client_data *radius)
1295{
1296	radius->acct_sock = -1;
1297
1298	if (radius->acct_serv_sock >= 0) {
1299		eloop_unregister_read_sock(radius->acct_serv_sock);
1300		close(radius->acct_serv_sock);
1301		radius->acct_serv_sock = -1;
1302	}
1303#ifdef CONFIG_IPV6
1304	if (radius->acct_serv_sock6 >= 0) {
1305		eloop_unregister_read_sock(radius->acct_serv_sock6);
1306		close(radius->acct_serv_sock6);
1307		radius->acct_serv_sock6 = -1;
1308	}
1309#endif /* CONFIG_IPV6 */
1310}
1311
1312
1313static int radius_client_init_auth(struct radius_client_data *radius)
1314{
1315	struct hostapd_radius_servers *conf = radius->conf;
1316	int ok = 0;
1317
1318	radius_close_auth_sockets(radius);
1319
1320	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1321	if (radius->auth_serv_sock < 0)
1322		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1323			   strerror(errno));
1324	else {
1325		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
1326		ok++;
1327	}
1328
1329#ifdef CONFIG_IPV6
1330	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1331	if (radius->auth_serv_sock6 < 0)
1332		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1333			   strerror(errno));
1334	else
1335		ok++;
1336#endif /* CONFIG_IPV6 */
1337
1338	if (ok == 0)
1339		return -1;
1340
1341	radius_change_server(radius, conf->auth_server, NULL,
1342			     radius->auth_serv_sock, radius->auth_serv_sock6,
1343			     1);
1344
1345	if (radius->auth_serv_sock >= 0 &&
1346	    eloop_register_read_sock(radius->auth_serv_sock,
1347				     radius_client_receive, radius,
1348				     (void *) RADIUS_AUTH)) {
1349		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1350		radius_close_auth_sockets(radius);
1351		return -1;
1352	}
1353
1354#ifdef CONFIG_IPV6
1355	if (radius->auth_serv_sock6 >= 0 &&
1356	    eloop_register_read_sock(radius->auth_serv_sock6,
1357				     radius_client_receive, radius,
1358				     (void *) RADIUS_AUTH)) {
1359		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1360		radius_close_auth_sockets(radius);
1361		return -1;
1362	}
1363#endif /* CONFIG_IPV6 */
1364
1365	return 0;
1366}
1367
1368
1369static int radius_client_init_acct(struct radius_client_data *radius)
1370{
1371	struct hostapd_radius_servers *conf = radius->conf;
1372	int ok = 0;
1373
1374	radius_close_acct_sockets(radius);
1375
1376	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1377	if (radius->acct_serv_sock < 0)
1378		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1379			   strerror(errno));
1380	else {
1381		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
1382		ok++;
1383	}
1384
1385#ifdef CONFIG_IPV6
1386	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1387	if (radius->acct_serv_sock6 < 0)
1388		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1389			   strerror(errno));
1390	else
1391		ok++;
1392#endif /* CONFIG_IPV6 */
1393
1394	if (ok == 0)
1395		return -1;
1396
1397	radius_change_server(radius, conf->acct_server, NULL,
1398			     radius->acct_serv_sock, radius->acct_serv_sock6,
1399			     0);
1400
1401	if (radius->acct_serv_sock >= 0 &&
1402	    eloop_register_read_sock(radius->acct_serv_sock,
1403				     radius_client_receive, radius,
1404				     (void *) RADIUS_ACCT)) {
1405		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1406		radius_close_acct_sockets(radius);
1407		return -1;
1408	}
1409
1410#ifdef CONFIG_IPV6
1411	if (radius->acct_serv_sock6 >= 0 &&
1412	    eloop_register_read_sock(radius->acct_serv_sock6,
1413				     radius_client_receive, radius,
1414				     (void *) RADIUS_ACCT)) {
1415		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1416		radius_close_acct_sockets(radius);
1417		return -1;
1418	}
1419#endif /* CONFIG_IPV6 */
1420
1421	return 0;
1422}
1423
1424
1425/**
1426 * radius_client_init - Initialize RADIUS client
1427 * @ctx: Callback context to be used in hostapd_logger() calls
1428 * @conf: RADIUS client configuration (RADIUS servers)
1429 * Returns: Pointer to private RADIUS client context or %NULL on failure
1430 *
1431 * The caller is responsible for keeping the configuration data available for
1432 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1433 * called for the returned context pointer.
1434 */
1435struct radius_client_data *
1436radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1437{
1438	struct radius_client_data *radius;
1439
1440	radius = os_zalloc(sizeof(struct radius_client_data));
1441	if (radius == NULL)
1442		return NULL;
1443
1444	radius->ctx = ctx;
1445	radius->conf = conf;
1446	radius->auth_serv_sock = radius->acct_serv_sock =
1447		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1448		radius->auth_sock = radius->acct_sock = -1;
1449
1450	if (conf->auth_server && radius_client_init_auth(radius)) {
1451		radius_client_deinit(radius);
1452		return NULL;
1453	}
1454
1455	if (conf->acct_server && radius_client_init_acct(radius)) {
1456		radius_client_deinit(radius);
1457		return NULL;
1458	}
1459
1460	if (conf->retry_primary_interval)
1461		eloop_register_timeout(conf->retry_primary_interval, 0,
1462				       radius_retry_primary_timer, radius,
1463				       NULL);
1464
1465	return radius;
1466}
1467
1468
1469/**
1470 * radius_client_deinit - Deinitialize RADIUS client
1471 * @radius: RADIUS client context from radius_client_init()
1472 */
1473void radius_client_deinit(struct radius_client_data *radius)
1474{
1475	if (!radius)
1476		return;
1477
1478	radius_close_auth_sockets(radius);
1479	radius_close_acct_sockets(radius);
1480
1481	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1482
1483	radius_client_flush(radius, 0);
1484	os_free(radius->auth_handlers);
1485	os_free(radius->acct_handlers);
1486	os_free(radius);
1487}
1488
1489
1490/**
1491 * radius_client_flush_auth - Flush pending RADIUS messages for an address
1492 * @radius: RADIUS client context from radius_client_init()
1493 * @addr: MAC address of the related device
1494 *
1495 * This function can be used to remove pending RADIUS authentication messages
1496 * that are related to a specific device. The addr parameter is matched with
1497 * the one used in radius_client_send() call that was used to transmit the
1498 * authentication request.
1499 */
1500void radius_client_flush_auth(struct radius_client_data *radius,
1501			      const u8 *addr)
1502{
1503	struct radius_msg_list *entry, *prev, *tmp;
1504
1505	prev = NULL;
1506	entry = radius->msgs;
1507	while (entry) {
1508		if (entry->msg_type == RADIUS_AUTH &&
1509		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1510			hostapd_logger(radius->ctx, addr,
1511				       HOSTAPD_MODULE_RADIUS,
1512				       HOSTAPD_LEVEL_DEBUG,
1513				       "Removing pending RADIUS authentication"
1514				       " message for removed client");
1515
1516			if (prev)
1517				prev->next = entry->next;
1518			else
1519				radius->msgs = entry->next;
1520
1521			tmp = entry;
1522			entry = entry->next;
1523			radius_client_msg_free(tmp);
1524			radius->num_msgs--;
1525			continue;
1526		}
1527
1528		prev = entry;
1529		entry = entry->next;
1530	}
1531}
1532
1533
1534static int radius_client_dump_auth_server(char *buf, size_t buflen,
1535					  struct hostapd_radius_server *serv,
1536					  struct radius_client_data *cli)
1537{
1538	int pending = 0;
1539	struct radius_msg_list *msg;
1540	char abuf[50];
1541
1542	if (cli) {
1543		for (msg = cli->msgs; msg; msg = msg->next) {
1544			if (msg->msg_type == RADIUS_AUTH)
1545				pending++;
1546		}
1547	}
1548
1549	return os_snprintf(buf, buflen,
1550			   "radiusAuthServerIndex=%d\n"
1551			   "radiusAuthServerAddress=%s\n"
1552			   "radiusAuthClientServerPortNumber=%d\n"
1553			   "radiusAuthClientRoundTripTime=%d\n"
1554			   "radiusAuthClientAccessRequests=%u\n"
1555			   "radiusAuthClientAccessRetransmissions=%u\n"
1556			   "radiusAuthClientAccessAccepts=%u\n"
1557			   "radiusAuthClientAccessRejects=%u\n"
1558			   "radiusAuthClientAccessChallenges=%u\n"
1559			   "radiusAuthClientMalformedAccessResponses=%u\n"
1560			   "radiusAuthClientBadAuthenticators=%u\n"
1561			   "radiusAuthClientPendingRequests=%u\n"
1562			   "radiusAuthClientTimeouts=%u\n"
1563			   "radiusAuthClientUnknownTypes=%u\n"
1564			   "radiusAuthClientPacketsDropped=%u\n",
1565			   serv->index,
1566			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1567			   serv->port,
1568			   serv->round_trip_time,
1569			   serv->requests,
1570			   serv->retransmissions,
1571			   serv->access_accepts,
1572			   serv->access_rejects,
1573			   serv->access_challenges,
1574			   serv->malformed_responses,
1575			   serv->bad_authenticators,
1576			   pending,
1577			   serv->timeouts,
1578			   serv->unknown_types,
1579			   serv->packets_dropped);
1580}
1581
1582
1583static int radius_client_dump_acct_server(char *buf, size_t buflen,
1584					  struct hostapd_radius_server *serv,
1585					  struct radius_client_data *cli)
1586{
1587	int pending = 0;
1588	struct radius_msg_list *msg;
1589	char abuf[50];
1590
1591	if (cli) {
1592		for (msg = cli->msgs; msg; msg = msg->next) {
1593			if (msg->msg_type == RADIUS_ACCT ||
1594			    msg->msg_type == RADIUS_ACCT_INTERIM)
1595				pending++;
1596		}
1597	}
1598
1599	return os_snprintf(buf, buflen,
1600			   "radiusAccServerIndex=%d\n"
1601			   "radiusAccServerAddress=%s\n"
1602			   "radiusAccClientServerPortNumber=%d\n"
1603			   "radiusAccClientRoundTripTime=%d\n"
1604			   "radiusAccClientRequests=%u\n"
1605			   "radiusAccClientRetransmissions=%u\n"
1606			   "radiusAccClientResponses=%u\n"
1607			   "radiusAccClientMalformedResponses=%u\n"
1608			   "radiusAccClientBadAuthenticators=%u\n"
1609			   "radiusAccClientPendingRequests=%u\n"
1610			   "radiusAccClientTimeouts=%u\n"
1611			   "radiusAccClientUnknownTypes=%u\n"
1612			   "radiusAccClientPacketsDropped=%u\n",
1613			   serv->index,
1614			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1615			   serv->port,
1616			   serv->round_trip_time,
1617			   serv->requests,
1618			   serv->retransmissions,
1619			   serv->responses,
1620			   serv->malformed_responses,
1621			   serv->bad_authenticators,
1622			   pending,
1623			   serv->timeouts,
1624			   serv->unknown_types,
1625			   serv->packets_dropped);
1626}
1627
1628
1629/**
1630 * radius_client_get_mib - Get RADIUS client MIB information
1631 * @radius: RADIUS client context from radius_client_init()
1632 * @buf: Buffer for returning MIB data in text format
1633 * @buflen: Maximum buf length in octets
1634 * Returns: Number of octets written into the buffer
1635 */
1636int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1637			  size_t buflen)
1638{
1639	struct hostapd_radius_servers *conf;
1640	int i;
1641	struct hostapd_radius_server *serv;
1642	int count = 0;
1643
1644	if (!radius)
1645		return 0;
1646
1647	conf = radius->conf;
1648
1649	if (conf->auth_servers) {
1650		for (i = 0; i < conf->num_auth_servers; i++) {
1651			serv = &conf->auth_servers[i];
1652			count += radius_client_dump_auth_server(
1653				buf + count, buflen - count, serv,
1654				serv == conf->auth_server ?
1655				radius : NULL);
1656		}
1657	}
1658
1659	if (conf->acct_servers) {
1660		for (i = 0; i < conf->num_acct_servers; i++) {
1661			serv = &conf->acct_servers[i];
1662			count += radius_client_dump_acct_server(
1663				buf + count, buflen - count, serv,
1664				serv == conf->acct_server ?
1665				radius : NULL);
1666		}
1667	}
1668
1669	return count;
1670}
1671
1672
1673void radius_client_reconfig(struct radius_client_data *radius,
1674			    struct hostapd_radius_servers *conf)
1675{
1676	if (radius)
1677		radius->conf = conf;
1678}
1679