From patchwork Mon Oct 8 12:45:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yury Shvedov X-Patchwork-Id: 980551 X-Patchwork-Delegate: ynezz@true.cz Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=wimarksystems.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="UANHib8l"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42TKtZ3Jx5z9s8r for ; Mon, 8 Oct 2018 23:49:10 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Subject:MIME-Version:References: In-Reply-To:Message-Id:Date:To:From:Reply-To:Cc:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=d5ZzK4srPn9HnGhNN2TuoTtst0tbJPcYm7A1z8uIWqc=; b=UANHib8lfGdOgUTxdRXs3JaZZF RU2veN46g87TTTIuR5fmNttYCAjgxFkQMBYLrs5xnNAZav8PuAwLZ1Z9lXSYF2+DoaCUxUX67c/Sv CrZSTT2ovew5g8cEUyML9kuqjMI9cwaDHcPDXhCeNMB37tTA+DwIqixiO4uTAkgFVRI2jCCcNfuWg cqqvDnpuv3Oti1tXmnvpVwYi2x4atX0MJ8GWh59pxua2oB/BArLTJgs7CSy7yJbveUt8C9RbZvZEl 2xhEZ+MFzn87ONsOlRAd2p1flBkFULirGChNeNRr6flvoWZOLqv+4EM6IabBBd3VomzHLAf7ZZRda VPaeCOzw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1g9Uy9-0001t3-5Q; Mon, 08 Oct 2018 12:49:05 +0000 Received: from forward103j.mail.yandex.net ([5.45.198.246]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1g9Uuq-0000Hp-0K for openwrt-devel@lists.openwrt.org; Mon, 08 Oct 2018 12:46:30 +0000 Received: from mxback5j.mail.yandex.net (mxback5j.mail.yandex.net [IPv6:2a02:6b8:0:1619::10e]) by forward103j.mail.yandex.net (Yandex) with ESMTP id D3FC534C264B for ; Mon, 8 Oct 2018 15:45:24 +0300 (MSK) Received: from smtp2o.mail.yandex.net (smtp2o.mail.yandex.net [2a02:6b8:0:1a2d::26]) by mxback5j.mail.yandex.net (nwsmtp/Yandex) with ESMTP id bTUZYbnP3e-jOM02aM4; Mon, 08 Oct 2018 15:45:24 +0300 Received: by smtp2o.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id wSOATOpRjx-jN1GAT8b; Mon, 08 Oct 2018 15:45:23 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client certificate not present) From: Yury Shvedov To: openwrt-devel@lists.openwrt.org Date: Mon, 8 Oct 2018 15:45:18 +0300 Message-Id: <20181008124520.30040-3-yshvedov@wimarksystems.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181008124520.30040-1-yshvedov@wimarksystems.com> References: <20181008122821.29237-4-yshvedov@wimarksystems.com> <20181008124520.30040-1-yshvedov@wimarksystems.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181008_054540_474978_1F4787B8 X-CRM114-Status: GOOD ( 17.28 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [5.45.198.246 listed in list.dnswl.org] Subject: [OpenWrt-Devel] [PATCH 3/5] hostapd: Add ubus accounting X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org This implements ubus accounting events. This accounting works the same manner as the RADIUS accounting, except the interim (see below). There tree types of messages: start, stop and interim. Start sent when new client connected. There just current time, address and session_id of client in message. Stop sent when client disconnected. This message contains extra counters and terminate_cause. Interim sent by timeout, configured with ubus_accounting_interval variable. This message contains an information about all connected to bss clients. Payload example: { "clients": [ { "session_time": 9, "address": "68:3e:34:f5:61:3f", "session_id": "A6367C8F6C0662C1", "accounting": { "rx_bytes": 2336, "tx_packets": 5, "tx_bytes": 533, "rx_packets": 17 }, "terminate_cause": 1 } ], "device": "radio0", "bssid": "44:d1:fa:12:4c:74", "freq": 5260, "iface": "wlan0" } Signed-off-by: Yury Shvedov --- .../hostapd/patches/600-ubus_support.patch | 165 +++++++++++- .../services/hostapd/src/src/ap/ubus.c | 238 +++++++++++++++++- .../services/hostapd/src/src/ap/ubus.h | 14 ++ 3 files changed, 405 insertions(+), 12 deletions(-) diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index c63b85c079..c0db5be4e9 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -99,7 +99,15 @@ hostapd_interface_deinit(iface); wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", __func__, driver, drv_priv); -@@ -3114,6 +3120,7 @@ void hostapd_set_state(struct hostapd_if +@@ -3050,6 +3056,7 @@ void hostapd_new_assoc_sta(struct hostap + ap_sta_set_authorized(hapd, sta, 1); + os_get_reltime(&sta->connected_time); + accounting_sta_start(hapd, sta); ++ hostapd_ubus_event_sta_account_start(hapd,sta); + } + + /* Start IEEE 802.1X authentication process for new stations */ +@@ -3114,6 +3121,7 @@ void hostapd_set_state(struct hostapd_if wpa_printf(MSG_INFO, "%s: interface state %s->%s", iface->conf ? iface->conf->bss[0]->iface : "N/A", hostapd_state_text(iface->state), hostapd_state_text(s)); @@ -201,7 +209,15 @@ sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { -@@ -3630,6 +3657,8 @@ static void handle_deauth(struct hostapd +@@ -3584,6 +3611,7 @@ static void handle_disassoc(struct hosta + /* Stop Accounting and IEEE 802.1X sessions, but leave the STA + * authenticated. */ + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + ieee802_1x_free_station(hapd, sta); + if (sta->ipaddr) + hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); +@@ -3630,6 +3658,8 @@ static void handle_deauth(struct hostapd " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); @@ -210,7 +226,7 @@ sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " -@@ -3949,7 +3978,7 @@ int ieee802_11_mgmt(struct hostapd_data +@@ -3949,7 +3979,7 @@ int ieee802_11_mgmt(struct hostapd_data if (stype == WLAN_FC_STYPE_PROBE_REQ) { @@ -219,7 +235,7 @@ return 1; } -@@ -3969,17 +3998,17 @@ int ieee802_11_mgmt(struct hostapd_data +@@ -3969,17 +3999,17 @@ int ieee802_11_mgmt(struct hostapd_data switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth"); @@ -240,6 +256,14 @@ ret = 1; break; case WLAN_FC_STYPE_DISASSOC: +@@ -4128,6 +4158,7 @@ static void handle_assoc_cb(struct hosta + /* Stop previous accounting session, if one is started, and allocate + * new session id for the new session. */ + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -720,7 +720,7 @@ void sta_track_claim_taxonomy_info(struc @@ -309,7 +333,15 @@ if (addr == NULL) { /* -@@ -195,6 +199,12 @@ int hostapd_notif_assoc(struct hostapd_d +@@ -164,6 +168,7 @@ int hostapd_notif_assoc(struct hostapd_d + if (sta) { + ap_sta_no_session_timeout(hapd, sta); + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + + /* + * Make sure that the previously registered inactivity timer +@@ -195,6 +200,12 @@ int hostapd_notif_assoc(struct hostapd_d goto fail; } @@ -324,7 +356,15 @@ wpabuf_free(sta->p2p_ie); --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c -@@ -415,6 +415,7 @@ void ap_handle_timer(void *eloop_ctx, vo +@@ -162,6 +162,7 @@ void ap_free_sta(struct hostapd_data *ha + int set_beacon = 0; + + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + + /* just in case */ + ap_sta_set_authorized(hapd, sta, 0); +@@ -415,6 +416,7 @@ void ap_handle_timer(void *eloop_ctx, vo HOSTAPD_LEVEL_INFO, "deauthenticated due to " "local deauth request"); ap_free_sta(hapd, sta); @@ -332,7 +372,15 @@ return; } -@@ -562,6 +563,7 @@ skip_poll: +@@ -535,6 +537,7 @@ skip_poll: + sta->acct_terminate_cause = + RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + ieee802_1x_free_station(hapd, sta); + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "disassociated due to " +@@ -562,6 +565,7 @@ skip_poll: hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); ap_free_sta(hapd, sta); @@ -340,7 +388,23 @@ break; } } -@@ -1223,6 +1225,7 @@ void ap_sta_set_authorized(struct hostap +@@ -796,6 +800,7 @@ void ap_sta_disassociate(struct hostapd_ + eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, + ap_handle_timer, hapd, sta); + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + ieee802_1x_free_station(hapd, sta); + + sta->disassoc_reason = reason; +@@ -845,6 +850,7 @@ void ap_sta_deauthenticate(struct hostap + eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, + ap_handle_timer, hapd, sta); + accounting_sta_stop(hapd, sta); ++ hostapd_ubus_event_sta_account_stop(hapd, sta); + ieee802_1x_free_station(hapd, sta); + + sta->deauth_reason = reason; +@@ -1223,6 +1229,7 @@ void ap_sta_set_authorized(struct hostap buf, ip_addr); } else { wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); @@ -360,7 +424,7 @@ --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -2663,6 +2663,11 @@ static int hostapd_config_fill(struct ho +@@ -2663,6 +2663,13 @@ static int hostapd_config_fill(struct ho 0) { bss->radius_das_require_message_authenticator = atoi(pos); #endif /* CONFIG_NO_RADIUS */ @@ -368,6 +432,8 @@ + } else if (os_strcmp(buf, "uci_device") == 0) { + os_free(bss->uci_device); + bss->uci_device = os_strdup(pos); ++ } else if (os_strcmp(buf, "ubus_acct_interim_interval") == 0) { ++ bss->ubus_acct_interim_interval = atoi(pos); +#endif /* UBUS_SUPPORT */ } else if (os_strcmp(buf, "auth_algs") == 0) { bss->auth_algs = atoi(pos); @@ -384,12 +450,91 @@ --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -470,6 +470,8 @@ struct hostapd_bss_config { +@@ -470,6 +470,9 @@ struct hostapd_bss_config { int pbc_in_m1; char *server_id; + char *uci_device; ++ int ubus_acct_interim_interval; + #define P2P_ENABLED BIT(0) #define P2P_GROUP_OWNER BIT(1) #define P2P_GROUP_FORMATION BIT(2) +--- a/src/ap/accounting.c ++++ b/src/ap/accounting.c +@@ -164,7 +164,7 @@ static struct radius_msg * accounting_ms + } + + +-static int accounting_sta_update_stats(struct hostapd_data *hapd, ++int accounting_sta_update_stats(struct hostapd_data *hapd, + struct sta_info *sta, + struct hostap_sta_driver_data *data) + { +--- a/src/ap/accounting.h ++++ b/src/ap/accounting.h +@@ -10,19 +10,13 @@ + #define ACCOUNTING_H + + #ifdef CONFIG_NO_ACCOUNTING +-static inline int accounting_sta_get_id(struct hostapd_data *hapd, +- struct sta_info *sta) +-{ +- return 0; +-} +- + static inline void accounting_sta_start(struct hostapd_data *hapd, + struct sta_info *sta) + { + } + + static inline void accounting_sta_stop(struct hostapd_data *hapd, +- struct sta_info *sta) ++ struct sta_info *sta) + { + } + +@@ -35,11 +29,32 @@ static inline void accounting_deinit(str + { + } + #else /* CONFIG_NO_ACCOUNTING */ +-int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta); + void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta); + void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta); + int accounting_init(struct hostapd_data *hapd); + void accounting_deinit(struct hostapd_data *hapd); + #endif /* CONFIG_NO_ACCOUNTING */ + ++#if defined (CONFIG_NO_ACCOUNTING ) && !defined (UBUS_SUPPORT) ++static inline int accounting_sta_get_id(struct hostapd_data *hapd, ++ struct sta_info *sta) ++{ ++ return 0; ++} ++static int accounting_sta_update_stats(struct hostapd_data *hapd, ++ struct sta_info *sta, ++ struct hostap_sta_driver_data *data) ++{ ++ return 0; ++} ++ ++#else ++ ++int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta); ++int accounting_sta_update_stats(struct hostapd_data *hapd, ++ struct sta_info *sta, ++ struct hostap_sta_driver_data *data); ++ ++#endif /* CONFIG_NO_ACCOUNTING && UBUS_SUPPORT */ ++ + #endif /* ACCOUNTING_H */ +--- a/src/ap/sta_info.h ++++ b/src/ap/sta_info.h +@@ -139,6 +139,7 @@ struct sta_info { + int acct_terminate_cause; /* Acct-Terminate-Cause */ + int acct_interim_interval; /* Acct-Interim-Interval */ + unsigned int acct_interim_errors; ++ int ubus_acct_session_started; + + /* For extending 32-bit driver counters to 64-bit counters */ + u32 last_rx_bytes_hi; diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c index 6d12126a1a..2ceb2de159 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.c +++ b/package/network/services/hostapd/src/src/ap/ubus.c @@ -18,10 +18,14 @@ #include "ubus.h" #include "ap_drv_ops.h" #include "beacon.h" +#include "accounting.h" +#include "radius/radius.h" #include "rrm.h" #include "wnm_ap.h" #include "taxonomy.h" +#define ACCT_DEFAULT_UPDATE_INTERVAL 300 + static struct ubus_context *ctx; static struct blob_buf b; static int ctx_ref; @@ -1099,6 +1103,21 @@ static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr) return memcmp(k1, k2, ETH_ALEN); } +static void hostapd_ubus_accounting_interim_update(void *eloop_ctx, void *); +static bool hostapd_ubus_accounting_init(struct hostapd_data *hapd) +{ + int interval = hapd->conf->ubus_acct_interim_interval; + if (!interval) + interval = ACCT_DEFAULT_UPDATE_INTERVAL; + eloop_register_timeout(interval, 0, hostapd_ubus_accounting_interim_update, + hapd, NULL); + return true; +} +static void hostapd_ubus_accounting_stop(struct hostapd_data *hapd) +{ + eloop_cancel_timeout(hostapd_ubus_accounting_interim_update, hapd, NULL); +} + void hostapd_ubus_add_bss(struct hostapd_data *hapd) { struct ubus_object *obj = &hapd->ubus.obj; @@ -1113,9 +1132,16 @@ void hostapd_ubus_add_bss(struct hostapd_data *hapd) if (!hostapd_ubus_init()) return; + if (obj->id) { + return; + } + if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0) return; + if (!hostapd_ubus_accounting_init(hapd)) + return; + avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL); obj->name = name; obj->type = &bss_object_type; @@ -1133,6 +1159,8 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd) if (!ctx) return; + hostapd_ubus_accounting_stop(hapd); + if (obj->id) { ubus_remove_object(ctx, obj); hostapd_ubus_ref_dec(); @@ -1207,7 +1235,7 @@ int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_req ht_capabilities = (struct ieee80211_ht_capabilities*) req->elems->ht_capabilities; ht_cap = blobmsg_open_table(&b, "ht_capabilities"); blobmsg_add_u16(&b, "ht_capabilities_info", ht_capabilities->ht_capabilities_info); - ht_cap_mcs_set = blobmsg_open_table(&b, "supported_mcs_set"); + ht_cap_mcs_set = blobmsg_open_table(&b, "supported_mcs_set"); blobmsg_add_u16(&b, "a_mpdu_params", ht_capabilities->a_mpdu_params); blobmsg_add_u16(&b, "ht_extended_capabilities", ht_capabilities->ht_extended_capabilities); blobmsg_add_u32(&b, "tx_bf_capability_info", ht_capabilities->tx_bf_capability_info); @@ -1218,7 +1246,7 @@ int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_req } blobmsg_close_array(&b, mcs_set); blobmsg_close_table(&b, ht_cap_mcs_set); - blobmsg_close_table(&b, ht_cap); + blobmsg_close_table(&b, ht_cap); } if(req->elems->vht_capabilities) { @@ -1294,3 +1322,209 @@ void hostapd_ubus_event_iface_state(struct hostapd_iface *iface, int s) blobmsg_add_string(&b, "state", hostapd_state_text(s)); ubus_send_event(ctx, "hostapd.iface_state", b.head); } +static void +blobmsg_add_sta_data(struct blob_buf *buf, const char *name, + struct sta_info *sta, + const struct hostap_sta_driver_data *data) +{ + u64 bytes; + void *tbl = blobmsg_open_table(buf, name); + + blobmsg_add_u32(buf, "rx_packets", data->rx_packets); + blobmsg_add_u32(buf, "tx_packets", data->tx_packets); + + if (data->bytes_64bit) + bytes = data->rx_bytes; + else + bytes = ((u64) sta->last_rx_bytes_hi << 32) | + sta->last_rx_bytes_lo; + blobmsg_add_u64(buf, "rx_bytes", bytes); + if (data->bytes_64bit) + bytes = data->tx_bytes; + else + bytes = ((u64) sta->last_tx_bytes_hi << 32) | + sta->last_tx_bytes_lo; + blobmsg_add_u64(buf, "tx_bytes", bytes); + blobmsg_add_double(buf, "rssi", data->last_ack_rssi); + blobmsg_add_double(buf, "signal", data->signal); + + blobmsg_close_table(buf, tbl); +} +static void +blobmsg_add_reltime(struct blob_buf *buf, const char *name, + const struct os_reltime *reltime) +{ + blobmsg_add_u32(buf, name, reltime->sec); +} +static void +blobmsg_add_session_id(struct blob_buf *buf, const char *name, + struct sta_info *sta) +{ + blobmsg_printf(buf, name, "%016llX", + (unsigned long long) sta->acct_session_id); +} +static void +blobmsg_add_station_accounting(struct blob_buf *buf, + const char *name, + struct sta_info *sta, + const struct hostap_sta_driver_data *data, + const struct os_reltime *session_time, + int cause) +{ + void *tbl = blobmsg_open_table(buf, name); + blobmsg_add_macaddr(buf, "address", sta->addr); + blobmsg_add_session_id(buf, "session_id", sta); + if(data) + blobmsg_add_sta_data(buf, "accounting", sta, data); + if(session_time) + blobmsg_add_reltime(buf, "session_time", session_time); + if (sta->identity) + blobmsg_add_string(buf, "identity", sta->identity); + if (cause > 0) + blobmsg_add_u32(buf, "terminate_cause", cause); + blobmsg_close_table(buf, tbl); +} +static void hostapd_ubus_event_sta_account(struct hostapd_data *hapd, + struct sta_info *sta, const char *status, + const struct hostap_sta_driver_data *data, + const struct os_reltime *session_time, + int cause) +{ + void *arr; + + if (!ctx) + return; + blob_buf_init(&b, 0); + + arr = blobmsg_open_array(&b, "clients"); + blobmsg_add_station_accounting(&b, NULL, sta, data, session_time, cause); + blobmsg_close_array(&b, arr); + blobmsg_add_u32(&b, "freq", hapd->iface->freq); + + blobmsg_add_hapd_id(&b, hapd); + ubus_notify(ctx, &hapd->ubus.obj, status, b.head, -1); +} +void hostapd_ubus_event_sta_account_start(struct hostapd_data *hapd, + struct sta_info *sta) +{ + if (sta->ubus_acct_session_started || !hapd->ubus.obj.has_subscribers) + return; +#ifdef CONFIG_NO_ACCOUNTING + os_get_reltime(&sta->acct_session_start); + sta->last_rx_bytes_hi = 0; + sta->last_rx_bytes_lo = 0; + sta->last_tx_bytes_hi = 0; + sta->last_tx_bytes_lo = 0; + hostapd_drv_sta_clear_stats(hapd, sta->addr); +#endif + sta->ubus_acct_session_started = 1; + hostapd_ubus_event_sta_account(hapd, sta, "start", NULL, NULL, 0); +} +void hostapd_ubus_event_sta_account_stop(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct hostap_sta_driver_data data, *pdata = NULL; + struct os_reltime now_r, diff; + int cause = sta->acct_terminate_cause; + + if (!sta->ubus_acct_session_started || !hapd->ubus.obj.has_subscribers) + return; + sta->ubus_acct_session_started = 0; + if (!ctx) + return; + if (eloop_terminated()) + cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT; + os_get_reltime(&now_r); + os_reltime_sub(&now_r, &sta->acct_session_start, &diff); + if (accounting_sta_update_stats(hapd, sta, &data) == 0) + pdata = &data; + hostapd_ubus_event_sta_account(hapd, sta, "stop", pdata, &diff, cause); +} +struct ubus_sta_acct_counter { + struct blob_buf *buf; + int counter; + struct os_reltime now; +}; +static int hostapd_ubus_event_sta_account_interim(struct hostapd_data *hapd, + struct sta_info *sta, void *ctx) +{ + struct ubus_sta_acct_counter *counter = ctx; + struct os_reltime diff; + struct hostap_sta_driver_data data, *pdata = NULL; + + if (!sta->ubus_acct_session_started) + return 0; + os_reltime_sub(&counter->now, &sta->acct_session_start, &diff); + if (accounting_sta_update_stats(hapd, sta, &data) == 0) + pdata = &data; + blobmsg_add_station_accounting(counter->buf, NULL, sta, pdata, &diff, 0); + ++counter->counter; +} +static void hostapd_ubus_accounting_interim(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct ubus_sta_acct_counter counter = { &b, 0 }; + void *arr; + + if (!hapd->ubus.obj.has_subscribers) + return; + blob_buf_init(&b, 0); + + os_get_reltime(&counter.now); + blobmsg_add_u32(&b, "freq", hapd->iface->freq); + blobmsg_add_hapd_id(&b, hapd); + arr = blobmsg_open_array(&b, "clients"); + + if (sta != NULL) + hostapd_ubus_event_sta_account_interim(hapd, sta, &counter); + else + ap_for_each_sta(hapd, hostapd_ubus_event_sta_account_interim, &counter); + blobmsg_close_array(&b, arr); + if (counter.counter > 0) + ubus_notify(ctx, &hapd->ubus.obj, "interim", b.head, -1); +} +static void hostapd_ubus_accounting_interim_update(void *eloop_ctx, + void *timer_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + hostapd_ubus_accounting_interim(hapd, NULL); + hostapd_ubus_accounting_init(hapd); +} + +#ifdef CONFIG_NO_ACCOUNTING +int accounting_sta_update_stats(struct hostapd_data *hapd, + struct sta_info *sta, + struct hostap_sta_driver_data *data) +{ + if (hostapd_drv_read_sta_data(hapd, data, sta->addr)) + return -1; + + if (!data->bytes_64bit) { + /* Extend 32-bit counters from the driver to 64-bit counters */ + if (sta->last_rx_bytes_lo > data->rx_bytes) + sta->last_rx_bytes_hi++; + sta->last_rx_bytes_lo = data->rx_bytes; + + if (sta->last_tx_bytes_lo > data->tx_bytes) + sta->last_tx_bytes_hi++; + sta->last_tx_bytes_lo = data->tx_bytes; + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, + "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d", + data->rx_bytes, sta->last_rx_bytes_hi, + sta->last_rx_bytes_lo, + data->tx_bytes, sta->last_tx_bytes_hi, + sta->last_tx_bytes_lo, + data->bytes_64bit); + + return 0; +} +int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta) +{ + /* Copied from radius_gen_session_id */ + return os_get_random((u8 *) &sta->acct_session_id, + sizeof(sta->acct_session_id)); +} +#endif diff --git a/package/network/services/hostapd/src/src/ap/ubus.h b/package/network/services/hostapd/src/src/ap/ubus.h index 840b000180..cc4b5fcb0f 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.h +++ b/package/network/services/hostapd/src/src/ap/ubus.h @@ -27,6 +27,7 @@ struct hostapd_ubus_request { struct hostapd_iface; struct hostapd_data; +struct sta_info; #ifdef UBUS_SUPPORT @@ -53,6 +54,11 @@ void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 * void hostapd_ubus_event_iface_state(struct hostapd_iface *iface, int s); +void hostapd_ubus_event_sta_account_start(struct hostapd_data *hapd, + struct sta_info *sta); +void hostapd_ubus_event_sta_account_stop(struct hostapd_data *hapd, + struct sta_info *sta); + #else struct hostapd_ubus_iface {}; @@ -86,6 +92,14 @@ static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *ty static inline void hostapd_ubus_event_iface_state(struct hostapd_iface *iface, int s) { } +static inline void hostapd_ubus_event_sta_account_start(struct hostapd_data *hapd, + struct sta_info *sta) +{ +} +static inline void hostapd_ubus_event_sta_account_stop(struct hostapd_data *hapd, + struct sta_info *sta) +{ +} #endif #endif