LCOV - code coverage report
Current view: top level - src/radius - radius_client.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 581 650 89.4 %
Date: 2015-09-27 Functions: 29 29 100.0 %

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

Generated by: LCOV version 1.10