static void radius_client_acct_failover(struct radius_client_data *radius)
{
	struct hostapd_radius_servers *conf = radius->conf;
	struct hostapd_radius_server *next, *old;
	struct radius_msg_list *entry;
	char abuf[50];

	old = conf->acct_server;
	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_NOTICE,
		       "No response from Accounting server %s:%d - failover",
		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
		       old->port);

	for (entry = radius->msgs; entry; entry = entry->next) {
		if (entry->msg_type == RADIUS_ACCT ||
		    entry->msg_type == RADIUS_ACCT_INTERIM)
			old->timeouts++;
	}

	next = old + 1;
	if (next > &conf->acct_servers[conf->num_acct_servers - 1])
		next = conf->acct_servers;
	conf->acct_server = next;
	radius_change_server(radius, next, old,
			     radius->acct_serv_sock,
			     radius->acct_serv_sock6, 0);
}
static int radius_client_dump_auth_server(char *buf, size_t buflen,
					  struct hostapd_radius_server *serv,
					  struct radius_client_data *cli)
{
	int pending = 0;
	struct radius_msg_list *msg;
	char abuf[50];

	if (cli) {
		for (msg = cli->msgs; msg; msg = msg->next) {
			if (msg->msg_type == RADIUS_AUTH)
				pending++;
		}
	}

	return os_snprintf(buf, buflen,
			   "radiusAuthServerIndex=%d\n"
			   "radiusAuthServerAddress=%s\n"
			   "radiusAuthClientServerPortNumber=%d\n"
			   "radiusAuthClientRoundTripTime=%d\n"
			   "radiusAuthClientAccessRequests=%u\n"
			   "radiusAuthClientAccessRetransmissions=%u\n"
			   "radiusAuthClientAccessAccepts=%u\n"
			   "radiusAuthClientAccessRejects=%u\n"
			   "radiusAuthClientAccessChallenges=%u\n"
			   "radiusAuthClientMalformedAccessResponses=%u\n"
			   "radiusAuthClientBadAuthenticators=%u\n"
			   "radiusAuthClientPendingRequests=%u\n"
			   "radiusAuthClientTimeouts=%u\n"
			   "radiusAuthClientUnknownTypes=%u\n"
			   "radiusAuthClientPacketsDropped=%u\n",
			   serv->index,
			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
			   serv->port,
			   serv->round_trip_time,
			   serv->requests,
			   serv->retransmissions,
			   serv->access_accepts,
			   serv->access_rejects,
			   serv->access_challenges,
			   serv->malformed_responses,
			   serv->bad_authenticators,
			   pending,
			   serv->timeouts,
			   serv->unknown_types,
			   serv->packets_dropped);
}
static int
radius_change_server(struct radius_client_data *radius,
		     struct hostapd_radius_server *nserv,
		     struct hostapd_radius_server *oserv,
		     int sock, int sock6, int auth)
{
	struct sockaddr_in serv, claddr;
#ifdef CONFIG_IPV6
	struct sockaddr_in6 serv6, claddr6;
#endif /* CONFIG_IPV6 */
	struct sockaddr *addr, *cl_addr;
	socklen_t addrlen, claddrlen;
	char abuf[50];
	int sel_sock;
	struct radius_msg_list *entry;
	struct hostapd_radius_servers *conf = radius->conf;
	struct sockaddr_in disconnect_addr = {
		.sin_family = AF_UNSPEC,
	};

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_INFO,
		       "%s server %s:%d",
		       auth ? "Authentication" : "Accounting",
		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
		       nserv->port);

	if (oserv && oserv == nserv) {
		/* Reconnect to same server, flush */
		if (auth)
			radius_client_flush(radius, 1);
	}

	if (oserv && oserv != nserv &&
	    (nserv->shared_secret_len != oserv->shared_secret_len ||
	     os_memcmp(nserv->shared_secret, oserv->shared_secret,
		       nserv->shared_secret_len) != 0)) {
		/* Pending RADIUS packets used different shared secret, so
		 * they need to be modified. Update accounting message
		 * authenticators here. Authentication messages are removed
		 * since they would require more changes and the new RADIUS
		 * server may not be prepared to receive them anyway due to
		 * missing state information. Client will likely retry
		 * authentication, so this should not be an issue. */
		if (auth)
			radius_client_flush(radius, 1);
		else {
			radius_client_update_acct_msgs(
				radius, nserv->shared_secret,
				nserv->shared_secret_len);
		}
	}

	/* Reset retry counters for the new server */
	for (entry = radius->msgs; oserv && oserv != nserv && entry;
	     entry = entry->next) {
		if ((auth && entry->msg_type != RADIUS_AUTH) ||
		    (!auth && entry->msg_type != RADIUS_ACCT))
			continue;
		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
		entry->attempts = 0;
		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
	}

	if (radius->msgs) {
		eloop_cancel_timeout(radius_client_timer, radius, NULL);
		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
				       radius_client_timer, radius, NULL);
	}

	switch (nserv->addr.af) {
	case AF_INET:
		os_memset(&serv, 0, sizeof(serv));
		serv.sin_family = AF_INET;
		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
		serv.sin_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv;
		addrlen = sizeof(serv);
		sel_sock = sock;
		break;
#ifdef CONFIG_IPV6
	case AF_INET6:
		os_memset(&serv6, 0, sizeof(serv6));
		serv6.sin6_family = AF_INET6;
		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
			  sizeof(struct in6_addr));
		serv6.sin6_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv6;
		addrlen = sizeof(serv6);
		sel_sock = sock6;
		break;
