~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to radius_client.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * hostapd / RADIUS client
 
3
 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "hostapd.h"
 
18
#include "radius.h"
 
19
#include "radius_client.h"
 
20
#include "eloop.h"
 
21
 
 
22
/* Defaults for RADIUS retransmit values (exponential backoff) */
 
23
#define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
 
24
#define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
 
25
#define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
 
26
                                      * before entry is removed from retransmit
 
27
                                      * list */
 
28
#define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
 
29
                                      * list (oldest will be removed, if this
 
30
                                      * limit is exceeded) */
 
31
#define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
 
32
                                      * many failed retry attempts */
 
33
 
 
34
 
 
35
struct radius_rx_handler {
 
36
        RadiusRxResult (*handler)(struct radius_msg *msg,
 
37
                                  struct radius_msg *req,
 
38
                                  u8 *shared_secret, size_t shared_secret_len,
 
39
                                  void *data);
 
40
        void *data;
 
41
};
 
42
 
 
43
 
 
44
/* RADIUS message retransmit list */
 
45
struct radius_msg_list {
 
46
        u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
 
47
                            * for the same STA. */
 
48
        struct radius_msg *msg;
 
49
        RadiusType msg_type;
 
50
        os_time_t first_try;
 
51
        os_time_t next_try;
 
52
        int attempts;
 
53
        int next_wait;
 
54
        struct os_time last_attempt;
 
55
 
 
56
        u8 *shared_secret;
 
57
        size_t shared_secret_len;
 
58
 
 
59
        /* TODO: server config with failover to backup server(s) */
 
60
 
 
61
        struct radius_msg_list *next;
 
62
};
 
63
 
 
64
 
 
65
struct radius_client_data {
 
66
        void *ctx;
 
67
        struct hostapd_radius_servers *conf;
 
68
 
 
69
        int auth_serv_sock; /* socket for authentication RADIUS messages */
 
70
        int acct_serv_sock; /* socket for accounting RADIUS messages */
 
71
        int auth_serv_sock6;
 
72
        int acct_serv_sock6;
 
73
        int auth_sock; /* currently used socket */
 
74
        int acct_sock; /* currently used socket */
 
75
 
 
76
        struct radius_rx_handler *auth_handlers;
 
77
        size_t num_auth_handlers;
 
78
        struct radius_rx_handler *acct_handlers;
 
79
        size_t num_acct_handlers;
 
80
 
 
81
        struct radius_msg_list *msgs;
 
82
        size_t num_msgs;
 
83
 
 
84
        u8 next_radius_identifier;
 
85
};
 
86
 
 
87
 
 
88
static int
 
89
radius_change_server(struct radius_client_data *radius,
 
90
                     struct hostapd_radius_server *nserv,
 
91
                     struct hostapd_radius_server *oserv,
 
92
                     int sock, int sock6, int auth);
 
93
static int radius_client_init_acct(struct radius_client_data *radius);
 
94
static int radius_client_init_auth(struct radius_client_data *radius);
 
95
 
 
96
 
 
97
static void radius_client_msg_free(struct radius_msg_list *req)
 
98
{
 
99
        radius_msg_free(req->msg);
 
100
        os_free(req->msg);
 
101
        os_free(req);
 
102
}
 
103
 
 
104
 
 
105
int radius_client_register(struct radius_client_data *radius,
 
106
                           RadiusType msg_type,
 
107
                           RadiusRxResult (*handler)(struct radius_msg *msg,
 
108
                                                     struct radius_msg *req,
 
109
                                                     u8 *shared_secret,
 
110
                                                     size_t shared_secret_len,
 
111
                                                     void *data),
 
112
                           void *data)
 
113
{
 
114
        struct radius_rx_handler **handlers, *newh;
 
115
        size_t *num;
 
116
 
 
117
        if (msg_type == RADIUS_ACCT) {
 
118
                handlers = &radius->acct_handlers;
 
119
                num = &radius->num_acct_handlers;
 
120
        } else {
 
121
                handlers = &radius->auth_handlers;
 
122
                num = &radius->num_auth_handlers;
 
123
        }
 
124
 
 
125
        newh = os_realloc(*handlers,
 
126
                          (*num + 1) * sizeof(struct radius_rx_handler));
 
127
        if (newh == NULL)
 
128
                return -1;
 
129
 
 
130
        newh[*num].handler = handler;
 
131
        newh[*num].data = data;
 
132
        (*num)++;
 
133
        *handlers = newh;
 
134
 
 
135
        return 0;
 
136
}
 
137
 
 
138
 
 
139
static void radius_client_handle_send_error(struct radius_client_data *radius,
 
140
                                            int s, RadiusType msg_type)
 
141
{
 
142
#ifndef CONFIG_NATIVE_WINDOWS
 
143
        int _errno = errno;
 
144
        perror("send[RADIUS]");
 
145
        if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
 
146
                hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
147
                               HOSTAPD_LEVEL_INFO,
 
148
                               "Send failed - maybe interface status changed -"
 
149
                               " try to connect again");
 
150
                eloop_unregister_read_sock(s);
 
151
                close(s);
 
152
                if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
 
153
                        radius_client_init_acct(radius);
 
154
                else
 
155
                        radius_client_init_auth(radius);
 
156
        }
 
157
#endif /* CONFIG_NATIVE_WINDOWS */
 
158
}
 
159
 
 
160
 
 
161
static int radius_client_retransmit(struct radius_client_data *radius,
 
162
                                    struct radius_msg_list *entry,
 
163
                                    os_time_t now)
 
