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