accounting.c 15 KB

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