PageRenderTime 259ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freebsd/contrib/wpa/src/ap/accounting.c

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