164
{
 
165
        struct hostapd_radius_servers *conf = radius->conf;
 
166
        int s;
 
167
 
 
168
        if (entry->msg_type == RADIUS_ACCT ||
 
169
            entry->msg_type == RADIUS_ACCT_INTERIM) {
 
170
                s = radius->acct_sock;
 
171
                if (entry->attempts == 0)
 
172
                        conf->acct_server->requests++;
 
173
                else {
 
174
                        conf->acct_server->timeouts++;
 
175
                        conf->acct_server->retransmissions++;
 
176
                }
 
177
        } else {
 
178
                s = radius->auth_sock;
 
179
                if (entry->attempts == 0)
 
180
                        conf->auth_server->requests++;
 
181
                else {
 
182
                        conf->auth_server->timeouts++;
 
183
                        conf->auth_server->retransmissions++;
 
184
                }
 
185
        }
 
186
 
 
187
        /* retransmit; remove entry if too many attempts */
 
188
        entry->attempts++;
 
189
        hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
 
190
                       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
 
191
                       entry->msg->hdr->identifier);
 
192
 
 
193
        os_get_time(&entry->last_attempt);
 
194
        if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
 
195
                radius_client_handle_send_error(radius, s, entry->msg_type);
 
196
 
 
197
        entry->next_try = now + entry->next_wait;
 
198
        entry->next_wait *= 2;
 
199
        if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
 
200
                entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
 
201
        if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
 
202
                printf("Removing un-ACKed RADIUS message due to too many "
 
203
                       "failed retransmit attempts\n");
 
204
                return 1;
 
205
        }
 
206
 
 
207
        return 0;
 
208
}
 
209
 
 
210
 
 
211
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
 
212
{
 
213
        struct radius_client_data *radius = eloop_ctx;
 
214
        struct hostapd_radius_servers *conf = radius->conf;
 
215
        struct os_time now;
 
216
        os_time_t first;
 
217
        struct radius_msg_list *entry, *prev, *tmp;
 
218
        int auth_failover = 0, acct_failover = 0;
 
219
        char abuf[50];
 
220
 
 
221
        entry = radius->msgs;
 
222
        if (!entry)
 
223
                return;
 
224
 
 
225
        os_get_time(&now);
 
226
        first = 0;
 
227
 
 
228
        prev = NULL;
 
229
        while (entry) {
 
230
                if (now.sec >= entry->next_try &&
 
231
                    radius_client_retransmit(radius, entry, now.sec)) {
 
232
                        if (prev)
 
233
                                prev->next = entry->next;
 
234
                        else
 
235
                                radius->msgs = entry->next;
 
236
 
 
237
                        tmp = entry;
 
238
                        entry = entry->next;
 
239
                        radius_client_msg_free(tmp);
 
240
                        radius->num_msgs--;
 
241
                        continue;
 
242
                }
 
243
 
 
244
                if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
 
245
                        if (entry->msg_type == RADIUS_ACCT ||
 
246
                            entry->msg_type == RADIUS_ACCT_INTERIM)
 
247
                                acct_failover++;
 
248
                        else
 
249
                                auth_failover++;
 
250
                }
 
251
 
 
252
                if (first == 0 || entry->next_try < first)
 
253
                        first = entry->next_try;
 
254
 
 
255
                prev = entry;
 
256
                entry = entry->next;
 
257
        }
 
258
 
 
259
        if (radius->msgs) {
 
260
                if (first < now.sec)
 
261
                        first = now.sec;
 
262
                eloop_register_timeout(first - now.sec, 0,
 
263
                                       radius_client_timer, radius, NULL);
 
264
                hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
265
                               HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
 
266
                               "retransmit in %ld seconds",
 
267
                               (long int) (first - now.sec));
 
268
        }
 
269
 
 
270
        if (auth_failover && conf->num_auth_servers > 1) {
 
271
                struct hostapd_radius_server *next, *old;
 
272
                old = conf->auth_server;
 
273
                hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
274
                               HOSTAPD_LEVEL_NOTICE,
 
275
                               "No response from Authentication server "
 
276
                               "%s:%d - failover",
 
277
                               hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
 
278
                               old->port);
 
279
 
 
280
                for (entry = radius->msgs; entry; entry = entry->next) {
 
281
                        if (entry->msg_type == RADIUS_AUTH)
 
282
                                old->timeouts++;
 
283
                }
 
284
 
 
285
                next = old + 1;
 
286
                if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
 
287
                        next = conf->auth_servers;
 
288
                conf->auth_server = next;
 
289
                radius_change_server(radius, next, old,
 
290
                                     radius->auth_serv_sock,
 
291
                                     radius->auth_serv_sock6, 1);
 
292
        }
 
293
 
 
294
        if (acct_failover && conf->num_acct_servers > 1) {
 
295
                struct hostapd_radius_server *next, *old;
 
296
                old = conf->acct_server;
 
297
                hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
298
                               HOSTAPD_LEVEL_NOTICE,
 
299
                               "No response from Accounting server "
 
300
                               "%s:%d - failover",
 
301
                               hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
 
302
                               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 > &conf->acct_servers[conf->num_acct_servers - 1])
 
312
                        next = conf->acct_servers;
 
313
                conf->acct_server = next;
 
314
                radius_change_server(radius, next, old,
 
315
                                     radius->acct_serv_sock,
 
316
                                     radius->acct_serv_sock6, 0);
 
317
        }
 
318
}
 
319
 
 
320
 
 
321
static void radius_client_update_timeout(struct radius_client_data *radius)
 