#endif /* CONFIG_IPV6 */
	default:
		return -1;
	}

	if (sel_sock < 0) {
		wpa_printf(MSG_INFO,
			   "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
			   nserv->addr.af, sock, sock6, auth);
		return -1;
	}

	if (conf->force_client_addr) {
		switch (conf->client_addr.af) {
		case AF_INET:
			os_memset(&claddr, 0, sizeof(claddr));
			claddr.sin_family = AF_INET;
			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
			claddr.sin_port = htons(0);
			cl_addr = (struct sockaddr *) &claddr;
			claddrlen = sizeof(claddr);
			break;
#ifdef CONFIG_IPV6
		case AF_INET6:
			os_memset(&claddr6, 0, sizeof(claddr6));
			claddr6.sin6_family = AF_INET6;
			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
				  sizeof(struct in6_addr));
			claddr6.sin6_port = htons(0);
			cl_addr = (struct sockaddr *) &claddr6;
			claddrlen = sizeof(claddr6);
			break;
#endif /* CONFIG_IPV6 */
		default:
			return -1;
		}

		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
			wpa_printf(MSG_INFO, "bind[radius]: %s",
				   strerror(errno));
			return -1;
		}
	}

	/* Force a reconnect by disconnecting the socket first */
	if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
		    sizeof(disconnect_addr)) < 0)
		wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));

	if (connect(sel_sock, addr, addrlen) < 0) {
		wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
		return -1;
	}

#ifndef CONFIG_NATIVE_WINDOWS
	switch (nserv->addr.af) {
	case AF_INET:
		claddrlen = sizeof(claddr);
		if (getsockname(sel_sock, (struct sockaddr *) &claddr,
				&claddrlen) == 0) {
			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
				   inet_ntoa(claddr.sin_addr),
				   ntohs(claddr.sin_port));
		}
		break;
#ifdef CONFIG_IPV6
	case AF_INET6: {
		claddrlen = sizeof(claddr6);
		if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
				&claddrlen) == 0) {
			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
				   inet_ntop(AF_INET6, &claddr6.sin6_addr,
					     abuf, sizeof(abuf)),
				   ntohs(claddr6.sin6_port));
		}
		break;
	}
#endif /* CONFIG_IPV6 */
	}
