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

Generated by: LCOV version 1.10