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