]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/hostapd/radius_client.c
This commit was generated by cvs2svn to compensate for changes in r156251,
[FreeBSD/FreeBSD.git] / contrib / hostapd / radius_client.c
1 /*
2  * Host AP (software wireless LAN access point) user space daemon for
3  * Host AP kernel driver / RADIUS client
4  * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <string.h>
21 #include <time.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/socket.h>
25 #include <arpa/inet.h>
26 #include <errno.h>
27
28 #include "hostapd.h"
29 #include "radius.h"
30 #include "radius_client.h"
31 #include "eloop.h"
32
33 /* Defaults for RADIUS retransmit values (exponential backoff) */
34 #define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
35 #define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
36 #define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
37                                       * before entry is removed from retransmit
38                                       * list */
39 #define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
40                                       * list (oldest will be removed, if this
41                                       * limit is exceeded) */
42 #define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
43                                       * many failed retry attempts */
44
45
46 struct radius_rx_handler {
47         RadiusRxResult (*handler)(struct radius_msg *msg,
48                                   struct radius_msg *req,
49                                   u8 *shared_secret, size_t shared_secret_len,
50                                   void *data);
51         void *data;
52 };
53
54
55 /* RADIUS message retransmit list */
56 struct radius_msg_list {
57         u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
58                             * for the same STA. */
59         struct radius_msg *msg;
60         RadiusType msg_type;
61         time_t first_try;
62         time_t next_try;
63         int attempts;
64         int next_wait;
65         struct timeval last_attempt;
66
67         u8 *shared_secret;
68         size_t shared_secret_len;
69
70         /* TODO: server config with failover to backup server(s) */
71
72         struct radius_msg_list *next;
73 };
74
75
76 struct radius_client_data {
77         struct hostapd_data *hapd;
78
79         int auth_serv_sock; /* socket for authentication RADIUS messages */
80         int acct_serv_sock; /* socket for accounting RADIUS messages */
81
82         struct radius_rx_handler *auth_handlers;
83         size_t num_auth_handlers;
84         struct radius_rx_handler *acct_handlers;
85         size_t num_acct_handlers;
86
87         struct radius_msg_list *msgs;
88         size_t num_msgs;
89
90         u8 next_radius_identifier;
91 };
92
93
94 static int
95 radius_change_server(struct radius_client_data *radius,
96                      struct hostapd_radius_server *nserv,
97                      struct hostapd_radius_server *oserv,
98                      int sock, int auth);
99 static int radius_client_init_acct(struct radius_client_data *radius);
100 static int radius_client_init_auth(struct radius_client_data *radius);
101
102
103 static void radius_client_msg_free(struct radius_msg_list *req)
104 {
105         radius_msg_free(req->msg);
106         free(req->msg);
107         free(req);
108 }
109
110
111 int radius_client_register(struct radius_client_data *radius,
112                            RadiusType msg_type,
113                            RadiusRxResult (*handler)(struct radius_msg *msg,
114                                                      struct radius_msg *req,
115                                                      u8 *shared_secret,
116                                                      size_t shared_secret_len,
117                                                      void *data),
118                            void *data)
119 {
120         struct radius_rx_handler **handlers, *newh;
121         size_t *num;
122
123         if (msg_type == RADIUS_ACCT) {
124                 handlers = &radius->acct_handlers;
125                 num = &radius->num_acct_handlers;
126         } else {
127                 handlers = &radius->auth_handlers;
128                 num = &radius->num_auth_handlers;
129         }
130
131         newh = (struct radius_rx_handler *)
132                 realloc(*handlers,
133                         (*num + 1) * sizeof(struct radius_rx_handler));
134         if (newh == NULL)
135                 return -1;
136
137         newh[*num].handler = handler;
138         newh[*num].data = data;
139         (*num)++;
140         *handlers = newh;
141
142         return 0;
143 }
144
145
146 static void radius_client_handle_send_error(struct radius_client_data *radius,
147                                             int s, RadiusType msg_type)
148 {
149         struct hostapd_data *hapd = radius->hapd;
150         int _errno = errno;
151         perror("send[RADIUS]");
152         if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
153                 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
154                                HOSTAPD_LEVEL_INFO,
155                                "Send failed - maybe interface status changed -"
156                                " try to connect again");
157                 eloop_unregister_read_sock(s);
158                 close(s);
159                 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
160                         radius_client_init_acct(radius);
161                 else
162                         radius_client_init_auth(radius);
163         }
164 }
165
166
167 static int radius_client_retransmit(struct radius_client_data *radius,
168                                     struct radius_msg_list *entry, time_t now)
169 {
170         struct hostapd_data *hapd = radius->hapd;
171         int s;
172
173         if (entry->msg_type == RADIUS_ACCT ||
174             entry->msg_type == RADIUS_ACCT_INTERIM) {
175                 s = radius->acct_serv_sock;
176                 if (entry->attempts == 0)
177                         hapd->conf->acct_server->requests++;
178                 else {
179                         hapd->conf->acct_server->timeouts++;
180                         hapd->conf->acct_server->retransmissions++;
181                 }
182         } else {
183                 s = radius->auth_serv_sock;
184                 if (entry->attempts == 0)
185                         hapd->conf->auth_server->requests++;
186                 else {
187                         hapd->conf->auth_server->timeouts++;
188                         hapd->conf->auth_server->retransmissions++;
189                 }
190         }
191
192         /* retransmit; remove entry if too many attempts */
193         entry->attempts++;
194         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Resending RADIUS message (id=%d)"
195                       "\n", entry->msg->hdr->identifier);
196
197         gettimeofday(&entry->last_attempt, NULL);
198         if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
199                 radius_client_handle_send_error(radius, s, entry->msg_type);
200
201         entry->next_try = now + entry->next_wait;
202         entry->next_wait *= 2;
203         if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
204                 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
205         if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
206                 printf("Removing un-ACKed RADIUS message due to too many "
207                        "failed retransmit attempts\n");
208                 return 1;
209         }
210
211         return 0;
212 }
213
214
215 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
216 {
217         struct radius_client_data *radius = eloop_ctx;
218         struct hostapd_data *hapd = radius->hapd;
219         time_t now, first;
220         struct radius_msg_list *entry, *prev, *tmp;
221         int auth_failover = 0, acct_failover = 0;
222
223         entry = radius->msgs;
224         if (!entry)
225                 return;
226
227         time(&now);
228         first = 0;
229
230         prev = NULL;
231         while (entry) {
232                 if (now >= entry->next_try &&
233                     radius_client_retransmit(radius, entry, now)) {
234                         if (prev)
235                                 prev->next = entry->next;
236                         else
237                                 radius->msgs = entry->next;
238
239                         tmp = entry;
240                         entry = entry->next;
241                         radius_client_msg_free(tmp);
242                         radius->num_msgs--;
243                         continue;
244                 }
245
246                 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
247                         if (entry->msg_type == RADIUS_ACCT ||
248                             entry->msg_type == RADIUS_ACCT_INTERIM)
249                                 acct_failover++;
250                         else
251                                 auth_failover++;
252                 }
253
254                 if (first == 0 || entry->next_try < first)
255                         first = entry->next_try;
256
257                 prev = entry;
258                 entry = entry->next;
259         }
260
261         if (radius->msgs) {
262                 if (first < now)
263                         first = now;
264                 eloop_register_timeout(first - now, 0,
265                                        radius_client_timer, radius, NULL);
266                 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Next RADIUS client "
267                               "retransmit in %ld seconds\n",
268                               (long int) (first - now));
269
270         }
271
272         if (auth_failover && hapd->conf->num_auth_servers > 1) {
273                 struct hostapd_radius_server *next, *old;
274                 old = hapd->conf->auth_server;
275                 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
276                                HOSTAPD_LEVEL_NOTICE,
277                                "No response from Authentication server "
278                                "%s:%d - failover",
279                                inet_ntoa(old->addr), old->port);
280
281                 for (entry = radius->msgs; entry; entry = entry->next) {
282                         if (entry->msg_type == RADIUS_AUTH)
283                                 old->timeouts++;
284                 }
285
286                 next = old + 1;
287                 if (next > &(hapd->conf->auth_servers
288                              [hapd->conf->num_auth_servers - 1]))
289                         next = hapd->conf->auth_servers;
290                 hapd->conf->auth_server = next;
291                 radius_change_server(radius, next, old,
292                                      radius->auth_serv_sock, 1);
293         }
294
295         if (acct_failover && hapd->conf->num_acct_servers > 1) {
296                 struct hostapd_radius_server *next, *old;
297                 old = hapd->conf->acct_server;
298                 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS,
299                                HOSTAPD_LEVEL_NOTICE,
300                                "No response from Accounting server "
301                                "%s:%d - failover",
302                                inet_ntoa(old->addr), old->port);
303
304                 for (entry = radius->msgs; entry; entry = entry->next) {
305                         if (entry->msg_type == RADIUS_ACCT ||
306                             entry->msg_type == RADIUS_ACCT_INTERIM)
307                                 old->timeouts++;
308                 }
309
310                 next = old + 1;
311                 if (next > &hapd->conf->acct_servers
312                     [hapd->conf->num_acct_servers - 1])
313                         next = hapd->conf->acct_servers;
314                 hapd->conf->acct_server = next;
315                 radius_change_server(radius, next, old,
316                                      radius->acct_serv_sock, 0);
317         }
318 }
319
320
321 static void radius_client_update_timeout(struct radius_client_data *radius)
322 {
323         struct hostapd_data *hapd = radius->hapd;
324         time_t now, first;
325         struct radius_msg_list *entry;
326
327         eloop_cancel_timeout(radius_client_timer, radius, NULL);
328
329         if (radius->msgs == NULL) {
330                 return;
331         }
332
333         first = 0;
334         for (entry = radius->msgs; entry; entry = entry->next) {
335                 if (first == 0 || entry->next_try < first)
336                         first = entry->next_try;
337         }
338
339         time(&now);
340         if (first < now)
341                 first = now;
342         eloop_register_timeout(first - now, 0, radius_client_timer, radius,
343                                NULL);
344         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Next RADIUS client retransmit in"
345                       " %ld seconds\n", (long int) (first - now));
346 }
347
348
349 static void radius_client_list_add(struct radius_client_data *radius,
350                                    struct radius_msg *msg,
351                                    RadiusType msg_type, u8 *shared_secret,
352                                    size_t shared_secret_len, u8 *addr)
353 {
354         struct radius_msg_list *entry, *prev;
355
356         if (eloop_terminated()) {
357                 /* No point in adding entries to retransmit queue since event
358                  * loop has already been terminated. */
359                 radius_msg_free(msg);
360                 free(msg);
361                 return;
362         }
363
364         entry = malloc(sizeof(*entry));
365         if (entry == NULL) {
366                 printf("Failed to add RADIUS packet into retransmit list\n");
367                 radius_msg_free(msg);
368                 free(msg);
369                 return;
370         }
371
372         memset(entry, 0, sizeof(*entry));
373         if (addr)
374                 memcpy(entry->addr, addr, ETH_ALEN);
375         entry->msg = msg;
376         entry->msg_type = msg_type;
377         entry->shared_secret = shared_secret;
378         entry->shared_secret_len = shared_secret_len;
379         time(&entry->first_try);
380         entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
381         entry->attempts = 1;
382         gettimeofday(&entry->last_attempt, NULL);
383         entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
384         entry->next = radius->msgs;
385         radius->msgs = entry;
386         radius_client_update_timeout(radius);
387
388         if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
389                 printf("Removing the oldest un-ACKed RADIUS packet due to "
390                        "retransmit list limits.\n");
391                 prev = NULL;
392                 while (entry->next) {
393                         prev = entry;
394                         entry = entry->next;
395                 }
396                 if (prev) {
397                         prev->next = NULL;
398                         radius_client_msg_free(entry);
399                 }
400         } else
401                 radius->num_msgs++;
402 }
403
404
405 static void radius_client_list_del(struct radius_client_data *radius,
406                                    RadiusType msg_type, u8 *addr)
407 {
408         struct hostapd_data *hapd = radius->hapd;
409         struct radius_msg_list *entry, *prev, *tmp;
410
411         if (addr == NULL)
412                 return;
413
414         entry = radius->msgs;
415         prev = NULL;
416         while (entry) {
417                 if (entry->msg_type == msg_type &&
418                     memcmp(entry->addr, addr, ETH_ALEN) == 0) {
419                         if (prev)
420                                 prev->next = entry->next;
421                         else
422                                 radius->msgs = entry->next;
423                         tmp = entry;
424                         entry = entry->next;
425                         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
426                                       "Removing matching RADIUS message for "
427                                       MACSTR "\n", MAC2STR(addr));
428                         radius_client_msg_free(tmp);
429                         radius->num_msgs--;
430                         continue;
431                 }
432                 prev = entry;
433                 entry = entry->next;
434         }
435 }
436
437
438 int radius_client_send(struct radius_client_data *radius,
439                        struct radius_msg *msg, RadiusType msg_type, u8 *addr)
440 {
441         struct hostapd_data *hapd = radius->hapd;
442         u8 *shared_secret;
443         size_t shared_secret_len;
444         char *name;
445         int s, res;
446
447         if (msg_type == RADIUS_ACCT_INTERIM) {
448                 /* Remove any pending interim acct update for the same STA. */
449                 radius_client_list_del(radius, msg_type, addr);
450         }
451
452         if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
453                 shared_secret = hapd->conf->acct_server->shared_secret;
454                 shared_secret_len = hapd->conf->acct_server->shared_secret_len;
455                 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
456                 name = "accounting";
457                 s = radius->acct_serv_sock;
458                 hapd->conf->acct_server->requests++;
459         } else {
460                 shared_secret = hapd->conf->auth_server->shared_secret;
461                 shared_secret_len = hapd->conf->auth_server->shared_secret_len;
462                 radius_msg_finish(msg, shared_secret, shared_secret_len);
463                 name = "authentication";
464                 s = radius->auth_serv_sock;
465                 hapd->conf->auth_server->requests++;
466         }
467
468         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
469                       "Sending RADIUS message to %s server\n", name);
470         if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
471                 radius_msg_dump(msg);
472
473         res = send(s, msg->buf, msg->buf_used, 0);
474         if (res < 0)
475                 radius_client_handle_send_error(radius, s, msg_type);
476
477         radius_client_list_add(radius, msg, msg_type, shared_secret,
478                                shared_secret_len, addr);
479
480         return res;
481 }
482
483
484 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
485 {
486         struct radius_client_data *radius = eloop_ctx;
487         struct hostapd_data *hapd = radius->hapd;
488         RadiusType msg_type = (RadiusType) sock_ctx;
489         int len, i, roundtrip;
490         unsigned char buf[3000];
491         struct radius_msg *msg;
492         struct radius_rx_handler *handlers;
493         size_t num_handlers;
494         struct radius_msg_list *req, *prev_req;
495         struct timeval tv;
496         struct hostapd_radius_server *rconf;
497         int invalid_authenticator = 0;
498
499         if (msg_type == RADIUS_ACCT) {
500                 handlers = radius->acct_handlers;
501                 num_handlers = radius->num_acct_handlers;
502                 rconf = hapd->conf->acct_server;
503         } else {
504                 handlers = radius->auth_handlers;
505                 num_handlers = radius->num_auth_handlers;
506                 rconf = hapd->conf->auth_server;
507         }
508
509         len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
510         if (len < 0) {
511                 perror("recv[RADIUS]");
512                 return;
513         }
514         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
515                       "Received %d bytes from RADIUS server\n", len);
516         if (len == sizeof(buf)) {
517                 printf("Possibly too long UDP frame for our buffer - "
518                        "dropping it\n");
519                 return;
520         }
521
522         msg = radius_msg_parse(buf, len);
523         if (msg == NULL) {
524                 printf("Parsing incoming RADIUS frame failed\n");
525                 rconf->malformed_responses++;
526                 return;
527         }
528
529         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
530                       "Received RADIUS message\n");
531         if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
532                 radius_msg_dump(msg);
533
534         switch (msg->hdr->code) {
535         case RADIUS_CODE_ACCESS_ACCEPT:
536                 rconf->access_accepts++;
537                 break;
538         case RADIUS_CODE_ACCESS_REJECT:
539                 rconf->access_rejects++;
540                 break;
541         case RADIUS_CODE_ACCESS_CHALLENGE:
542                 rconf->access_challenges++;
543                 break;
544         case RADIUS_CODE_ACCOUNTING_RESPONSE:
545                 rconf->responses++;
546                 break;
547         }
548
549         prev_req = NULL;
550         req = radius->msgs;
551         while (req) {
552                 /* TODO: also match by src addr:port of the packet when using
553                  * alternative RADIUS servers (?) */
554                 if ((req->msg_type == msg_type ||
555                      (req->msg_type == RADIUS_ACCT_INTERIM &&
556                       msg_type == RADIUS_ACCT)) &&
557                     req->msg->hdr->identifier == msg->hdr->identifier)
558                         break;
559
560                 prev_req = req;
561                 req = req->next;
562         }
563
564         if (req == NULL) {
565                 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
566                               "No matching RADIUS request found (type=%d "
567                               "id=%d) - dropping packet\n",
568                               msg_type, msg->hdr->identifier);
569                 goto fail;
570         }
571
572         gettimeofday(&tv, NULL);
573         roundtrip = (tv.tv_sec - req->last_attempt.tv_sec) * 100 +
574                 (tv.tv_usec - req->last_attempt.tv_usec) / 10000;
575         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Received RADIUS packet matched "
576                       "with a pending request, round trip time %d.%02d sec\n",
577                       roundtrip / 100, roundtrip % 100);
578         rconf->round_trip_time = roundtrip;
579
580         /* Remove ACKed RADIUS packet from retransmit list */
581         if (prev_req)
582                 prev_req->next = req->next;
583         else
584                 radius->msgs = req->next;
585         radius->num_msgs--;
586
587         for (i = 0; i < num_handlers; i++) {
588                 RadiusRxResult res;
589                 res = handlers[i].handler(msg, req->msg, req->shared_secret,
590                                           req->shared_secret_len,
591                                           handlers[i].data);
592                 switch (res) {
593                 case RADIUS_RX_PROCESSED:
594                         radius_msg_free(msg);
595                         free(msg);
596                         /* continue */
597                 case RADIUS_RX_QUEUED:
598                         radius_client_msg_free(req);
599                         return;
600                 case RADIUS_RX_INVALID_AUTHENTICATOR:
601                         invalid_authenticator++;
602                         /* continue */
603                 case RADIUS_RX_UNKNOWN:
604                         /* continue with next handler */
605                         break;
606                 }
607         }
608
609         if (invalid_authenticator)
610                 rconf->bad_authenticators++;
611         else
612                 rconf->unknown_types++;
613         hostapd_logger(hapd, req->addr, HOSTAPD_MODULE_RADIUS,
614                        HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
615                        "(type=%d code=%d id=%d)%s - dropping packet",
616                        msg_type, msg->hdr->code, msg->hdr->identifier,
617                        invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
618                        "");
619         radius_client_msg_free(req);
620
621  fail:
622         radius_msg_free(msg);
623         free(msg);
624 }
625
626
627 u8 radius_client_get_id(struct radius_client_data *radius)
628 {
629         struct hostapd_data *hapd = radius->hapd;
630         struct radius_msg_list *entry, *prev, *remove;
631         u8 id = radius->next_radius_identifier++;
632
633         /* remove entries with matching id from retransmit list to avoid
634          * using new reply from the RADIUS server with an old request */
635         entry = radius->msgs;
636         prev = NULL;
637         while (entry) {
638                 if (entry->msg->hdr->identifier == id) {
639                         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
640                                       "Removing pending RADIUS message, since "
641                                       "its id (%d) is reused\n", id);
642                         if (prev)
643                                 prev->next = entry->next;
644                         else
645                                 radius->msgs = entry->next;
646                         remove = entry;
647                 } else
648                         remove = NULL;
649                 prev = entry;
650                 entry = entry->next;
651
652                 if (remove)
653                         radius_client_msg_free(remove);
654         }
655
656         return id;
657 }
658
659
660 void radius_client_flush(struct radius_client_data *radius)
661 {
662         struct radius_msg_list *entry, *prev;
663
664         if (!radius)
665                 return;
666
667         eloop_cancel_timeout(radius_client_timer, radius, NULL);
668
669         entry = radius->msgs;
670         radius->msgs = NULL;
671         radius->num_msgs = 0;
672         while (entry) {
673                 prev = entry;
674                 entry = entry->next;
675                 radius_client_msg_free(prev);
676         }
677 }
678
679
680 static int
681 radius_change_server(struct radius_client_data *radius,
682                      struct hostapd_radius_server *nserv,
683                      struct hostapd_radius_server *oserv,
684                      int sock, int auth)
685 {
686         struct hostapd_data *hapd = radius->hapd;
687         struct sockaddr_in serv;
688
689         hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO,
690                        "%s server %s:%d",
691                        auth ? "Authentication" : "Accounting",
692                        inet_ntoa(nserv->addr), nserv->port);
693
694         if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
695             memcmp(nserv->shared_secret, oserv->shared_secret,
696                    nserv->shared_secret_len) != 0) {
697                 /* Pending RADIUS packets used different shared
698                  * secret, so they would need to be modified. Could
699                  * update all message authenticators and
700                  * User-Passwords, etc. and retry with new server. For
701                  * now, just drop all pending packets. */
702                 radius_client_flush(radius);
703         } else {
704                 /* Reset retry counters for the new server */
705                 struct radius_msg_list *entry;
706                 entry = radius->msgs;
707                 while (entry) {
708                         entry->next_try = entry->first_try +
709                                 RADIUS_CLIENT_FIRST_WAIT;
710                         entry->attempts = 0;
711                         entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
712                         entry = entry->next;
713                 }
714                 if (radius->msgs) {
715                         eloop_cancel_timeout(radius_client_timer, radius,
716                                              NULL);
717                         eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
718                                                radius_client_timer, radius,
719                                                NULL);
720                 }
721         }
722
723         memset(&serv, 0, sizeof(serv));
724         serv.sin_family = AF_INET;
725         serv.sin_addr.s_addr = nserv->addr.s_addr;
726         serv.sin_port = htons(nserv->port);
727
728         if (connect(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
729                 perror("connect[radius]");
730                 return -1;
731         }
732
733         return 0;
734 }
735
736
737 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
738 {
739         struct radius_client_data *radius = eloop_ctx;
740         struct hostapd_data *hapd = radius->hapd;
741         struct hostapd_radius_server *oserv;
742
743         if (radius->auth_serv_sock >= 0 && hapd->conf->auth_servers &&
744             hapd->conf->auth_server != hapd->conf->auth_servers) {
745                 oserv = hapd->conf->auth_server;
746                 hapd->conf->auth_server = hapd->conf->auth_servers;
747                 radius_change_server(radius, hapd->conf->auth_server, oserv,
748                                      radius->auth_serv_sock, 1);
749         }
750
751         if (radius->acct_serv_sock >= 0 && hapd->conf->acct_servers &&
752             hapd->conf->acct_server != hapd->conf->acct_servers) {
753                 oserv = hapd->conf->acct_server;
754                 hapd->conf->acct_server = hapd->conf->acct_servers;
755                 radius_change_server(radius, hapd->conf->acct_server, oserv,
756                                      radius->acct_serv_sock, 0);
757         }
758
759         if (hapd->conf->radius_retry_primary_interval)
760                 eloop_register_timeout(hapd->conf->
761                                        radius_retry_primary_interval, 0,
762                                        radius_retry_primary_timer, radius,
763                                        NULL);
764 }
765
766
767 static int radius_client_init_auth(struct radius_client_data *radius)
768 {
769         struct hostapd_data *hapd = radius->hapd;
770         radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
771         if (radius->auth_serv_sock < 0) {
772                 perror("socket[PF_INET,SOCK_DGRAM]");
773                 return -1;
774         }
775
776         radius_change_server(radius, hapd->conf->auth_server, NULL,
777                              radius->auth_serv_sock, 1);
778
779         if (eloop_register_read_sock(radius->auth_serv_sock,
780                                      radius_client_receive, radius,
781                                      (void *) RADIUS_AUTH)) {
782                 printf("Could not register read socket for authentication "
783                        "server\n");
784                 return -1;
785         }
786
787         return 0;
788 }
789
790
791 static int radius_client_init_acct(struct radius_client_data *radius)
792 {
793         struct hostapd_data *hapd = radius->hapd;
794         radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
795         if (radius->acct_serv_sock < 0) {
796                 perror("socket[PF_INET,SOCK_DGRAM]");
797                 return -1;
798         }
799
800         radius_change_server(radius, hapd->conf->acct_server, NULL,
801                              radius->acct_serv_sock, 0);
802
803         if (eloop_register_read_sock(radius->acct_serv_sock,
804                                      radius_client_receive, radius,
805                                      (void *) RADIUS_ACCT)) {
806                 printf("Could not register read socket for accounting "
807                        "server\n");
808                 return -1;
809         }
810
811         return 0;
812 }
813
814
815 struct radius_client_data * radius_client_init(struct hostapd_data *hapd)
816 {
817         struct radius_client_data *radius;
818
819         radius = malloc(sizeof(struct radius_client_data));
820         if (radius == NULL)
821                 return NULL;
822
823         memset(radius, 0, sizeof(struct radius_client_data));
824         radius->hapd = hapd;
825         radius->auth_serv_sock = radius->acct_serv_sock = -1;
826
827         if (hapd->conf->auth_server && radius_client_init_auth(radius)) {
828                 radius_client_deinit(radius);
829                 return NULL;
830         }
831
832         if (hapd->conf->acct_server && radius_client_init_acct(radius)) {
833                 radius_client_deinit(radius);
834                 return NULL;
835         }
836
837         if (hapd->conf->radius_retry_primary_interval)
838                 eloop_register_timeout(hapd->conf->
839                                        radius_retry_primary_interval, 0,
840                                        radius_retry_primary_timer, radius,
841                                        NULL);
842
843         return radius;
844 }
845
846
847 void radius_client_deinit(struct radius_client_data *radius)
848 {
849         if (!radius)
850                 return;
851
852         eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
853
854         radius_client_flush(radius);
855         free(radius->auth_handlers);
856         free(radius->acct_handlers);
857         free(radius);
858 }
859
860
861 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
862 {
863         struct hostapd_data *hapd = radius->hapd;
864         struct radius_msg_list *entry, *prev, *tmp;
865
866         prev = NULL;
867         entry = radius->msgs;
868         while (entry) {
869                 if (entry->msg_type == RADIUS_AUTH &&
870                     memcmp(entry->addr, addr, ETH_ALEN) == 0) {
871                         hostapd_logger(hapd, addr, HOSTAPD_MODULE_RADIUS,
872                                        HOSTAPD_LEVEL_DEBUG,
873                                        "Removing pending RADIUS authentication"
874                                        " message for removed client");
875
876                         if (prev)
877                                 prev->next = entry->next;
878                         else
879                                 radius->msgs = entry->next;
880
881                         tmp = entry;
882                         entry = entry->next;
883                         radius_client_msg_free(tmp);
884                         radius->num_msgs--;
885                         continue;
886                 }
887
888                 prev = entry;
889                 entry = entry->next;
890         }
891 }
892
893
894 static int radius_client_dump_auth_server(char *buf, size_t buflen,
895                                           struct hostapd_radius_server *serv,
896                                           struct radius_client_data *cli)
897 {
898         int pending = 0;
899         struct radius_msg_list *msg;
900
901         if (cli) {
902                 for (msg = cli->msgs; msg; msg = msg->next) {
903                         if (msg->msg_type == RADIUS_AUTH)
904                                 pending++;
905                 }
906         }
907
908         return snprintf(buf, buflen,
909                         "radiusAuthServerIndex=%d\n"
910                         "radiusAuthServerAddress=%s\n"
911                         "radiusAuthClientServerPortNumber=%d\n"
912                         "radiusAuthClientRoundTripTime=%d\n"
913                         "radiusAuthClientAccessRequests=%u\n"
914                         "radiusAuthClientAccessRetransmissions=%u\n"
915                         "radiusAuthClientAccessAccepts=%u\n"
916                         "radiusAuthClientAccessRejects=%u\n"
917                         "radiusAuthClientAccessChallenges=%u\n"
918                         "radiusAuthClientMalformedAccessResponses=%u\n"
919                         "radiusAuthClientBadAuthenticators=%u\n"
920                         "radiusAuthClientPendingRequests=%u\n"
921                         "radiusAuthClientTimeouts=%u\n"
922                         "radiusAuthClientUnknownTypes=%u\n"
923                         "radiusAuthClientPacketsDropped=%u\n",
924                         serv->index,
925                         inet_ntoa(serv->addr),
926                         serv->port,
927                         serv->round_trip_time,
928                         serv->requests,
929                         serv->retransmissions,
930                         serv->access_accepts,
931                         serv->access_rejects,
932                         serv->access_challenges,
933                         serv->malformed_responses,
934                         serv->bad_authenticators,
935                         pending,
936                         serv->timeouts,
937                         serv->unknown_types,
938                         serv->packets_dropped);
939 }
940
941
942 static int radius_client_dump_acct_server(char *buf, size_t buflen,
943                                           struct hostapd_radius_server *serv,
944                                           struct radius_client_data *cli)
945 {
946         int pending = 0;
947         struct radius_msg_list *msg;
948
949         if (cli) {
950                 for (msg = cli->msgs; msg; msg = msg->next) {
951                         if (msg->msg_type == RADIUS_ACCT ||
952                             msg->msg_type == RADIUS_ACCT_INTERIM)
953                                 pending++;
954                 }
955         }
956
957         return snprintf(buf, buflen,
958                         "radiusAccServerIndex=%d\n"
959                         "radiusAccServerAddress=%s\n"
960                         "radiusAccClientServerPortNumber=%d\n"
961                         "radiusAccClientRoundTripTime=%d\n"
962                         "radiusAccClientRequests=%u\n"
963                         "radiusAccClientRetransmissions=%u\n"
964                         "radiusAccClientResponses=%u\n"
965                         "radiusAccClientMalformedResponses=%u\n"
966                         "radiusAccClientBadAuthenticators=%u\n"
967                         "radiusAccClientPendingRequests=%u\n"
968                         "radiusAccClientTimeouts=%u\n"
969                         "radiusAccClientUnknownTypes=%u\n"
970                         "radiusAccClientPacketsDropped=%u\n",
971                         serv->index,
972                         inet_ntoa(serv->addr),
973                         serv->port,
974                         serv->round_trip_time,
975                         serv->requests,
976                         serv->retransmissions,
977                         serv->responses,
978                         serv->malformed_responses,
979                         serv->bad_authenticators,
980                         pending,
981                         serv->timeouts,
982                         serv->unknown_types,
983                         serv->packets_dropped);
984 }
985
986
987 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
988                           size_t buflen)
989 {
990         struct hostapd_data *hapd = radius->hapd;
991         int i;
992         struct hostapd_radius_server *serv;
993         int count = 0;
994
995         if (hapd->conf->auth_servers) {
996                 for (i = 0; i < hapd->conf->num_auth_servers; i++) {
997                         serv = &hapd->conf->auth_servers[i];
998                         count += radius_client_dump_auth_server(
999                                 buf + count, buflen - count, serv,
1000                                 serv == hapd->conf->auth_server ?
1001                                 radius : NULL);
1002                 }
1003         }
1004
1005         if (hapd->conf->acct_servers) {
1006                 for (i = 0; i < hapd->conf->num_acct_servers; i++) {
1007                         serv = &hapd->conf->acct_servers[i];
1008                         count += radius_client_dump_acct_server(
1009                                 buf + count, buflen - count, serv,
1010                                 serv == hapd->conf->acct_server ?
1011                                 radius : NULL);
1012                 }
1013         }
1014
1015         return count;
1016 }