322
{
 
323
        struct os_time now;
 
324
        os_time_t 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
        os_get_time(&now);
 
340
        if (first < now.sec)
 
341
                first = now.sec;
 
342
        eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
 
343
                               NULL);
 
344
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
345
                       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
 
346
                       " %ld seconds\n", (long int) (first - now.sec));
 
347
}
 
348
 
 
349
 
 
350
static void radius_client_list_add(struct radius_client_data *radius,
 
351
                                   struct radius_msg *msg,
 
352
                                   RadiusType msg_type, u8 *shared_secret,
 
353
                                   size_t shared_secret_len, const u8 *addr)
 
354
{
 
355
        struct radius_msg_list *entry, *prev;
 
356
 
 
357
        if (eloop_terminated()) {
 
358
                /* No point in adding entries to retransmit queue since event
 
359
                 * loop has already been terminated. */
 
360
                radius_msg_free(msg);
 
361
                os_free(msg);
 
362
                return;
 
363
        }
 
364
 
 
365
        entry = wpa_zalloc(sizeof(*entry));
 
366
        if (entry == NULL) {
 
367
                printf("Failed to add RADIUS packet into retransmit list\n");
 
368
                radius_msg_free(msg);
 
369
                os_free(msg);
 
370
                return;
 
371
        }
 
372
 
 
373
        if (addr)
 
374
                os_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
        os_get_time(&entry->last_attempt);
 
380
        entry->first_try = entry->last_attempt.sec;
 
381
        entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
 
382
        entry->attempts = 1;
 
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, const u8 *addr)
 
407
{
 
408
        struct radius_msg_list *entry, *prev, *tmp;
 
409
 
 
410
        if (addr == NULL)
 
411
                return;
 
412
 
 
413
        entry = radius->msgs;
 
414
        prev = NULL;
 
415
        while (entry) {
 
416
                if (entry->msg_type == msg_type &&
 
417
                    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
 
418
                        if (prev)
 
419
                                prev->next = entry->next;
 
420
                        else
 
421
                                radius->msgs = entry->next;
 
422
                        tmp = entry;
 
423
                        entry = entry->next;
 
424
                        hostapd_logger(radius->ctx, addr,
 
425
                                       HOSTAPD_MODULE_RADIUS,
 
426
                                       HOSTAPD_LEVEL_DEBUG,
 
427
                                       "Removing matching RADIUS message");
 
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,
 
440
                       const u8 *addr)
 
441
{
 
442
        struct hostapd_radius_servers *conf = radius->conf;
 
443
        u8 *shared_secret;
 
444
        size_t shared_secret_len;
 
445
        char *name;
 
446
        int s, res;
 
447
 
 
448
        if (msg_type == RADIUS_ACCT_INTERIM) {
 
449
                /* Remove any pending interim acct update for the same STA. */
 
450
                radius_client_list_del(radius, msg_type, addr);
 
451
        }
 
452
 
 
453
        if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
 
454
                shared_secret = conf->acct_server->shared_secret;
 
455
                shared_secret_len = conf->acct_server->shared_secret_len;
 
456
                radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
 
457
                name = "accounting";
 
458
                s = radius->acct_sock;
 
459
                conf->acct_server->requests++;
 
460
        } else {
 
461
                shared_secret = conf->auth_server->shared_secret;
 
462
                shared_secret_len = conf->auth_server->shared_secret_len;
 
463
                radius_msg_finish(msg, shared_secret, shared_secret_len);
 
464
                name = "authentication";
 
465
                s = radius->auth_sock;
 
466
                conf->auth_server->requests++;
 
467
        }
 
468
 
 
469
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
470
                       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
 
471
                       "server", name);
 
472
        if (conf->msg_dumps)
 
473
                radius_msg_dump(msg);
 
474
 
 
475
        res = send(s, msg->buf, msg->buf_used, 0);
 
476
        if (res < 0)
 
477
                radius_client_handle_send_error(radius, s, msg_type);
 
478
 
 
479
        radius_client_list_add(radius, msg, msg_type, shared_secret,
 
480
                               shared_secret_len, addr);
 
481
 
 
482
        return res;
 
483
}
 
484
 
 
485
 
 
486
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
 
487
{
 
488
        struct radius_client_data *radius = eloop_ctx;
 
489
        struct hostapd_radius_servers *conf = radius->conf;
 
490
        RadiusType msg_type = (RadiusType) sock_ctx;
 
491
        int len, roundtrip;
 
492
        unsigned char buf[3000];
 
493
        struct radius_msg *msg;
 
494
        struct radius_rx_handler *handlers;
 
495
        size_t num_handlers, i;
 
496
        struct radius_msg_list *req, *prev_req;
 
497
        struct os_time now;
 
498
        struct hostapd_radius_server *rconf;
 
499
        int invalid_authenticator = 0;
 
500
 
 
501
        if (msg_type == RADIUS_ACCT) {
 
502
                handlers = radius->acct_handlers;
 
503
                num_handlers = radius->num_acct_handlers;
 
504
                rconf = conf->acct_server;
 
505
        } else {
 
506
                handlers = radius->auth_handlers;
 
507
                num_handlers = radius->num_auth_handlers;
 
508
                rconf = conf->auth_server;
 
509
        }
 
510
 
 
511
        len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
 
512
        if (len < 0) {
 
513
                perror("recv[RADIUS]");
 
514
                return;
 
515
        }
 
516
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
517
                       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
 
518
                       "server", len);
 
519
        if (len == sizeof(buf)) {
 
520
                printf("Possibly too long UDP frame for our buffer - "
 
521
                       "dropping it\n");
 
522
                return;
 
523
        }
 
