radius_client.c revision 717574375e969e8272c6d1a26137286eac158abb
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		getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
1084		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1085			   inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
1086		break;
1087#ifdef CONFIG_IPV6
1088	case AF_INET6: {
1089		claddrlen = sizeof(claddr6);
1090		getsockname(sel_sock, (struct sockaddr *) &claddr6,
1091			    &claddrlen);
1092		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1093			   inet_ntop(AF_INET6, &claddr6.sin6_addr,
1094				     abuf, sizeof(abuf)),
1095			   ntohs(claddr6.sin6_port));
1096		break;
1097	}
1098#endif /* CONFIG_IPV6 */
1099	}
1100#endif /* CONFIG_NATIVE_WINDOWS */
1101
1102	if (auth)
1103		radius->auth_sock = sel_sock;
1104	else
1105		radius->acct_sock = sel_sock;
1106
1107	return 0;
1108}
1109
1110
1111static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1112{
1113	struct radius_client_data *radius = eloop_ctx;
1114	struct hostapd_radius_servers *conf = radius->conf;
1115	struct hostapd_radius_server *oserv;
1116
1117	if (radius->auth_sock >= 0 && conf->auth_servers &&
1118	    conf->auth_server != conf->auth_servers) {
1119		oserv = conf->auth_server;
1120		conf->auth_server = conf->auth_servers;
1121		radius_change_server(radius, conf->auth_server, oserv,
1122				     radius->auth_serv_sock,
1123				     radius->auth_serv_sock6, 1);
1124	}
1125
1126	if (radius->acct_sock >= 0 && conf->acct_servers &&
1127	    conf->acct_server != conf->acct_servers) {
1128		oserv = conf->acct_server;
1129		conf->acct_server = conf->acct_servers;
1130		radius_change_server(radius, conf->acct_server, oserv,
1131				     radius->acct_serv_sock,
1132				     radius->acct_serv_sock6, 0);
1133	}
1134
1135	if (conf->retry_primary_interval)
1136		eloop_register_timeout(conf->retry_primary_interval, 0,
1137				       radius_retry_primary_timer, radius,
1138				       NULL);
1139}
1140
1141
1142static int radius_client_disable_pmtu_discovery(int s)
1143{
1144	int r = -1;
1145#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1146	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
1147	int action = IP_PMTUDISC_DONT;
1148	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1149		       sizeof(action));
1150	if (r == -1)
1151		wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1152			   strerror(errno));
1153#endif
1154	return r;
1155}
1156
1157
1158static void radius_close_auth_sockets(struct radius_client_data *radius)
1159{
1160	radius->auth_sock = -1;
1161
1162	if (radius->auth_serv_sock >= 0) {
1163		eloop_unregister_read_sock(radius->auth_serv_sock);
1164		close(radius->auth_serv_sock);
1165		radius->auth_serv_sock = -1;
1166	}
1167#ifdef CONFIG_IPV6
1168	if (radius->auth_serv_sock6 >= 0) {
1169		eloop_unregister_read_sock(radius->auth_serv_sock6);
1170		close(radius->auth_serv_sock6);
1171		radius->auth_serv_sock6 = -1;
1172	}
1173#endif /* CONFIG_IPV6 */
1174}
1175
1176
1177static void radius_close_acct_sockets(struct radius_client_data *radius)
1178{
1179	radius->acct_sock = -1;
1180
1181	if (radius->acct_serv_sock >= 0) {
1182		eloop_unregister_read_sock(radius->acct_serv_sock);
1183		close(radius->acct_serv_sock);
1184		radius->acct_serv_sock = -1;
1185	}
1186#ifdef CONFIG_IPV6
1187	if (radius->acct_serv_sock6 >= 0) {
1188		eloop_unregister_read_sock(radius->acct_serv_sock6);
1189		close(radius->acct_serv_sock6);
1190		radius->acct_serv_sock6 = -1;
1191	}
1192#endif /* CONFIG_IPV6 */
1193}
1194
1195
1196static int radius_client_init_auth(struct radius_client_data *radius)
1197{
1198	struct hostapd_radius_servers *conf = radius->conf;
1199	int ok = 0;
1200
1201	radius_close_auth_sockets(radius);
1202
1203	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1204	if (radius->auth_serv_sock < 0)
1205		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1206			   strerror(errno));
1207	else {
1208		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
1209		ok++;
1210	}
1211
1212#ifdef CONFIG_IPV6
1213	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1214	if (radius->auth_serv_sock6 < 0)
1215		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1216			   strerror(errno));
1217	else
1218		ok++;
1219#endif /* CONFIG_IPV6 */
1220
1221	if (ok == 0)
1222		return -1;
1223
1224	radius_change_server(radius, conf->auth_server, NULL,
1225			     radius->auth_serv_sock, radius->auth_serv_sock6,
1226			     1);
1227
1228	if (radius->auth_serv_sock >= 0 &&
1229	    eloop_register_read_sock(radius->auth_serv_sock,
1230				     radius_client_receive, radius,
1231				     (void *) RADIUS_AUTH)) {
1232		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1233		radius_close_auth_sockets(radius);
1234		return -1;
1235	}
1236
1237#ifdef CONFIG_IPV6
1238	if (radius->auth_serv_sock6 >= 0 &&
1239	    eloop_register_read_sock(radius->auth_serv_sock6,
1240				     radius_client_receive, radius,
1241				     (void *) RADIUS_AUTH)) {
1242		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1243		radius_close_auth_sockets(radius);
1244		return -1;
1245	}
1246#endif /* CONFIG_IPV6 */
1247
1248	return 0;
1249}
1250
1251
1252static int radius_client_init_acct(struct radius_client_data *radius)
1253{
1254	struct hostapd_radius_servers *conf = radius->conf;
1255	int ok = 0;
1256
1257	radius_close_acct_sockets(radius);
1258
1259	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1260	if (radius->acct_serv_sock < 0)
1261		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1262			   strerror(errno));
1263	else {
1264		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
1265		ok++;
1266	}
1267
1268#ifdef CONFIG_IPV6
1269	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1270	if (radius->acct_serv_sock6 < 0)
1271		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1272			   strerror(errno));
1273	else
1274		ok++;
1275#endif /* CONFIG_IPV6 */
1276
1277	if (ok == 0)
1278		return -1;
1279
1280	radius_change_server(radius, conf->acct_server, NULL,
1281			     radius->acct_serv_sock, radius->acct_serv_sock6,
1282			     0);
1283
1284	if (radius->acct_serv_sock >= 0 &&
1285	    eloop_register_read_sock(radius->acct_serv_sock,
1286				     radius_client_receive, radius,
1287				     (void *) RADIUS_ACCT)) {
1288		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1289		radius_close_acct_sockets(radius);
1290		return -1;
1291	}
1292
1293#ifdef CONFIG_IPV6
1294	if (radius->acct_serv_sock6 >= 0 &&
1295	    eloop_register_read_sock(radius->acct_serv_sock6,
1296				     radius_client_receive, radius,
1297				     (void *) RADIUS_ACCT)) {
1298		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1299		radius_close_acct_sockets(radius);
1300		return -1;
1301	}
1302#endif /* CONFIG_IPV6 */
1303
1304	return 0;
1305}
1306
1307
1308/**
1309 * radius_client_init - Initialize RADIUS client
1310 * @ctx: Callback context to be used in hostapd_logger() calls
1311 * @conf: RADIUS client configuration (RADIUS servers)
1312 * Returns: Pointer to private RADIUS client context or %NULL on failure
1313 *
1314 * The caller is responsible for keeping the configuration data available for
1315 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1316 * called for the returned context pointer.
1317 */
1318struct radius_client_data *
1319radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1320{
1321	struct radius_client_data *radius;
1322
1323	radius = os_zalloc(sizeof(struct radius_client_data));
1324	if (radius == NULL)
1325		return NULL;
1326
1327	radius->ctx = ctx;
1328	radius->conf = conf;
1329	radius->auth_serv_sock = radius->acct_serv_sock =
1330		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1331		radius->auth_sock = radius->acct_sock = -1;
1332
1333	if (conf->auth_server && radius_client_init_auth(radius)) {
1334		radius_client_deinit(radius);
1335		return NULL;
1336	}
1337
1338	if (conf->acct_server && radius_client_init_acct(radius)) {
1339		radius_client_deinit(radius);
1340		return NULL;
1341	}
1342
1343	if (conf->retry_primary_interval)
1344		eloop_register_timeout(conf->retry_primary_interval, 0,
1345				       radius_retry_primary_timer, radius,
1346				       NULL);
1347
1348	return radius;
1349}
1350
1351
1352/**
1353 * radius_client_deinit - Deinitialize RADIUS client
1354 * @radius: RADIUS client context from radius_client_init()
1355 */
1356void radius_client_deinit(struct radius_client_data *radius)
1357{
1358	if (!radius)
1359		return;
1360
1361	radius_close_auth_sockets(radius);
1362	radius_close_acct_sockets(radius);
1363
1364	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1365
1366	radius_client_flush(radius, 0);
1367	os_free(radius->auth_handlers);
1368	os_free(radius->acct_handlers);
1369	os_free(radius);
1370}
1371
1372
1373/**
1374 * radius_client_flush_auth - Flush pending RADIUS messages for an address
1375 * @radius: RADIUS client context from radius_client_init()
1376 * @addr: MAC address of the related device
1377 *
1378 * This function can be used to remove pending RADIUS authentication messages
1379 * that are related to a specific device. The addr parameter is matched with
1380 * the one used in radius_client_send() call that was used to transmit the
1381 * authentication request.
1382 */
1383void radius_client_flush_auth(struct radius_client_data *radius,
1384			      const u8 *addr)
1385{
1386	struct radius_msg_list *entry, *prev, *tmp;
1387
1388	prev = NULL;
1389	entry = radius->msgs;
1390	while (entry) {
1391		if (entry->msg_type == RADIUS_AUTH &&
1392		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1393			hostapd_logger(radius->ctx, addr,
1394				       HOSTAPD_MODULE_RADIUS,
1395				       HOSTAPD_LEVEL_DEBUG,
1396				       "Removing pending RADIUS authentication"
1397				       " message for removed client");
1398
1399			if (prev)
1400				prev->next = entry->next;
1401			else
1402				radius->msgs = entry->next;
1403
1404			tmp = entry;
1405			entry = entry->next;
1406			radius_client_msg_free(tmp);
1407			radius->num_msgs--;
1408			continue;
1409		}
1410
1411		prev = entry;
1412		entry = entry->next;
1413	}
1414}
1415
1416
1417static int radius_client_dump_auth_server(char *buf, size_t buflen,
1418					  struct hostapd_radius_server *serv,
1419					  struct radius_client_data *cli)
1420{
1421	int pending = 0;
1422	struct radius_msg_list *msg;
1423	char abuf[50];
1424
1425	if (cli) {
1426		for (msg = cli->msgs; msg; msg = msg->next) {
1427			if (msg->msg_type == RADIUS_AUTH)
1428				pending++;
1429		}
1430	}
1431
1432	return os_snprintf(buf, buflen,
1433			   "radiusAuthServerIndex=%d\n"
1434			   "radiusAuthServerAddress=%s\n"
1435			   "radiusAuthClientServerPortNumber=%d\n"
1436			   "radiusAuthClientRoundTripTime=%d\n"
1437			   "radiusAuthClientAccessRequests=%u\n"
1438			   "radiusAuthClientAccessRetransmissions=%u\n"
1439			   "radiusAuthClientAccessAccepts=%u\n"
1440			   "radiusAuthClientAccessRejects=%u\n"
1441			   "radiusAuthClientAccessChallenges=%u\n"
1442			   "radiusAuthClientMalformedAccessResponses=%u\n"
1443			   "radiusAuthClientBadAuthenticators=%u\n"
1444			   "radiusAuthClientPendingRequests=%u\n"
1445			   "radiusAuthClientTimeouts=%u\n"
1446			   "radiusAuthClientUnknownTypes=%u\n"
1447			   "radiusAuthClientPacketsDropped=%u\n",
1448			   serv->index,
1449			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1450			   serv->port,
1451			   serv->round_trip_time,
1452			   serv->requests,
1453			   serv->retransmissions,
1454			   serv->access_accepts,
1455			   serv->access_rejects,
1456			   serv->access_challenges,
1457			   serv->malformed_responses,
1458			   serv->bad_authenticators,
1459			   pending,
1460			   serv->timeouts,
1461			   serv->unknown_types,
1462			   serv->packets_dropped);
1463}
1464
1465
1466static int radius_client_dump_acct_server(char *buf, size_t buflen,
1467					  struct hostapd_radius_server *serv,
1468					  struct radius_client_data *cli)
1469{
1470	int pending = 0;
1471	struct radius_msg_list *msg;
1472	char abuf[50];
1473
1474	if (cli) {
1475		for (msg = cli->msgs; msg; msg = msg->next) {
1476			if (msg->msg_type == RADIUS_ACCT ||
1477			    msg->msg_type == RADIUS_ACCT_INTERIM)
1478				pending++;
1479		}
1480	}
1481
1482	return os_snprintf(buf, buflen,
1483			   "radiusAccServerIndex=%d\n"
1484			   "radiusAccServerAddress=%s\n"
1485			   "radiusAccClientServerPortNumber=%d\n"
1486			   "radiusAccClientRoundTripTime=%d\n"
1487			   "radiusAccClientRequests=%u\n"
1488			   "radiusAccClientRetransmissions=%u\n"
1489			   "radiusAccClientResponses=%u\n"
1490			   "radiusAccClientMalformedResponses=%u\n"
1491			   "radiusAccClientBadAuthenticators=%u\n"
1492			   "radiusAccClientPendingRequests=%u\n"
1493			   "radiusAccClientTimeouts=%u\n"
1494			   "radiusAccClientUnknownTypes=%u\n"
1495			   "radiusAccClientPacketsDropped=%u\n",
1496			   serv->index,
1497			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1498			   serv->port,
1499			   serv->round_trip_time,
1500			   serv->requests,
1501			   serv->retransmissions,
1502			   serv->responses,
1503			   serv->malformed_responses,
1504			   serv->bad_authenticators,
1505			   pending,
1506			   serv->timeouts,
1507			   serv->unknown_types,
1508			   serv->packets_dropped);
1509}
1510
1511
1512/**
1513 * radius_client_get_mib - Get RADIUS client MIB information
1514 * @radius: RADIUS client context from radius_client_init()
1515 * @buf: Buffer for returning MIB data in text format
1516 * @buflen: Maximum buf length in octets
1517 * Returns: Number of octets written into the buffer
1518 */
1519int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1520			  size_t buflen)
1521{
1522	struct hostapd_radius_servers *conf = radius->conf;
1523	int i;
1524	struct hostapd_radius_server *serv;
1525	int count = 0;
1526
1527	if (conf->auth_servers) {
1528		for (i = 0; i < conf->num_auth_servers; i++) {
1529			serv = &conf->auth_servers[i];
1530			count += radius_client_dump_auth_server(
1531				buf + count, buflen - count, serv,
1532				serv == conf->auth_server ?
1533				radius : NULL);
1534		}
1535	}
1536
1537	if (conf->acct_servers) {
1538		for (i = 0; i < conf->num_acct_servers; i++) {
1539			serv = &conf->acct_servers[i];
1540			count += radius_client_dump_acct_server(
1541				buf + count, buflen - count, serv,
1542				serv == conf->acct_server ?
1543				radius : NULL);
1544		}
1545	}
1546
1547	return count;
1548}
1549
1550
1551void radius_client_reconfig(struct radius_client_data *radius,
1552			    struct hostapd_radius_servers *conf)
1553{
1554	if (radius)
1555		radius->conf = conf;
1556}
1557