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