#endif /* CONFIG_NATIVE_WINDOWS */

	if (auth)
		radius->auth_sock = sel_sock;
	else
		radius->acct_sock = sel_sock;

	return 0;
}
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
	struct radius_client_data *radius = eloop_ctx;
	struct hostapd_radius_servers *conf = radius->conf;
	struct os_time now;
	os_time_t first;
	struct radius_msg_list *entry, *prev, *tmp;
	int auth_failover = 0, acct_failover = 0;
	char abuf[50];

	entry = radius->msgs;
	if (!entry)
		return;

	os_get_time(&now);
	first = 0;

	prev = NULL;
	while (entry) {
		if (now.sec >= entry->next_try &&
		    radius_client_retransmit(radius, entry, now.sec)) {
			if (prev)
				prev->next = entry->next;
			else
				radius->msgs = entry->next;

			tmp = entry;
			entry = entry->next;
			radius_client_msg_free(tmp);
			radius->num_msgs--;
			continue;
		}

		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
			if (entry->msg_type == RADIUS_ACCT ||
			    entry->msg_type == RADIUS_ACCT_INTERIM)
				acct_failover++;
			else
				auth_failover++;
		}

		if (first == 0 || entry->next_try < first)
			first = entry->next_try;

		prev = entry;
		entry = entry->next;
	}

	if (radius->msgs) {
		if (first < now.sec)
			first = now.sec;
		eloop_register_timeout(first - now.sec, 0,
				       radius_client_timer, radius, NULL);
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
			       "retransmit in %ld seconds",
			       (long int) (first - now.sec));
	}

	if (auth_failover && conf->num_auth_servers > 1) {
		struct hostapd_radius_server *next, *old;
		old = conf->auth_server;
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_NOTICE,
			       "No response from Authentication server "
			       "%s:%d - failover",
			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
			       old->port);

		for (entry = radius->msgs; entry; entry = entry->next) {
			if (entry->msg_type == RADIUS_AUTH)
				old->timeouts++;
		}

		next = old + 1;
		if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
			next = conf->auth_servers;
		conf->auth_server = next;
		radius_change_server(radius, next, old,
				     radius->auth_serv_sock,
				     radius->auth_serv_sock6, 1);
	}

	if (acct_failover && conf->num_acct_servers > 1) {
		struct hostapd_radius_server *next, *old;
		old = conf->acct_server;
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_NOTICE,
			       "No response from Accounting server "
			       "%s:%d - failover",
			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
			       old->port);

		for (entry = radius->msgs; entry; entry = entry->next) {
			if (entry->msg_type == RADIUS_ACCT ||
			    entry->msg_type == RADIUS_ACCT_INTERIM)
				old->timeouts++;
		}

		next = old + 1;
		if (next > &conf->acct_servers[conf->num_acct_servers - 1])
			next = conf->acct_servers;
		conf->acct_server = next;
		radius_change_server(radius, next, old,
				     radius->acct_serv_sock,
				     radius->acct_serv_sock6, 0);
	}
}
static int hostapd_ctrl_iface_status(struct hostapd_data *hapd,
				      char *buf, size_t buflen)
{
	char *pos, *end, tmp[150];
	int res, ret;
#ifdef EAP_WPS
	struct wps_config *wps = hapd->conf->wps;
#endif /* EAP_WPS */

	pos = buf;
	end = buf + buflen;

	ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
			   MAC2STR(hapd->own_addr));
	if (ret < 0 || ret >= end - pos)
		return pos - buf;
	pos += ret;
	if (hapd->conf) {
		struct hostapd_bss_config *bss = hapd->conf;
		struct hostapd_ssid *ssid = &bss->ssid;
		u8 *_ssid = (u8 *)ssid->ssid;
		size_t ssid_len = ssid->ssid_len;
		u8 ssid_buf[HOSTAPD_MAX_SSID_LEN];
		if (ssid_len == 0) {
			res = hostapd_get_ssid(hapd, ssid_buf, sizeof(ssid_buf));
			if (res < 0)
				ssid_len = 0;
			else
				ssid_len = res;
			_ssid = ssid_buf;
		} else {
			memcpy(ssid_buf, _ssid, ssid_len);
		}
		ssid_buf[ssid_len] = 0;
		ret = os_snprintf(pos, end - pos, "ssid=%s\n", ssid_buf);
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;

		ret = os_snprintf(pos, end - pos, "encription=");
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;
		if (bss->wpa) {
			if (bss->wpa_pairwise & WPA_CIPHER_CCMP) {
				ret = os_snprintf(pos, end - pos, "CCMP ");
				if (ret < 0 || ret >= end - pos)
					return pos - buf;
				pos += ret;
			}
			if (bss->wpa_pairwise & WPA_CIPHER_TKIP) {
				ret = os_snprintf(pos, end - pos, "TKIP ");
				if (ret < 0 || ret >= end - pos)
					return pos - buf;
				pos += ret;
			}
		} else {
			if (ssid->wep.keys_set) {
				ret = os_snprintf(pos, end - pos, "WEP ");
				if (ret < 0 || ret >= end - pos)
					return pos - buf;
				pos += ret;
			} else {
				ret = os_snprintf(pos, end - pos, "NONE ");
				if (ret < 0 || ret >= end - pos)
					return pos - buf;
				pos += ret;
			}
		}
		ret = os_snprintf(pos, end - pos, "\n");
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;

		ret = os_snprintf(pos, end - pos, "key_mgmt=");
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;
		if (bss->wpa) {
			if (bss->wpa & HOSTAPD_WPA_VERSION_WPA2) {
				ret = os_snprintf(pos, end - pos, "WPA2 ");
				if (ret < 0 || ret >= end - pos)
					return pos - buf;
				pos += ret;
			}
			if (bss->wpa & HOSTAPD_WPA_VERSION_WPA) {
				ret = os_snprintf(pos, end - pos, "WPA ");
				if (ret < 0 || ret >= end - pos)
					return pos - buf;
				pos += ret;
			}
		} else if (bss->auth_algs & HOSTAPD_AUTH_SHARED_KEY) {
			ret = os_snprintf(pos, end - pos, "SHARED ");
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		} else {
			ret = os_snprintf(pos, end - pos, "OPEN ");
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		}
		ret = os_snprintf(pos, end - pos, "\n");
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;

		#ifdef CONFIG_CTRL_IFACE_SHOW_KEY
                if (bss == NULL || bss->eap_user == NULL) {
                        sprintf(tmp, "No eap user");
                } else
		if (bss->eap_user->password_len > 64 ||
		    bss->eap_user->password_len <= 0 ) {
			sprintf(tmp, "invalid password_len %zu",
				bss->eap_user->password_len);
		} else {
			int i;
			for (i = 0; i < bss->eap_user->password_len; i++ ) {
				sprintf(tmp+i*2, "%02X", 
					bss->eap_user->password[i]);
			}
		}
		ret = os_snprintf(pos, end - pos, "password=%s\n", tmp);
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;

		if (bss->ssid.wpa_psk) {
			int i;
			for (i = 0; i < PMK_LEN; i++ ) {
				sprintf(tmp+i*2, "%02X", 
					bss->ssid.wpa_psk->psk[i]);
			}
			ret = os_snprintf(pos, end - pos, "psk=%s\n", tmp);
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		}
		#endif 	/* CONFIG_CTRL_IFACE_SHOW_KEY */

		ret = os_snprintf(pos, end - pos, "ip_address=%s\n",
					   hostapd_ip_txt(&bss->own_ip_addr, tmp, sizeof(tmp)));
		if (ret < 0 || ret >= end - pos)
			return pos - buf;
		pos += ret;
	}

