Convert RADIUS message code to use wpabuf internally
[mech_eap.git] / src / radius / radius_client.c
1 /*
2  * RADIUS client
3  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "radius.h"
19 #include "radius_client.h"
20 #include "eloop.h"
21
22 /* Defaults for RADIUS retransmit values (exponential backoff) */
23
24 /**
25  * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
26  */
27 #define RADIUS_CLIENT_FIRST_WAIT 3
28
29 /**
30  * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
31  */
32 #define RADIUS_CLIENT_MAX_WAIT 120
33
34 /**
35  * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
36  *
37  * Maximum number of retransmit attempts before the entry is removed from
38  * retransmit list.
39  */
40 #define RADIUS_CLIENT_MAX_RETRIES 10
41
42 /**
43  * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
44  *
45  * Maximum number of entries in retransmit list (oldest entries will be
46  * removed, if this limit is exceeded).
47  */
48 #define RADIUS_CLIENT_MAX_ENTRIES 30
49
50 /**
51  * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
52  *
53  * The number of failed retry attempts after which the RADIUS server will be
54  * changed (if one of more backup servers are configured).
55  */
56 #define RADIUS_CLIENT_NUM_FAILOVER 4
57
58
59 /**
60  * struct radius_rx_handler - RADIUS client RX handler
61  *
62  * This data structure is used internally inside the RADIUS client module to
63  * store registered RX handlers. These handlers are registered by calls to
64  * radius_client_register() and unregistered when the RADIUS client is
65  * deinitialized with a call to radius_client_deinit().
66  */
67 struct radius_rx_handler {
68         /**
69          * handler - Received RADIUS message handler
70          */
71         RadiusRxResult (*handler)(struct radius_msg *msg,
72                                   struct radius_msg *req,
73                                   const u8 *shared_secret,
74                                   size_t shared_secret_len,
75                                   void *data);
76
77         /**
78          * data - Context data for the handler
79          */
80         void *data;
81 };
82
83
84 /**
85  * struct radius_msg_list - RADIUS client message retransmit list
86  *
87  * This data structure is used internally inside the RADIUS client module to
88  * store pending RADIUS requests that may still need to be retransmitted.
89  */
90 struct radius_msg_list {
91         /**
92          * addr - STA/client address
93          *
94          * This is used to find RADIUS messages for the same STA.
95          */
96         u8 addr[ETH_ALEN];
97
98         /**
99          * msg - RADIUS message
100          */
101         struct radius_msg *msg;
102
103         /**
104          * msg_type - Message type
105          */
106         RadiusType msg_type;
107
108         /**
109          * first_try - Time of the first transmission attempt
110          */
111         os_time_t first_try;
112
113         /**
114          * next_try - Time for the next transmission attempt
115          */
116         os_time_t next_try;
117
118         /**
119          * attempts - Number of transmission attempts
120          */
121         int attempts;
122
123         /**
124          * next_wait - Next retransmission wait time in seconds
125          */
126         int next_wait;
127
128         /**
129          * last_attempt - Time of the last transmission attempt
130          */
131         struct os_time last_attempt;
132
133         /**
134          * shared_secret - Shared secret with the target RADIUS server
135          */
136         const u8 *shared_secret;
137
138         /**
139          * shared_secret_len - shared_secret length in octets
140          */
141         size_t shared_secret_len;
142
143         /* TODO: server config with failover to backup server(s) */
144
145         /**
146          * next - Next message in the list
147          */
148         struct radius_msg_list *next;
149 };
150
151
152 /**
153  * struct radius_client_data - Internal RADIUS client data
154  *
155  * This data structure is used internally inside the RADIUS client module.
156  * External users allocate this by calling radius_client_init() and free it by
157  * calling radius_client_deinit(). The pointer to this opaque data is used in
158  * calls to other functions as an identifier for the RADIUS client instance.
159  */
160 struct radius_client_data {
161         /**
162          * ctx - Context pointer for hostapd_logger() callbacks
163          */
164         void *ctx;
165
166         /**
167          * conf - RADIUS client configuration (list of RADIUS servers to use)
168          */
169         struct hostapd_radius_servers *conf;
170
171         /**
172          * auth_serv_sock - IPv4 socket for RADIUS authentication messages
173          */
174         int auth_serv_sock;
175
176         /**
177          * acct_serv_sock - IPv4 socket for RADIUS accounting messages
178          */
179         int acct_serv_sock;
180
181         /**
182          * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
183          */
184         int auth_serv_sock6;
185
186         /**
187          * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
188          */
189         int acct_serv_sock6;
190
191         /**
192          * auth_sock - Currently used socket for RADIUS authentication server
193          */
194         int auth_sock;
195
196         /**
197          * acct_sock - Currently used socket for RADIUS accounting server
198          */
199         int acct_sock;
200
201         /**
202          * auth_handlers - Authentication message handlers
203          */
204         struct radius_rx_handler *auth_handlers;
205
206         /**
207          * num_auth_handlers - Number of handlers in auth_handlers
208          */
209         size_t num_auth_handlers;
210
211         /**
212          * acct_handlers - Accounting message handlers
213          */
214         struct radius_rx_handler *acct_handlers;
215
216         /**
217          * num_acct_handlers - Number of handlers in acct_handlers
218          */
219         size_t num_acct_handlers;
220
221         /**
222          * msgs - Pending outgoing RADIUS messages
223          */
224         struct radius_msg_list *msgs;
225
226         /**
227          * num_msgs - Number of pending messages in the msgs list
228          */
229         size_t num_msgs;
230
231         /**
232          * next_radius_identifier - Next RADIUS message identifier to use
233          */
234         u8 next_radius_identifier;
235 };
236
237
238 static int
239 radius_change_server(struct radius_client_data *radius,
240                      struct hostapd_radius_server *nserv,
241                      struct hostapd_radius_server *oserv,
242                      int sock, int sock6, int auth);
243 static int radius_client_init_acct(struct radius_client_data *radius);
244 static int radius_client_init_auth(struct radius_client_data *radius);
245
246
247 static void radius_client_msg_free(struct radius_msg_list *req)
248 {
249         radius_msg_free(req->msg);
250         os_free(req);
251 }
252
253
254 /**
255  * radius_client_register - Register a RADIUS client RX handler
256  * @radius: RADIUS client context from radius_client_init()
257  * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
258  * @handler: Handler for received RADIUS messages
259  * @data: Context pointer for handler callbacks
260  * Returns: 0 on success, -1 on failure
261  *
262  * This function is used to register a handler for processing received RADIUS
263  * authentication and accounting messages. The handler() callback function will
264  * be called whenever a RADIUS message is received from the active server.
265  *
266  * There can be multiple registered RADIUS message handlers. The handlers will
267  * be called in order until one of them indicates that it has processed or
268  * queued the message.
269  */
270 int radius_client_register(struct radius_client_data *radius,
271                            RadiusType msg_type,
272                            RadiusRxResult (*handler)(struct radius_msg *msg,
273                                                      struct radius_msg *req,
274                                                      const u8 *shared_secret,
275                                                      size_t shared_secret_len,
276                                                      void *data),
277                            void *data)
278 {
279         struct radius_rx_handler **handlers, *newh;
280         size_t *num;
281
282         if (msg_type == RADIUS_ACCT) {
283                 handlers = &radius->acct_handlers;
284                 num = &radius->num_acct_handlers;
285         } else {
286                 handlers = &radius->auth_handlers;
287                 num = &radius->num_auth_handlers;
288         }
289
290         newh = os_realloc(*handlers,
291                           (*num + 1) * sizeof(struct radius_rx_handler));
292         if (newh == NULL)
293                 return -1;
294
295         newh[*num].handler = handler;
296         newh[*num].data = data;
297         (*num)++;
298         *handlers = newh;
299
300         return 0;
301 }
302
303
304 static void radius_client_handle_send_error(struct radius_client_data *radius,
305                                             int s, RadiusType msg_type)
306 {
307 #ifndef CONFIG_NATIVE_WINDOWS
308         int _errno = errno;
309         perror("send[RADIUS]");
310         if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
311             _errno == EBADF) {
312                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
313                                HOSTAPD_LEVEL_INFO,
314                                "Send failed - maybe interface status changed -"
315                                " try to connect again");
316                 eloop_unregister_read_sock(s);
317                 close(s);
318                 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
319                         radius_client_init_acct(radius);
320                 else
321                         radius_client_init_auth(radius);
322         }
323 #endif /* CONFIG_NATIVE_WINDOWS */
324 }
325
326
327 static int radius_client_retransmit(struct radius_client_data *radius,
328                                     struct radius_msg_list *entry,
329                                     os_time_t now)
330 {
331         struct hostapd_radius_servers *conf = radius->conf;
332         int s;
333
334         if (entry->msg_type == RADIUS_ACCT ||
335             entry->msg_type == RADIUS_ACCT_INTERIM) {
336                 s = radius->acct_sock;
337                 if (entry->attempts == 0)
338                         conf->acct_server->requests++;
339                 else {
340                         conf->acct_server->timeouts++;
341                         conf->acct_server->retransmissions++;
342                 }
343         } else {
344                 s = radius->auth_sock;
345                 if (entry->attempts == 0)
346                         conf->auth_server->requests++;
347                 else {
348                         conf->auth_server->timeouts++;
349                         conf->auth_server->retransmissions++;
350                 }
351         }
352
353         /* retransmit; remove entry if too many attempts */
354         entry->attempts++;
355         hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
356                        HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
357                        entry->msg->hdr->identifier);
358
359         os_get_time(&entry->last_attempt);
360         if (send(s, wpabuf_head(entry->msg->buf), wpabuf_len(entry->msg->buf),
361                  0) < 0)
362                 radius_client_handle_send_error(radius, s, entry->msg_type);
363
364         entry->next_try = now + entry->next_wait;
365         entry->next_wait *= 2;
366         if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
367                 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
368         if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
369                 printf("Removing un-ACKed RADIUS message due to too many "
370                        "failed retransmit attempts\n");
371                 return 1;
372         }
373
374         return 0;
375 }
376
377
378 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
379 {
380         struct radius_client_data *radius = eloop_ctx;
381         struct hostapd_radius_servers *conf = radius->conf;
382         struct os_time now;
383         os_time_t first;
384         struct radius_msg_list *entry, *prev, *tmp;
385         int auth_failover = 0, acct_failover = 0;
386         char abuf[50];
387
388         entry = radius->msgs;
389         if (!entry)
390                 return;
391
392         os_get_time(&now);
393         first = 0;
394
395         prev = NULL;
396         while (entry) {
397                 if (now.sec >= entry->next_try &&
398                     radius_client_retransmit(radius, entry, now.sec)) {
399                         if (prev)
400                                 prev->next = entry->next;
401                         else
402                                 radius->msgs = entry->next;
403
404                         tmp = entry;
405                         entry = entry->next;
406                         radius_client_msg_free(tmp);
407                         radius->num_msgs--;
408                         continue;
409                 }
410
411                 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
412                         if (entry->msg_type == RADIUS_ACCT ||
413                             entry->msg_type == RADIUS_ACCT_INTERIM)
414                                 acct_failover++;
415                         else
416                                 auth_failover++;
417                 }
418
419                 if (first == 0 || entry->next_try < first)
420                         first = entry->next_try;
421
422                 prev = entry;
423                 entry = entry->next;
424         }
425
426         if (radius->msgs) {
427                 if (first < now.sec)
428                         first = now.sec;
429                 eloop_register_timeout(first - now.sec, 0,
430                                        radius_client_timer, radius, NULL);
431                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
432                                HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
433                                "retransmit in %ld seconds",
434                                (long int) (first - now.sec));
435         }
436
437         if (auth_failover && conf->num_auth_servers > 1) {
438                 struct hostapd_radius_server *next, *old;
439                 old = conf->auth_server;
440                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
441                                HOSTAPD_LEVEL_NOTICE,
442                                "No response from Authentication server "
443                                "%s:%d - failover",
444                                hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
445                                old->port);
446
447                 for (entry = radius->msgs; entry; entry = entry->next) {
448                         if (entry->msg_type == RADIUS_AUTH)
449                                 old->timeouts++;
450                 }
451
452                 next = old + 1;
453                 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
454                         next = conf->auth_servers;
455                 conf->auth_server = next;
456                 radius_change_server(radius, next, old,
457                                      radius->auth_serv_sock,
458                                      radius->auth_serv_sock6, 1);
459         }
460
461         if (acct_failover && conf->num_acct_servers > 1) {
462                 struct hostapd_radius_server *next, *old;
463                 old = conf->acct_server;
464                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
465                                HOSTAPD_LEVEL_NOTICE,
466                                "No response from Accounting server "
467                                "%s:%d - failover",
468                                hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
469                                old->port);
470
471                 for (entry = radius->msgs; entry; entry = entry->next) {
472                         if (entry->msg_type == RADIUS_ACCT ||
473                             entry->msg_type == RADIUS_ACCT_INTERIM)
474                                 old->timeouts++;
475                 }
476
477                 next = old + 1;
478                 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
479                         next = conf->acct_servers;
480                 conf->acct_server = next;
481                 radius_change_server(radius, next, old,
482                                      radius->acct_serv_sock,
483                                      radius->acct_serv_sock6, 0);
484         }
485 }
486
487
488 static void radius_client_update_timeout(struct radius_client_data *radius)
489 {
490         struct os_time now;
491         os_time_t first;
492         struct radius_msg_list *entry;
493
494         eloop_cancel_timeout(radius_client_timer, radius, NULL);
495
496         if (radius->msgs == NULL) {
497                 return;
498         }
499
500         first = 0;
501         for (entry = radius->msgs; entry; entry = entry->next) {
502                 if (first == 0 || entry->next_try < first)
503                         first = entry->next_try;
504         }
505
506         os_get_time(&now);
507         if (first < now.sec)
508                 first = now.sec;
509         eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
510                                NULL);
511         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
512                        HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
513                        " %ld seconds\n", (long int) (first - now.sec));
514 }
515
516
517 static void radius_client_list_add(struct radius_client_data *radius,
518                                    struct radius_msg *msg,
519                                    RadiusType msg_type,
520                                    const u8 *shared_secret,
521                                    size_t shared_secret_len, const u8 *addr)
522 {
523         struct radius_msg_list *entry, *prev;
524
525         if (eloop_terminated()) {
526                 /* No point in adding entries to retransmit queue since event
527                  * loop has already been terminated. */
528                 radius_msg_free(msg);
529                 return;
530         }
531
532         entry = os_zalloc(sizeof(*entry));
533         if (entry == NULL) {
534                 printf("Failed to add RADIUS packet into retransmit list\n");
535                 radius_msg_free(msg);
536                 return;
537         }
538
539         if (addr)
540                 os_memcpy(entry->addr, addr, ETH_ALEN);
541         entry->msg = msg;
542         entry->msg_type = msg_type;
543         entry->shared_secret = shared_secret;
544         entry->shared_secret_len = shared_secret_len;
545         os_get_time(&entry->last_attempt);
546         entry->first_try = entry->last_attempt.sec;
547         entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
548         entry->attempts = 1;
549         entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
550         entry->next = radius->msgs;
551         radius->msgs = entry;
552         radius_client_update_timeout(radius);
553
554         if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
555                 printf("Removing the oldest un-ACKed RADIUS packet due to "
556                        "retransmit list limits.\n");
557                 prev = NULL;
558                 while (entry->next) {
559                         prev = entry;
560                         entry = entry->next;
561                 }
562                 if (prev) {
563                         prev->next = NULL;
564                         radius_client_msg_free(entry);
565                 }
566         } else
567                 radius->num_msgs++;
568 }
569
570
571 static void radius_client_list_del(struct radius_client_data *radius,
572                                    RadiusType msg_type, const u8 *addr)
573 {
574         struct radius_msg_list *entry, *prev, *tmp;
575
576         if (addr == NULL)
577                 return;
578
579         entry = radius->msgs;
580         prev = NULL;
581         while (entry) {
582                 if (entry->msg_type == msg_type &&
583                     os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
584                         if (prev)
585                                 prev->next = entry->next;
586                         else
587                                 radius->msgs = entry->next;
588                         tmp = entry;
589                         entry = entry->next;
590                         hostapd_logger(radius->ctx, addr,
591                                        HOSTAPD_MODULE_RADIUS,
592                                        HOSTAPD_LEVEL_DEBUG,
593                                        "Removing matching RADIUS message");
594                         radius_client_msg_free(tmp);
595                         radius->num_msgs--;
596                         continue;
597                 }
598                 prev = entry;
599                 entry = entry->next;
600         }
601 }
602
603
604 /**
605  * radius_client_send - Send a RADIUS request
606  * @radius: RADIUS client context from radius_client_init()
607  * @msg: RADIUS message to be sent
608  * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
609  * @addr: MAC address of the device related to this message or %NULL
610  * Returns: 0 on success, -1 on failure
611  *
612  * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
613  * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
614  * between accounting and interim accounting messages is that the interim
615  * message will override any pending interim accounting updates while a new
616  * accounting message does not remove any pending messages.
617  *
618  * The message is added on the retransmission queue and will be retransmitted
619  * automatically until a response is received or maximum number of retries
620  * (RADIUS_CLIENT_MAX_RETRIES) is reached.
621  *
622  * The related device MAC address can be used to identify pending messages that
623  * can be removed with radius_client_flush_auth() or with interim accounting
624  * updates.
625  */
626 int radius_client_send(struct radius_client_data *radius,
627                        struct radius_msg *msg, RadiusType msg_type,
628                        const u8 *addr)
629 {
630         struct hostapd_radius_servers *conf = radius->conf;
631         const u8 *shared_secret;
632         size_t shared_secret_len;
633         char *name;
634         int s, res;
635
636         if (msg_type == RADIUS_ACCT_INTERIM) {
637                 /* Remove any pending interim acct update for the same STA. */
638                 radius_client_list_del(radius, msg_type, addr);
639         }
640
641         if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
642                 if (conf->acct_server == NULL) {
643                         hostapd_logger(radius->ctx, NULL,
644                                        HOSTAPD_MODULE_RADIUS,
645                                        HOSTAPD_LEVEL_INFO,
646                                        "No accounting server configured");
647                         return -1;
648                 }
649                 shared_secret = conf->acct_server->shared_secret;
650                 shared_secret_len = conf->acct_server->shared_secret_len;
651                 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
652                 name = "accounting";
653                 s = radius->acct_sock;
654                 conf->acct_server->requests++;
655         } else {
656                 if (conf->auth_server == NULL) {
657                         hostapd_logger(radius->ctx, NULL,
658                                        HOSTAPD_MODULE_RADIUS,
659                                        HOSTAPD_LEVEL_INFO,
660                                        "No authentication server configured");
661                         return -1;
662                 }
663                 shared_secret = conf->auth_server->shared_secret;
664                 shared_secret_len = conf->auth_server->shared_secret_len;
665                 radius_msg_finish(msg, shared_secret, shared_secret_len);
666                 name = "authentication";
667                 s = radius->auth_sock;
668                 conf->auth_server->requests++;
669         }
670
671         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
672                        HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
673                        "server", name);
674         if (conf->msg_dumps)
675                 radius_msg_dump(msg);
676
677         res = send(s, wpabuf_head(msg->buf), wpabuf_len(msg->buf), 0);
678         if (res < 0)
679                 radius_client_handle_send_error(radius, s, msg_type);
680
681         radius_client_list_add(radius, msg, msg_type, shared_secret,
682                                shared_secret_len, addr);
683
684         return res;
685 }
686
687
688 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
689 {
690         struct radius_client_data *radius = eloop_ctx;
691         struct hostapd_radius_servers *conf = radius->conf;
692         RadiusType msg_type = (RadiusType) sock_ctx;
693         int len, roundtrip;
694         unsigned char buf[3000];
695         struct radius_msg *msg;
696         struct radius_rx_handler *handlers;
697         size_t num_handlers, i;
698         struct radius_msg_list *req, *prev_req;
699         struct os_time now;
700         struct hostapd_radius_server *rconf;
701         int invalid_authenticator = 0;
702
703         if (msg_type == RADIUS_ACCT) {
704                 handlers = radius->acct_handlers;
705                 num_handlers = radius->num_acct_handlers;
706                 rconf = conf->acct_server;
707         } else {
708                 handlers = radius->auth_handlers;
709                 num_handlers = radius->num_auth_handlers;
710                 rconf = conf->auth_server;
711         }
712
713         len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
714         if (len < 0) {
715                 perror("recv[RADIUS]");
716                 return;
717         }
718         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
719                        HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
720                        "server", len);
721         if (len == sizeof(buf)) {
722                 printf("Possibly too long UDP frame for our buffer - "
723                        "dropping it\n");
724                 return;
725         }
726
727         msg = radius_msg_parse(buf, len);
728         if (msg == NULL) {
729                 printf("Parsing incoming RADIUS frame failed\n");
730                 rconf->malformed_responses++;
731                 return;
732         }
733
734         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
735                        HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
736         if (conf->msg_dumps)
737                 radius_msg_dump(msg);
738
739         switch (msg->hdr->code) {
740         case RADIUS_CODE_ACCESS_ACCEPT:
741                 rconf->access_accepts++;
742                 break;
743         case RADIUS_CODE_ACCESS_REJECT:
744                 rconf->access_rejects++;
745                 break;
746         case RADIUS_CODE_ACCESS_CHALLENGE:
747                 rconf->access_challenges++;
748                 break;
749         case RADIUS_CODE_ACCOUNTING_RESPONSE:
750                 rconf->responses++;
751                 break;
752         }
753
754         prev_req = NULL;
755         req = radius->msgs;
756         while (req) {
757                 /* TODO: also match by src addr:port of the packet when using
758                  * alternative RADIUS servers (?) */
759                 if ((req->msg_type == msg_type ||
760                      (req->msg_type == RADIUS_ACCT_INTERIM &&
761                       msg_type == RADIUS_ACCT)) &&
762                     req->msg->hdr->identifier == msg->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, msg->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, msg->hdr->code, msg->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 (entry->msg->hdr->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
1295         eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1296
1297         radius_client_flush(radius, 0);
1298         os_free(radius->auth_handlers);
1299         os_free(radius->acct_handlers);
1300         os_free(radius);
1301 }
1302
1303
1304 /**
1305  * radius_client_flush_auth - Flush pending RADIUS messages for an address
1306  * @radius: RADIUS client context from radius_client_init()
1307  * @addr: MAC address of the related device
1308  *
1309  * This function can be used to remove pending RADIUS authentication messages
1310  * that are related to a specific device. The addr parameter is matched with
1311  * the one used in radius_client_send() call that was used to transmit the
1312  * authentication request.
1313  */
1314 void radius_client_flush_auth(struct radius_client_data *radius,
1315                               const u8 *addr)
1316 {
1317         struct radius_msg_list *entry, *prev, *tmp;
1318
1319         prev = NULL;
1320         entry = radius->msgs;
1321         while (entry) {
1322                 if (entry->msg_type == RADIUS_AUTH &&
1323                     os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1324                         hostapd_logger(radius->ctx, addr,
1325                                        HOSTAPD_MODULE_RADIUS,
1326                                        HOSTAPD_LEVEL_DEBUG,
1327                                        "Removing pending RADIUS authentication"
1328                                        " message for removed client");
1329
1330                         if (prev)
1331                                 prev->next = entry->next;
1332                         else
1333                                 radius->msgs = entry->next;
1334
1335                         tmp = entry;
1336                         entry = entry->next;
1337                         radius_client_msg_free(tmp);
1338                         radius->num_msgs--;
1339                         continue;
1340                 }
1341
1342                 prev = entry;
1343                 entry = entry->next;
1344         }
1345 }
1346
1347
1348 static int radius_client_dump_auth_server(char *buf, size_t buflen,
1349                                           struct hostapd_radius_server *serv,
1350                                           struct radius_client_data *cli)
1351 {
1352         int pending = 0;
1353         struct radius_msg_list *msg;
1354         char abuf[50];
1355
1356         if (cli) {
1357                 for (msg = cli->msgs; msg; msg = msg->next) {
1358                         if (msg->msg_type == RADIUS_AUTH)
1359                                 pending++;
1360                 }
1361         }
1362
1363         return os_snprintf(buf, buflen,
1364                            "radiusAuthServerIndex=%d\n"
1365                            "radiusAuthServerAddress=%s\n"
1366                            "radiusAuthClientServerPortNumber=%d\n"
1367                            "radiusAuthClientRoundTripTime=%d\n"
1368                            "radiusAuthClientAccessRequests=%u\n"
1369                            "radiusAuthClientAccessRetransmissions=%u\n"
1370                            "radiusAuthClientAccessAccepts=%u\n"
1371                            "radiusAuthClientAccessRejects=%u\n"
1372                            "radiusAuthClientAccessChallenges=%u\n"
1373                            "radiusAuthClientMalformedAccessResponses=%u\n"
1374                            "radiusAuthClientBadAuthenticators=%u\n"
1375                            "radiusAuthClientPendingRequests=%u\n"
1376                            "radiusAuthClientTimeouts=%u\n"
1377                            "radiusAuthClientUnknownTypes=%u\n"
1378                            "radiusAuthClientPacketsDropped=%u\n",
1379                            serv->index,
1380                            hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1381                            serv->port,
1382                            serv->round_trip_time,
1383                            serv->requests,
1384                            serv->retransmissions,
1385                            serv->access_accepts,
1386                            serv->access_rejects,
1387                            serv->access_challenges,
1388                            serv->malformed_responses,
1389                            serv->bad_authenticators,
1390                            pending,
1391                            serv->timeouts,
1392                            serv->unknown_types,
1393                            serv->packets_dropped);
1394 }
1395
1396
1397 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1398                                           struct hostapd_radius_server *serv,
1399                                           struct radius_client_data *cli)
1400 {
1401         int pending = 0;
1402         struct radius_msg_list *msg;
1403         char abuf[50];
1404
1405         if (cli) {
1406                 for (msg = cli->msgs; msg; msg = msg->next) {
1407                         if (msg->msg_type == RADIUS_ACCT ||
1408                             msg->msg_type == RADIUS_ACCT_INTERIM)
1409                                 pending++;
1410                 }
1411         }
1412
1413         return os_snprintf(buf, buflen,
1414                            "radiusAccServerIndex=%d\n"
1415                            "radiusAccServerAddress=%s\n"
1416                            "radiusAccClientServerPortNumber=%d\n"
1417                            "radiusAccClientRoundTripTime=%d\n"
1418                            "radiusAccClientRequests=%u\n"
1419                            "radiusAccClientRetransmissions=%u\n"
1420                            "radiusAccClientResponses=%u\n"
1421                            "radiusAccClientMalformedResponses=%u\n"
1422                            "radiusAccClientBadAuthenticators=%u\n"
1423                            "radiusAccClientPendingRequests=%u\n"
1424                            "radiusAccClientTimeouts=%u\n"
1425                            "radiusAccClientUnknownTypes=%u\n"
1426                            "radiusAccClientPacketsDropped=%u\n",
1427                            serv->index,
1428                            hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1429                            serv->port,
1430                            serv->round_trip_time,
1431                            serv->requests,
1432                            serv->retransmissions,
1433                            serv->responses,
1434                            serv->malformed_responses,
1435                            serv->bad_authenticators,
1436                            pending,
1437                            serv->timeouts,
1438                            serv->unknown_types,
1439                            serv->packets_dropped);
1440 }
1441
1442
1443 /**
1444  * radius_client_get_mib - Get RADIUS client MIB information
1445  * @radius: RADIUS client context from radius_client_init()
1446  * @buf: Buffer for returning MIB data in text format
1447  * @buflen: Maximum buf length in octets
1448  * Returns: Number of octets written into the buffer
1449  */
1450 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1451                           size_t buflen)
1452 {
1453         struct hostapd_radius_servers *conf = radius->conf;
1454         int i;
1455         struct hostapd_radius_server *serv;
1456         int count = 0;
1457
1458         if (conf->auth_servers) {
1459                 for (i = 0; i < conf->num_auth_servers; i++) {
1460                         serv = &conf->auth_servers[i];
1461                         count += radius_client_dump_auth_server(
1462                                 buf + count, buflen - count, serv,
1463                                 serv == conf->auth_server ?
1464                                 radius : NULL);
1465                 }
1466         }
1467
1468         if (conf->acct_servers) {
1469                 for (i = 0; i < conf->num_acct_servers; i++) {
1470                         serv = &conf->acct_servers[i];
1471                         count += radius_client_dump_acct_server(
1472                                 buf + count, buflen - count, serv,
1473                                 serv == conf->acct_server ?
1474                                 radius : NULL);
1475                 }
1476         }
1477
1478         return count;
1479 }