524
 
 
525
        msg = radius_msg_parse(buf, len);
 
526
        if (msg == NULL) {
 
527
                printf("Parsing incoming RADIUS frame failed\n");
 
528
                rconf->malformed_responses++;
 
529
                return;
 
530
        }
 
531
 
 
532
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
533
                       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
 
534
        if (conf->msg_dumps)
 
535
                radius_msg_dump(msg);
 
536
 
 
537
        switch (msg->hdr->code) {
 
538
        case RADIUS_CODE_ACCESS_ACCEPT:
 
539
                rconf->access_accepts++;
 
540
                break;
 
541
        case RADIUS_CODE_ACCESS_REJECT:
 
542
                rconf->access_rejects++;
 
543
                break;
 
544
        case RADIUS_CODE_ACCESS_CHALLENGE:
 
545
                rconf->access_challenges++;
 
546
                break;
 
547
        case RADIUS_CODE_ACCOUNTING_RESPONSE:
 
548
                rconf->responses++;
 
549
                break;
 
550
        }
 
551
 
 
552
        prev_req = NULL;
 
553
        req = radius->msgs;
 
554
        while (req) {
 
555
                /* TODO: also match by src addr:port of the packet when using
 
556
                 * alternative RADIUS servers (?) */
 
557
                if ((req->msg_type == msg_type ||
 
558
                     (req->msg_type == RADIUS_ACCT_INTERIM &&
 
559
                      msg_type == RADIUS_ACCT)) &&
 
560
                    req->msg->hdr->identifier == msg->hdr->identifier)
 
561
                        break;
 
562
 
 
563
                prev_req = req;
 
564
                req = req->next;
 
565
        }
 
566
 
 
567
        if (req == NULL) {
 
568
                hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
569
                               HOSTAPD_LEVEL_DEBUG,
 
570
                               "No matching RADIUS request found (type=%d "
 
571
                               "id=%d) - dropping packet",
 
572
                               msg_type, msg->hdr->identifier);
 
573
                goto fail;
 
574
        }
 
575
 
 
576
        os_get_time(&now);
 
577
        roundtrip = (now.sec - req->last_attempt.sec) * 100 +
 
578
                (now.usec - req->last_attempt.usec) / 10000;
 
579
        hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
 
580
                       HOSTAPD_LEVEL_DEBUG,
 
581
                       "Received RADIUS packet matched with a pending "
 
582
                       "request, round trip time %d.%02d sec",
 
583
                       roundtrip / 100, roundtrip % 100);
 
584
        rconf->round_trip_time = roundtrip;
 
585
 
 
586
        /* Remove ACKed RADIUS packet from retransmit list */
 
587
        if (prev_req)
 
588
                prev_req->next = req->next;
 
589
        else
 
590
                radius->msgs = req->next;
 
591
        radius->num_msgs--;
 
592
 
 
593
        for (i = 0; i < num_handlers; i++) {
 
594
                RadiusRxResult res;
 
595
                res = handlers[i].handler(msg, req->msg, req->shared_secret,
 
596
                                          req->shared_secret_len,
 
597
                                          handlers[i].data);
 
598
                switch (res) {
 
599
                case RADIUS_RX_PROCESSED:
 
600
                        radius_msg_free(msg);
 
601
                        os_free(msg);
 
602
                        /* continue */
 
603
                case RADIUS_RX_QUEUED:
 
604
                        radius_client_msg_free(req);
 
605
                        return;
 
606
                case RADIUS_RX_INVALID_AUTHENTICATOR:
 
607
                        invalid_authenticator++;
 
608
                        /* continue */
 
609
                case RADIUS_RX_UNKNOWN:
 
610
                        /* continue with next handler */
 
611
                        break;
 
612
                }
 
613
        }
 
614
 
 
615
        if (invalid_authenticator)
 
616
                rconf->bad_authenticators++;
 
617
        else
 
618
                rconf->unknown_types++;
 
619
        hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
 
620
                       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
 
621
                       "(type=%d code=%d id=%d)%s - dropping packet",
 
622
                       msg_type, msg->hdr->code, msg->hdr->identifier,
 
623
                       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
 
624
                       "");
 
625
        radius_client_msg_free(req);
 
626
 
 
627
 fail:
 
628
        radius_msg_free(msg);
 
629
        os_free(msg);
 
630
}
 
631
 
 
632
 
 
633
u8 radius_client_get_id(struct radius_client_data *radius)
 
634
{
 
635
        struct radius_msg_list *entry, *prev, *_remove;
 
636
        u8 id = radius->next_radius_identifier++;
 
637
 
 
638
        /* remove entries with matching id from retransmit list to avoid
 
639
         * using new reply from the RADIUS server with an old request */
 
640
        entry = radius->msgs;
 
641
        prev = NULL;
 
642
        while (entry) {
 
643
                if (entry->msg->hdr->identifier == id) {
 
644
                        hostapd_logger(radius->ctx, entry->addr,
 
645
                                       HOSTAPD_MODULE_RADIUS,
 
646
                                       HOSTAPD_LEVEL_DEBUG,
 
647
                                       "Removing pending RADIUS message, "
 
648
                                       "since its id (%d) is reused", id);
 
649
                        if (prev)
 
650
                                prev->next = entry->next;
 
651
                        else
 
652
                                radius->msgs = entry->next;
 
653
                        _remove = entry;
 
654
                } else {
 
655
                        _remove = NULL;
 
656
                        prev = entry;
 
657
                }
 
658
                entry = entry->next;
 
659
 
 
660
                if (_remove)
 
661
                        radius_client_msg_free(_remove);
 
662
        }
 
663
 
 
664
        return id;
 
665
}
 
