18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / RADIUS Accounting
3d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * Copyright (c) 2002-2009, 2012-2015, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "eapol_auth/eapol_auth_sm.h"
14fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "eapol_auth/eapol_auth_sm_i.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radius/radius.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radius/radius_client.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_1x.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sta_info.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_drv_ops.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "accounting.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Default interval in seconds for polling TX/RX octets from the driver if
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * STA is not using interim accounting. This detects wrap arounds for
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * input/output octets and updates Acct-{Input,Output}-Gigawords. */
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define ACCT_DEFAULT_UPDATE_INTERVAL 300
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void accounting_sta_interim(struct hostapd_data *hapd,
3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   struct sta_info *sta);
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct radius_msg * accounting_msg(struct hostapd_data *hapd,
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  struct sta_info *sta,
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  int status_type)
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct radius_msg *msg;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[128];
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *val;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *b;
44b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	struct os_time now;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     radius_client_get_id(hapd->radius));
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
49cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (radius_msg_make_authenticator(msg) < 0) {
54b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_INFO, "Could not make Request Authenticator");
55b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		goto fail;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       status_type)) {
60cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta) {
65b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (!hostapd_config_get_radius_attr(
66b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			    hapd->conf->radius_acct_req_attr,
67b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			    RADIUS_ATTR_ACCT_AUTHENTIC) &&
68b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
69b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt					       hapd->conf->ieee802_1x ?
70b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt					       RADIUS_ACCT_AUTHENTIC_RADIUS :
71b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt					       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
72b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
73b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			goto fail;
74b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		}
75b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* Use 802.1X identity if available */
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = ieee802_1x_get_identity(sta->eapol_sm, &len);
7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* Use RADIUS ACL identity if 802.1X provides no identity */
8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (!val && sta->identity) {
8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			val = (u8 *) sta->identity;
8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			len = os_strlen(sta->identity);
8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* Use STA MAC if neither 802.1X nor RADIUS ACL provided
8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 * identity */
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!val) {
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    MAC2STR(sta->addr));
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			val = (u8 *) buf;
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			len = os_strlen(buf);
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 len)) {
96cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add User-Name");
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
10261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   msg) < 0)
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta) {
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; ; i++) {
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  i);
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (val == NULL)
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 val, len)) {
114cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				wpa_printf(MSG_INFO, "Could not add Class");
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		b = ieee802_1x_get_radius_cui(sta->eapol_sm);
12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (b &&
12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		    !radius_msg_add_attr(msg,
12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					 wpabuf_head(b), wpabuf_len(b))) {
12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_ERROR, "Could not add CUI");
12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			goto fail;
12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (!b && sta->radius_cui &&
12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    !radius_msg_add_attr(msg,
13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 (u8 *) sta->radius_cui,
13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 os_strlen(sta->radius_cui))) {
13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
13404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			goto fail;
13504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
136d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
137d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (sta->ipaddr &&
138d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		    !radius_msg_add_attr_int32(msg,
139d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt					       RADIUS_ATTR_FRAMED_IP_ADDRESS,
140d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt					       be_to_host32(sta->ipaddr))) {
141d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			wpa_printf(MSG_ERROR,
142d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				   "Could not add Framed-IP-Address");
143d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			goto fail;
144d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
147b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	os_get_time(&now);
148b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (now.sec > 1000000000 &&
149b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
150b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				       now.sec)) {
151b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
152b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		goto fail;
153b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	}
154b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
1559c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	/*
1569c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * Add Acct-Delay-Time with zero value for the first transmission. This
1579c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * will be updated within radius_client.c when retransmitting the frame.
1589c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 */
1599c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_DELAY_TIME, 0)) {
1609c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not add Acct-Delay-Time");
1619c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		goto fail;
1629c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	}
1639c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail:
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_msg_free(msg);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int accounting_sta_update_stats(struct hostapd_data *hapd,
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct sta_info *sta,
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct hostap_sta_driver_data *data)
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	if (!data->bytes_64bit) {
18057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		/* Extend 32-bit counters from the driver to 64-bit counters */
18157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (sta->last_rx_bytes_lo > data->rx_bytes)
18257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			sta->last_rx_bytes_hi++;
18357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		sta->last_rx_bytes_lo = data->rx_bytes;
18457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
18557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (sta->last_tx_bytes_lo > data->tx_bytes)
18657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			sta->last_tx_bytes_hi++;
18757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		sta->last_tx_bytes_lo = data->tx_bytes;
18857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	}
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
19157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       HOSTAPD_LEVEL_DEBUG,
19257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d",
19357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       data->rx_bytes, sta->last_rx_bytes_hi,
19457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       sta->last_rx_bytes_lo,
19557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       data->tx_bytes, sta->last_tx_bytes_hi,
19657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       sta->last_tx_bytes_lo,
19757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       data->bytes_64bit);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd = eloop_ctx;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sta_info *sta = timeout_ctx;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int interval;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->acct_interim_interval) {
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accounting_sta_interim(hapd, sta);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		interval = sta->acct_interim_interval;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostap_sta_driver_data data;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accounting_sta_update_stats(hapd, sta, &data);
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(interval, 0, accounting_interim_update,
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       hapd, sta);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting_sta_start - Start STA accounting
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sta: The station
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct radius_msg *msg;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int interval;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->acct_session_started)
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       HOSTAPD_LEVEL_INFO,
23857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       "starting accounting session %016llX",
23957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		       (unsigned long long) sta->acct_session_id);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
241fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&sta->acct_session_start);
24257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	sta->last_rx_bytes_hi = 0;
24357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	sta->last_rx_bytes_lo = 0;
24457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	sta->last_tx_bytes_hi = 0;
24557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	sta->last_tx_bytes_lo = 0;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_drv_sta_clear_stats(hapd, sta->addr);
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!hapd->conf->radius->acct_server)
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->acct_interim_interval)
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		interval = sta->acct_interim_interval;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(interval, 0, accounting_interim_update,
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       hapd, sta);
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (msg &&
26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		radius_msg_free(msg);
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta->acct_session_started = 1;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void accounting_sta_report(struct hostapd_data *hapd,
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct sta_info *sta, int stop)
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct radius_msg *msg;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int cause = sta->acct_terminate_cause;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data data;
273fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct os_reltime now_r, diff;
27457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	u64 bytes;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!hapd->conf->radius->acct_server)
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = accounting_msg(hapd, sta,
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg) {
283cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
287fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_get_reltime(&now_r);
288fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
290fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				       diff.sec)) {
291cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!radius_msg_add_attr_int32(msg,
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       data.rx_packets)) {
299cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!radius_msg_add_attr_int32(msg,
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       data.tx_packets)) {
305cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
30857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (data.bytes_64bit)
30957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			bytes = data.rx_bytes;
31057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		else
31157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			bytes = ((u64) sta->last_rx_bytes_hi << 32) |
31257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt				sta->last_rx_bytes_lo;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!radius_msg_add_attr_int32(msg,
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
31557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt					       (u32) bytes)) {
316cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
31957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (!radius_msg_add_attr_int32(msg,
32057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt					       RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
32157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt					       (u32) (bytes >> 32))) {
322cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (data.bytes_64bit)
32657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			bytes = data.tx_bytes;
32757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		else
32857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			bytes = ((u64) sta->last_tx_bytes_hi << 32) |
32957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt				sta->last_tx_bytes_lo;
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!radius_msg_add_attr_int32(msg,
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
33257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt					       (u32) bytes)) {
333cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
33657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		if (!radius_msg_add_attr_int32(msg,
33757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt					       RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
33857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt					       (u32) (bytes >> 32))) {
339cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_terminated())
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stop && cause &&
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       cause)) {
350cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (radius_client_send(hapd->radius, msg,
35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			       stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
35604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			       sta->addr) < 0)
35704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		goto fail;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail:
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_msg_free(msg);
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting_sta_interim - Send a interim STA accounting report
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sta: The station
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
37061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void accounting_sta_interim(struct hostapd_data *hapd,
37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   struct sta_info *sta)
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->acct_session_started)
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accounting_sta_report(hapd, sta, 0);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting_sta_stop - Stop STA accounting
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sta: The station
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->acct_session_started) {
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accounting_sta_report(hapd, sta, 1);
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(accounting_interim_update, hapd, sta);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       HOSTAPD_LEVEL_INFO,
39057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			       "stopped accounting session %016llX",
39157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			       (unsigned long long) sta->acct_session_id);
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->acct_session_started = 0;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
397b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtint accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta)
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
399b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	return radius_gen_session_id((u8 *) &sta->acct_session_id,
400b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				     sizeof(sta->acct_session_id));
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting_receive - Process the RADIUS frames from Accounting Server
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS response message
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @req: RADIUS request message
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @shared_secret: RADIUS shared secret
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @shared_secret_len: Length of shared_secret in octets
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Context data (struct hostapd_data *)
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Processing status
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic RadiusRxResult
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtaccounting_receive(struct radius_msg *msg, struct radius_msg *req,
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   const u8 *shared_secret, size_t shared_secret_len,
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   void *data)
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
419cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return RADIUS_RX_UNKNOWN;
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return RADIUS_RX_INVALID_AUTHENTICATOR;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return RADIUS_RX_PROCESSED;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void accounting_report_state(struct hostapd_data *hapd, int on)
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct radius_msg *msg;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Inform RADIUS server that accounting will start/stop so that the
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * server can close old accounting sessions. */
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = accounting_msg(hapd, NULL,
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
447b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (hapd->acct_session_id) {
448b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		char buf[20];
449b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt
45057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		os_snprintf(buf, sizeof(buf), "%016llX",
45157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt			    (unsigned long long) hapd->acct_session_id);
452b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
453b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt					 (u8 *) buf, os_strlen(buf)))
454b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt			wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
45804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		radius_msg_free(msg);
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4629c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidtstatic void accounting_interim_error_cb(const u8 *addr, void *ctx)
4639c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt{
4649c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	struct hostapd_data *hapd = ctx;
4659c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	struct sta_info *sta;
4669c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	unsigned int i, wait_time;
4679c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	int res;
4689c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
4699c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	sta = ap_get_sta(hapd, addr);
4709c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (!sta)
4719c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		return;
4729c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	sta->acct_interim_errors++;
4739c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
4749c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wpa_printf(MSG_DEBUG,
4759c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   "Interim RADIUS accounting update failed for " MACSTR
4769c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   " - too many errors, abandon this interim accounting update",
4779c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   MAC2STR(addr));
4789c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		sta->acct_interim_errors = 0;
4799c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		/* Next update will be tried after normal update interval */
4809c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		return;
4819c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	}
4829c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
4839c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	/*
4849c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * Use a shorter update interval as an improved retransmission mechanism
4859c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * for failed interim accounting updates. This allows the statistics to
4869c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * be updated for each retransmission.
4879c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 *
4889c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
4899c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * Schedule the first retry attempt immediately and every following one
4909c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 * with exponential backoff.
4919c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	 */
4929c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (sta->acct_interim_errors == 1) {
4939c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wait_time = 0;
4949c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	} else {
4959c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */
4969c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		for (i = 1; i < sta->acct_interim_errors; i++)
4979c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			wait_time *= 2;
4989c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	}
4999c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update,
5009c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt				    hapd, sta);
5019c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (res == 1)
5029c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wpa_printf(MSG_DEBUG,
5039c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   "Interim RADIUS accounting update failed for " MACSTR
5049c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   " (error count: %u) - schedule next update in %u seconds",
5059c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   MAC2STR(addr), sta->acct_interim_errors, wait_time);
5069c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	else if (res == 0)
5079c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wpa_printf(MSG_DEBUG,
5089c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   "Interim RADIUS accounting update failed for " MACSTR
5099c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   " (error count: %u)", MAC2STR(addr),
5109c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   sta->acct_interim_errors);
5119c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	else
5129c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt		wpa_printf(MSG_DEBUG,
5139c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   "Interim RADIUS accounting update failed for " MACSTR
5149c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   " (error count: %u) - no timer found", MAC2STR(addr),
5159c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt			   sta->acct_interim_errors);
5169c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt}
5179c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
5189c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting_init: Initialize accounting
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint accounting_init(struct hostapd_data *hapd)
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
526b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt	if (radius_gen_session_id((u8 *) &hapd->acct_session_id,
527b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt				  sizeof(hapd->acct_session_id)) < 0)
528b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt		return -1;
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (radius_client_register(hapd->radius, RADIUS_ACCT,
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   accounting_receive, hapd))
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5339c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	radius_client_set_interim_error_cb(hapd->radius,
5349c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt					   accounting_interim_error_cb, hapd);
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	accounting_report_state(hapd, 1);
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5437a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt * accounting_deinit: Deinitialize accounting
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid accounting_deinit(struct hostapd_data *hapd)
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	accounting_report_state(hapd, 0);
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
550