]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/wpa/src/radius/radius_client.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / wpa / src / radius / radius_client.c
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  */
61 struct 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  */
84 struct 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  */
154 struct 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
232 static int
233 radius_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);
237 static int radius_client_init_acct(struct radius_client_data *radius);
238 static int radius_client_init_auth(struct radius_client_data *radius);
239
240
241 static 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  */
264 int 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 static 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
321 static 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
373 static 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
483 static 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
512 static 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
566 static 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  */
621 int 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
685 static 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  */
841 u8 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  */
881 void 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
913 static 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
933 static int
934 radius_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
1086 static 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
1117 static 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
1133 static 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
1185 static 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  */
1247 struct radius_client_data *
1248 radius_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  */
1285 void 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  */
1320 void 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
1354 static 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
1403 static 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  */
1456 int 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
1488 void radius_client_reconfig(struct radius_client_data *radius,
1489                             struct hostapd_radius_servers *conf)
1490 {
1491         if (radius)
1492                 radius->conf = conf;
1493 }