Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / hostapd / src / radius / radius_client.c
1 /*
2  * RADIUS client
3  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "radius.h"
13 #include "radius_client.h"
14 #include "eloop.h"
15
16 /* Defaults for RADIUS retransmit values (exponential backoff) */
17
18 /**
19  * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
20  */
21 #define RADIUS_CLIENT_FIRST_WAIT 3
22
23 /**
24  * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
25  */
26 #define RADIUS_CLIENT_MAX_WAIT 120
27
28 /**
29  * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
30  *
31  * Maximum number of retransmit attempts before the entry is removed from
32  * retransmit list.
33  */
34 #define RADIUS_CLIENT_MAX_RETRIES 10
35
36 /**
37  * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
38  *
39  * Maximum number of entries in retransmit list (oldest entries will be
40  * removed, if this limit is exceeded).
41  */
42 #define RADIUS_CLIENT_MAX_ENTRIES 30
43
44 /**
45  * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
46  *
47  * The number of failed retry attempts after which the RADIUS server will be
48  * changed (if one of more backup servers are configured).
49  */
50 #define RADIUS_CLIENT_NUM_FAILOVER 4
51
52
53 /**
54  * struct radius_rx_handler - RADIUS client RX handler
55  *
56  * This data structure is used internally inside the RADIUS client module to
57  * store registered RX handlers. These handlers are registered by calls to
58  * radius_client_register() and unregistered when the RADIUS client is
59  * deinitialized with a call to radius_client_deinit().
60  */
61 struct radius_rx_handler {
62         /**
63          * handler - Received RADIUS message handler
64          */
65         RadiusRxResult (*handler)(struct radius_msg *msg,
66                                   struct radius_msg *req,
67                                   const u8 *shared_secret,
68                                   size_t shared_secret_len,
69                                   void *data);
70
71         /**
72          * data - Context data for the handler
73          */
74         void *data;
75 };
76
77
78 /**
79  * struct radius_msg_list - RADIUS client message retransmit list
80  *
81  * This data structure is used internally inside the RADIUS client module to
82  * store pending RADIUS requests that may still need to be retransmitted.
83  */
84 struct radius_msg_list {
85         /**
86          * addr - STA/client address
87          *
88          * This is used to find RADIUS messages for the same STA.
89          */
90         u8 addr[ETH_ALEN];
91
92         /**
93          * msg - RADIUS message
94          */
95         struct radius_msg *msg;
96
97         /**
98          * msg_type - Message type
99          */
100         RadiusType msg_type;
101
102         /**
103          * first_try - Time of the first transmission attempt
104          */
105         os_time_t first_try;
106
107         /**
108          * next_try - Time for the next transmission attempt
109          */
110         os_time_t next_try;
111
112         /**
113          * attempts - Number of transmission attempts
114          */
115         int attempts;
116
117         /**
118          * next_wait - Next retransmission wait time in seconds
119          */
120         int next_wait;
121
122         /**
123          * last_attempt - Time of the last transmission attempt
124          */
125         struct os_reltime last_attempt;
126
127         /**
128          * shared_secret - Shared secret with the target RADIUS server
129          */
130         const u8 *shared_secret;
131
132         /**
133          * shared_secret_len - shared_secret length in octets
134          */
135         size_t shared_secret_len;
136
137         /* TODO: server config with failover to backup server(s) */
138
139         /**
140          * next - Next message in the list
141          */
142         struct radius_msg_list *next;
143 };
144
145
146 /**
147  * struct radius_client_data - Internal RADIUS client data
148  *
149  * This data structure is used internally inside the RADIUS client module.
150  * External users allocate this by calling radius_client_init() and free it by
151  * calling radius_client_deinit(). The pointer to this opaque data is used in
152  * calls to other functions as an identifier for the RADIUS client instance.
153  */
154 struct radius_client_data {
155         /**
156          * ctx - Context pointer for hostapd_logger() callbacks
157          */
158         void *ctx;
159
160         /**
161          * conf - RADIUS client configuration (list of RADIUS servers to use)
162          */
163         struct hostapd_radius_servers *conf;
164
165         /**
166          * auth_serv_sock - IPv4 socket for RADIUS authentication messages
167          */
168         int auth_serv_sock;
169
170         /**
171          * acct_serv_sock - IPv4 socket for RADIUS accounting messages
172          */
173         int acct_serv_sock;
174
175         /**
176          * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
177          */
178         int auth_serv_sock6;
179
180         /**
181          * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
182          */
183         int acct_serv_sock6;
184
185         /**
186          * auth_sock - Currently used socket for RADIUS authentication server
187          */
188         int auth_sock;
189
190         /**
191          * acct_sock - Currently used socket for RADIUS accounting server
192          */
193         int acct_sock;
194
195         /**
196          * auth_handlers - Authentication message handlers
197          */
198         struct radius_rx_handler *auth_handlers;
199
200         /**
201          * num_auth_handlers - Number of handlers in auth_handlers
202          */
203         size_t num_auth_handlers;
204
205         /**
206          * acct_handlers - Accounting message handlers
207          */
208         struct radius_rx_handler *acct_handlers;
209
210         /**
211          * num_acct_handlers - Number of handlers in acct_handlers
212          */
213         size_t num_acct_handlers;
214
215         /**
216          * msgs - Pending outgoing RADIUS messages
217          */
218         struct radius_msg_list *msgs;
219
220         /**
221          * num_msgs - Number of pending messages in the msgs list
222          */
223         size_t num_msgs;
224
225         /**
226          * next_radius_identifier - Next RADIUS message identifier to use
227          */
228         u8 next_radius_identifier;
229 };
230
231
232 static int
233 radius_change_server(struct radius_client_data *radius,
234                      struct hostapd_radius_server *nserv,
235                      struct hostapd_radius_server *oserv,
236                      int sock, int sock6, int auth);
237 static int radius_client_init_acct(struct radius_client_data *radius);
238 static int radius_client_init_auth(struct radius_client_data *radius);
239
240
241 static void radius_client_msg_free(struct radius_msg_list *req)
242 {
243         radius_msg_free(req->msg);
244         os_free(req);
245 }
246
247
248 /**
249  * radius_client_register - Register a RADIUS client RX handler
250  * @radius: RADIUS client context from radius_client_init()
251  * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
252  * @handler: Handler for received RADIUS messages
253  * @data: Context pointer for handler callbacks
254  * Returns: 0 on success, -1 on failure
255  *
256  * This function is used to register a handler for processing received RADIUS
257  * authentication and accounting messages. The handler() callback function will
258  * be called whenever a RADIUS message is received from the active server.
259  *
260  * There can be multiple registered RADIUS message handlers. The handlers will
261  * be called in order until one of them indicates that it has processed or
262  * queued the message.
263  */
264 int radius_client_register(struct radius_client_data *radius,
265                            RadiusType msg_type,
266                            RadiusRxResult (*handler)(struct radius_msg *msg,
267                                                      struct radius_msg *req,
268                                                      const u8 *shared_secret,
269                                                      size_t shared_secret_len,
270                                                      void *data),
271                            void *data)
272 {
273         struct radius_rx_handler **handlers, *newh;
274         size_t *num;
275
276         if (msg_type == RADIUS_ACCT) {
277                 handlers = &radius->acct_handlers;
278                 num = &radius->num_acct_handlers;
279         } else {
280                 handlers = &radius->auth_handlers;
281                 num = &radius->num_auth_handlers;
282         }
283
284         newh = os_realloc_array(*handlers, *num + 1,
285                                 sizeof(struct radius_rx_handler));
286         if (newh == NULL)
287                 return -1;
288
289         newh[*num].handler = handler;
290         newh[*num].data = data;
291         (*num)++;
292         *handlers = newh;
293
294         return 0;
295 }
296
297
298 static void radius_client_handle_send_error(struct radius_client_data *radius,
299                                             int s, RadiusType msg_type)
300 {
301 #ifndef CONFIG_NATIVE_WINDOWS
302         int _errno = errno;
303         wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
304         if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
305             _errno == EBADF) {
306                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
307                                HOSTAPD_LEVEL_INFO,
308                                "Send failed - maybe interface status changed -"
309                                " try to connect again");
310                 eloop_unregister_read_sock(s);
311                 close(s);
312                 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
313                         radius_client_init_acct(radius);
314                 else
315                         radius_client_init_auth(radius);
316         }
317 #endif /* CONFIG_NATIVE_WINDOWS */
318 }
319
320
321 static int radius_client_retransmit(struct radius_client_data *radius,
322                                     struct radius_msg_list *entry,
323                                     os_time_t now)
324 {
325         struct hostapd_radius_servers *conf = radius->conf;
326         int s;
327         struct wpabuf *buf;
328
329         if (entry->msg_type == RADIUS_ACCT ||
330             entry->msg_type == RADIUS_ACCT_INTERIM) {
331                 s = radius->acct_sock;
332                 if (entry->attempts == 0)
333                         conf->acct_server->requests++;
334                 else {
335                         conf->acct_server->timeouts++;
336                         conf->acct_server->retransmissions++;
337                 }
338         } else {
339                 s = radius->auth_sock;
340                 if (entry->attempts == 0)
341                         conf->auth_server->requests++;
342                 else {
343                         conf->auth_server->timeouts++;
344                         conf->auth_server->retransmissions++;
345                 }
346         }
347
348         /* retransmit; remove entry if too many attempts */
349         entry->attempts++;
350         hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
351                        HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
352                        radius_msg_get_hdr(entry->msg)->identifier);
353
354         os_get_reltime(&entry->last_attempt);
355         buf = radius_msg_get_buf(entry->msg);
356         if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
357                 radius_client_handle_send_error(radius, s, entry->msg_type);
358
359         entry->next_try = now + entry->next_wait;
360         entry->next_wait *= 2;
361         if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
362                 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
363         if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
364                 wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
365                 return 1;
366         }
367
368         return 0;
369 }
370
371
372 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
373 {
374         struct radius_client_data *radius = eloop_ctx;
375         struct hostapd_radius_servers *conf = radius->conf;
376         struct os_reltime now;
377         os_time_t first;
378         struct radius_msg_list *entry, *prev, *tmp;
379         int auth_failover = 0, acct_failover = 0;
380         char abuf[50];
381
382         entry = radius->msgs;
383         if (!entry)
384                 return;
385
386         os_get_reltime(&now);
387         first = 0;
388
389         prev = NULL;
390         while (entry) {
391                 if (now.sec >= entry->next_try &&
392                     radius_client_retransmit(radius, entry, now.sec)) {
393                         if (prev)
394                                 prev->next = entry->next;
395                         else
396                                 radius->msgs = entry->next;
397
398                         tmp = entry;
399                         entry = entry->next;
400                         radius_client_msg_free(tmp);
401                         radius->num_msgs--;
402                         continue;
403                 }
404
405                 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
406                         if (entry->msg_type == RADIUS_ACCT ||
407                             entry->msg_type == RADIUS_ACCT_INTERIM)
408                                 acct_failover++;
409                         else
410                                 auth_failover++;
411                 }
412
413                 if (first == 0 || entry->next_try < first)
414                         first = entry->next_try;
415
416                 prev = entry;
417                 entry = entry->next;
418         }
419
420         if (radius->msgs) {
421                 if (first < now.sec)
422                         first = now.sec;
423                 eloop_register_timeout(first - now.sec, 0,
424                                        radius_client_timer, radius, NULL);
425                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
426                                HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
427                                "retransmit in %ld seconds",
428                                (long int) (first - now.sec));
429         }
430
431         if (auth_failover && conf->num_auth_servers > 1) {
432                 struct hostapd_radius_server *next, *old;
433                 old = conf->auth_server;
434                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
435                                HOSTAPD_LEVEL_NOTICE,
436                                "No response from Authentication server "
437                                "%s:%d - failover",
438                                hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
439                                old->port);
440
441                 for (entry = radius->msgs; entry; entry = entry->next) {
442                         if (entry->msg_type == RADIUS_AUTH)
443                                 old->timeouts++;
444                 }
445
446                 next = old + 1;
447                 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
448                         next = conf->auth_servers;
449                 conf->auth_server = next;
450                 radius_change_server(radius, next, old,
451                                      radius->auth_serv_sock,
452                                      radius->auth_serv_sock6, 1);
453         }
454
455         if (acct_failover && conf->num_acct_servers > 1) {
456                 struct hostapd_radius_server *next, *old;
457                 old = conf->acct_server;
458                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
459                                HOSTAPD_LEVEL_NOTICE,
460                                "No response from Accounting server "
461                                "%s:%d - failover",
462                                hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
463                                old->port);
464
465                 for (entry = radius->msgs; entry; entry = entry->next) {
466                         if (entry->msg_type == RADIUS_ACCT ||
467                             entry->msg_type == RADIUS_ACCT_INTERIM)
468                                 old->timeouts++;
469                 }
470
471                 next = old + 1;
472                 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
473                         next = conf->acct_servers;
474                 conf->acct_server = next;
475                 radius_change_server(radius, next, old,
476                                      radius->acct_serv_sock,
477                                      radius->acct_serv_sock6, 0);
478         }
479 }
480
481
482 static void radius_client_update_timeout(struct radius_client_data *radius)
483 {
484         struct os_reltime now;
485         os_time_t first;
486         struct radius_msg_list *entry;
487
488         eloop_cancel_timeout(radius_client_timer, radius, NULL);
489
490         if (radius->msgs == NULL) {
491                 return;
492         }
493
494         first = 0;
495         for (entry = radius->msgs; entry; entry = entry->next) {
496                 if (first == 0 || entry->next_try < first)
497                         first = entry->next_try;
498         }
499
500         os_get_reltime(&now);
501         if (first < now.sec)
502                 first = now.sec;
503         eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
504                                NULL);
505         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
506                        HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
507                        " %ld seconds", (long int) (first - now.sec));
508 }
509
510
511 static void radius_client_list_add(struct radius_client_data *radius,
512                                    struct radius_msg *msg,
513                                    RadiusType msg_type,
514                                    const u8 *shared_secret,
515                                    size_t shared_secret_len, const u8 *addr)
516 {
517         struct radius_msg_list *entry, *prev;
518
519         if (eloop_terminated()) {
520                 /* No point in adding entries to retransmit queue since event
521                  * loop has already been terminated. */
522                 radius_msg_free(msg);
523                 return;
524         }
525
526         entry = os_zalloc(sizeof(*entry));
527         if (entry == NULL) {
528                 wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
529                 radius_msg_free(msg);
530                 return;
531         }
532
533         if (addr)
534                 os_memcpy(entry->addr, addr, ETH_ALEN);
535         entry->msg = msg;
536         entry->msg_type = msg_type;
537         entry->shared_secret = shared_secret;
538         entry->shared_secret_len = shared_secret_len;
539         os_get_reltime(&entry->last_attempt);
540         entry->first_try = entry->last_attempt.sec;
541         entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
542         entry->attempts = 1;
543         entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
544         entry->next = radius->msgs;
545         radius->msgs = entry;
546         radius_client_update_timeout(radius);
547
548         if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
549                 wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
550                 prev = NULL;
551                 while (entry->next) {
552                         prev = entry;
553                         entry = entry->next;
554                 }
555                 if (prev) {
556                         prev->next = NULL;
557                         radius_client_msg_free(entry);
558                 }
559         } else
560                 radius->num_msgs++;
561 }
562
563
564 static void radius_client_list_del(struct radius_client_data *radius,
565                                    RadiusType msg_type, const u8 *addr)
566 {
567         struct radius_msg_list *entry, *prev, *tmp;
568
569         if (addr == NULL)
570                 return;
571
572         entry = radius->msgs;
573         prev = NULL;
574         while (entry) {
575                 if (entry->msg_type == msg_type &&
576                     os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
577                         if (prev)
578                                 prev->next = entry->next;
579                         else
580                                 radius->msgs = entry->next;
581                         tmp = entry;
582                         entry = entry->next;
583                         hostapd_logger(radius->ctx, addr,
584                                        HOSTAPD_MODULE_RADIUS,
585                                        HOSTAPD_LEVEL_DEBUG,
586                                        "Removing matching RADIUS message");
587                         radius_client_msg_free(tmp);
588                         radius->num_msgs--;
589                         continue;
590                 }
591                 prev = entry;
592                 entry = entry->next;
593         }
594 }
595
596
597 /**
598  * radius_client_send - Send a RADIUS request
599  * @radius: RADIUS client context from radius_client_init()
600  * @msg: RADIUS message to be sent
601  * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
602  * @addr: MAC address of the device related to this message or %NULL
603  * Returns: 0 on success, -1 on failure
604  *
605  * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
606  * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
607  * between accounting and interim accounting messages is that the interim
608  * message will override any pending interim accounting updates while a new
609  * accounting message does not remove any pending messages.
610  *
611  * The message is added on the retransmission queue and will be retransmitted
612  * automatically until a response is received or maximum number of retries
613  * (RADIUS_CLIENT_MAX_RETRIES) is reached.
614  *
615  * The related device MAC address can be used to identify pending messages that
616  * can be removed with radius_client_flush_auth() or with interim accounting
617  * updates.
618  */
619 int radius_client_send(struct radius_client_data *radius,
620                        struct radius_msg *msg, RadiusType msg_type,
621                        const u8 *addr)
622 {
623         struct hostapd_radius_servers *conf = radius->conf;
624         const u8 *shared_secret;
625         size_t shared_secret_len;
626         char *name;
627         int s, res;
628         struct wpabuf *buf;
629
630         if (msg_type == RADIUS_ACCT_INTERIM) {
631                 /* Remove any pending interim acct update for the same STA. */
632                 radius_client_list_del(radius, msg_type, addr);
633         }
634
635         if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
636                 if (conf->acct_server == NULL) {
637                         hostapd_logger(radius->ctx, NULL,
638                                        HOSTAPD_MODULE_RADIUS,
639                                        HOSTAPD_LEVEL_INFO,
640                                        "No accounting server configured");
641                         return -1;
642                 }
643                 shared_secret = conf->acct_server->shared_secret;
644                 shared_secret_len = conf->acct_server->shared_secret_len;
645                 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
646                 name = "accounting";
647                 s = radius->acct_sock;
648                 conf->acct_server->requests++;
649         } else {
650                 if (conf->auth_server == NULL) {
651                         hostapd_logger(radius->ctx, NULL,
652                                        HOSTAPD_MODULE_RADIUS,
653                                        HOSTAPD_LEVEL_INFO,
654                                        "No authentication server configured");
655                         return -1;
656                 }
657                 shared_secret = conf->auth_server->shared_secret;
658                 shared_secret_len = conf->auth_server->shared_secret_len;
659                 radius_msg_finish(msg, shared_secret, shared_secret_len);
660                 name = "authentication";
661                 s = radius->auth_sock;
662                 conf->auth_server->requests++;
663         }
664
665         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
666                        HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
667                        "server", name);
668         if (conf->msg_dumps)
669                 radius_msg_dump(msg);
670
671         buf = radius_msg_get_buf(msg);
672         res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
673         if (res < 0)
674                 radius_client_handle_send_error(radius, s, msg_type);
675
676         radius_client_list_add(radius, msg, msg_type, shared_secret,
677                                shared_secret_len, addr);
678
679         return 0;
680 }
681
682
683 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
684 {
685         struct radius_client_data *radius = eloop_ctx;
686         struct hostapd_radius_servers *conf = radius->conf;
687         RadiusType msg_type = (RadiusType) sock_ctx;
688         int len, roundtrip;
689         unsigned char buf[3000];
690         struct radius_msg *msg;
691         struct radius_hdr *hdr;
692         struct radius_rx_handler *handlers;
693         size_t num_handlers, i;
694         struct radius_msg_list *req, *prev_req;
695         struct os_reltime now;
696         struct hostapd_radius_server *rconf;
697         int invalid_authenticator = 0;
698
699         if (msg_type == RADIUS_ACCT) {
700                 handlers = radius->acct_handlers;
701                 num_handlers = radius->num_acct_handlers;
702                 rconf = conf->acct_server;
703         } else {
704                 handlers = radius->auth_handlers;
705                 num_handlers = radius->num_auth_handlers;
706                 rconf = conf->auth_server;
707         }
708
709         len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
710         if (len < 0) {
711                 wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
712                 return;
713         }
714         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
715                        HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
716                        "server", len);
717         if (len == sizeof(buf)) {
718                 wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
719                 return;
720         }
721
722         msg = radius_msg_parse(buf, len);
723         if (msg == NULL) {
724                 wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
725                 rconf->malformed_responses++;
726                 return;
727         }
728         hdr = radius_msg_get_hdr(msg);
729
730         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
731                        HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
732         if (conf->msg_dumps)
733                 radius_msg_dump(msg);
734
735         switch (hdr->code) {
736         case RADIUS_CODE_ACCESS_ACCEPT:
737                 rconf->access_accepts++;
738                 break;
739         case RADIUS_CODE_ACCESS_REJECT:
740                 rconf->access_rejects++;
741                 break;
742         case RADIUS_CODE_ACCESS_CHALLENGE:
743                 rconf->access_challenges++;
744                 break;
745         case RADIUS_CODE_ACCOUNTING_RESPONSE:
746                 rconf->responses++;
747                 break;
748         }
749
750         prev_req = NULL;
751         req = radius->msgs;
752         while (req) {
753                 /* TODO: also match by src addr:port of the packet when using
754                  * alternative RADIUS servers (?) */
755                 if ((req->msg_type == msg_type ||
756                      (req->msg_type == RADIUS_ACCT_INTERIM &&
757                       msg_type == RADIUS_ACCT)) &&
758                     radius_msg_get_hdr(req->msg)->identifier ==
759                     hdr->identifier)
760                         break;
761
762                 prev_req = req;
763                 req = req->next;
764         }
765
766         if (req == NULL) {
767                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
768                                HOSTAPD_LEVEL_DEBUG,
769                                "No matching RADIUS request found (type=%d "
770                                "id=%d) - dropping packet",
771                                msg_type, hdr->identifier);
772                 goto fail;
773         }
774
775         os_get_reltime(&now);
776         roundtrip = (now.sec - req->last_attempt.sec) * 100 +
777                 (now.usec - req->last_attempt.usec) / 10000;
778         hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
779                        HOSTAPD_LEVEL_DEBUG,
780                        "Received RADIUS packet matched with a pending "
781                        "request, round trip time %d.%02d sec",
782                        roundtrip / 100, roundtrip % 100);
783         rconf->round_trip_time = roundtrip;
784
785         /* Remove ACKed RADIUS packet from retransmit list */
786         if (prev_req)
787                 prev_req->next = req->next;
788         else
789                 radius->msgs = req->next;
790         radius->num_msgs--;
791
792         for (i = 0; i < num_handlers; i++) {
793                 RadiusRxResult res;
794                 res = handlers[i].handler(msg, req->msg, req->shared_secret,
795                                           req->shared_secret_len,
796                                           handlers[i].data);
797                 switch (res) {
798                 case RADIUS_RX_PROCESSED:
799                         radius_msg_free(msg);
800                         /* continue */
801                 case RADIUS_RX_QUEUED:
802                         radius_client_msg_free(req);
803                         return;
804                 case RADIUS_RX_INVALID_AUTHENTICATOR:
805                         invalid_authenticator++;
806                         /* continue */
807                 case RADIUS_RX_UNKNOWN:
808                         /* continue with next handler */
809                         break;
810                 }
811         }
812
813         if (invalid_authenticator)
814                 rconf->bad_authenticators++;
815         else
816                 rconf->unknown_types++;
817         hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
818                        HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
819                        "(type=%d code=%d id=%d)%s - dropping packet",
820                        msg_type, hdr->code, hdr->identifier,
821                        invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
822                        "");
823         radius_client_msg_free(req);
824
825  fail:
826         radius_msg_free(msg);
827 }
828
829
830 /**
831  * radius_client_get_id - Get an identifier for a new RADIUS message
832  * @radius: RADIUS client context from radius_client_init()
833  * Returns: Allocated identifier
834  *
835  * This function is used to fetch a unique (among pending requests) identifier
836  * for a new RADIUS message.
837  */
838 u8 radius_client_get_id(struct radius_client_data *radius)
839 {
840         struct radius_msg_list *entry, *prev, *_remove;
841         u8 id = radius->next_radius_identifier++;
842
843         /* remove entries with matching id from retransmit list to avoid
844          * using new reply from the RADIUS server with an old request */
845         entry = radius->msgs;
846         prev = NULL;
847         while (entry) {
848                 if (radius_msg_get_hdr(entry->msg)->identifier == id) {
849                         hostapd_logger(radius->ctx, entry->addr,
850                                        HOSTAPD_MODULE_RADIUS,
851                                        HOSTAPD_LEVEL_DEBUG,
852                                        "Removing pending RADIUS message, "
853                                        "since its id (%d) is reused", id);
854                         if (prev)
855                                 prev->next = entry->next;
856                         else
857                                 radius->msgs = entry->next;
858                         _remove = entry;
859                 } else {
860                         _remove = NULL;
861                         prev = entry;
862                 }
863                 entry = entry->next;
864
865                 if (_remove)
866                         radius_client_msg_free(_remove);
867         }
868
869         return id;
870 }
871
872
873 /**
874  * radius_client_flush - Flush all pending RADIUS client messages
875  * @radius: RADIUS client context from radius_client_init()
876  * @only_auth: Whether only authentication messages are removed
877  */
878 void radius_client_flush(struct radius_client_data *radius, int only_auth)
879 {
880         struct radius_msg_list *entry, *prev, *tmp;
881
882         if (!radius)
883                 return;
884
885         prev = NULL;
886         entry = radius->msgs;
887
888         while (entry) {
889                 if (!only_auth || entry->msg_type == RADIUS_AUTH) {
890                         if (prev)
891                                 prev->next = entry->next;
892                         else
893                                 radius->msgs = entry->next;
894
895                         tmp = entry;
896                         entry = entry->next;
897                         radius_client_msg_free(tmp);
898                         radius->num_msgs--;
899                 } else {
900                         prev = entry;
901                         entry = entry->next;
902                 }
903         }
904
905         if (radius->msgs == NULL)
906                 eloop_cancel_timeout(radius_client_timer, radius, NULL);
907 }
908
909
910 static void radius_client_update_acct_msgs(struct radius_client_data *radius,
911                                            const u8 *shared_secret,
912                                            size_t shared_secret_len)
913 {
914         struct radius_msg_list *entry;
915
916         if (!radius)
917                 return;
918
919         for (entry = radius->msgs; entry; entry = entry->next) {
920                 if (entry->msg_type == RADIUS_ACCT) {
921                         entry->shared_secret = shared_secret;
922                         entry->shared_secret_len = shared_secret_len;
923                         radius_msg_finish_acct(entry->msg, shared_secret,
924                                                shared_secret_len);
925                 }
926         }
927 }
928
929
930 static int
931 radius_change_server(struct radius_client_data *radius,
932                      struct hostapd_radius_server *nserv,
933                      struct hostapd_radius_server *oserv,
934                      int sock, int sock6, int auth)
935 {
936         struct sockaddr_in serv, claddr;
937 #ifdef CONFIG_IPV6
938         struct sockaddr_in6 serv6, claddr6;
939 #endif /* CONFIG_IPV6 */
940         struct sockaddr *addr, *cl_addr;
941         socklen_t addrlen, claddrlen;
942         char abuf[50];
943         int sel_sock;
944         struct radius_msg_list *entry;
945         struct hostapd_radius_servers *conf = radius->conf;
946
947         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
948                        HOSTAPD_LEVEL_INFO,
949                        "%s server %s:%d",
950                        auth ? "Authentication" : "Accounting",
951                        hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
952                        nserv->port);
953
954         if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
955             os_memcmp(nserv->shared_secret, oserv->shared_secret,
956                       nserv->shared_secret_len) != 0) {
957                 /* Pending RADIUS packets used different shared secret, so
958                  * they need to be modified. Update accounting message
959                  * authenticators here. Authentication messages are removed
960                  * since they would require more changes and the new RADIUS
961                  * server may not be prepared to receive them anyway due to
962                  * missing state information. Client will likely retry
963                  * authentication, so this should not be an issue. */
964                 if (auth)
965                         radius_client_flush(radius, 1);
966                 else {
967                         radius_client_update_acct_msgs(
968                                 radius, nserv->shared_secret,
969                                 nserv->shared_secret_len);
970                 }
971         }
972
973         /* Reset retry counters for the new server */
974         for (entry = radius->msgs; entry; entry = entry->next) {
975                 if ((auth && entry->msg_type != RADIUS_AUTH) ||
976                     (!auth && entry->msg_type != RADIUS_ACCT))
977                         continue;
978                 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
979                 entry->attempts = 0;
980                 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
981         }
982
983         if (radius->msgs) {
984                 eloop_cancel_timeout(radius_client_timer, radius, NULL);
985                 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
986                                        radius_client_timer, radius, NULL);
987         }
988
989         switch (nserv->addr.af) {
990         case AF_INET:
991                 os_memset(&serv, 0, sizeof(serv));
992                 serv.sin_family = AF_INET;
993                 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
994                 serv.sin_port = htons(nserv->port);
995                 addr = (struct sockaddr *) &serv;
996                 addrlen = sizeof(serv);
997                 sel_sock = sock;
998                 break;
999 #ifdef CONFIG_IPV6
1000         case AF_INET6:
1001                 os_memset(&serv6, 0, sizeof(serv6));
1002                 serv6.sin6_family = AF_INET6;
1003                 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
1004                           sizeof(struct in6_addr));
1005                 serv6.sin6_port = htons(nserv->port);
1006                 addr = (struct sockaddr *) &serv6;
1007                 addrlen = sizeof(serv6);
1008                 sel_sock = sock6;
1009                 break;
1010 #endif /* CONFIG_IPV6 */
1011         default:
1012                 return -1;
1013         }
1014
1015         if (conf->force_client_addr) {
1016                 switch (conf->client_addr.af) {
1017                 case AF_INET:
1018                         os_memset(&claddr, 0, sizeof(claddr));
1019                         claddr.sin_family = AF_INET;
1020                         claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
1021                         claddr.sin_port = htons(0);
1022                         cl_addr = (struct sockaddr *) &claddr;
1023                         claddrlen = sizeof(claddr);
1024                         break;
1025 #ifdef CONFIG_IPV6
1026                 case AF_INET6:
1027                         os_memset(&claddr6, 0, sizeof(claddr6));
1028                         claddr6.sin6_family = AF_INET6;
1029                         os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
1030                                   sizeof(struct in6_addr));
1031                         claddr6.sin6_port = htons(0);
1032                         cl_addr = (struct sockaddr *) &claddr6;
1033                         claddrlen = sizeof(claddr6);
1034                         break;
1035 #endif /* CONFIG_IPV6 */
1036                 default:
1037                         return -1;
1038                 }
1039
1040                 if (bind(sel_sock, cl_addr, claddrlen) < 0) {
1041                         wpa_printf(MSG_INFO, "bind[radius]: %s",
1042                                    strerror(errno));
1043                         return -1;
1044                 }
1045         }
1046
1047         if (connect(sel_sock, addr, addrlen) < 0) {
1048                 wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
1049                 return -1;
1050         }
1051
1052 #ifndef CONFIG_NATIVE_WINDOWS
1053         switch (nserv->addr.af) {
1054         case AF_INET:
1055                 claddrlen = sizeof(claddr);
1056                 getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
1057                 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1058                            inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
1059                 break;
1060 #ifdef CONFIG_IPV6
1061         case AF_INET6: {
1062                 claddrlen = sizeof(claddr6);
1063                 getsockname(sel_sock, (struct sockaddr *) &claddr6,
1064                             &claddrlen);
1065                 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1066                            inet_ntop(AF_INET6, &claddr6.sin6_addr,
1067                                      abuf, sizeof(abuf)),
1068                            ntohs(claddr6.sin6_port));
1069                 break;
1070         }
1071 #endif /* CONFIG_IPV6 */
1072         }
1073 #endif /* CONFIG_NATIVE_WINDOWS */
1074
1075         if (auth)
1076                 radius->auth_sock = sel_sock;
1077         else
1078                 radius->acct_sock = sel_sock;
1079
1080         return 0;
1081 }
1082
1083
1084 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1085 {
1086         struct radius_client_data *radius = eloop_ctx;
1087         struct hostapd_radius_servers *conf = radius->conf;
1088         struct hostapd_radius_server *oserv;
1089
1090         if (radius->auth_sock >= 0 && conf->auth_servers &&
1091             conf->auth_server != conf->auth_servers) {
1092                 oserv = conf->auth_server;
1093                 conf->auth_server = conf->auth_servers;
1094                 radius_change_server(radius, conf->auth_server, oserv,
1095                                      radius->auth_serv_sock,
1096                                      radius->auth_serv_sock6, 1);
1097         }
1098
1099         if (radius->acct_sock >= 0 && conf->acct_servers &&
1100             conf->acct_server != conf->acct_servers) {
1101                 oserv = conf->acct_server;
1102                 conf->acct_server = conf->acct_servers;
1103                 radius_change_server(radius, conf->acct_server, oserv,
1104                                      radius->acct_serv_sock,
1105                                      radius->acct_serv_sock6, 0);
1106         }
1107
1108         if (conf->retry_primary_interval)
1109                 eloop_register_timeout(conf->retry_primary_interval, 0,
1110                                        radius_retry_primary_timer, radius,
1111                                        NULL);
1112 }
1113
1114
1115 static int radius_client_disable_pmtu_discovery(int s)
1116 {
1117         int r = -1;
1118 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1119         /* Turn off Path MTU discovery on IPv4/UDP sockets. */
1120         int action = IP_PMTUDISC_DONT;
1121         r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1122                        sizeof(action));
1123         if (r == -1)
1124                 wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1125                            strerror(errno));
1126 #endif
1127         return r;
1128 }
1129
1130
1131 static int radius_client_init_auth(struct radius_client_data *radius)
1132 {
1133         struct hostapd_radius_servers *conf = radius->conf;
1134         int ok = 0;
1135
1136         radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1137         if (radius->auth_serv_sock < 0)
1138                 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1139                            strerror(errno));
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                 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1149                            strerror(errno));
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                 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
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                 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1175                 return -1;
1176         }
1177 #endif /* CONFIG_IPV6 */
1178
1179         return 0;
1180 }
1181
1182
1183 static int radius_client_init_acct(struct radius_client_data *radius)
1184 {
1185         struct hostapd_radius_servers *conf = radius->conf;
1186         int ok = 0;
1187
1188         radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1189         if (radius->acct_serv_sock < 0)
1190                 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1191                            strerror(errno));
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                 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1201                            strerror(errno));
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                 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
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                 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1227                 return -1;
1228         }
1229 #endif /* CONFIG_IPV6 */
1230
1231         return 0;
1232 }
1233
1234
1235 /**
1236  * radius_client_init - Initialize RADIUS client
1237  * @ctx: Callback context to be used in hostapd_logger() calls
1238  * @conf: RADIUS client configuration (RADIUS servers)
1239  * Returns: Pointer to private RADIUS client context or %NULL on failure
1240  *
1241  * The caller is responsible for keeping the configuration data available for
1242  * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1243  * called for the returned context pointer.
1244  */
1245 struct radius_client_data *
1246 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1247 {
1248         struct radius_client_data *radius;
1249
1250         radius = os_zalloc(sizeof(struct radius_client_data));
1251         if (radius == NULL)
1252                 return NULL;
1253
1254         radius->ctx = ctx;
1255         radius->conf = conf;
1256         radius->auth_serv_sock = radius->acct_serv_sock =
1257                 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1258                 radius->auth_sock = radius->acct_sock = -1;
1259
1260         if (conf->auth_server && radius_client_init_auth(radius)) {
1261                 radius_client_deinit(radius);
1262                 return NULL;
1263         }
1264
1265         if (conf->acct_server && radius_client_init_acct(radius)) {
1266                 radius_client_deinit(radius);
1267                 return NULL;
1268         }
1269
1270         if (conf->retry_primary_interval)
1271                 eloop_register_timeout(conf->retry_primary_interval, 0,
1272                                        radius_retry_primary_timer, radius,
1273                                        NULL);
1274
1275         return radius;
1276 }
1277
1278
1279 /**
1280  * radius_client_deinit - Deinitialize RADIUS client
1281  * @radius: RADIUS client context from radius_client_init()
1282  */
1283 void radius_client_deinit(struct radius_client_data *radius)
1284 {
1285         if (!radius)
1286                 return;
1287
1288         if (radius->auth_serv_sock >= 0)
1289                 eloop_unregister_read_sock(radius->auth_serv_sock);
1290         if (radius->acct_serv_sock >= 0)
1291                 eloop_unregister_read_sock(radius->acct_serv_sock);
1292 #ifdef CONFIG_IPV6
1293         if (radius->auth_serv_sock6 >= 0)
1294                 eloop_unregister_read_sock(radius->auth_serv_sock6);
1295         if (radius->acct_serv_sock6 >= 0)
1296                 eloop_unregister_read_sock(radius->acct_serv_sock6);
1297 #endif /* CONFIG_IPV6 */
1298
1299         eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1300
1301         radius_client_flush(radius, 0);
1302         os_free(radius->auth_handlers);
1303         os_free(radius->acct_handlers);
1304         os_free(radius);
1305 }
1306
1307
1308 /**
1309  * radius_client_flush_auth - Flush pending RADIUS messages for an address
1310  * @radius: RADIUS client context from radius_client_init()
1311  * @addr: MAC address of the related device
1312  *
1313  * This function can be used to remove pending RADIUS authentication messages
1314  * that are related to a specific device. The addr parameter is matched with
1315  * the one used in radius_client_send() call that was used to transmit the
1316  * authentication request.
1317  */
1318 void radius_client_flush_auth(struct radius_client_data *radius,
1319                               const u8 *addr)
1320 {
1321         struct radius_msg_list *entry, *prev, *tmp;
1322
1323         prev = NULL;
1324         entry = radius->msgs;
1325         while (entry) {
1326                 if (entry->msg_type == RADIUS_AUTH &&
1327                     os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1328                         hostapd_logger(radius->ctx, addr,
1329                                        HOSTAPD_MODULE_RADIUS,
1330                                        HOSTAPD_LEVEL_DEBUG,
1331                                        "Removing pending RADIUS authentication"
1332                                        " message for removed client");
1333
1334                         if (prev)
1335                                 prev->next = entry->next;
1336                         else
1337                                 radius->msgs = entry->next;
1338
1339                         tmp = entry;
1340                         entry = entry->next;
1341                         radius_client_msg_free(tmp);
1342                         radius->num_msgs--;
1343                         continue;
1344                 }
1345
1346                 prev = entry;
1347                 entry = entry->next;
1348         }
1349 }
1350
1351
1352 static int radius_client_dump_auth_server(char *buf, size_t buflen,
1353                                           struct hostapd_radius_server *serv,
1354                                           struct radius_client_data *cli)
1355 {
1356         int pending = 0;
1357         struct radius_msg_list *msg;
1358         char abuf[50];
1359
1360         if (cli) {
1361                 for (msg = cli->msgs; msg; msg = msg->next) {
1362                         if (msg->msg_type == RADIUS_AUTH)
1363                                 pending++;
1364                 }
1365         }
1366
1367         return os_snprintf(buf, buflen,
1368                            "radiusAuthServerIndex=%d\n"
1369                            "radiusAuthServerAddress=%s\n"
1370                            "radiusAuthClientServerPortNumber=%d\n"
1371                            "radiusAuthClientRoundTripTime=%d\n"
1372                            "radiusAuthClientAccessRequests=%u\n"
1373                            "radiusAuthClientAccessRetransmissions=%u\n"
1374                            "radiusAuthClientAccessAccepts=%u\n"
1375                            "radiusAuthClientAccessRejects=%u\n"
1376                            "radiusAuthClientAccessChallenges=%u\n"
1377                            "radiusAuthClientMalformedAccessResponses=%u\n"
1378                            "radiusAuthClientBadAuthenticators=%u\n"
1379                            "radiusAuthClientPendingRequests=%u\n"
1380                            "radiusAuthClientTimeouts=%u\n"
1381                            "radiusAuthClientUnknownTypes=%u\n"
1382                            "radiusAuthClientPacketsDropped=%u\n",
1383                            serv->index,
1384                            hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1385                            serv->port,
1386                            serv->round_trip_time,
1387                            serv->requests,
1388                            serv->retransmissions,
1389                            serv->access_accepts,
1390                            serv->access_rejects,
1391                            serv->access_challenges,
1392                            serv->malformed_responses,
1393                            serv->bad_authenticators,
1394                            pending,
1395                            serv->timeouts,
1396                            serv->unknown_types,
1397                            serv->packets_dropped);
1398 }
1399
1400
1401 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1402                                           struct hostapd_radius_server *serv,
1403                                           struct radius_client_data *cli)
1404 {
1405         int pending = 0;
1406         struct radius_msg_list *msg;
1407         char abuf[50];
1408
1409         if (cli) {
1410                 for (msg = cli->msgs; msg; msg = msg->next) {
1411                         if (msg->msg_type == RADIUS_ACCT ||
1412                             msg->msg_type == RADIUS_ACCT_INTERIM)
1413                                 pending++;
1414                 }
1415         }
1416
1417         return os_snprintf(buf, buflen,
1418                            "radiusAccServerIndex=%d\n"
1419                            "radiusAccServerAddress=%s\n"
1420                            "radiusAccClientServerPortNumber=%d\n"
1421                            "radiusAccClientRoundTripTime=%d\n"
1422                            "radiusAccClientRequests=%u\n"
1423                            "radiusAccClientRetransmissions=%u\n"
1424                            "radiusAccClientResponses=%u\n"
1425                            "radiusAccClientMalformedResponses=%u\n"
1426                            "radiusAccClientBadAuthenticators=%u\n"
1427                            "radiusAccClientPendingRequests=%u\n"
1428                            "radiusAccClientTimeouts=%u\n"
1429                            "radiusAccClientUnknownTypes=%u\n"
1430                            "radiusAccClientPacketsDropped=%u\n",
1431                            serv->index,
1432                            hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1433                            serv->port,
1434                            serv->round_trip_time,
1435                            serv->requests,
1436                            serv->retransmissions,
1437                            serv->responses,
1438                            serv->malformed_responses,
1439                            serv->bad_authenticators,
1440                            pending,
1441                            serv->timeouts,
1442                            serv->unknown_types,
1443                            serv->packets_dropped);
1444 }
1445
1446
1447 /**
1448  * radius_client_get_mib - Get RADIUS client MIB information
1449  * @radius: RADIUS client context from radius_client_init()
1450  * @buf: Buffer for returning MIB data in text format
1451  * @buflen: Maximum buf length in octets
1452  * Returns: Number of octets written into the buffer
1453  */
1454 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1455                           size_t buflen)
1456 {
1457         struct hostapd_radius_servers *conf = radius->conf;
1458         int i;
1459         struct hostapd_radius_server *serv;
1460         int count = 0;
1461
1462         if (conf->auth_servers) {
1463                 for (i = 0; i < conf->num_auth_servers; i++) {
1464                         serv = &conf->auth_servers[i];
1465                         count += radius_client_dump_auth_server(
1466                                 buf + count, buflen - count, serv,
1467                                 serv == conf->auth_server ?
1468                                 radius : NULL);
1469                 }
1470         }
1471
1472         if (conf->acct_servers) {
1473                 for (i = 0; i < conf->num_acct_servers; i++) {
1474                         serv = &conf->acct_servers[i];
1475                         count += radius_client_dump_acct_server(
1476                                 buf + count, buflen - count, serv,
1477                                 serv == conf->acct_server ?
1478                                 radius : NULL);
1479                 }
1480         }
1481
1482         return count;
1483 }
1484
1485
1486 void radius_client_reconfig(struct radius_client_data *radius,
1487                             struct hostapd_radius_servers *conf)
1488 {
1489         if (radius)
1490                 radius->conf = conf;
1491 }