666
 
 
667
 
 
668
void radius_client_flush(struct radius_client_data *radius, int only_auth)
 
669
{
 
670
        struct radius_msg_list *entry, *prev, *tmp;
 
671
 
 
672
        if (!radius)
 
673
                return;
 
674
 
 
675
        prev = NULL;
 
676
        entry = radius->msgs;
 
677
 
 
678
        while (entry) {
 
679
                if (!only_auth || entry->msg_type == RADIUS_AUTH) {
 
680
                        if (prev)
 
681
                                prev->next = entry->next;
 
682
                        else
 
683
                                radius->msgs = entry->next;
 
684
 
 
685
                        tmp = entry;
 
686
                        entry = entry->next;
 
687
                        radius_client_msg_free(tmp);
 
688
                        radius->num_msgs--;
 
689
                } else {
 
690
                        prev = entry;
 
691
                        entry = entry->next;
 
692
                }
 
693
        }
 
694
 
 
695
        if (radius->msgs == NULL)
 
696
                eloop_cancel_timeout(radius_client_timer, radius, NULL);
 
697
}
 
698
 
 
699
 
 
700
void radius_client_update_acct_msgs(struct radius_client_data *radius,
 
701
                                    u8 *shared_secret,
 
702
                                    size_t shared_secret_len)
 
703
{
 
704
        struct radius_msg_list *entry;
 
705
 
 
706
        if (!radius)
 
707
                return;
 
708
 
 
709
        for (entry = radius->msgs; entry; entry = entry->next) {
 
710
                if (entry->msg_type == RADIUS_ACCT) {
 
711
                        entry->shared_secret = shared_secret;
 
712
                        entry->shared_secret_len = shared_secret_len;
 
713
                        radius_msg_finish_acct(entry->msg, shared_secret,
 
714
                                               shared_secret_len);
 
715
                }
 
716
        }
 
717
}
 
718
 
 
719
 
 
720
static int
 
721
radius_change_server(struct radius_client_data *radius,
 
722
                     struct hostapd_radius_server *nserv,
 
723
                     struct hostapd_radius_server *oserv,
 
724
                     int sock, int sock6, int auth)
 
725
{
 
726
        struct sockaddr_in serv;
 
727
#ifdef CONFIG_IPV6
 
728
        struct sockaddr_in6 serv6;
 
729
#endif /* CONFIG_IPV6 */
 
730
        struct sockaddr *addr;
 
731
        socklen_t addrlen;
 
732
        char abuf[50];
 
733
        int sel_sock;
 
734
        struct radius_msg_list *entry;
 
735
 
 
736
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
737
                       HOSTAPD_LEVEL_INFO,
 
738
                       "%s server %s:%d",
 
739
                       auth ? "Authentication" : "Accounting",
 
740
                       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
 
741
                       nserv->port);
 
742
 
 
743
        if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
 
744
            os_memcmp(nserv->shared_secret, oserv->shared_secret,
 
745
                      nserv->shared_secret_len) != 0) {
 
746
                /* Pending RADIUS packets used different shared secret, so
 
747
                 * they need to be modified. Update accounting message
 
748
                 * authenticators here. Authentication messages are removed
 
749
                 * since they would require more changes and the new RADIUS
 
750
                 * server may not be prepared to receive them anyway due to
 
751
                 * missing state information. Client will likely retry
 
752
                 * authentication, so this should not be an issue. */
 
753
                if (auth)
 
754
                        radius_client_flush(radius, 1);
 
755
                else {
 
756
                        radius_client_update_acct_msgs(
 
757
                                radius, nserv->shared_secret,
 
758
                                nserv->shared_secret_len);
 
759
                }
 
760
        }
 
761
 
 
762
        /* Reset retry counters for the new server */
 
763
        for (entry = radius->msgs; entry; entry = entry->next) {
 
764
                if ((auth && entry->msg_type != RADIUS_AUTH) ||
 
765
                    (!auth && entry->msg_type != RADIUS_ACCT))
 
766
                        continue;
 
767
                entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
 
768
                entry->attempts = 0;
 
769
                entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
 
770
        }
 
771
 
 
772
        if (radius->msgs) {
 
773
                eloop_cancel_timeout(radius_client_timer, radius, NULL);
 
774
                eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
 
775
                                       radius_client_timer, radius, NULL);
 
776
        }
 
777
 
 
778
        switch (nserv->addr.af) {
 
779
        case AF_INET:
 
780
                os_memset(&serv, 0, sizeof(serv));
 
781
                serv.sin_family = AF_INET;
 
782
                serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
 
783
                serv.sin_port = htons(nserv->port);
 
784
                addr = (struct sockaddr *) &serv;
 
785
                addrlen = sizeof(serv);
 
786
                sel_sock = sock;
 
787
                break;
 
788
#ifdef CONFIG_IPV6
 
789
        case AF_INET6:
 
790
                os_memset(&serv6, 0, sizeof(serv6));
 
791
                serv6.sin6_family = AF_INET6;
 
792
                os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
 
793
                          sizeof(struct in6_addr));
 
794
                serv6.sin6_port = htons(nserv->port);
 
795
                addr = (struct sockaddr *) &serv6;
 
796
                addrlen = sizeof(serv6);
 
797
                sel_sock = sock6;
 
798
                break;
 
799
#endif /* CONFIG_IPV6 */
 
