accounting.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "hostapd.h"
00019 #include "radius/radius.h"
00020 #include "radius/radius_client.h"
00021 #include "eloop.h"
00022 #include "accounting.h"
00023 #include "ieee802_1x.h"
00024 #include "driver_i.h"
00025 #include "sta_info.h"
00026 
00027 
00028 /* Default interval in seconds for polling TX/RX octets from the driver if
00029  * STA is not using interim accounting. This detects wrap arounds for
00030  * input/output octets and updates Acct-{Input,Output}-Gigawords. */
00031 #define ACCT_DEFAULT_UPDATE_INTERVAL 300
00032 
00033 static void accounting_sta_get_id(struct hostapd_data *hapd,
00034                                   struct sta_info *sta);
00035 
00036 
00037 static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
00038                                           struct sta_info *sta,
00039                                           int status_type)
00040 {
00041         struct radius_msg *msg;
00042         char buf[128];
00043         u8 *val;
00044         size_t len;
00045         int i;
00046 
00047         msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
00048                              radius_client_get_id(hapd->radius));
00049         if (msg == NULL) {
00050                 printf("Could not create net RADIUS packet\n");
00051                 return NULL;
00052         }
00053 
00054         if (sta) {
00055                 radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
00056 
00057                 os_snprintf(buf, sizeof(buf), "%08X-%08X",
00058                             sta->acct_session_id_hi, sta->acct_session_id_lo);
00059                 if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
00060                                          (u8 *) buf, os_strlen(buf))) {
00061                         printf("Could not add Acct-Session-Id\n");
00062                         goto fail;
00063                 }
00064         } else {
00065                 radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
00066         }
00067 
00068         if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
00069                                        status_type)) {
00070                 printf("Could not add Acct-Status-Type\n");
00071                 goto fail;
00072         }
00073 
00074         if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
00075                                        hapd->conf->ieee802_1x ?
00076                                        RADIUS_ACCT_AUTHENTIC_RADIUS :
00077                                        RADIUS_ACCT_AUTHENTIC_LOCAL)) {
00078                 printf("Could not add Acct-Authentic\n");
00079                 goto fail;
00080         }
00081 
00082         if (sta) {
00083                 val = ieee802_1x_get_identity(sta->eapol_sm, &len);
00084                 if (!val) {
00085                         os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
00086                                     MAC2STR(sta->addr));
00087                         val = (u8 *) buf;
00088                         len = os_strlen(buf);
00089                 }
00090 
00091                 if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
00092                                          len)) {
00093                         printf("Could not add User-Name\n");
00094                         goto fail;
00095                 }
00096         }
00097 
00098         if (hapd->conf->own_ip_addr.af == AF_INET &&
00099             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
00100                                  (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
00101                 printf("Could not add NAS-IP-Address\n");
00102                 goto fail;
00103         }
00104 
00105 #ifdef CONFIG_IPV6
00106         if (hapd->conf->own_ip_addr.af == AF_INET6 &&
00107             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
00108                                  (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
00109                 printf("Could not add NAS-IPv6-Address\n");
00110                 goto fail;
00111         }
00112 #endif /* CONFIG_IPV6 */
00113 
00114         if (hapd->conf->nas_identifier &&
00115             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
00116                                  (u8 *) hapd->conf->nas_identifier,
00117                                  os_strlen(hapd->conf->nas_identifier))) {
00118                 printf("Could not add NAS-Identifier\n");
00119                 goto fail;
00120         }
00121 
00122         if (sta &&
00123             !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
00124                 printf("Could not add NAS-Port\n");
00125                 goto fail;
00126         }
00127 
00128         os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
00129                     MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
00130         if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
00131                                  (u8 *) buf, os_strlen(buf))) {
00132                 printf("Could not add Called-Station-Id\n");
00133                 goto fail;
00134         }
00135 
00136         if (sta) {
00137                 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
00138                             MAC2STR(sta->addr));
00139                 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
00140                                          (u8 *) buf, os_strlen(buf))) {
00141                         printf("Could not add Calling-Station-Id\n");
00142                         goto fail;
00143                 }
00144 
00145                 if (!radius_msg_add_attr_int32(
00146                             msg, RADIUS_ATTR_NAS_PORT_TYPE,
00147                             RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
00148                         printf("Could not add NAS-Port-Type\n");
00149                         goto fail;
00150                 }
00151 
00152                 os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
00153                             radius_sta_rate(hapd, sta) / 2,
00154                             (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
00155                             radius_mode_txt(hapd));
00156                 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
00157                                          (u8 *) buf, os_strlen(buf))) {
00158                         printf("Could not add Connect-Info\n");
00159                         goto fail;
00160                 }
00161 
00162                 for (i = 0; ; i++) {
00163                         val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
00164                                                           i);
00165                         if (val == NULL)
00166                                 break;
00167 
00168                         if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
00169                                                  val, len)) {
00170                                 printf("Could not add Class\n");
00171                                 goto fail;
00172                         }
00173                 }
00174         }
00175 
00176         return msg;
00177 
00178  fail:
00179         radius_msg_free(msg);
00180         os_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 (hostapd_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 
00236 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
00237 {
00238         struct radius_msg *msg;
00239         int interval;
00240 
00241         if (sta->acct_session_started)
00242                 return;
00243 
00244         accounting_sta_get_id(hapd, sta);
00245         hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
00246                        HOSTAPD_LEVEL_INFO,
00247                        "starting accounting session %08X-%08X",
00248                        sta->acct_session_id_hi, sta->acct_session_id_lo);
00249 
00250         time(&sta->acct_session_start);
00251         sta->last_rx_bytes = sta->last_tx_bytes = 0;
00252         sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
00253         hostapd_sta_clear_stats(hapd, sta->addr);
00254 
00255         if (!hapd->conf->radius->acct_server)
00256                 return;
00257 
00258         if (sta->acct_interim_interval)
00259                 interval = sta->acct_interim_interval;
00260         else
00261                 interval = ACCT_DEFAULT_UPDATE_INTERVAL;
00262         eloop_register_timeout(interval, 0, accounting_interim_update,
00263                                hapd, sta);
00264 
00265         msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
00266         if (msg)
00267                 radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
00268 
00269         sta->acct_session_started = 1;
00270 }
00271 
00272 
00273 static void accounting_sta_report(struct hostapd_data *hapd,
00274                                   struct sta_info *sta, int stop)
00275 {
00276         struct radius_msg *msg;
00277         int cause = sta->acct_terminate_cause;
00278         struct hostap_sta_driver_data data;
00279         u32 gigawords;
00280 
00281         if (!hapd->conf->radius->acct_server)
00282                 return;
00283 
00284         msg = accounting_msg(hapd, sta,
00285                              stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
00286                              RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
00287         if (!msg) {
00288                 printf("Could not create RADIUS Accounting message\n");
00289                 return;
00290         }
00291 
00292         if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
00293                                        time(NULL) - sta->acct_session_start)) {
00294                 printf("Could not add Acct-Session-Time\n");
00295                 goto fail;
00296         }
00297 
00298         if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
00299                 if (!radius_msg_add_attr_int32(msg,
00300                                                RADIUS_ATTR_ACCT_INPUT_PACKETS,
00301                                                data.rx_packets)) {
00302                         printf("Could not add Acct-Input-Packets\n");
00303                         goto fail;
00304                 }
00305                 if (!radius_msg_add_attr_int32(msg,
00306                                                RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
00307                                                data.tx_packets)) {
00308                         printf("Could not add Acct-Output-Packets\n");
00309                         goto fail;
00310                 }
00311                 if (!radius_msg_add_attr_int32(msg,
00312                                                RADIUS_ATTR_ACCT_INPUT_OCTETS,
00313                                                data.rx_bytes)) {
00314                         printf("Could not add Acct-Input-Octets\n");
00315                         goto fail;
00316                 }
00317                 gigawords = sta->acct_input_gigawords;
00318 #if __WORDSIZE == 64
00319                 gigawords += data.rx_bytes >> 32;
00320 #endif
00321                 if (gigawords &&
00322                     !radius_msg_add_attr_int32(
00323                             msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
00324                             gigawords)) {
00325                         printf("Could not add Acct-Input-Gigawords\n");
00326                         goto fail;
00327                 }
00328                 if (!radius_msg_add_attr_int32(msg,
00329                                                RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
00330                                                data.tx_bytes)) {
00331                         printf("Could not add Acct-Output-Octets\n");
00332                         goto fail;
00333                 }
00334                 gigawords = sta->acct_output_gigawords;
00335 #if __WORDSIZE == 64
00336                 gigawords += data.tx_bytes >> 32;
00337 #endif
00338                 if (gigawords &&
00339                     !radius_msg_add_attr_int32(
00340                             msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
00341                             gigawords)) {
00342                         printf("Could not add Acct-Output-Gigawords\n");
00343                         goto fail;
00344                 }
00345         }
00346 
00347         if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
00348                                        time(NULL))) {
00349                 printf("Could not add Event-Timestamp\n");
00350                 goto fail;
00351         }
00352 
00353         if (eloop_terminated())
00354                 cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
00355 
00356         if (stop && cause &&
00357             !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
00358                                        cause)) {
00359                 printf("Could not add Acct-Terminate-Cause\n");
00360                 goto fail;
00361         }
00362 
00363         radius_client_send(hapd->radius, msg,
00364                            stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
00365                            sta->addr);
00366         return;
00367 
00368  fail:
00369         radius_msg_free(msg);
00370         os_free(msg);
00371 }
00372 
00373 
00380 void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
00381 {
00382         if (sta->acct_session_started)
00383                 accounting_sta_report(hapd, sta, 0);
00384 }
00385 
00386 
00393 void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
00394 {
00395         if (sta->acct_session_started) {
00396                 accounting_sta_report(hapd, sta, 1);
00397                 eloop_cancel_timeout(accounting_interim_update, hapd, sta);
00398                 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
00399                                HOSTAPD_LEVEL_INFO,
00400                                "stopped accounting session %08X-%08X",
00401                                sta->acct_session_id_hi,
00402                                sta->acct_session_id_lo);
00403                 sta->acct_session_started = 0;
00404         }
00405 }
00406 
00407 
00408 static void accounting_sta_get_id(struct hostapd_data *hapd,
00409                                   struct sta_info *sta)
00410 {
00411         sta->acct_session_id_lo = hapd->acct_session_id_lo++;
00412         if (hapd->acct_session_id_lo == 0) {
00413                 hapd->acct_session_id_hi++;
00414         }
00415         sta->acct_session_id_hi = hapd->acct_session_id_hi;
00416 }
00417 
00418 
00429 static RadiusRxResult
00430 accounting_receive(struct radius_msg *msg, struct radius_msg *req,
00431                    const u8 *shared_secret, size_t shared_secret_len,
00432                    void *data)
00433 {
00434         if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
00435                 printf("Unknown RADIUS message code\n");
00436                 return RADIUS_RX_UNKNOWN;
00437         }
00438 
00439         if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
00440                 printf("Incoming RADIUS packet did not have correct "
00441                        "Authenticator - dropped\n");
00442                 return RADIUS_RX_INVALID_AUTHENTICATOR;
00443         }
00444 
00445         return RADIUS_RX_PROCESSED;
00446 }
00447 
00448 
00449 static void accounting_report_state(struct hostapd_data *hapd, int on)
00450 {
00451         struct radius_msg *msg;
00452 
00453         if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
00454                 return;
00455 
00456         /* Inform RADIUS server that accounting will start/stop so that the
00457          * server can close old accounting sessions. */
00458         msg = accounting_msg(hapd, NULL,
00459                              on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
00460                              RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
00461         if (!msg)
00462                 return;
00463 
00464         if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
00465                                        RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
00466         {
00467                 printf("Could not add Acct-Terminate-Cause\n");
00468                 radius_msg_free(msg);
00469                 os_free(msg);
00470                 return;
00471         }
00472 
00473         radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
00474 }
00475 
00476 
00482 int accounting_init(struct hostapd_data *hapd)
00483 {
00484         /* Acct-Session-Id should be unique over reboots. If reliable clock is
00485          * not available, this could be replaced with reboot counter, etc. */
00486         hapd->acct_session_id_hi = time(NULL);
00487 
00488         if (radius_client_register(hapd->radius, RADIUS_ACCT,
00489                                    accounting_receive, hapd))
00490                 return -1;
00491 
00492         accounting_report_state(hapd, 1);
00493 
00494         return 0;
00495 }
00496 
00497 
00502 void accounting_deinit(struct hostapd_data *hapd)
00503 {
00504         accounting_report_state(hapd, 0);
00505 }
00506 
00507 
00508 int accounting_reconfig(struct hostapd_data *hapd,
00509                         struct hostapd_config *oldconf)
00510 {
00511         if (!hapd->radius_client_reconfigured)
00512                 return 0;
00513 
00514         accounting_deinit(hapd);
00515         return accounting_init(hapd);
00516 }
00517 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:47 2009 for hostapd by  doxygen 1.6.1