/src/hostap/src/ap/accounting.c
Line | Count | Source |
1 | | /* |
2 | | * hostapd / RADIUS Accounting |
3 | | * Copyright (c) 2002-2009, 2012-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 "utils/includes.h" |
10 | | |
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" |
17 | | #include "hostapd.h" |
18 | | #include "ieee802_1x.h" |
19 | | #include "ap_config.h" |
20 | | #include "sta_info.h" |
21 | | #include "ap_drv_ops.h" |
22 | | #include "accounting.h" |
23 | | |
24 | | |
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 | 0 | #define ACCT_DEFAULT_UPDATE_INTERVAL 300 |
29 | | |
30 | | static void accounting_sta_interim(struct hostapd_data *hapd, |
31 | | struct sta_info *sta); |
32 | | |
33 | | |
34 | | static struct radius_msg * accounting_msg(struct hostapd_data *hapd, |
35 | | struct sta_info *sta, |
36 | | int status_type) |
37 | 0 | { |
38 | 0 | struct radius_msg *msg; |
39 | 0 | char buf[128]; |
40 | 0 | u8 *val; |
41 | 0 | size_t len; |
42 | 0 | int i; |
43 | 0 | struct wpabuf *b; |
44 | 0 | struct os_time now; |
45 | |
|
46 | 0 | msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST, |
47 | 0 | radius_client_get_id(hapd->radius)); |
48 | 0 | if (msg == NULL) { |
49 | 0 | wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); |
50 | 0 | return NULL; |
51 | 0 | } |
52 | | |
53 | 0 | if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE, |
54 | 0 | status_type)) { |
55 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Status-Type"); |
56 | 0 | goto fail; |
57 | 0 | } |
58 | | |
59 | 0 | if (sta) { |
60 | 0 | if (!hostapd_config_get_radius_attr( |
61 | 0 | hapd->conf->radius_acct_req_attr, |
62 | 0 | RADIUS_ATTR_ACCT_AUTHENTIC) && |
63 | 0 | !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC, |
64 | 0 | hapd->conf->ieee802_1x ? |
65 | 0 | RADIUS_ACCT_AUTHENTIC_RADIUS : |
66 | 0 | RADIUS_ACCT_AUTHENTIC_LOCAL)) { |
67 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Authentic"); |
68 | 0 | goto fail; |
69 | 0 | } |
70 | | |
71 | | /* Use 802.1X identity if available */ |
72 | 0 | val = ieee802_1x_get_identity(sta->eapol_sm, &len); |
73 | | |
74 | | /* Use RADIUS ACL identity if 802.1X provides no identity */ |
75 | 0 | if (!val && sta->identity) { |
76 | 0 | val = (u8 *) sta->identity; |
77 | 0 | len = os_strlen(sta->identity); |
78 | 0 | } |
79 | | |
80 | | /* Use STA MAC if neither 802.1X nor RADIUS ACL provided |
81 | | * identity */ |
82 | 0 | if (!val) { |
83 | 0 | os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, |
84 | 0 | MAC2STR(sta->addr)); |
85 | 0 | val = (u8 *) buf; |
86 | 0 | len = os_strlen(buf); |
87 | 0 | } |
88 | |
|
89 | 0 | if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val, |
90 | 0 | len)) { |
91 | 0 | wpa_printf(MSG_INFO, "Could not add User-Name"); |
92 | 0 | goto fail; |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | 0 | if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta, |
97 | 0 | msg) < 0) |
98 | 0 | goto fail; |
99 | | |
100 | 0 | if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0) |
101 | 0 | goto fail; |
102 | | |
103 | 0 | if (sta) { |
104 | 0 | for (i = 0; ; i++) { |
105 | 0 | val = ieee802_1x_get_radius_class(sta->eapol_sm, &len, |
106 | 0 | i); |
107 | 0 | if (val == NULL) |
108 | 0 | break; |
109 | | |
110 | 0 | if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS, |
111 | 0 | val, len)) { |
112 | 0 | wpa_printf(MSG_INFO, "Could not add Class"); |
113 | 0 | goto fail; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | 0 | b = ieee802_1x_get_radius_cui(sta->eapol_sm); |
118 | 0 | if (b && |
119 | 0 | !radius_msg_add_attr(msg, |
120 | 0 | RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, |
121 | 0 | wpabuf_head(b), wpabuf_len(b))) { |
122 | 0 | wpa_printf(MSG_ERROR, "Could not add CUI"); |
123 | 0 | goto fail; |
124 | 0 | } |
125 | | |
126 | 0 | if (!b && sta->radius_cui && |
127 | 0 | !radius_msg_add_attr(msg, |
128 | 0 | RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, |
129 | 0 | (u8 *) sta->radius_cui, |
130 | 0 | os_strlen(sta->radius_cui))) { |
131 | 0 | wpa_printf(MSG_ERROR, "Could not add CUI from ACL"); |
132 | 0 | goto fail; |
133 | 0 | } |
134 | | |
135 | 0 | if (sta->ipaddr && |
136 | 0 | !radius_msg_add_attr_int32(msg, |
137 | 0 | RADIUS_ATTR_FRAMED_IP_ADDRESS, |
138 | 0 | be_to_host32(sta->ipaddr))) { |
139 | 0 | wpa_printf(MSG_ERROR, |
140 | 0 | "Could not add Framed-IP-Address"); |
141 | 0 | goto fail; |
142 | 0 | } |
143 | 0 | } |
144 | | |
145 | 0 | os_get_time(&now); |
146 | 0 | if (now.sec > 1000000000 && |
147 | 0 | !radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP, |
148 | 0 | now.sec)) { |
149 | 0 | wpa_printf(MSG_INFO, "Could not add Event-Timestamp"); |
150 | 0 | goto fail; |
151 | 0 | } |
152 | | |
153 | | /* |
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. |
156 | | */ |
157 | 0 | if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_DELAY_TIME, 0)) { |
158 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Delay-Time"); |
159 | 0 | goto fail; |
160 | 0 | } |
161 | | |
162 | 0 | return msg; |
163 | | |
164 | 0 | fail: |
165 | 0 | radius_msg_free(msg); |
166 | 0 | return NULL; |
167 | 0 | } |
168 | | |
169 | | |
170 | | static int accounting_sta_update_stats(struct hostapd_data *hapd, |
171 | | struct sta_info *sta, |
172 | | struct hostap_sta_driver_data *data) |
173 | 0 | { |
174 | 0 | if (hostapd_drv_read_sta_data(hapd, data, sta->addr)) |
175 | 0 | return -1; |
176 | | |
177 | 0 | if (!data->bytes_64bit) { |
178 | | /* Extend 32-bit counters from the driver to 64-bit counters */ |
179 | 0 | if (sta->last_rx_bytes_lo > data->rx_bytes) |
180 | 0 | sta->last_rx_bytes_hi++; |
181 | 0 | sta->last_rx_bytes_lo = data->rx_bytes; |
182 | |
|
183 | 0 | if (sta->last_tx_bytes_lo > data->tx_bytes) |
184 | 0 | sta->last_tx_bytes_hi++; |
185 | 0 | sta->last_tx_bytes_lo = data->tx_bytes; |
186 | 0 | } |
187 | |
|
188 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, |
189 | 0 | HOSTAPD_LEVEL_DEBUG, |
190 | 0 | "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d", |
191 | 0 | data->rx_bytes, sta->last_rx_bytes_hi, |
192 | 0 | sta->last_rx_bytes_lo, |
193 | 0 | data->tx_bytes, sta->last_tx_bytes_hi, |
194 | 0 | sta->last_tx_bytes_lo, |
195 | 0 | data->bytes_64bit); |
196 | |
|
197 | 0 | return 0; |
198 | 0 | } |
199 | | |
200 | | |
201 | | static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) |
202 | 0 | { |
203 | 0 | struct hostapd_data *hapd = eloop_ctx; |
204 | 0 | struct sta_info *sta = timeout_ctx; |
205 | 0 | int interval; |
206 | |
|
207 | 0 | if (sta->acct_interim_interval) { |
208 | 0 | accounting_sta_interim(hapd, sta); |
209 | 0 | interval = sta->acct_interim_interval; |
210 | 0 | } else { |
211 | 0 | struct hostap_sta_driver_data data; |
212 | 0 | accounting_sta_update_stats(hapd, sta, &data); |
213 | 0 | interval = ACCT_DEFAULT_UPDATE_INTERVAL; |
214 | 0 | } |
215 | |
|
216 | 0 | eloop_register_timeout(interval, 0, accounting_interim_update, |
217 | 0 | hapd, sta); |
218 | 0 | } |
219 | | |
220 | | |
221 | | /** |
222 | | * accounting_sta_start - Start STA accounting |
223 | | * @hapd: hostapd BSS data |
224 | | * @sta: The station |
225 | | */ |
226 | | void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) |
227 | 0 | { |
228 | 0 | struct radius_msg *msg; |
229 | 0 | int interval; |
230 | |
|
231 | 0 | if (sta->acct_session_started) |
232 | 0 | return; |
233 | | |
234 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, |
235 | 0 | HOSTAPD_LEVEL_INFO, |
236 | 0 | "starting accounting session %016llX", |
237 | 0 | (unsigned long long) sta->acct_session_id); |
238 | |
|
239 | 0 | os_get_reltime(&sta->acct_session_start); |
240 | 0 | sta->last_rx_bytes_hi = 0; |
241 | 0 | sta->last_rx_bytes_lo = 0; |
242 | 0 | sta->last_tx_bytes_hi = 0; |
243 | 0 | sta->last_tx_bytes_lo = 0; |
244 | 0 | hostapd_drv_sta_clear_stats(hapd, sta->addr); |
245 | |
|
246 | 0 | if (!hapd->conf->radius->acct_server) |
247 | 0 | return; |
248 | | |
249 | 0 | if (sta->acct_interim_interval) |
250 | 0 | interval = sta->acct_interim_interval; |
251 | 0 | else |
252 | 0 | interval = ACCT_DEFAULT_UPDATE_INTERVAL; |
253 | 0 | eloop_register_timeout(interval, 0, accounting_interim_update, |
254 | 0 | hapd, sta); |
255 | |
|
256 | 0 | msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START); |
257 | 0 | if (msg && |
258 | 0 | radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0) |
259 | 0 | radius_msg_free(msg); |
260 | |
|
261 | 0 | sta->acct_session_started = 1; |
262 | 0 | } |
263 | | |
264 | | |
265 | | static void accounting_sta_report(struct hostapd_data *hapd, |
266 | | struct sta_info *sta, int stop) |
267 | 0 | { |
268 | 0 | struct radius_msg *msg; |
269 | 0 | int cause = sta->acct_terminate_cause; |
270 | 0 | struct hostap_sta_driver_data data; |
271 | 0 | struct os_reltime now_r, diff; |
272 | 0 | u64 bytes; |
273 | |
|
274 | 0 | if (!hapd->conf->radius->acct_server) |
275 | 0 | return; |
276 | | |
277 | 0 | msg = accounting_msg(hapd, sta, |
278 | 0 | stop ? RADIUS_ACCT_STATUS_TYPE_STOP : |
279 | 0 | RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE); |
280 | 0 | if (!msg) { |
281 | 0 | wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message"); |
282 | 0 | return; |
283 | 0 | } |
284 | | |
285 | 0 | os_get_reltime(&now_r); |
286 | 0 | os_reltime_sub(&now_r, &sta->acct_session_start, &diff); |
287 | 0 | if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME, |
288 | 0 | diff.sec)) { |
289 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Session-Time"); |
290 | 0 | goto fail; |
291 | 0 | } |
292 | | |
293 | 0 | if (accounting_sta_update_stats(hapd, sta, &data) == 0) { |
294 | 0 | if (!radius_msg_add_attr_int32(msg, |
295 | 0 | RADIUS_ATTR_ACCT_INPUT_PACKETS, |
296 | 0 | data.rx_packets)) { |
297 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets"); |
298 | 0 | goto fail; |
299 | 0 | } |
300 | 0 | if (!radius_msg_add_attr_int32(msg, |
301 | 0 | RADIUS_ATTR_ACCT_OUTPUT_PACKETS, |
302 | 0 | data.tx_packets)) { |
303 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets"); |
304 | 0 | goto fail; |
305 | 0 | } |
306 | 0 | if (data.bytes_64bit) |
307 | 0 | bytes = data.rx_bytes; |
308 | 0 | else |
309 | 0 | bytes = ((u64) sta->last_rx_bytes_hi << 32) | |
310 | 0 | sta->last_rx_bytes_lo; |
311 | 0 | if (!radius_msg_add_attr_int32(msg, |
312 | 0 | RADIUS_ATTR_ACCT_INPUT_OCTETS, |
313 | 0 | (u32) bytes)) { |
314 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets"); |
315 | 0 | goto fail; |
316 | 0 | } |
317 | 0 | if (!radius_msg_add_attr_int32(msg, |
318 | 0 | RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, |
319 | 0 | (u32) (bytes >> 32))) { |
320 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords"); |
321 | 0 | goto fail; |
322 | 0 | } |
323 | 0 | if (data.bytes_64bit) |
324 | 0 | bytes = data.tx_bytes; |
325 | 0 | else |
326 | 0 | bytes = ((u64) sta->last_tx_bytes_hi << 32) | |
327 | 0 | sta->last_tx_bytes_lo; |
328 | 0 | if (!radius_msg_add_attr_int32(msg, |
329 | 0 | RADIUS_ATTR_ACCT_OUTPUT_OCTETS, |
330 | 0 | (u32) bytes)) { |
331 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets"); |
332 | 0 | goto fail; |
333 | 0 | } |
334 | 0 | if (!radius_msg_add_attr_int32(msg, |
335 | 0 | RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, |
336 | 0 | (u32) (bytes >> 32))) { |
337 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords"); |
338 | 0 | goto fail; |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | 0 | if (eloop_terminated()) |
343 | 0 | cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT; |
344 | |
|
345 | 0 | if (stop && cause && |
346 | 0 | !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE, |
347 | 0 | cause)) { |
348 | 0 | wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause"); |
349 | 0 | goto fail; |
350 | 0 | } |
351 | | |
352 | 0 | if (radius_client_send(hapd->radius, msg, |
353 | 0 | stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM, |
354 | 0 | sta->addr) < 0) |
355 | 0 | goto fail; |
356 | 0 | return; |
357 | | |
358 | 0 | fail: |
359 | 0 | radius_msg_free(msg); |
360 | 0 | } |
361 | | |
362 | | |
363 | | /** |
364 | | * accounting_sta_interim - Send a interim STA accounting report |
365 | | * @hapd: hostapd BSS data |
366 | | * @sta: The station |
367 | | */ |
368 | | static void accounting_sta_interim(struct hostapd_data *hapd, |
369 | | struct sta_info *sta) |
370 | 0 | { |
371 | 0 | if (sta->acct_session_started) |
372 | 0 | accounting_sta_report(hapd, sta, 0); |
373 | 0 | } |
374 | | |
375 | | |
376 | | /** |
377 | | * accounting_sta_stop - Stop STA accounting |
378 | | * @hapd: hostapd BSS data |
379 | | * @sta: The station |
380 | | */ |
381 | | void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta) |
382 | 2.29k | { |
383 | 2.29k | if (sta->acct_session_started) { |
384 | 0 | accounting_sta_report(hapd, sta, 1); |
385 | 0 | eloop_cancel_timeout(accounting_interim_update, hapd, sta); |
386 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, |
387 | 0 | HOSTAPD_LEVEL_INFO, |
388 | 0 | "stopped accounting session %016llX", |
389 | 0 | (unsigned long long) sta->acct_session_id); |
390 | 0 | sta->acct_session_started = 0; |
391 | 0 | } |
392 | 2.29k | } |
393 | | |
394 | | |
395 | | int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta) |
396 | 2.29k | { |
397 | 2.29k | return radius_gen_session_id((u8 *) &sta->acct_session_id, |
398 | 2.29k | sizeof(sta->acct_session_id)); |
399 | 2.29k | } |
400 | | |
401 | | |
402 | | /** |
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 |
410 | | */ |
411 | | static RadiusRxResult |
412 | | accounting_receive(struct radius_msg *msg, struct radius_msg *req, |
413 | | const u8 *shared_secret, size_t shared_secret_len, |
414 | | void *data) |
415 | 0 | { |
416 | 0 | if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { |
417 | 0 | wpa_printf(MSG_INFO, "Unknown RADIUS message code"); |
418 | 0 | return RADIUS_RX_UNKNOWN; |
419 | 0 | } |
420 | | |
421 | 0 | if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { |
422 | 0 | wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped"); |
423 | 0 | return RADIUS_RX_INVALID_AUTHENTICATOR; |
424 | 0 | } |
425 | | |
426 | 0 | return RADIUS_RX_PROCESSED; |
427 | 0 | } |
428 | | |
429 | | |
430 | | static void accounting_report_state(struct hostapd_data *hapd, int on) |
431 | 0 | { |
432 | 0 | struct radius_msg *msg; |
433 | |
|
434 | 0 | if (!hapd->conf->radius->acct_server || hapd->radius == NULL) |
435 | 0 | return; |
436 | | |
437 | | /* Inform RADIUS server that accounting will start/stop so that the |
438 | | * server can close old accounting sessions. */ |
439 | 0 | msg = accounting_msg(hapd, NULL, |
440 | 0 | on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON : |
441 | 0 | RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF); |
442 | 0 | if (!msg) |
443 | 0 | return; |
444 | | |
445 | 0 | if (hapd->acct_session_id) { |
446 | 0 | char buf[20]; |
447 | |
|
448 | 0 | os_snprintf(buf, sizeof(buf), "%016llX", |
449 | 0 | (unsigned long long) hapd->acct_session_id); |
450 | 0 | if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, |
451 | 0 | (u8 *) buf, os_strlen(buf))) |
452 | 0 | wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); |
453 | 0 | } |
454 | |
|
455 | 0 | if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0) |
456 | 0 | radius_msg_free(msg); |
457 | 0 | } |
458 | | |
459 | | |
460 | | static void accounting_interim_error_cb(const u8 *addr, void *ctx) |
461 | 0 | { |
462 | 0 | struct hostapd_data *hapd = ctx; |
463 | 0 | struct sta_info *sta; |
464 | 0 | unsigned int i, wait_time; |
465 | 0 | int res; |
466 | |
|
467 | 0 | sta = ap_get_sta(hapd, addr); |
468 | 0 | if (!sta) |
469 | 0 | return; |
470 | 0 | sta->acct_interim_errors++; |
471 | 0 | if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) { |
472 | 0 | wpa_printf(MSG_DEBUG, |
473 | 0 | "Interim RADIUS accounting update failed for " MACSTR |
474 | 0 | " - too many errors, abandon this interim accounting update", |
475 | 0 | MAC2STR(addr)); |
476 | 0 | sta->acct_interim_errors = 0; |
477 | | /* Next update will be tried after normal update interval */ |
478 | 0 | return; |
479 | 0 | } |
480 | | |
481 | | /* |
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. |
485 | | * |
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. |
489 | | */ |
490 | 0 | if (sta->acct_interim_errors == 1) { |
491 | 0 | wait_time = 0; |
492 | 0 | } else { |
493 | 0 | wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */ |
494 | 0 | for (i = 1; i < sta->acct_interim_errors; i++) |
495 | 0 | wait_time *= 2; |
496 | 0 | } |
497 | 0 | res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update, |
498 | 0 | hapd, sta); |
499 | 0 | if (res == 1) |
500 | 0 | wpa_printf(MSG_DEBUG, |
501 | 0 | "Interim RADIUS accounting update failed for " MACSTR |
502 | 0 | " (error count: %u) - schedule next update in %u seconds", |
503 | 0 | MAC2STR(addr), sta->acct_interim_errors, wait_time); |
504 | 0 | else if (res == 0) |
505 | 0 | wpa_printf(MSG_DEBUG, |
506 | 0 | "Interim RADIUS accounting update failed for " MACSTR |
507 | 0 | " (error count: %u)", MAC2STR(addr), |
508 | 0 | sta->acct_interim_errors); |
509 | 0 | else |
510 | 0 | wpa_printf(MSG_DEBUG, |
511 | 0 | "Interim RADIUS accounting update failed for " MACSTR |
512 | 0 | " (error count: %u) - no timer found", MAC2STR(addr), |
513 | 0 | sta->acct_interim_errors); |
514 | 0 | } |
515 | | |
516 | | |
517 | | /** |
518 | | * accounting_init: Initialize accounting |
519 | | * @hapd: hostapd BSS data |
520 | | * Returns: 0 on success, -1 on failure |
521 | | */ |
522 | | int accounting_init(struct hostapd_data *hapd) |
523 | 0 | { |
524 | 0 | if (radius_gen_session_id((u8 *) &hapd->acct_session_id, |
525 | 0 | sizeof(hapd->acct_session_id)) < 0) |
526 | 0 | return -1; |
527 | | |
528 | 0 | if (radius_client_register(hapd->radius, RADIUS_ACCT, |
529 | 0 | accounting_receive, hapd)) |
530 | 0 | return -1; |
531 | 0 | radius_client_set_interim_error_cb(hapd->radius, |
532 | 0 | accounting_interim_error_cb, hapd); |
533 | |
|
534 | 0 | accounting_report_state(hapd, 1); |
535 | |
|
536 | 0 | return 0; |
537 | 0 | } |
538 | | |
539 | | |
540 | | /** |
541 | | * accounting_deinit: Deinitialize accounting |
542 | | * @hapd: hostapd BSS data |
543 | | */ |
544 | | void accounting_deinit(struct hostapd_data *hapd) |
545 | 0 | { |
546 | 0 | accounting_report_state(hapd, 0); |
547 | 0 | } |