800
        default:
 
801
                return -1;
 
802
        }
 
803
 
 
804
        if (connect(sel_sock, addr, addrlen) < 0) {
 
805
                perror("connect[radius]");
 
806
                return -1;
 
807
        }
 
808
 
 
809
        if (auth)
 
810
                radius->auth_sock = sel_sock;
 
811
        else
 
812
                radius->acct_sock = sel_sock;
 
813
 
 
814
        return 0;
 
815
}
 
816
 
 
817
 
 
818
static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
 
819
{
 
820
        struct radius_client_data *radius = eloop_ctx;
 
821
        struct hostapd_radius_servers *conf = radius->conf;
 
822
        struct hostapd_radius_server *oserv;
 
823
 
 
824
        if (radius->auth_sock >= 0 && conf->auth_servers &&
 
825
            conf->auth_server != conf->auth_servers) {
 
826
                oserv = conf->auth_server;
 
827
                conf->auth_server = conf->auth_servers;
 
828
                radius_change_server(radius, conf->auth_server, oserv,
 
829
                                     radius->auth_serv_sock,
 
830
                                     radius->auth_serv_sock6, 1);
 
831
        }
 
832
 
 
833
        if (radius->acct_sock >= 0 && conf->acct_servers &&
 
834
            conf->acct_server != conf->acct_servers) {
 
835
                oserv = conf->acct_server;
 
836
                conf->acct_server = conf->acct_servers;
 
837
                radius_change_server(radius, conf->acct_server, oserv,
 
838
                                     radius->acct_serv_sock,
 
839
                                     radius->acct_serv_sock6, 0);
 
840
        }
 
841
 
 
842
        if (conf->retry_primary_interval)
 
843
                eloop_register_timeout(conf->retry_primary_interval, 0,
 
844
                                       radius_retry_primary_timer, radius,
 
845
                                       NULL);
 
846
}
 
847
 
 
848
 
 
849
static int radius_client_init_auth(struct radius_client_data *radius)
 
850
{
 
851
        struct hostapd_radius_servers *conf = radius->conf;
 
852
        int ok = 0;
 
853
 
 
854
        radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 
855
        if (radius->auth_serv_sock < 0)
 
856
                perror("socket[PF_INET,SOCK_DGRAM]");
 
857
        else
 
858
                ok++;
 
859
 
 
860
#ifdef CONFIG_IPV6
 
861
        radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
 
862
        if (radius->auth_serv_sock6 < 0)
 
863
                perror("socket[PF_INET6,SOCK_DGRAM]");
 
864
        else
 
865
                ok++;
 
866
#endif /* CONFIG_IPV6 */
 
867
 
 
868
        if (ok == 0)
 
869
                return -1;
 
870
 
 
871
        radius_change_server(radius, conf->auth_server, NULL,
 
872
                             radius->auth_serv_sock, radius->auth_serv_sock6,
 
873
                             1);
 
874
 
 
875
        if (radius->auth_serv_sock >= 0 &&
 
876
            eloop_register_read_sock(radius->auth_serv_sock,
 
877
                                     radius_client_receive, radius,
 
878
                                     (void *) RADIUS_AUTH)) {
 
879
                printf("Could not register read socket for authentication "
 
880
                       "server\n");
 
881
                return -1;
 
882
        }
 
883
 
 
884
#ifdef CONFIG_IPV6
 
885
        if (radius->auth_serv_sock6 >= 0 &&
 
886
            eloop_register_read_sock(radius->auth_serv_sock6,
 
887
                                     radius_client_receive, radius,
 
888
                                     (void *) RADIUS_AUTH)) {
 
889
                printf("Could not register read socket for authentication "
 
890
                       "server\n");
 
891
                return -1;
 
892
        }
 
893
#endif /* CONFIG_IPV6 */
 
894
 
 
895
        return 0;
 
896
}
 
897
 
 
898
 
 
899
static int radius_client_init_acct(struct radius_client_data *radius)
 
900
{
 
901
        struct hostapd_radius_servers *conf = radius->conf;
 
902
        int ok = 0;
 
903
 
 
904
        radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 
905
        if (radius->acct_serv_sock < 0)
 
906
                perror("socket[PF_INET,SOCK_DGRAM]");
 
907
        else
 
908
                ok++;
 
909
 
 
910
#ifdef CONFIG_IPV6
 
911
        radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
 
912
        if (radius->acct_serv_sock6 < 0)
 
913
                perror("socket[PF_INET6,SOCK_DGRAM]");
 
914
        else
 
915
                ok++;
 
916
#endif /* CONFIG_IPV6 */
 
917
 
 
918
        if (ok == 0)
 
919
                return -1;
 
920
 
 
921
        radius_change_server(radius, conf->acct_server, NULL,
 
922
                             radius->acct_serv_sock, radius->acct_serv_sock6,
 
923
                             0);
 
924
 
 
925
        if (radius->acct_serv_sock >= 0 &&
 
926
            eloop_register_read_sock(radius->acct_serv_sock,
 
927
                                     radius_client_receive, radius,
 
928
                                     (void *) RADIUS_ACCT)) {
 
929
                printf("Could not register read socket for accounting "
 
930
                       "server\n");
 
931
                return -1;
 
932
        }
 
933
 
 
934
#ifdef CONFIG_IPV6
 
935
        if (radius->acct_serv_sock6 >= 0 &&
 
936
            eloop_register_read_sock(radius->acct_serv_sock6,
 
937
                                     radius_client_receive, radius,
 
938
                                     (void *) RADIUS_ACCT)) {
 
939
                printf("Could not register read socket for accounting "
 
940
                       "server\n");
 
941
                return -1;
 
942
        }
 
943
#endif /* CONFIG_IPV6 */
 
944
 
 
945
        return 0;
 
946
}
 
