diff --git a/CMakeLists.txt b/CMakeLists.txt index 12cd9ba..58ae59d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,7 @@ add_executable(owanalytics src/RESTAPI/RESTAPI_routers.cpp src/Daemon.cpp src/Daemon.h src/Dashboard.h src/Dashboard.cpp - src/StorageService.cpp src/StorageService.h src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h src/StateReceiver.cpp src/StateReceiver.h src/VenueWatcher.cpp src/VenueWatcher.h src/VenueCoordinator.cpp src/VenueCoordinator.h src/sdks/SDK_prov.cpp src/sdks/SDK_prov.h src/storage/storage_boards.cpp src/storage/storage_boards.h) + src/StorageService.cpp src/StorageService.h src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h src/StateReceiver.cpp src/StateReceiver.h src/VenueWatcher.cpp src/VenueWatcher.h src/VenueCoordinator.cpp src/VenueCoordinator.h src/sdks/SDK_prov.cpp src/sdks/SDK_prov.h src/storage/storage_boards.cpp src/storage/storage_boards.h src/RESTAPI/RESTAPI_board_list_handler.cpp src/RESTAPI/RESTAPI_board_list_handler.h src/RESTAPI/RESTAPI_board_handler.cpp src/RESTAPI/RESTAPI_board_handler.h src/RESTAPI/RESTAPI_analytics_db_helpers.h src/APStats.cpp src/APStats.h src/dict_ssid.h src/dict_ue.h src/dict_bssid.h) target_link_libraries(owanalytics PUBLIC ${Poco_LIBRARIES} ${MySQL_LIBRARIES} diff --git a/src/APStats.cpp b/src/APStats.cpp new file mode 100644 index 0000000..1498bf1 --- /dev/null +++ b/src/APStats.cpp @@ -0,0 +1,13 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#include "APStats.h" + +namespace OpenWifi { + + void AP::Update(std::shared_ptr &State) { + std::cout << "MAC: " << Utils::IntToSerialNumber(mac_) << std::endl; + } + +} \ No newline at end of file diff --git a/src/APStats.h b/src/APStats.h new file mode 100644 index 0000000..2823235 --- /dev/null +++ b/src/APStats.h @@ -0,0 +1,65 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#pragma once + +#include +#include "framework/MicroService.h" +#include "nlohmann/json.hpp" + +namespace OpenWifi { + const uint32_t interval = 20; // how big per sample + const uint32_t ap_length = 2 * 24 * 60 * 60; // buffer length in seconds + const uint32_t ue_length = 2 * 60 * 60; // buffer length in seconds + const uint32_t ap_buffer_size = ap_length / interval; + const uint32_t ue_buffer_size = ue_length / interval; + + + enum wifi_band { + band_2g=0, band_5g=1, band_6g=2 + }; + + struct AP_Point { + uint32_t rx_bytes=0, tx_bytes=0; + uint32_t rx_pkts=0,tx_pkts=0; + u_char bands[4]; + }; + + struct UE_Point { + uint32_t bssid_index; + int8_t rssi; + uint32_t rx_bytes,tx_bytes; + uint16_t tx_retries; + wifi_band band; + }; + + class UE { + public: + UE(uint64_t Station): + Station_(Station) { + } + + private: + uint64_t last_contact_=0; + uint64_t Station_=0; + uint64_t Start_=std::time(nullptr); + uint64_t Current_BSSID_=0; + uint32_t Current_BSSID_index_=0; + std::array Data_; + }; + + class AP { + public: + AP(uint64_t mac) : mac_(mac) { + + } + + void Update(std::shared_ptr & State); + + private: + uint64_t mac_=0; + uint64_t last_contact_=0; + std::array Data_; + }; +} diff --git a/src/Daemon.cpp b/src/Daemon.cpp index f8335ac..a925737 100644 --- a/src/Daemon.cpp +++ b/src/Daemon.cpp @@ -35,7 +35,7 @@ namespace OpenWifi { return instance_; } - void Daemon::initialize() { + void Daemon::initialize() { } void MicroServicePostInitialization() { diff --git a/src/RESTAPI/RESTAPI_analytics_db_helpers.h b/src/RESTAPI/RESTAPI_analytics_db_helpers.h new file mode 100644 index 0000000..66a2de2 --- /dev/null +++ b/src/RESTAPI/RESTAPI_analytics_db_helpers.h @@ -0,0 +1,62 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#pragma once + +#include "framework/MicroService.h" +#include "RESTObjects/RESTAPI_AnalyticsObjects.h" +#include "StorageService.h" +#include "framework/orm.h" + +namespace OpenWifi { + + template void ReturnRecordList(const char *ArrayName,DB & DBInstance, RESTAPIHandler & R) { + Poco::JSON::Array ObjArr; + for(const auto &i:R.SelectedRecords()) { + typename DB::RecordName Rec; + if(DBInstance.GetRecord("id",i,Rec)) { + Poco::JSON::Object Obj; + Rec.to_json(Obj); + ObjArr.add(Obj); + } else { + return R.BadRequest(RESTAPI::Errors::UnknownId + i); + } + } + Poco::JSON::Object Answer; + Answer.set(ArrayName, ObjArr); + return R.ReturnObject(Answer); + } + + template void MakeJSONObjectArray(const char * ArrayName, const std::vector & V, RESTAPIHandler & R) { + Poco::JSON::Array ObjArray; + for(const auto &i:V) { + Poco::JSON::Object Obj; + i.to_json(Obj); + ObjArray.add(Obj); + } + Poco::JSON::Object Answer; + Answer.set(ArrayName,ObjArray); + return R.ReturnObject(Answer); + } + + template + void ListHandler(const char *BlockName, DB &DBInstance, RESTAPIHandler &R) { + + typedef typename DB::RecordVec RecVec; + typedef typename DB::RecordName RecType; + + if (!R.QB_.Select.empty()) { + return ReturnRecordList(BlockName, DBInstance, R); + } else if (R.QB_.CountOnly) { + Poco::JSON::Object Answer; + auto C = DBInstance.Count(); + return R.ReturnCountOnly(C); + } else { + RecVec Entries; + DBInstance.GetRecords(R.QB_.Offset, R.QB_.Limit, Entries); + return MakeJSONObjectArray(BlockName, Entries, R); + } + } + +} \ No newline at end of file diff --git a/src/RESTAPI/RESTAPI_board_handler.cpp b/src/RESTAPI/RESTAPI_board_handler.cpp new file mode 100644 index 0000000..52bb02c --- /dev/null +++ b/src/RESTAPI/RESTAPI_board_handler.cpp @@ -0,0 +1,98 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#include "RESTAPI_board_handler.h" +#include "VenueCoordinator.h" + +namespace OpenWifi { + void RESTAPI_board_handler::DoGet() { + auto id = GetBinding("id",""); + if(id.empty()) { + return BadRequest(RESTAPI::Errors::MissingUUID); + } + + AnalyticsObjects::BoardInfo B; + if(!StorageService()->BoardsDB().GetRecord("id",id,B)) { + return NotFound(); + } + + Poco::JSON::Object Answer; + B.to_json(Answer); + return ReturnObject(Answer); + } + + void RESTAPI_board_handler::DoDelete() { + auto id = GetBinding("id",""); + if(id.empty()) { + return BadRequest(RESTAPI::Errors::MissingUUID); + } + + AnalyticsObjects::BoardInfo B; + if(!StorageService()->BoardsDB().GetRecord("id",id,B)) { + return NotFound(); + } + + if(!StorageService()->BoardsDB().DeleteRecord("id",id)) { + return NotFound(); + } + VenueCoordinator()->StopVenue(id); + return OK(); + } + + void RESTAPI_board_handler::DoPost() { + auto id= GetBinding("id",""); + if(id.empty()) { + return BadRequest(RESTAPI::Errors::MissingUUID); + } + + auto RawObject = ParseStream(); + AnalyticsObjects::BoardInfo NewObject; + if(!NewObject.from_json(RawObject)) { + return BadRequest(RESTAPI::Errors::InvalidJSONDocument); + } + + ProvObjects::CreateObjectInfo(RawObject,UserInfo_.userinfo,NewObject.info); + + if(StorageService()->BoardsDB().CreateRecord(NewObject)) { + VenueCoordinator()->AddVenue(NewObject.info.id); + AnalyticsObjects::BoardInfo NewBoard; + StorageService()->BoardsDB().GetRecord("id",NewObject.info.id,NewBoard); + Poco::JSON::Object Answer; + NewBoard.to_json(Answer); + return ReturnObject(Answer); + } + } + + void RESTAPI_board_handler::DoPut() { + auto id= GetBinding("id",""); + if(id.empty()) { + return BadRequest(RESTAPI::Errors::MissingUUID); + } + + AnalyticsObjects::BoardInfo Existing; + if(!StorageService()->BoardsDB().GetRecord("id",id,Existing)) { + return NotFound(); + } + + auto RawObject = ParseStream(); + AnalyticsObjects::BoardInfo NewObject; + if(!NewObject.from_json(RawObject)) { + return BadRequest(RESTAPI::Errors::InvalidJSONDocument); + } + + ProvObjects::UpdateObjectInfo(RawObject,UserInfo_.userinfo,Existing.info); + if(RawObject->has("venueList")) { + // reconsile new venuelist compared to old... + } + + if(StorageService()->BoardsDB().CreateRecord(NewObject)) { + VenueCoordinator()->ModifyVenue(NewObject.info.id); + AnalyticsObjects::BoardInfo NewBoard; + StorageService()->BoardsDB().GetRecord("id",NewObject.info.id,NewBoard); + Poco::JSON::Object Answer; + NewBoard.to_json(Answer); + return ReturnObject(Answer); + } + } +} \ No newline at end of file diff --git a/src/RESTAPI/RESTAPI_board_handler.h b/src/RESTAPI/RESTAPI_board_handler.h new file mode 100644 index 0000000..dc2db35 --- /dev/null +++ b/src/RESTAPI/RESTAPI_board_handler.h @@ -0,0 +1,35 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#pragma once + +#include "framework/MicroService.h" +#include "StorageService.h" + +namespace OpenWifi { + + class RESTAPI_board_handler : public RESTAPIHandler { + public: + RESTAPI_board_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) + : RESTAPIHandler(bindings, L, + std::vector{ + Poco::Net::HTTPRequest::HTTP_GET, + Poco::Net::HTTPRequest::HTTP_POST, + Poco::Net::HTTPRequest::HTTP_PUT, + Poco::Net::HTTPRequest::HTTP_DELETE, + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Server, + TransactionId, + Internal){} + + static const std::list PathName() { return std::list{"/api/v1/board/{id}"}; }; + + private: + BoardsDB & DB_=StorageService()->BoardsDB(); + void DoGet() final; + void DoPost() final; + void DoPut() final; + void DoDelete() final; + }; +} diff --git a/src/RESTAPI/RESTAPI_board_list_handler.cpp b/src/RESTAPI/RESTAPI_board_list_handler.cpp new file mode 100644 index 0000000..d546494 --- /dev/null +++ b/src/RESTAPI/RESTAPI_board_list_handler.cpp @@ -0,0 +1,14 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#include "RESTAPI_board_list_handler.h" +#include "StorageService.h" +#include "RESTAPI/RESTAPI_analytics_db_helpers.h" + +namespace OpenWifi { + void RESTAPI_board_list_handler::DoGet() { + return ListHandler("boards", DB_, *this); + } + +} \ No newline at end of file diff --git a/src/RESTAPI/RESTAPI_board_list_handler.h b/src/RESTAPI/RESTAPI_board_list_handler.h new file mode 100644 index 0000000..5f516b9 --- /dev/null +++ b/src/RESTAPI/RESTAPI_board_list_handler.h @@ -0,0 +1,33 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#pragma once + +#include "framework/MicroService.h" +#include "StorageService.h" +#include "RESTObjects/RESTAPI_AnalyticsObjects.h" + +namespace OpenWifi { + + class RESTAPI_board_list_handler : public RESTAPIHandler { + public: + RESTAPI_board_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) + : RESTAPIHandler(bindings, L, + std::vector{ + Poco::Net::HTTPRequest::HTTP_GET, + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Server, + TransactionId, + Internal){} + + static const std::list PathName() { return std::list{"/api/v1/boards"}; }; + + private: + BoardsDB & DB_=StorageService()->BoardsDB(); + void DoGet() final; + void DoPost() final {}; + void DoPut() final {}; + void DoDelete() final {}; + }; +} diff --git a/src/RESTAPI/RESTAPI_routers.cpp b/src/RESTAPI/RESTAPI_routers.cpp index 355398e..508175e 100644 --- a/src/RESTAPI/RESTAPI_routers.cpp +++ b/src/RESTAPI/RESTAPI_routers.cpp @@ -3,20 +3,26 @@ // #include "framework/MicroService.h" +#include "RESTAPI/RESTAPI_board_list_handler.h" +#include "RESTAPI/RESTAPI_board_handler.h" namespace OpenWifi { Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { return RESTAPI_Router< - RESTAPI_system_command + RESTAPI_system_command, + RESTAPI_board_handler, + RESTAPI_board_list_handler >(Path,Bindings,L, S, TransactionId); } Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { return RESTAPI_Router_I< - RESTAPI_system_command + RESTAPI_system_command, + RESTAPI_board_handler, + RESTAPI_board_list_handler >(Path, Bindings, L, S, TransactionId); } diff --git a/src/VenueCoordinator.cpp b/src/VenueCoordinator.cpp index 8436636..6b83d8d 100644 --- a/src/VenueCoordinator.cpp +++ b/src/VenueCoordinator.cpp @@ -44,4 +44,16 @@ namespace OpenWifi { } } + void VenueCoordinator::StopVenue(const std::string &id) { + + } + + void VenueCoordinator::ModifyVenue(const std::string &id) { + + } + + void VenueCoordinator::AddVenue(const std::string &id) { + + } + } \ No newline at end of file diff --git a/src/VenueCoordinator.h b/src/VenueCoordinator.h index 8ac00a2..880607c 100644 --- a/src/VenueCoordinator.h +++ b/src/VenueCoordinator.h @@ -20,6 +20,10 @@ namespace OpenWifi { void Stop() override; void run() override; + void StopVenue(const std::string &id); + void ModifyVenue(const std::string &id); + void AddVenue(const std::string &id); + private: Poco::Thread Worker_; std::atomic_bool Running_=false; diff --git a/src/VenueWatcher.cpp b/src/VenueWatcher.cpp index 71820ef..2da08d2 100644 --- a/src/VenueWatcher.cpp +++ b/src/VenueWatcher.cpp @@ -27,8 +27,10 @@ namespace OpenWifi { if(MsgContent!= nullptr) { try { auto State = MsgContent->Payload(); - std::cout << "SerialNumber: " << Utils::IntToSerialNumber(MsgContent->SerialNumber()) << std::endl; - std::cout << to_string(*State) << std::endl; + auto It = APs_.find(MsgContent->SerialNumber()); + if(It!=end(APs_)) { + It->second->Update(MsgContent->Payload()); + } } catch (const Poco::Exception &E) { Logger().log(E); } catch (...) { diff --git a/src/VenueWatcher.h b/src/VenueWatcher.h index acdbbf1..e08ac0d 100644 --- a/src/VenueWatcher.h +++ b/src/VenueWatcher.h @@ -5,6 +5,7 @@ #pragma once #include "framework/MicroService.h" +#include "APStats.h" namespace OpenWifi { @@ -27,9 +28,15 @@ namespace OpenWifi { Id_(id), Logger_(L), SerialNumbers_(SerialNumbers) { + std::sort(SerialNumbers_.begin(),SerialNumbers_.end()); auto last = std::unique(SerialNumbers_.begin(),SerialNumbers_.end()); SerialNumbers_.erase(last,SerialNumbers_.end()); + + for(const auto &mac:SerialNumbers_) { + auto ap = std::make_shared(mac); + APs_[mac ] = ap; + } } void Post(uint64_t SerialNumber, std::shared_ptr &Msg) { @@ -45,13 +52,14 @@ namespace OpenWifi { void ModifySerialNumbers(const std::vector &SerialNumbers); private: - std::recursive_mutex Mutex_; - std::string Id_; - Poco::NotificationQueue Queue_; - Poco::Logger &Logger_; - Poco::Thread Worker_; - std::atomic_bool Running_=false; - std::vector SerialNumbers_; + std::recursive_mutex Mutex_; + std::string Id_; + Poco::NotificationQueue Queue_; + Poco::Logger &Logger_; + Poco::Thread Worker_; + std::atomic_bool Running_=false; + std::vector SerialNumbers_; + std::map> APs_; }; } \ No newline at end of file diff --git a/src/dict_bssid.h b/src/dict_bssid.h new file mode 100644 index 0000000..eca85cc --- /dev/null +++ b/src/dict_bssid.h @@ -0,0 +1,41 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#pragma once + +#include +#include + +namespace OpenWifi { + class BSSID_DICT { + public: + static auto instance() { + static auto instance_ = new BSSID_DICT; + return instance_; + } + + inline uint32_t Get(uint64_t bssid) { + std::lock_guard G(Mutex_); + auto it = Dict_.find(bssid); + if(it==end(Dict_)) { + auto I = Index_++; + Dict_[bssid]=I; + return I; + } else { + return it->second; + } + } + + inline void Remove(uint64_t bssid) { + std::lock_guard G(Mutex_); + Dict_.erase(bssid); + } + + private: + uint32_t Index_=1; + std::mutex Mutex_; + std::map Dict_; + }; + inline auto BSSID_DICT() { return BSSID_DICT::instance(); } +} \ No newline at end of file diff --git a/src/dict_ssid.h b/src/dict_ssid.h new file mode 100644 index 0000000..339767e --- /dev/null +++ b/src/dict_ssid.h @@ -0,0 +1,38 @@ +#include +#include +#include + +namespace OpenWifi { + + class SSID_DICT { + public: + static auto instance() { + static auto instance_ = new SSID_DICT; + return instance_; + } + + inline uint32_t Add(const std::string &ssid) { + std::lock_guard G(Mutex_); + auto it = Dict_.find(ssid); + if (it == end(Dict_)) { + auto Id = Index_++; + Dict_[station] = Id; + return Id; + } else { + return it->second; + } + } + + inline void Remove(const std::string &ssid) { + std::lock_guard G(Mutex_); + Dict_.erase(ssid); + } + + private: + std::mutex Mutex_; + uint32_t Index_=1; + std::map Dict_; + }; + + inline auto SSID_DICT() { return SSID_DICT::instance(); } +} \ No newline at end of file diff --git a/src/dict_ue.h b/src/dict_ue.h new file mode 100644 index 0000000..4255cd3 --- /dev/null +++ b/src/dict_ue.h @@ -0,0 +1,49 @@ +// +// Created by stephane bourque on 2022-03-11. +// + +#pragma once + +#include +#include + +namespace OpenWifi { + + class UE_DICT { + public: + static auto instance() { + static auto instance_ = new UE_DICT; + return instance_; + } + + inline void Add(uint64_t station, UE *ue) { + std::lock_guard G(Mutex_); + auto it = Dict_.find(station); + if (it == end(Dict_)) { + Dict_[station] = ue; + return; + } else { + it->second = ue; + } + } + + inline void Remove(uint64_t station) { + std::lock_guard G(Mutex_); + Dict_.erase(station); + } + + inline UE *Get(uint64_t station) { + std::lock_guard G(Mutex_); + auto it = Dict_.find(station); + if (it == end(Dict_)) + return nullptr; + return it->second; + } + + private: + std::mutex Mutex_; + std::map Dict_; + }; + + inline auto UE_DICT() { return UE_DICT::instance(); } +} \ No newline at end of file diff --git a/stats_sample/bridge_stats.json b/stats_sample/bridge_stats.json new file mode 100644 index 0000000..cb10775 --- /dev/null +++ b/stats_sample/bridge_stats.json @@ -0,0 +1,1554 @@ +{ + "interfaces": [ + { + "clients": [ + { + "ipv6_addresses": [ + "fe80:0:0:0:1ab4:30ff:feb7:11a2" + ], + "mac": "18:b4:30:b7:11:a2", + "ports": [ + "wlan1" + ] + }, + { + "ipv4_addresses": [ + "10.100.14.61" + ], + "mac": "34:d2:70:67:b9:de", + "ports": [ + "wlan0-1" + ] + }, + { + "ipv6_addresses": [ + "fe80:0:0:0:4e8:b4a4:9976:b85e" + ], + "mac": "36:3b:d9:f3:bd:bb", + "ports": [ + "wlan0-1" + ] + }, + { + "ipv4_addresses": [ + "10.100.34.123" + ], + "ipv6_addresses": [ + "fe80:0:0:0:4600:49ff:fe3d:667b" + ], + "mac": "44:00:49:3d:66:7b", + "ports": [ + "wlan0-1" + ] + }, + { + "ipv4_addresses": [ + "10.100.164.73" + ], + "ipv6_addresses": [ + "fe80:0:0:0:e2:5d0e:1f50:fc90" + ], + "mac": "58:d3:49:0d:d2:56", + "ports": [ + "wlan0-1" + ] + }, + { + "ipv6_addresses": [ + "fe80:0:0:0:6072:4bff:fe45:5eb6" + ], + "mac": "62:72:4b:45:5e:b6", + "ports": [ + "wlan0-1" + ] + }, + { + "ipv4_addresses": [ + "10.100.71.149" + ], + "ipv6_addresses": [ + "fe80:0:0:0:6a21:5fff:fe04:2c32" + ], + "mac": "68:21:5f:04:2c:32", + "ports": [ + "eth0" + ] + }, + { + "ipv4_addresses": [ + "10.100.173.115" + ], + "ipv6_addresses": [ + "fe80:0:0:0:18ff:6919:f36:6faa" + ], + "mac": "7a:c5:5b:a1:2b:89", + "ports": [ + "wlan0-1" + ] + }, + { + "ipv6_addresses": [ + "fe80:0:0:0:923c:b3ff:febb:1ef4" + ], + "mac": "90:3c:b3:bb:1e:f4", + "ports": [ + "eth0" + ] + }, + { + "ipv4_addresses": [ + "10.100.0.1" + ], + "ipv6_addresses": [ + "fe80:0:0:0:dc41:8bff:fe8f:a5e7", + "2604:3d08:9680:bd01:0:0:0:1" + ], + "mac": "e0:63:da:86:64:97", + "ports": [ + "eth0" + ] + } + ], + "counters": { + "collisions": 0, + "multicast": 8834831, + "rx_bytes": 1027147259, + "rx_dropped": 0, + "rx_errors": 0, + "rx_packets": 10013707, + "tx_bytes": 386397108, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 4033748 + }, + "location": "/interfaces/0", + "name": "up0v100", + "ssids": [ + { + "associations": [ + { + "bssid": "36:3b:d9:f3:bd:bb", + "connected": 16843, + "deltas": { + "rx_bytes": 3796, + "rx_packets": 30, + "tx_bytes": 1458, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 16, + "tx_retries": 0 + }, + "inactive": 23, + "msdu": [ + { + "rx_msdu": 51595, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -64, + "rx_bytes": 10109437, + "rx_packets": 51607, + "rx_rate": { + "bitrate": 286700, + "chwidth": 20 + }, + "station": "36:3b:d9:f3:bd:bb", + "tx_bytes": 31546941, + "tx_duration": 10624, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 57293, + "tx_rate": { + "bitrate": 6000, + "chwidth": 20 + }, + "tx_retries": 0 + }, + { + "bssid": "7a:c5:5b:a1:2b:89", + "connected": 20200, + "deltas": { + "rx_bytes": 4146, + "rx_packets": 39, + "tx_bytes": 11675, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 34, + "tx_retries": 0 + }, + "inactive": 0, + "msdu": [ + { + "rx_msdu": 37868, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -58, + "rx_bytes": 6038108, + "rx_packets": 37884, + "rx_rate": { + "bitrate": 960700, + "chwidth": 80 + }, + "station": "7a:c5:5b:a1:2b:89", + "tx_bytes": 19993325, + "tx_duration": 9603, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 38810, + "tx_rate": { + "bitrate": 1200900, + "chwidth": 80 + }, + "tx_retries": 0 + }, + { + "bssid": "58:d3:49:0d:d2:56", + "connected": 23990, + "deltas": { + "rx_bytes": 9460, + "rx_packets": 40, + "tx_bytes": 7072, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 26, + "tx_retries": 0 + }, + "inactive": 2, + "msdu": [ + { + "rx_msdu": 28255, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 2, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -52, + "rx_bytes": 4500613, + "rx_packets": 28265, + "rx_rate": { + "bitrate": 72200, + "chwidth": 20, + "ht": true, + "mcs": 7, + "sgi": true + }, + "station": "58:d3:49:0d:d2:56", + "tx_bytes": 6133006, + "tx_duration": 6582, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 25314, + "tx_rate": { + "bitrate": 72200, + "chwidth": 20, + "ht": true, + "mcs": 7, + "sgi": true + }, + "tx_retries": 0 + }, + { + "bssid": "44:00:49:3d:66:7b", + "connected": 251763, + "deltas": { + "rx_bytes": 47048, + "rx_packets": 453, + "tx_bytes": 48516, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 432, + "tx_retries": 0 + }, + "inactive": 2, + "msdu": [ + { + "rx_msdu": 1534244, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -41, + "rx_bytes": 113926061, + "rx_packets": 1537596, + "rx_rate": { + "bitrate": 135000, + "chwidth": 40, + "ht": true, + "mcs": 7, + "sgi": true + }, + "station": "44:00:49:3d:66:7b", + "tx_bytes": 109067775, + "tx_duration": 8173557, + "tx_failed": 553, + "tx_offset": 0, + "tx_packets": 1518351, + "tx_rate": { + "bitrate": 6000, + "chwidth": 20, + "ht": true, + "mcs": 5, + "sgi": true + }, + "tx_retries": 0 + }, + { + "bssid": "cc:f7:35:8d:70:2b", + "connected": 269879, + "deltas": { + "rx_bytes": 44344, + "rx_packets": 277, + "tx_bytes": 28186, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 207, + "tx_retries": 0 + }, + "inactive": 2, + "msdu": [ + { + "rx_msdu": 1152146, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -68, + "rx_bytes": 217448410, + "rx_packets": 1152149, + "rx_rate": { + "bitrate": 433300, + "chwidth": 80, + "mcs": 9, + "nss": 1, + "sgi": true, + "vht": true + }, + "station": "cc:f7:35:8d:70:2b", + "tx_bytes": 159221293, + "tx_duration": 3335601, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 839779, + "tx_rate": { + "bitrate": 650000, + "chwidth": 80, + "mcs": 7, + "nss": 2, + "sgi": true, + "vht": true + }, + "tx_retries": 0 + }, + { + "bssid": "1c:12:b0:97:f2:57", + "connected": 278640, + "deltas": { + "rx_bytes": 27695, + "rx_packets": 248, + "tx_bytes": 29801, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 210, + "tx_retries": 0 + }, + "inactive": 2, + "msdu": [ + { + "rx_msdu": 7693187, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 5, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -76, + "rx_bytes": 604578068, + "rx_packets": 7693200, + "rx_rate": { + "bitrate": 234000, + "chwidth": 80, + "mcs": 3, + "nss": 2, + "sgi": true, + "vht": true + }, + "station": "1c:12:b0:97:f2:57", + "tx_bytes": -854970439, + "tx_duration": 62704209, + "tx_failed": 579, + "tx_offset": 0, + "tx_packets": 20172259, + "tx_rate": { + "bitrate": 585100, + "chwidth": 80, + "mcs": 6, + "nss": 2, + "sgi": true, + "vht": true + }, + "tx_retries": 0 + }, + { + "bssid": "62:72:4b:45:5e:b6", + "connected": 635029, + "deltas": { + "rx_bytes": 0, + "rx_packets": 0, + "tx_bytes": 0, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 0, + "tx_retries": 0 + }, + "inactive": 183, + "msdu": [ + { + "rx_msdu": 936248, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 10, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -46, + "rx_bytes": 841656999, + "rx_packets": 936326, + "rx_rate": { + "bitrate": 864800, + "chwidth": 80 + }, + "station": "62:72:4b:45:5e:b6", + "tx_bytes": 512402837, + "tx_duration": 7042856, + "tx_failed": 1156, + "tx_offset": 0, + "tx_packets": 3651797, + "tx_rate": { + "bitrate": 1080600, + "chwidth": 80 + }, + "tx_retries": 0 + }, + { + "bssid": "34:d2:70:67:b9:de", + "connected": 1048051, + "deltas": { + "rx_bytes": 17672, + "rx_packets": 168, + "tx_bytes": 24179, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 176, + "tx_retries": 0 + }, + "inactive": 3, + "msdu": [ + { + "rx_msdu": 2580453, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 14, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -73, + "rx_bytes": 219183284, + "rx_packets": 2580595, + "rx_rate": { + "bitrate": 54000, + "chwidth": 40, + "ht": true, + "mcs": 3, + "sgi": true + }, + "station": "34:d2:70:67:b9:de", + "tx_bytes": 268980509, + "tx_duration": 26594148, + "tx_failed": 3, + "tx_offset": 0, + "tx_packets": 2475047, + "tx_rate": { + "bitrate": 300000, + "chwidth": 40, + "ht": true, + "mcs": 15, + "sgi": true + }, + "tx_retries": 0 + } + ], + "bssid": "92:3c:b3:bb:1e:f8", + "iface": "wlan0-1", + "mode": "ap", + "phy": "platform/soc/c000000.wifi", + "radio": { + "$ref": "#/radios/0" + }, + "ssid": "petunia" + }, + { + "associations": [ + { + "bssid": "18:b4:30:b7:11:a2", + "connected": 440815, + "deltas": { + "rx_bytes": 110, + "rx_packets": 2, + "tx_bytes": 112, + "tx_failed": 0, + "tx_offset": 0, + "tx_packets": 2, + "tx_retries": 0 + }, + "inactive": 0, + "msdu": [ + { + "rx_msdu": 35753, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -50, + "rx_bytes": 6483053, + "rx_packets": 35759, + "rx_rate": { + "bitrate": 65000, + "chwidth": 20, + "ht": true, + "mcs": 7 + }, + "station": "18:b4:30:b7:11:a2", + "tx_bytes": 3428522, + "tx_duration": 187024, + "tx_failed": 13, + "tx_offset": 0, + "tx_packets": 34026, + "tx_rate": { + "bitrate": 65000, + "chwidth": 20, + "ht": true, + "mcs": 7, + "sgi": true + }, + "tx_retries": 0 + }, + { + "bssid": "48:e1:e9:3d:a2:06", + "connected": 1256955, + "deltas": { + "rx_bytes": 546, + "rx_packets": 8, + "tx_bytes": 526, + "tx_failed": 1, + "tx_offset": 0, + "tx_packets": 7, + "tx_retries": 0 + }, + "inactive": 17, + "msdu": [ + { + "rx_msdu": 162991, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + }, + { + "rx_msdu": 0, + "tx_msdu": 0, + "tx_msdu_failed": 0, + "tx_msdu_retries": 0 + } + ], + "rssi": -65, + "rx_bytes": 11418291, + "rx_packets": 163010, + "rx_rate": { + "bitrate": 11000, + "chwidth": 20, + "ht": true, + "mcs": 5, + "sgi": true + }, + "station": "48:e1:e9:3d:a2:06", + "tx_bytes": 9950518, + "tx_duration": 2603010, + "tx_failed": 2027, + "tx_offset": 0, + "tx_packets": 123572, + "tx_rate": { + "bitrate": 48000, + "chwidth": 20 + }, + "tx_retries": 0 + } + ], + "bssid": "90:3c:b3:bb:1e:f7", + "iface": "wlan1", + "mode": "ap", + "phy": "platform/soc/c000000.wifi+1", + "radio": { + "$ref": "#/radios/1" + }, + "ssid": "petunia" + } + ], + "uptime": 1319998 + } + ], + "link-state": { + "lan": { + "eth1": { + "carrier": 0 + }, + "eth2": { + "carrier": 0 + } + }, + "wan": { + "eth0": { + "carrier": 0 + } + } + }, + "radios": [ + { + "active_ms": 1319570519, + "busy_ms": 57586707, + "channel": 36, + "channel_width": "80", + "noise": -104, + "phy": "platform/soc/c000000.wifi", + "receive_ms": 6548669, + "temperature": 47, + "transmit_ms": 19698623, + "tx_power": 23 + }, + { + "active_ms": 1319560001, + "busy_ms": 130190566, + "channel": 11, + "channel_width": "20", + "noise": -99, + "phy": "platform/soc/c000000.wifi+1", + "receive_ms": 325756, + "temperature": 46, + "transmit_ms": 13548246, + "tx_power": 10 + } + ], + "unit": { + "load": [ + 0.005859, + 0.022461, + 0 + ], + "localtime": 1646893048, + "memory": { + "buffered": 8839168, + "cached": 25149440, + "free": 792580096, + "total": 973135872 + }, + "uptime": 1320021 + }, + "version": 1 +} \ No newline at end of file diff --git a/stats_sample/nat_stats.json b/stats_sample/nat_stats.json new file mode 100644 index 0000000..7a1e47e --- /dev/null +++ b/stats_sample/nat_stats.json @@ -0,0 +1,150 @@ +{ + "interfaces": [ + { + "clients": [ + { + "ipv4_addresses": [ + "10.2.140.145" + ], + "mac": "00:23:a4:05:05:95", + "ports": [ + "eth1" + ] + }, + { + "ipv4_addresses": [ + "10.2.0.1" + ], + "ipv6_addresses": [ + "fe80:0:0:0:a8a2:caff:fe45:bc6b" + ], + "mac": "e2:63:da:86:64:8e", + "ports": [ + "eth1" + ] + } + ], + "counters": { + "collisions": 0, + "multicast": 662754, + "rx_bytes": 151712263, + "rx_dropped": 0, + "rx_errors": 0, + "rx_packets": 939389, + "tx_bytes": 17826254, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 91600 + }, + "dns_servers": [ + "10.2.0.1" + ], + "ipv4": { + "addresses": [ + "10.2.172.66/16" + ], + "dhcp_server": "10.2.0.1", + "leasetime": 86400 + }, + "location": "/interfaces/0", + "name": "up0v0", + "uptime": 116194 + }, + { + "counters": { + "collisions": 0, + "multicast": 819, + "rx_bytes": 12894844, + "rx_dropped": 0, + "rx_errors": 0, + "rx_packets": 79306, + "tx_bytes": 31429410, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 92656 + }, + "ipv4": { + "addresses": [ + "192.168.1.1/24" + ] + }, + "location": "/interfaces/1", + "name": "down1v0", + "ssids": [ + { + "bssid": "04:f8:f8:fc:37:74", + "iface": "wlan0", + "mode": "ap", + "phy": "soc/1b700000.pci/pci0001:00/0001:00:00.0/0001:01:00.0", + "radio": { + "$ref": "#/radios/0" + }, + "ssid": "OpenWifi-fc3771" + }, + { + "bssid": "04:f8:f8:fc:37:73", + "iface": "wlan1", + "mode": "ap", + "phy": "soc/1b900000.pci/pci0002:00/0002:00:00.0/0002:01:00.0", + "radio": { + "$ref": "#/radios/1" + }, + "ssid": "OpenWifi-fc3771" + } + ], + "uptime": 116195 + } + ], + "link-state": { + "lan": { + "eth1": { + "carrier": 0 + } + }, + "wan": { + "eth0": { + "carrier": 0 + } + } + }, + "radios": [ + { + "active_ms": 116149120, + "busy_ms": 1061014, + "channel": 157, + "channel_width": "40", + "noise": -102, + "phy": "soc/1b700000.pci/pci0001:00/0001:00:00.0/0001:01:00.0", + "receive_ms": 749022, + "transmit_ms": 130980, + "tx_power": 24 + }, + { + "active_ms": 116142427, + "busy_ms": 4820047, + "channel": 1, + "channel_width": "20", + "noise": -94, + "phy": "soc/1b900000.pci/pci0002:00/0002:00:00.0/0002:01:00.0", + "receive_ms": 1345110, + "transmit_ms": 121020, + "tx_power": 24 + } + ], + "unit": { + "load": [ + 0, + 0, + 0 + ], + "localtime": 1646897100, + "memory": { + "buffered": 6762496, + "cached": 17715200, + "free": 100237312, + "total": 217239552 + }, + "uptime": 116225 + }, + "version": 1 +} \ No newline at end of file