00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "utils/includes.h"
00016
00017 #include "utils/common.h"
00018 #include "utils/eloop.h"
00019 #include "drivers/driver.h"
00020 #include "radius/radius.h"
00021 #include "radius/radius_client.h"
00022 #include "hostapd.h"
00023 #include "ieee802_1x.h"
00024 #include "ap_config.h"
00025 #include "sta_info.h"
00026 #include "accounting.h"
00027
00028
00029
00030
00031
00032 #define ACCT_DEFAULT_UPDATE_INTERVAL 300
00033
00034 static void accounting_sta_get_id(struct hostapd_data *hapd,
00035 struct sta_info *sta);
00036
00037
00038 static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
00039 struct sta_info *sta,
00040 int status_type)
00041 {
00042 struct radius_msg *msg;
00043 char buf[128];
00044 u8 *val;
00045 size_t len;
00046 int i;
00047
00048 msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
00049 radius_client_get_id(hapd->radius));
00050 if (msg == NULL) {
00051 printf("Could not create net RADIUS packet\n");
00052 return NULL;
00053 }
00054
00055 if (sta) {
00056 radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
00057
00058 os_snprintf(buf, sizeof(buf), "%08X-%08X",
00059 sta->acct_session_id_hi, sta->acct_session_id_lo);
00060 if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
00061 (u8 *) buf, os_strlen(buf))) {
00062 printf("Could not add Acct-Session-Id\n");
00063 goto fail;
00064 }
00065 } else {
00066 radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
00067 }
00068
00069 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
00070 status_type)) {
00071 printf("Could not add Acct-Status-Type\n");
00072 goto fail;
00073 }
00074
00075 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
00076 hapd->conf->ieee802_1x ?
00077 RADIUS_ACCT_AUTHENTIC_RADIUS :
00078 RADIUS_ACCT_AUTHENTIC_LOCAL)) {
00079 printf("Could not add Acct-Authentic\n");
00080 goto fail;
00081 }
00082
00083 if (sta) {
00084 val = ieee802_1x_get_identity(sta->eapol_sm, &len);
00085 if (!val) {
00086 os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
00087 MAC2STR(sta->addr));
00088 val = (u8 *) buf;
00089 len = os_strlen(buf);
00090 }
00091
00092 if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
00093 len)) {
00094 printf("Could not add User-Name\n");
00095 goto fail;
00096 }
00097 }
00098
00099 if (hapd->conf->own_ip_addr.af == AF_INET &&
00100 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
00101 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
00102 printf("Could not add NAS-IP-Address\n");
00103 goto fail;
00104 }
00105
00106 #ifdef CONFIG_IPV6
00107 if (hapd->conf->own_ip_addr.af == AF_INET6 &&
00108 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
00109 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
00110 printf("Could not add NAS-IPv6-Address\n");
00111 goto fail;
00112 }
00113 #endif
00114
00115 if (hapd->conf->nas_identifier &&
00116 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
00117 (u8 *) hapd->conf->nas_identifier,
00118 os_strlen(hapd->conf->nas_identifier))) {
00119 printf("Could not add NAS-Identifier\n");
00120 goto fail;
00121 }
00122
00123 if (sta &&
00124 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
00125 printf("Could not add NAS-Port\n");
00126 goto fail;
00127 }
00128
00129 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
00130 MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
00131 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
00132 (u8 *) buf, os_strlen(buf))) {
00133 printf("Could not add Called-Station-Id\n");
00134 goto fail;
00135 }
00136
00137 if (sta) {
00138 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
00139 MAC2STR(sta->addr));
00140 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
00141 (u8 *) buf, os_strlen(buf))) {
00142 printf("Could not add Calling-Station-Id\n");
00143 goto fail;
00144 }
00145
00146 if (!radius_msg_add_attr_int32(
00147 msg, RADIUS_ATTR_NAS_PORT_TYPE,
00148 RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
00149 printf("Could not add NAS-Port-Type\n");
00150 goto fail;
00151 }
00152
00153 os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
00154 radius_sta_rate(hapd, sta) / 2,
00155 (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
00156 radius_mode_txt(hapd));
00157 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
00158 (u8 *) buf, os_strlen(buf))) {
00159 printf("Could not add Connect-Info\n");
00160 goto fail;
00161 }
00162
00163 for (i = 0; ; i++) {
00164 val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
00165 i);
00166 if (val == NULL)
00167 break;
00168
00169 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
00170 val, len)) {
00171 printf("Could not add Class\n");
00172 goto fail;
00173 }
00174 }
00175 }
00176
00177 return msg;
00178
00179 fail:
00180 radius_msg_free(msg);
00181 return NULL;
00182 }
00183
00184
00185 static int accounting_sta_update_stats(struct hostapd_data *hapd,
00186 struct sta_info *sta,
00187 struct hostap_sta_driver_data *data)
00188 {
00189 if (hapd->drv.read_sta_data(hapd, data, sta->addr))
00190 return -1;
00191
00192 if (sta->last_rx_bytes > data->rx_bytes)
00193 sta->acct_input_gigawords++;
00194 if (sta->last_tx_bytes > data->tx_bytes)
00195 sta->acct_output_gigawords++;
00196 sta->last_rx_bytes = data->rx_bytes;
00197 sta->last_tx_bytes = data->tx_bytes;
00198
00199 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
00200 HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
00201 "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
00202 "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
00203 sta->last_rx_bytes, sta->acct_input_gigawords,
00204 sta->last_tx_bytes, sta->acct_output_gigawords);
00205
00206 return 0;
00207 }
00208
00209
00210 static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
00211 {
00212 struct hostapd_data *hapd = eloop_ctx;
00213 struct sta_info *sta = timeout_ctx;
00214 int interval;
00215
00216 if (sta->acct_interim_interval) {
00217 accounting_sta_interim(hapd, sta);
00218 interval = sta->acct_interim_interval;
00219 } else {
00220 struct hostap_sta_driver_data data;
00221 accounting_sta_update_stats(hapd, sta, &data);
00222 interval = ACCT_DEFAULT_UPDATE_INTERVAL;
00223 }
00224
00225 eloop_register_timeout(interval, 0, accounting_interim_update,
00226 hapd, sta);
00227 }
00228
00229
00235 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
00236 {
00237 struct radius_msg *msg;
00238 int interval;
00239
00240 if (sta->acct_session_started)
00241 return;
00242
00243 accounting_sta_get_id(hapd, sta);
00244 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
00245 HOSTAPD_LEVEL_INFO,
00246 "starting accounting session %08X-%08X",
00247 sta->acct_session_id_hi, sta->acct_session_id_lo);
00248
00249 time(&sta->acct_session_start);
00250 sta->last_rx_bytes = sta->last_tx_bytes = 0;
00251 sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
00252 hapd->drv.sta_clear_stats(hapd, sta->addr);
00253
00254 if (!hapd->conf->radius->acct_server)
00255 return;
00256
00257 if (sta->acct_interim_interval)
00258 interval = sta->acct_interim_interval;
00259 else
00260 interval = ACCT_DEFAULT_UPDATE_INTERVAL;
00261 eloop_register_timeout(interval, 0, accounting_interim_update,
00262 hapd, sta);
00263
00264 msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
00265 if (msg)
00266 radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
00267
00268 sta->acct_session_started = 1;
00269 }
00270
00271
00272 static void accounting_sta_report(struct hostapd_data *hapd,
00273 struct sta_info *sta, int stop)
00274 {
00275 struct radius_msg *msg;
00276 int cause = sta->acct_terminate_cause;
00277 struct hostap_sta_driver_data data;
00278 u32 gigawords;
00279
00280 if (!hapd->conf->radius->acct_server)
00281 return;
00282
00283 msg = accounting_msg(hapd, sta,
00284 stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
00285 RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
00286 if (!msg) {
00287 printf("Could not create RADIUS Accounting message\n");
00288 return;
00289 }
00290
00291 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
00292 time(NULL) - sta->acct_session_start)) {
00293 printf("Could not add Acct-Session-Time\n");
00294 goto fail;
00295 }
00296
00297 if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
00298 if (!radius_msg_add_attr_int32(msg,
00299 RADIUS_ATTR_ACCT_INPUT_PACKETS,
00300 data.rx_packets)) {
00301 printf("Could not add Acct-Input-Packets\n");
00302 goto fail;
00303 }
00304 if (!radius_msg_add_attr_int32(msg,
00305 RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
00306 data.tx_packets)) {
00307 printf("Could not add Acct-Output-Packets\n");
00308 goto fail;
00309 }
00310 if (!radius_msg_add_attr_int32(msg,
00311 RADIUS_ATTR_ACCT_INPUT_OCTETS,
00312 data.rx_bytes)) {
00313 printf("Could not add Acct-Input-Octets\n");
00314 goto fail;
00315 }
00316 gigawords = sta->acct_input_gigawords;
00317 #if __WORDSIZE == 64
00318 gigawords += data.rx_bytes >> 32;
00319 #endif
00320 if (gigawords &&
00321 !radius_msg_add_attr_int32(
00322 msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
00323 gigawords)) {
00324 printf("Could not add Acct-Input-Gigawords\n");
00325 goto fail;
00326 }
00327 if (!radius_msg_add_attr_int32(msg,
00328 RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
00329 data.tx_bytes)) {
00330 printf("Could not add Acct-Output-Octets\n");
00331 goto fail;
00332 }
00333 gigawords = sta->acct_output_gigawords;
00334 #if __WORDSIZE == 64
00335 gigawords += data.tx_bytes >> 32;
00336 #endif
00337 if (gigawords &&
00338 !radius_msg_add_attr_int32(
00339 msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
00340 gigawords)) {
00341 printf("Could not add Acct-Output-Gigawords\n");
00342 goto fail;
00343 }
00344 }
00345
00346 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
00347 time(NULL))) {
00348 printf("Could not add Event-Timestamp\n");
00349 goto fail;
00350 }
00351
00352 if (eloop_terminated())
00353 cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
00354
00355 if (stop && cause &&
00356 !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
00357 cause)) {
00358 printf("Could not add Acct-Terminate-Cause\n");
00359 goto fail;
00360 }
00361
00362 radius_client_send(hapd->radius, msg,
00363 stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
00364 sta->addr);
00365 return;
00366
00367 fail:
00368 radius_msg_free(msg);
00369 }
00370
00371
00377 void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
00378 {
00379 if (sta->acct_session_started)
00380 accounting_sta_report(hapd, sta, 0);
00381 }
00382
00383
00389 void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
00390 {
00391 if (sta->acct_session_started) {
00392 accounting_sta_report(hapd, sta, 1);
00393 eloop_cancel_timeout(accounting_interim_update, hapd, sta);
00394 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
00395 HOSTAPD_LEVEL_INFO,
00396 "stopped accounting session %08X-%08X",
00397 sta->acct_session_id_hi,
00398 sta->acct_session_id_lo);
00399 sta->acct_session_started = 0;
00400 }
00401 }
00402
00403
00404 static void accounting_sta_get_id(struct hostapd_data *hapd,
00405 struct sta_info *sta)
00406 {
00407 sta->acct_session_id_lo = hapd->acct_session_id_lo++;
00408 if (hapd->acct_session_id_lo == 0) {
00409 hapd->acct_session_id_hi++;
00410 }
00411 sta->acct_session_id_hi = hapd->acct_session_id_hi;
00412 }
00413
00414
00424 static RadiusRxResult
00425 accounting_receive(struct radius_msg *msg, struct radius_msg *req,
00426 const u8 *shared_secret, size_t shared_secret_len,
00427 void *data)
00428 {
00429 if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
00430 printf("Unknown RADIUS message code\n");
00431 return RADIUS_RX_UNKNOWN;
00432 }
00433
00434 if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
00435 printf("Incoming RADIUS packet did not have correct "
00436 "Authenticator - dropped\n");
00437 return RADIUS_RX_INVALID_AUTHENTICATOR;
00438 }
00439
00440 return RADIUS_RX_PROCESSED;
00441 }
00442
00443
00444 static void accounting_report_state(struct hostapd_data *hapd, int on)
00445 {
00446 struct radius_msg *msg;
00447
00448 if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
00449 return;
00450
00451
00452
00453 msg = accounting_msg(hapd, NULL,
00454 on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
00455 RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
00456 if (!msg)
00457 return;
00458
00459 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
00460 RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
00461 {
00462 printf("Could not add Acct-Terminate-Cause\n");
00463 radius_msg_free(msg);
00464 return;
00465 }
00466
00467 radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
00468 }
00469
00470
00476 int accounting_init(struct hostapd_data *hapd)
00477 {
00478
00479
00480 hapd->acct_session_id_hi = time(NULL);
00481
00482 if (radius_client_register(hapd->radius, RADIUS_ACCT,
00483 accounting_receive, hapd))
00484 return -1;
00485
00486 accounting_report_state(hapd, 1);
00487
00488 return 0;
00489 }
00490
00491
00496 void accounting_deinit(struct hostapd_data *hapd)
00497 {
00498 accounting_report_state(hapd, 0);
00499 }