947
 
 
948
 
 
949
struct radius_client_data *
 
950
radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
 
951
{
 
952
        struct radius_client_data *radius;
 
953
 
 
954
        radius = wpa_zalloc(sizeof(struct radius_client_data));
 
955
        if (radius == NULL)
 
956
                return NULL;
 
957
 
 
958
        radius->ctx = ctx;
 
959
        radius->conf = conf;
 
960
        radius->auth_serv_sock = radius->acct_serv_sock =
 
961
                radius->auth_serv_sock6 = radius->acct_serv_sock6 =
 
962
                radius->auth_sock = radius->acct_sock = -1;
 
963
 
 
964
        if (conf->auth_server && radius_client_init_auth(radius)) {
 
965
                radius_client_deinit(radius);
 
966
                return NULL;
 
967
        }
 
968
 
 
969
        if (conf->acct_server && radius_client_init_acct(radius)) {
 
970
                radius_client_deinit(radius);
 
971
                return NULL;
 
972
        }
 
973
 
 
974
        if (conf->retry_primary_interval)
 
975
                eloop_register_timeout(conf->retry_primary_interval, 0,
 
976
                                       radius_retry_primary_timer, radius,
 
977
                                       NULL);
 
978
 
 
979
        return radius;
 
980
}
 
981
 
 
982
 
 
983
void radius_client_deinit(struct radius_client_data *radius)
 
984
{
 
985
        if (!radius)
 
986
                return;
 
987
 
 
988
        if (radius->auth_serv_sock >= 0)
 
989
                eloop_unregister_read_sock(radius->auth_serv_sock);
 
990
        if (radius->acct_serv_sock >= 0)
 
991
                eloop_unregister_read_sock(radius->acct_serv_sock);
 
992
 
 
993
        eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
 
994
 
 
995
        radius_client_flush(radius, 0);
 
996
        os_free(radius->auth_handlers);
 
997
        os_free(radius->acct_handlers);
 
998
        os_free(radius);
 
999
}
 
1000
 
 
1001
 
 
1002
void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
 
1003
{
 
1004
        struct radius_msg_list *entry, *prev, *tmp;
 
1005
 
 
1006
        prev = NULL;
 
1007
        entry = radius->msgs;
 
1008
        while (entry) {
 
1009
                if (entry->msg_type == RADIUS_AUTH &&
 
1010
                    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
 
1011
                        hostapd_logger(radius->ctx, addr,
 
1012
                                       HOSTAPD_MODULE_RADIUS,
 
1013
                                       HOSTAPD_LEVEL_DEBUG,
 
1014
                                       "Removing pending RADIUS authentication"
 
1015
                                       " message for removed client");
 
1016
 
 
1017
                        if (prev)
 
1018
                                prev->next = entry->next;
 
1019
                        else
 
1020
                                radius->msgs = entry->next;
 
1021
 
 
1022
                        tmp = entry;
 
1023
                        entry = entry->next;
 
1024
                        radius_client_msg_free(tmp);
 
1025
                        radius->num_msgs--;
 
1026
                        continue;
 
1027
                }
 
1028
 
 
1029
                prev = entry;
 
1030
                entry = entry->next;
 
1031
        }
 
1032
}
 
1033
 
 
1034
 
 
1035
static int radius_client_dump_auth_server(char *buf, size_t buflen,
 
1036
                                          struct hostapd_radius_server *serv,
 
1037
                                          struct radius_client_data *cli)
 
1038
{
 
1039
        int pending = 0;
 
1040
        struct radius_msg_list *msg;
 
1041
        char abuf[50];
 
1042
 
 
1043
        if (cli) {
 
1044
                for (msg = cli->msgs; msg; msg = msg->next) {
 
1045
                        if (msg->msg_type == RADIUS_AUTH)
 
1046
                                pending++;
 
1047
                }
 
1048
        }
 
1049
 
 
1050
        return os_snprintf(buf, buflen,
 
1051
                           "radiusAuthServerIndex=%d\n"
 
1052
                           "radiusAuthServerAddress=%s\n"
 
1053
                           "radiusAuthClientServerPortNumber=%d\n"
 
1054
                           "radiusAuthClientRoundTripTime=%d\n"
 
1055
                           "radiusAuthClientAccessRequests=%u\n"
 
1056
                           "radiusAuthClientAccessRetransmissions=%u\n"
 
1057
                           "radiusAuthClientAccessAccepts=%u\n"
 
1058
                           "radiusAuthClientAccessRejects=%u\n"
 
1059
                           "radiusAuthClientAccessChallenges=%u\n"
 
1060
                           "radiusAuthClientMalformedAccessResponses=%u\n"
 
1061
                           "radiusAuthClientBadAuthenticators=%u\n"
 
1062
                           "radiusAuthClientPendingRequests=%u\n"
 
1063
                           "radiusAuthClientTimeouts=%u\n"
 
1064
                           "radiusAuthClientUnknownTypes=%u\n"
 
1065
                           "radiusAuthClientPacketsDropped=%u\n",
 
1066
                           serv->index,
 
1067
                           hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
 
1068
                           serv->port,
 
1069
                           serv->round_trip_time,
 
1070
                           serv->requests,
 
1071
                           serv->retransmissions,
 
1072
                           serv->access_accepts,
 
1073
                           serv->access_rejects,
 
1074
                           serv->access_challenges,
 
1075
                           serv->malformed_responses,
 
1076
                           serv->bad_authenticators,
 
1077
                           pending,
 
1078
                           serv->timeouts,
 
1079
                           serv->unknown_types,
 
1080
                           serv->packets_dropped);
 
1081
}
 
