2 * hostapd / RADIUS Accounting
3 * Copyright (c) 2002-2009, 2012-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "eapol_auth/eapol_auth_sm.h"
14 #include "eapol_auth/eapol_auth_sm_i.h"
15 #include "radius/radius.h"
16 #include "radius/radius_client.h"
18 #include "ieee802_1x.h"
19 #include "ap_config.h"
21 #include "ap_drv_ops.h"
22 #include "accounting.h"
25 /* Default interval in seconds for polling TX/RX octets from the driver if
26 * STA is not using interim accounting. This detects wrap arounds for
27 * input/output octets and updates Acct-{Input,Output}-Gigawords. */
28 #define ACCT_DEFAULT_UPDATE_INTERVAL 300
30 static void accounting_sta_interim(struct hostapd_data
*hapd
,
31 struct sta_info
*sta
);
34 static struct radius_msg
* accounting_msg(struct hostapd_data
*hapd
,
38 struct radius_msg
*msg
;
46 msg
= radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST
,
47 radius_client_get_id(hapd
->radius
));
49 wpa_printf(MSG_INFO
, "Could not create new RADIUS packet");
53 if (!radius_msg_add_attr_int32(msg
, RADIUS_ATTR_ACCT_STATUS_TYPE
,
55 wpa_printf(MSG_INFO
, "Could not add Acct-Status-Type");
60 if (!hostapd_config_get_radius_attr(
61 hapd
->conf
->radius_acct_req_attr
,
62 RADIUS_ATTR_ACCT_AUTHENTIC
) &&
63 !radius_msg_add_attr_int32(msg
, RADIUS_ATTR_ACCT_AUTHENTIC
,
64 hapd
->conf
->ieee802_1x
?
65 RADIUS_ACCT_AUTHENTIC_RADIUS
:
66 RADIUS_ACCT_AUTHENTIC_LOCAL
)) {
67 wpa_printf(MSG_INFO
, "Could not add Acct-Authentic");
71 /* Use 802.1X identity if available */
72 val
= ieee802_1x_get_identity(sta
->eapol_sm
, &len
);
74 /* Use RADIUS ACL identity if 802.1X provides no identity */
75 if (!val
&& sta
->identity
) {
76 val
= (u8
*) sta
->identity
;
77 len
= os_strlen(sta
->identity
);
80 /* Use STA MAC if neither 802.1X nor RADIUS ACL provided
83 os_snprintf(buf
, sizeof(buf
), RADIUS_ADDR_FORMAT
,
89 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_USER_NAME
, val
,
91 wpa_printf(MSG_INFO
, "Could not add User-Name");
96 if (add_common_radius_attr(hapd
, hapd
->conf
->radius_acct_req_attr
, sta
,
100 if (sta
&& add_sqlite_radius_attr(hapd
, sta
, msg
, 1) < 0)
105 val
= ieee802_1x_get_radius_class(sta
->eapol_sm
, &len
,
110 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_CLASS
,
112 wpa_printf(MSG_INFO
, "Could not add Class");
117 b
= ieee802_1x_get_radius_cui(sta
->eapol_sm
);
119 !radius_msg_add_attr(msg
,
120 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY
,
121 wpabuf_head(b
), wpabuf_len(b
))) {
122 wpa_printf(MSG_ERROR
, "Could not add CUI");
126 if (!b
&& sta
->radius_cui
&&
127 !radius_msg_add_attr(msg
,
128 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY
,
129 (u8
*) sta
->radius_cui
,
130 os_strlen(sta
->radius_cui
))) {
131 wpa_printf(MSG_ERROR
, "Could not add CUI from ACL");
136 !radius_msg_add_attr_int32(msg
,
137 RADIUS_ATTR_FRAMED_IP_ADDRESS
,
138 be_to_host32(sta
->ipaddr
))) {
139 wpa_printf(MSG_ERROR
,
140 "Could not add Framed-IP-Address");
146 if (now
.sec
> 1000000000 &&
147 !radius_msg_add_attr_int32(msg
, RADIUS_ATTR_EVENT_TIMESTAMP
,
149 wpa_printf(MSG_INFO
, "Could not add Event-Timestamp");
154 * Add Acct-Delay-Time with zero value for the first transmission. This
155 * will be updated within radius_client.c when retransmitting the frame.
157 if (!radius_msg_add_attr_int32(msg
, RADIUS_ATTR_ACCT_DELAY_TIME
, 0)) {
158 wpa_printf(MSG_INFO
, "Could not add Acct-Delay-Time");
165 radius_msg_free(msg
);
170 static int accounting_sta_update_stats(struct hostapd_data
*hapd
,
171 struct sta_info
*sta
,
172 struct hostap_sta_driver_data
*data
)
174 if (hostapd_drv_read_sta_data(hapd
, data
, sta
->addr
))
177 if (!data
->bytes_64bit
) {
178 /* Extend 32-bit counters from the driver to 64-bit counters */
179 if (sta
->last_rx_bytes_lo
> data
->rx_bytes
)
180 sta
->last_rx_bytes_hi
++;
181 sta
->last_rx_bytes_lo
= data
->rx_bytes
;
183 if (sta
->last_tx_bytes_lo
> data
->tx_bytes
)
184 sta
->last_tx_bytes_hi
++;
185 sta
->last_tx_bytes_lo
= data
->tx_bytes
;
188 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_RADIUS
,
190 "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d",
191 data
->rx_bytes
, sta
->last_rx_bytes_hi
,
192 sta
->last_rx_bytes_lo
,
193 data
->tx_bytes
, sta
->last_tx_bytes_hi
,
194 sta
->last_tx_bytes_lo
,
201 static void accounting_interim_update(void *eloop_ctx
, void *timeout_ctx
)
203 struct hostapd_data
*hapd
= eloop_ctx
;
204 struct sta_info
*sta
= timeout_ctx
;
207 if (sta
->acct_interim_interval
) {
208 accounting_sta_interim(hapd
, sta
);
209 interval
= sta
->acct_interim_interval
;
211 struct hostap_sta_driver_data data
;
212 accounting_sta_update_stats(hapd
, sta
, &data
);
213 interval
= ACCT_DEFAULT_UPDATE_INTERVAL
;
216 eloop_register_timeout(interval
, 0, accounting_interim_update
,
222 * accounting_sta_start - Start STA accounting
223 * @hapd: hostapd BSS data
226 void accounting_sta_start(struct hostapd_data
*hapd
, struct sta_info
*sta
)
228 struct radius_msg
*msg
;
231 if (sta
->acct_session_started
)
234 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_RADIUS
,
236 "starting accounting session %016llX",
237 (unsigned long long) sta
->acct_session_id
);
239 os_get_reltime(&sta
->acct_session_start
);
240 sta
->last_rx_bytes_hi
= 0;
241 sta
->last_rx_bytes_lo
= 0;
242 sta
->last_tx_bytes_hi
= 0;
243 sta
->last_tx_bytes_lo
= 0;
244 hostapd_drv_sta_clear_stats(hapd
, sta
->addr
);
246 if (!hapd
->conf
->radius
->acct_server
)
249 if (sta
->acct_interim_interval
)
250 interval
= sta
->acct_interim_interval
;
252 interval
= ACCT_DEFAULT_UPDATE_INTERVAL
;
253 eloop_register_timeout(interval
, 0, accounting_interim_update
,
256 msg
= accounting_msg(hapd
, sta
, RADIUS_ACCT_STATUS_TYPE_START
);
258 radius_client_send(hapd
->radius
, msg
, RADIUS_ACCT
, sta
->addr
) < 0)
259 radius_msg_free(msg
);
261 sta
->acct_session_started
= 1;
265 static void accounting_sta_report(struct hostapd_data
*hapd
,
266 struct sta_info
*sta
, int stop
)
268 struct radius_msg
*msg
;
269 int cause
= sta
->acct_terminate_cause
;
270 struct hostap_sta_driver_data data
;
271 struct os_reltime now_r
, diff
;
274 if (!hapd
->conf
->radius
->acct_server
)
277 msg
= accounting_msg(hapd
, sta
,
278 stop
? RADIUS_ACCT_STATUS_TYPE_STOP
:
279 RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE
);
281 wpa_printf(MSG_INFO
, "Could not create RADIUS Accounting message");
285 os_get_reltime(&now_r
);
286 os_reltime_sub(&now_r
, &sta
->acct_session_start
, &diff
);
287 if (!radius_msg_add_attr_int32(msg
, RADIUS_ATTR_ACCT_SESSION_TIME
,
289 wpa_printf(MSG_INFO
, "Could not add Acct-Session-Time");
293 if (accounting_sta_update_stats(hapd
, sta
, &data
) == 0) {
294 if (!radius_msg_add_attr_int32(msg
,
295 RADIUS_ATTR_ACCT_INPUT_PACKETS
,
297 wpa_printf(MSG_INFO
, "Could not add Acct-Input-Packets");
300 if (!radius_msg_add_attr_int32(msg
,
301 RADIUS_ATTR_ACCT_OUTPUT_PACKETS
,
303 wpa_printf(MSG_INFO
, "Could not add Acct-Output-Packets");
306 if (data
.bytes_64bit
)
307 bytes
= data
.rx_bytes
;
309 bytes
= ((u64
) sta
->last_rx_bytes_hi
<< 32) |
310 sta
->last_rx_bytes_lo
;
311 if (!radius_msg_add_attr_int32(msg
,
312 RADIUS_ATTR_ACCT_INPUT_OCTETS
,
314 wpa_printf(MSG_INFO
, "Could not add Acct-Input-Octets");
317 if (!radius_msg_add_attr_int32(msg
,
318 RADIUS_ATTR_ACCT_INPUT_GIGAWORDS
,
319 (u32
) (bytes
>> 32))) {
320 wpa_printf(MSG_INFO
, "Could not add Acct-Input-Gigawords");
323 if (data
.bytes_64bit
)
324 bytes
= data
.tx_bytes
;
326 bytes
= ((u64
) sta
->last_tx_bytes_hi
<< 32) |
327 sta
->last_tx_bytes_lo
;
328 if (!radius_msg_add_attr_int32(msg
,
329 RADIUS_ATTR_ACCT_OUTPUT_OCTETS
,
331 wpa_printf(MSG_INFO
, "Could not add Acct-Output-Octets");
334 if (!radius_msg_add_attr_int32(msg
,
335 RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS
,
336 (u32
) (bytes
>> 32))) {
337 wpa_printf(MSG_INFO
, "Could not add Acct-Output-Gigawords");
342 if (eloop_terminated())
343 cause
= RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT
;
346 !radius_msg_add_attr_int32(msg
, RADIUS_ATTR_ACCT_TERMINATE_CAUSE
,
348 wpa_printf(MSG_INFO
, "Could not add Acct-Terminate-Cause");
352 if (radius_client_send(hapd
->radius
, msg
,
353 stop
? RADIUS_ACCT
: RADIUS_ACCT_INTERIM
,
359 radius_msg_free(msg
);
364 * accounting_sta_interim - Send a interim STA accounting report
365 * @hapd: hostapd BSS data
368 static void accounting_sta_interim(struct hostapd_data
*hapd
,
369 struct sta_info
*sta
)
371 if (sta
->acct_session_started
)
372 accounting_sta_report(hapd
, sta
, 0);
377 * accounting_sta_stop - Stop STA accounting
378 * @hapd: hostapd BSS data
381 void accounting_sta_stop(struct hostapd_data
*hapd
, struct sta_info
*sta
)
383 if (sta
->acct_session_started
) {
384 accounting_sta_report(hapd
, sta
, 1);
385 eloop_cancel_timeout(accounting_interim_update
, hapd
, sta
);
386 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_RADIUS
,
388 "stopped accounting session %016llX",
389 (unsigned long long) sta
->acct_session_id
);
390 sta
->acct_session_started
= 0;
395 int accounting_sta_get_id(struct hostapd_data
*hapd
, struct sta_info
*sta
)
397 return radius_gen_session_id((u8
*) &sta
->acct_session_id
,
398 sizeof(sta
->acct_session_id
));
403 * accounting_receive - Process the RADIUS frames from Accounting Server
404 * @msg: RADIUS response message
405 * @req: RADIUS request message
406 * @shared_secret: RADIUS shared secret
407 * @shared_secret_len: Length of shared_secret in octets
408 * @data: Context data (struct hostapd_data *)
409 * Returns: Processing status
411 static RadiusRxResult
412 accounting_receive(struct radius_msg
*msg
, struct radius_msg
*req
,
413 const u8
*shared_secret
, size_t shared_secret_len
,
416 if (radius_msg_get_hdr(msg
)->code
!= RADIUS_CODE_ACCOUNTING_RESPONSE
) {
417 wpa_printf(MSG_INFO
, "Unknown RADIUS message code");
418 return RADIUS_RX_UNKNOWN
;
421 if (radius_msg_verify(msg
, shared_secret
, shared_secret_len
, req
, 0)) {
422 wpa_printf(MSG_INFO
, "Incoming RADIUS packet did not have correct Authenticator - dropped");
423 return RADIUS_RX_INVALID_AUTHENTICATOR
;
426 return RADIUS_RX_PROCESSED
;
430 static void accounting_report_state(struct hostapd_data
*hapd
, int on
)
432 struct radius_msg
*msg
;
434 if (!hapd
->conf
->radius
->acct_server
|| hapd
->radius
== NULL
)
437 /* Inform RADIUS server that accounting will start/stop so that the
438 * server can close old accounting sessions. */
439 msg
= accounting_msg(hapd
, NULL
,
440 on
? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON
:
441 RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF
);
445 if (hapd
->acct_session_id
) {
448 os_snprintf(buf
, sizeof(buf
), "%016llX",
449 (unsigned long long) hapd
->acct_session_id
);
450 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_ACCT_SESSION_ID
,
451 (u8
*) buf
, os_strlen(buf
)))
452 wpa_printf(MSG_ERROR
, "Could not add Acct-Session-Id");
455 if (radius_client_send(hapd
->radius
, msg
, RADIUS_ACCT
, NULL
) < 0)
456 radius_msg_free(msg
);
460 static void accounting_interim_error_cb(const u8
*addr
, void *ctx
)
462 struct hostapd_data
*hapd
= ctx
;
463 struct sta_info
*sta
;
464 unsigned int i
, wait_time
;
467 sta
= ap_get_sta(hapd
, addr
);
470 sta
->acct_interim_errors
++;
471 if (sta
->acct_interim_errors
> 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
472 wpa_printf(MSG_DEBUG
,
473 "Interim RADIUS accounting update failed for " MACSTR
474 " - too many errors, abandon this interim accounting update",
476 sta
->acct_interim_errors
= 0;
477 /* Next update will be tried after normal update interval */
482 * Use a shorter update interval as an improved retransmission mechanism
483 * for failed interim accounting updates. This allows the statistics to
484 * be updated for each retransmission.
486 * RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
487 * Schedule the first retry attempt immediately and every following one
488 * with exponential backoff.
490 if (sta
->acct_interim_errors
== 1) {
493 wait_time
= 3; /* RADIUS_CLIENT_FIRST_WAIT */
494 for (i
= 1; i
< sta
->acct_interim_errors
; i
++)
497 res
= eloop_deplete_timeout(wait_time
, 0, accounting_interim_update
,
500 wpa_printf(MSG_DEBUG
,
501 "Interim RADIUS accounting update failed for " MACSTR
502 " (error count: %u) - schedule next update in %u seconds",
503 MAC2STR(addr
), sta
->acct_interim_errors
, wait_time
);
505 wpa_printf(MSG_DEBUG
,
506 "Interim RADIUS accounting update failed for " MACSTR
507 " (error count: %u)", MAC2STR(addr
),
508 sta
->acct_interim_errors
);
510 wpa_printf(MSG_DEBUG
,
511 "Interim RADIUS accounting update failed for " MACSTR
512 " (error count: %u) - no timer found", MAC2STR(addr
),
513 sta
->acct_interim_errors
);
518 * accounting_init: Initialize accounting
519 * @hapd: hostapd BSS data
520 * Returns: 0 on success, -1 on failure
522 int accounting_init(struct hostapd_data
*hapd
)
524 if (radius_gen_session_id((u8
*) &hapd
->acct_session_id
,
525 sizeof(hapd
->acct_session_id
)) < 0)
528 if (radius_client_register(hapd
->radius
, RADIUS_ACCT
,
529 accounting_receive
, hapd
))
531 radius_client_set_interim_error_cb(hapd
->radius
,
532 accounting_interim_error_cb
, hapd
);
534 accounting_report_state(hapd
, 1);
541 * accounting_deinit: Deinitialize accounting
542 * @hapd: hostapd BSS data
544 void accounting_deinit(struct hostapd_data
*hapd
)
546 accounting_report_state(hapd
, 0);