#ifdef EAP_WPS
	if (wps) {
		if (WPS_WPSSTATE_UNCONFIGURED == wps->wps_state) {
			ret = os_snprintf(pos, end - pos, "wps_configured=Unconfigured\n");
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		} else if (WPS_WPSSTATE_CONFIGURED == wps->wps_state) {
			ret = os_snprintf(pos, end - pos, "wps_configured=Configured\n");
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		}

		if (!wps->selreg) {
			ret = os_snprintf(pos, end - pos, "selected_registrar=FALSE\n");
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		} else {
			ret = os_snprintf(pos, end - pos, "selected_registrar=TRUE\n");
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;

			tmp[0] = 0;
			switch (wps->dev_pwd_id) {
			case WPS_DEVICEPWDID_DEFAULT:
				os_snprintf(tmp, sizeof(tmp), "Default");
				break;
			case WPS_DEVICEPWDID_USER_SPEC:
				os_snprintf(tmp, sizeof(tmp), "User-specified");
				break;
			case WPS_DEVICEPWDID_MACHINE_SPEC:
				os_snprintf(tmp, sizeof(tmp), "Machine-specified");
				break;
			case WPS_DEVICEPWDID_PUSH_BTN:
				os_snprintf(tmp, sizeof(tmp), "PushButton");
				break;
			case WPS_DEVICEPWDID_REG_SPEC:
				os_snprintf(tmp, sizeof(tmp), "Registrar-specified");
				break;
			default:
				os_snprintf(tmp, sizeof(tmp), "%04X", wps->dev_pwd_id);
				break;
			}
			ret = os_snprintf(pos, end - pos, "dev_pwd_id=%s\n", tmp);
			if (ret < 0 || ret >= end - pos)
				return pos - buf;
			pos += ret;
		}
	}
