accounting.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. * hostapd / RADIUS Accounting
  3. * Copyright (c) 2002-2009, 2012, 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. #include "utils/includes.h"
  9. #include "utils/common.h"
  10. #include "utils/eloop.h"
  11. #include "radius/radius.h"
  12. #include "radius/radius_client.h"
  13. #include "hostapd.h"
  14. #include "ieee802_1x.h"
  15. #include "ap_config.h"
  16. #include "sta_info.h"
  17. #include "ap_drv_ops.h"
  18. #include "accounting.h"
  19. /* Default interval in seconds for polling TX/RX octets from the driver if
  20. * STA is not using interim accounting. This detects wrap arounds for
  21. * input/output octets and updates Acct-{Input,Output}-Gigawords. */
  22. #define ACCT_DEFAULT_UPDATE_INTERVAL 300
  23. static void accounting_sta_interim(struct hostapd_data *hapd,
  24. struct sta_info *sta);
  25. static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
  26. struct sta_info *sta,
  27. int status_type)
  28. {
  29. struct radius_msg *msg;
  30. char buf[128];
  31. u8 *val;
  32. size_t len;
  33. int i;
  34. struct wpabuf *b;
  35. msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
  36. radius_client_get_id(hapd->radius));
  37. if (msg == NULL) {
  38. wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
  39. return NULL;
  40. }
  41. if (sta) {
  42. radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
  43. } else {
  44. radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
  45. }
  46. if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
  47. status_type)) {
  48. wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
  49. goto fail;
  50. }
  51. if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
  52. RADIUS_ATTR_ACCT_AUTHENTIC) &&
  53. !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
  54. hapd->conf->ieee802_1x ?
  55. RADIUS_ACCT_AUTHENTIC_RADIUS :
  56. RADIUS_ACCT_AUTHENTIC_LOCAL)) {
  57. wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
  58. goto fail;
  59. }
  60. if (sta) {
  61. /* Use 802.1X identity if available */
  62. val = ieee802_1x_get_identity(sta->eapol_sm, &len);
  63. /* Use RADIUS ACL identity if 802.1X provides no identity */
  64. if (!val && sta->identity) {
  65. val = (u8 *) sta->identity;
  66. len = os_strlen(sta->identity);
  67. }
  68. /* Use STA MAC if neither 802.1X nor RADIUS ACL provided
  69. * identity */
  70. if (!val) {
  71. os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
  72. MAC2STR(sta->addr));
  73. val = (u8 *) buf;
  74. len = os_strlen(buf);
  75. }
  76. if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
  77. len)) {
  78. wpa_printf(MSG_INFO, "Could not add User-Name");
  79. goto fail;
  80. }
  81. }
  82. if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
  83. msg) < 0)
  84. goto fail;
  85. if (sta) {
  86. for (i = 0; ; i++) {
  87. val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
  88. i);
  89. if (val == NULL)
  90. break;
  91. if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
  92. val, len)) {
  93. wpa_printf(MSG_INFO, "Could not add Class");
  94. goto fail;
  95. }
  96. }
  97. b = ieee802_1x_get_radius_cui(sta->eapol_sm);
  98. if (b &&
  99. !radius_msg_add_attr(msg,
  100. RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
  101. wpabuf_head(b), wpabuf_len(b))) {
  102. wpa_printf(MSG_ERROR, "Could not add CUI");
  103. goto fail;
  104. }
  105. if (!b && sta->radius_cui &&
  106. !radius_msg_add_attr(msg,
  107. RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
  108. (u8 *) sta->radius_cui,
  109. os_strlen(sta->radius_cui))) {
  110. wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
  111. goto fail;
  112. }
  113. }
  114. return msg;
  115. fail:
  116. radius_msg_free(msg);
  117. return NULL;
  118. }
  119. static int accounting_sta_update_stats(struct hostapd_data *hapd,
  120. struct sta_info *sta,
  121. struct hostap_sta_driver_data *data)
  122. {
  123. if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
  124. return -1;
  125. if (sta->last_rx_bytes > data->rx_bytes)
  126. sta->acct_input_gigawords++;
  127. if (sta->last_tx_bytes > data->tx_bytes)
  128. sta->acct_output_gigawords++;
  129. sta->last_rx_bytes = data->rx_bytes;
  130. sta->last_tx_bytes = data->tx_bytes;
  131. hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
  132. HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
  133. "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
  134. "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
  135. sta->last_rx_bytes, sta->acct_input_gigawords,
  136. sta->last_tx_bytes, sta->acct_output_gigawords);
  137. return 0;
  138. }
  139. static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
  140. {
  141. struct hostapd_data *hapd = eloop_ctx;
  142. struct sta_info *sta = timeout_ctx;
  143. int interval;
  144. if (sta->acct_interim_interval) {
  145. accounting_sta_interim(hapd, sta);
  146. interval = sta->acct_interim_interval;
  147. } else {
  148. struct hostap_sta_driver_data data;
  149. accounting_sta_update_stats(hapd, sta, &data);
  150. interval = ACCT_DEFAULT_UPDATE_INTERVAL;
  151. }
  152. eloop_register_timeout(interval, 0, accounting_interim_update,
  153. hapd, sta);
  154. }
  155. /**
  156. * accounting_sta_start - Start STA accounting
  157. * @hapd: hostapd BSS data
  158. * @sta: The station
  159. */
  160. void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
  161. {
  162. struct radius_msg *msg;
  163. int interval;
  164. if (sta->acct_session_started)
  165. return;
  166. hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
  167. HOSTAPD_LEVEL_INFO,
  168. "starting accounting session %08X-%08X",
  169. sta->acct_session_id_hi, sta->acct_session_id_lo);
  170. os_get_reltime(&sta->acct_session_start);
  171. sta->last_rx_bytes = sta->last_tx_bytes = 0;
  172. sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
  173. hostapd_drv_sta_clear_stats(hapd, sta->addr);
  174. if (!hapd->conf->radius->acct_server)
  175. return;
  176. if (sta->acct_interim_interval)
  177. interval = sta->acct_interim_interval;
  178. else
  179. interval = ACCT_DEFAULT_UPDATE_INTERVAL;
  180. eloop_register_timeout(interval, 0, accounting_interim_update,
  181. hapd, sta);
  182. msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
  183. if (msg &&
  184. radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
  185. radius_msg_free(msg);
  186. sta->acct_session_started = 1;
  187. }
  188. static void accounting_sta_report(struct hostapd_data *hapd,
  189. struct sta_info *sta, int stop)
  190. {
  191. struct radius_msg *msg;
  192. int cause = sta->acct_terminate_cause;
  193. struct hostap_sta_driver_data data;
  194. struct os_reltime now_r, diff;
  195. struct os_time now;
  196. u32 gigawords;
  197. if (!hapd->conf->radius->acct_server)
  198. return;
  199. msg = accounting_msg(hapd, sta,
  200. stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
  201. RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
  202. if (!msg) {
  203. wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
  204. return;
  205. }
  206. os_get_reltime(&now_r);
  207. os_get_time(&now);
  208. os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
  209. if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
  210. diff.sec)) {
  211. wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
  212. goto fail;
  213. }
  214. if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
  215. if (!radius_msg_add_attr_int32(msg,
  216. RADIUS_ATTR_ACCT_INPUT_PACKETS,
  217. data.rx_packets)) {
  218. wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
  219. goto fail;
  220. }
  221. if (!radius_msg_add_attr_int32(msg,
  222. RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
  223. data.tx_packets)) {
  224. wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
  225. goto fail;
  226. }
  227. if (!radius_msg_add_attr_int32(msg,
  228. RADIUS_ATTR_ACCT_INPUT_OCTETS,
  229. data.rx_bytes)) {
  230. wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
  231. goto fail;
  232. }
  233. gigawords = sta->acct_input_gigawords;
  234. #if __WORDSIZE == 64
  235. gigawords += data.rx_bytes >> 32;
  236. #endif
  237. if (gigawords &&
  238. !radius_msg_add_attr_int32(
  239. msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
  240. gigawords)) {
  241. wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
  242. goto fail;
  243. }
  244. if (!radius_msg_add_attr_int32(msg,
  245. RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
  246. data.tx_bytes)) {
  247. wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
  248. goto fail;
  249. }
  250. gigawords = sta->acct_output_gigawords;
  251. #if __WORDSIZE == 64
  252. gigawords += data.tx_bytes >> 32;
  253. #endif
  254. if (gigawords &&
  255. !radius_msg_add_attr_int32(
  256. msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
  257. gigawords)) {
  258. wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
  259. goto fail;
  260. }
  261. }
  262. if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
  263. now.sec)) {
  264. wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
  265. goto fail;
  266. }
  267. if (eloop_terminated())
  268. cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
  269. if (stop && cause &&
  270. !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
  271. cause)) {
  272. wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
  273. goto fail;
  274. }
  275. if (radius_client_send(hapd->radius, msg,
  276. stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
  277. sta->addr) < 0)
  278. goto fail;
  279. return;
  280. fail:
  281. radius_msg_free(msg);
  282. }
  283. /**
  284. * accounting_sta_interim - Send a interim STA accounting report
  285. * @hapd: hostapd BSS data
  286. * @sta: The station
  287. */
  288. static void accounting_sta_interim(struct hostapd_data *hapd,
  289. struct sta_info *sta)
  290. {
  291. if (sta->acct_session_started)
  292. accounting_sta_report(hapd, sta, 0);
  293. }
  294. /**
  295. * accounting_sta_stop - Stop STA accounting
  296. * @hapd: hostapd BSS data
  297. * @sta: The station
  298. */
  299. void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
  300. {
  301. if (sta->acct_session_started) {
  302. accounting_sta_report(hapd, sta, 1);
  303. eloop_cancel_timeout(accounting_interim_update, hapd, sta);
  304. hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
  305. HOSTAPD_LEVEL_INFO,
  306. "stopped accounting session %08X-%08X",
  307. sta->acct_session_id_hi,
  308. sta->acct_session_id_lo);
  309. sta->acct_session_started = 0;
  310. }
  311. }
  312. void accounting_sta_get_id(struct hostapd_data *hapd,
  313. struct sta_info *sta)
  314. {
  315. sta->acct_session_id_lo = hapd->acct_session_id_lo++;
  316. if (hapd->acct_session_id_lo == 0) {
  317. hapd->acct_session_id_hi++;
  318. }
  319. sta->acct_session_id_hi = hapd->acct_session_id_hi;
  320. }
  321. /**
  322. * accounting_receive - Process the RADIUS frames from Accounting Server
  323. * @msg: RADIUS response message
  324. * @req: RADIUS request message
  325. * @shared_secret: RADIUS shared secret
  326. * @shared_secret_len: Length of shared_secret in octets
  327. * @data: Context data (struct hostapd_data *)
  328. * Returns: Processing status
  329. */
  330. static RadiusRxResult
  331. accounting_receive(struct radius_msg *msg, struct radius_msg *req,
  332. const u8 *shared_secret, size_t shared_secret_len,
  333. void *data)
  334. {
  335. if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
  336. wpa_printf(MSG_INFO, "Unknown RADIUS message code");
  337. return RADIUS_RX_UNKNOWN;
  338. }
  339. if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
  340. wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
  341. return RADIUS_RX_INVALID_AUTHENTICATOR;
  342. }
  343. return RADIUS_RX_PROCESSED;
  344. }
  345. static void accounting_report_state(struct hostapd_data *hapd, int on)
  346. {
  347. struct radius_msg *msg;
  348. if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
  349. return;
  350. /* Inform RADIUS server that accounting will start/stop so that the
  351. * server can close old accounting sessions. */
  352. msg = accounting_msg(hapd, NULL,
  353. on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
  354. RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
  355. if (!msg)
  356. return;
  357. if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
  358. RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
  359. {
  360. wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
  361. radius_msg_free(msg);
  362. return;
  363. }
  364. if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
  365. radius_msg_free(msg);
  366. }
  367. /**
  368. * accounting_init: Initialize accounting
  369. * @hapd: hostapd BSS data
  370. * Returns: 0 on success, -1 on failure
  371. */
  372. int accounting_init(struct hostapd_data *hapd)
  373. {
  374. struct os_time now;
  375. /* Acct-Session-Id should be unique over reboots. If reliable clock is
  376. * not available, this could be replaced with reboot counter, etc. */
  377. os_get_time(&now);
  378. hapd->acct_session_id_hi = now.sec;
  379. if (radius_client_register(hapd->radius, RADIUS_ACCT,
  380. accounting_receive, hapd))
  381. return -1;
  382. accounting_report_state(hapd, 1);
  383. return 0;
  384. }
  385. /**
  386. * accounting_deinit: Deinitilize accounting
  387. * @hapd: hostapd BSS data
  388. */
  389. void accounting_deinit(struct hostapd_data *hapd)
  390. {
  391. accounting_report_state(hapd, 0);
  392. }