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