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