1082
 
 
1083
 
 
1084
static int radius_client_dump_acct_server(char *buf, size_t buflen,
 
1085
                                          struct hostapd_radius_server *serv,
 
1086
                                          struct radius_client_data *cli)
 
1087
{
 
1088
        int pending = 0;
 
1089
        struct radius_msg_list *msg;
 
1090
        char abuf[50];
 
1091
 
 
1092
        if (cli) {
 
1093
                for (msg = cli->msgs; msg; msg = msg->next) {
 
1094
                        if (msg->msg_type == RADIUS_ACCT ||
 
1095
                            msg->msg_type == RADIUS_ACCT_INTERIM)
 
1096
                                pending++;
 
1097
                }
 
1098
        }
 
1099
 
 
1100
        return os_snprintf(buf, buflen,
 
1101
                           "radiusAccServerIndex=%d\n"
 
1102
                           "radiusAccServerAddress=%s\n"
 
1103
                           "radiusAccClientServerPortNumber=%d\n"
 
1104
                           "radiusAccClientRoundTripTime=%d\n"
 
1105
                           "radiusAccClientRequests=%u\n"
 
1106
                           "radiusAccClientRetransmissions=%u\n"
 
1107
                           "radiusAccClientResponses=%u\n"
 
1108
                           "radiusAccClientMalformedResponses=%u\n"
 
1109
                           "radiusAccClientBadAuthenticators=%u\n"
 
1110
                           "radiusAccClientPendingRequests=%u\n"
 
1111
                           "radiusAccClientTimeouts=%u\n"
 
1112
                           "radiusAccClientUnknownTypes=%u\n"
 
1113
                           "radiusAccClientPacketsDropped=%u\n",
 
1114
                           serv->index,
 
1115
                           hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
 
1116
                           serv->port,
 
1117
                           serv->round_trip_time,
 
1118
                           serv->requests,
 
1119
                           serv->retransmissions,
 
1120
                           serv->responses,
 
1121
                           serv->malformed_responses,
 
1122
                           serv->bad_authenticators,
 
1123
                           pending,
 
1124
                           serv->timeouts,
 
1125
                           serv->unknown_types,
 
1126
                           serv->packets_dropped);
 
1127
}
 
1128
 
 
1129
 
 
1130
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
 
1131
                          size_t buflen)
 
1132
{
 
1133
        struct hostapd_radius_servers *conf = radius->conf;
 
1134
        int i;
 
1135
        struct hostapd_radius_server *serv;
 
1136
        int count = 0;
 
1137
 
 
1138
        if (conf->auth_servers) {
 
1139
                for (i = 0; i < conf->num_auth_servers; i++) {
 
1140
                        serv = &conf->auth_servers[i];
 
1141
                        count += radius_client_dump_auth_server(
 
1142
                                buf + count, buflen - count, serv,
 
1143
                                serv == conf->auth_server ?
 
1144
                                radius : NULL);
 
1145
                }
 
1146
        }
 
1147
 
 
1148
        if (conf->acct_servers) {
 
1149
                for (i = 0; i < conf->num_acct_servers; i++) {
 
1150
                        serv = &conf->acct_servers[i];
 
1151
                        count += radius_client_dump_acct_server(
 
1152
                                buf + count, buflen - count, serv,
 
1153
                                serv == conf->acct_server ?
 
1154
                                radius : NULL);
 
1155
                }
 
1156
        }
 
1157
 
 
1158
        return count;
 
1159
}
 
1160
 
 
1161
 
 
1162
static int radius_servers_diff(struct hostapd_radius_server *nserv,
 
1163
                               struct hostapd_radius_server *oserv,
 
1164
                               int num)
 
1165
{
 
1166
        int i;
 
1167
 
 
1168
        for (i = 0; i < num; i++) {
 
1169
                if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
 
1170
                    nserv[i].port != oserv[i].port ||
 
1171
                    nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
 
1172
                    memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
 
1173
                           nserv[i].shared_secret_len) != 0)
 
1174
                        return 1;
 
1175
        }
 
1176
 
 
1177
        return 0;
 
1178
}
 
1179
 
 
1180
 
 
1181
struct radius_client_data *
 
1182
radius_client_reconfig(struct radius_client_data *old, void *ctx,
 
1183
                       struct hostapd_radius_servers *oldconf,
 
1184
                       struct hostapd_radius_servers *newconf)
 
1185
{
 
1186
        radius_client_flush(old, 0);
 
1187
 
 
1188
        if (newconf->retry_primary_interval !=
 
1189
            oldconf->retry_primary_interval ||
 
1190
            newconf->num_auth_servers != oldconf->num_auth_servers ||
 
1191
            newconf->num_acct_servers != oldconf->num_acct_servers ||
 
1192
            radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
 
1193
                                newconf->num_auth_servers) ||
 
1194
            radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
 
1195
                                newconf->num_acct_servers)) {
 
1196
                hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
 
1197
                               HOSTAPD_LEVEL_DEBUG,
 
1198
                               "Reconfiguring RADIUS client");
 
1199
                radius_client_deinit(old);
 
1200
                return radius_client_init(ctx, newconf);
 
1201
        }
 
1202
 
 
1203
        return old;
 
1204
}