#endif /* EAP_WPS */

        /* Track memory usage... useful to check for leaks (unix only) */
	ret = os_snprintf(pos, end - pos, "sbrk(0)=%p\n", sbrk(0));
	if (ret < 0 || ret >= end - pos)
		return pos - buf;
	pos += ret;

	return pos - buf;
}
static int
radius_change_server(struct radius_client_data *radius,
		     struct hostapd_radius_server *nserv,
		     struct hostapd_radius_server *oserv,
		     int sock, int sock6, int auth)
{
	struct sockaddr_in serv;
#ifdef CONFIG_IPV6
	struct sockaddr_in6 serv6;
#endif /* CONFIG_IPV6 */
	struct sockaddr *addr;
	socklen_t addrlen;
	char abuf[50];
	int sel_sock;
	struct radius_msg_list *entry;

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_INFO,
		       "%s server %s:%d",
		       auth ? "Authentication" : "Accounting",
		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
		       nserv->port);

	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
		      nserv->shared_secret_len) != 0) {
		/* Pending RADIUS packets used different shared secret, so
		 * they need to be modified. Update accounting message
		 * authenticators here. Authentication messages are removed
		 * since they would require more changes and the new RADIUS
		 * server may not be prepared to receive them anyway due to
		 * missing state information. Client will likely retry
		 * authentication, so this should not be an issue. */
		if (auth)
			radius_client_flush(radius, 1);
		else {
			radius_client_update_acct_msgs(
				radius, nserv->shared_secret,
				nserv->shared_secret_len);
		}
	}

	/* Reset retry counters for the new server */
	for (entry = radius->msgs; entry; entry = entry->next) {
		if ((auth && entry->msg_type != RADIUS_AUTH) ||
		    (!auth && entry->msg_type != RADIUS_ACCT))
			continue;
		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
		entry->attempts = 0;
		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
	}

	if (radius->msgs) {
		eloop_cancel_timeout(radius_client_timer, radius, NULL);
		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
				       radius_client_timer, radius, NULL);
	}

	switch (nserv->addr.af) {
	case AF_INET:
		os_memset(&serv, 0, sizeof(serv));
		serv.sin_family = AF_INET;
		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
		serv.sin_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv;
		addrlen = sizeof(serv);
		sel_sock = sock;
		break;
#ifdef CONFIG_IPV6
	case AF_INET6:
		os_memset(&serv6, 0, sizeof(serv6));
		serv6.sin6_family = AF_INET6;
		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
			  sizeof(struct in6_addr));
		serv6.sin6_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv6;
		addrlen = sizeof(serv6);
		sel_sock = sock6;
		break;
#endif /* CONFIG_IPV6 */
	default:
		return -1;
	}

	if (connect(sel_sock, addr, addrlen) < 0) {
		perror("connect[radius]");
		return -1;
	}

	if (auth)
		radius->auth_sock = sel_sock;
	else
		radius->acct_sock = sel_sock;

	return 0;
}
static int
radius_change_server(struct radius_client_data *radius,
		     struct hostapd_radius_server *nserv,
		     struct hostapd_radius_server *oserv,
		     int sock, int sock6, int auth)
{
	struct sockaddr_in serv;
#ifdef CONFIG_IPV6
	struct sockaddr_in6 serv6;
#endif /* CONFIG_IPV6 */
	struct sockaddr *addr;
	socklen_t addrlen;
	char abuf[50];
	int sel_sock;

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_INFO,
		       "%s server %s:%d",
		       auth ? "Authentication" : "Accounting",
		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
		       nserv->port);

	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
	    memcmp(nserv->shared_secret, oserv->shared_secret,
		   nserv->shared_secret_len) != 0) {
		/* Pending RADIUS packets used different shared
		 * secret, so they would need to be modified. Could
		 * update all message authenticators and
		 * User-Passwords, etc. and retry with new server. For
		 * now, just drop all pending packets. */
		radius_client_flush(radius);
	} else {
		/* Reset retry counters for the new server */
		struct radius_msg_list *entry;
		entry = radius->msgs;
		while (entry) {
			entry->next_try = entry->first_try +
				RADIUS_CLIENT_FIRST_WAIT;
			entry->attempts = 0;
			entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
			entry = entry->next;
		}
		if (radius->msgs) {
			eloop_cancel_timeout(radius_client_timer, radius,
					     NULL);
			eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
					       radius_client_timer, radius,
					       NULL);
		}
	}

	switch (nserv->addr.af) {
	case AF_INET:
		memset(&serv, 0, sizeof(serv));
		serv.sin_family = AF_INET;
		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
		serv.sin_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv;
		addrlen = sizeof(serv);
		sel_sock = sock;
		break;
#ifdef CONFIG_IPV6
	case AF_INET6:
		memset(&serv6, 0, sizeof(serv6));
		serv6.sin6_family = AF_INET6;
		memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
		       sizeof(struct in6_addr));
		serv6.sin6_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv6;
		addrlen = sizeof(serv6);
		sel_sock = sock6;
		break;
#endif /* CONFIG_IPV6 */
	default:
		return -1;
	}

	if (connect(sel_sock, addr, addrlen) < 0) {
		perror("connect[radius]");
		return -1;
	}

	if (auth)
		radius->auth_sock = sel_sock;
	else
		radius->acct_sock = sel_sock;

	return 0;
}