wireshark/ui/qt/wlan_statistics_dialog.cpp

758 lines
26 KiB
C++

/* wlan_statistics_dialog.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "wlan_statistics_dialog.h"
#include <epan/packet.h>
#include <epan/strutil.h>
#include <epan/tap.h>
#include <epan/dissectors/packet-ieee80211.h>
#include <QElapsedTimer>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <ui/qt/models/percent_bar_delegate.h>
#include <ui/qt/utils/qt_ui_utils.h>
#include "main_application.h"
// To do:
// - Add the name resolution checkbox
// - Add the "Only show defined networks" checkbox
enum {
col_bssid_,
col_channel_,
col_ssid_,
col_pct_packets_,
col_pct_retry_,
col_retry_packets_,
col_beacons_,
col_data_packets_,
col_probe_reqs_,
col_probe_resps_,
col_auths_,
col_deauths_,
col_others_,
col_protection_
};
enum {
wlan_network_row_type_ = 1000,
wlan_station_row_type_
};
class WlanStationTreeWidgetItem : public QTreeWidgetItem
{
public:
WlanStationTreeWidgetItem(const address *addr) :
QTreeWidgetItem (wlan_station_row_type_),
packets_(0),
retry_(0),
sent_(0),
received_(0),
probe_req_(0),
probe_resp_(0),
auth_(0),
deauth_(0),
other_(0)
{
copy_address(&addr_, addr);
setText(col_bssid_, address_to_qstring(&addr_));
}
bool isMatch(const address *addr) {
return addresses_equal(&addr_, addr);
}
void update(const wlan_hdr_t *wlan_hdr) {
bool is_sender = addresses_equal(&addr_, &wlan_hdr->src);
if (wlan_hdr->stats.fc_retry != 0) {
retry_++;
}
// XXX Should we count received probes and auths? This is what the
// GTK+ UI does, but it seems odd.
switch (wlan_hdr->type) {
case MGT_PROBE_REQ:
probe_req_++;
break;
case MGT_PROBE_RESP:
probe_resp_++;
break;
case MGT_BEACON:
// Skip
break;
case MGT_AUTHENTICATION:
auth_++;
break;
case MGT_DEAUTHENTICATION:
deauth_++;
break;
case DATA:
case DATA_CF_ACK:
case DATA_CF_POLL:
case DATA_CF_ACK_POLL:
case DATA_QOS_DATA:
case DATA_QOS_DATA_CF_ACK:
case DATA_QOS_DATA_CF_POLL:
case DATA_QOS_DATA_CF_ACK_POLL:
if (is_sender) {
sent_++;
} else {
received_++;
}
break;
default:
other_++;
break;
}
if (wlan_hdr->type != MGT_BEACON) packets_++;
}
void draw(address *bssid, int num_packets) {
if (packets_ && num_packets > 0) {
setData(col_pct_packets_, Qt::UserRole, QVariant::fromValue<double>(packets_ * 100.0 / num_packets));
setData(col_pct_retry_, Qt::UserRole, QVariant::fromValue<double>(retry_ * 100.0 / packets_));
} else {
setData(col_pct_packets_, Qt::UserRole, QVariant::fromValue<double>(0));
setData(col_pct_retry_, Qt::UserRole, QVariant::fromValue<double>(0));
}
setText(col_beacons_, QString::number(sent_));
setText(col_data_packets_, QString::number(received_));
setText(col_retry_packets_, QString::number(retry_));
setText(col_probe_reqs_, QString::number(probe_req_));
setText(col_probe_resps_, QString::number(probe_resp_));
setText(col_auths_, QString::number(auth_));
setText(col_deauths_, QString::number(deauth_));
setText(col_others_, QString::number(other_));
if (!is_broadcast_bssid(bssid) && addresses_data_equal(&addr_, bssid)) {
setText(col_protection_, QObject::tr("Base station"));
}
}
bool operator< (const QTreeWidgetItem &other) const
{
if (other.type() != wlan_station_row_type_) return QTreeWidgetItem::operator< (other);
const WlanStationTreeWidgetItem *other_row = static_cast<const WlanStationTreeWidgetItem *>(&other);
switch (treeWidget()->sortColumn()) {
case col_bssid_:
return cmp_address(&addr_, &other_row->addr_) < 0;
case col_pct_packets_:
return packets_ < other_row->packets_;
case col_beacons_:
return sent_ < other_row->sent_;
case col_data_packets_:
return received_ < other_row->received_;
case col_probe_reqs_:
return probe_req_ < other_row->probe_req_;
case col_probe_resps_:
return probe_resp_ < other_row->probe_resp_;
case col_auths_:
return auth_ < other_row->auth_;
case col_deauths_:
return deauth_ < other_row->deauth_;
case col_others_:
return other_ < other_row->other_;
case col_retry_packets_:
case col_pct_retry_:
return retry_ < other_row->retry_;
default:
break;
}
return QTreeWidgetItem::operator< (other);
}
QList<QVariant> rowData() {
return QList<QVariant>()
<< address_to_qstring(&addr_)
<< data(col_pct_packets_, Qt::UserRole).toDouble()
<< data(col_pct_retry_, Qt::UserRole).toDouble() << retry_
<< sent_ << received_ << probe_req_ << probe_resp_
<< auth_ << deauth_ << other_ << text(col_protection_);
}
const QString filterExpression() {
QString filter_expr = QString("wlan.addr==%1")
.arg(address_to_qstring(&addr_));
return filter_expr;
}
private:
address addr_;
int packets_;
int retry_;
int sent_;
int received_;
int probe_req_;
int probe_resp_;
int auth_;
int deauth_;
int other_;
};
class WlanNetworkTreeWidgetItem : public QTreeWidgetItem
{
public:
WlanNetworkTreeWidgetItem(QTreeWidget *parent, const wlan_hdr_t *wlan_hdr) :
QTreeWidgetItem (parent, wlan_network_row_type_),
beacon_(0),
data_packet_(0),
retry_packet_(0),
probe_req_(0),
probe_resp_(0),
auth_(0),
deauth_(0),
other_(0),
packets_(0)
{
updateBssid(wlan_hdr);
channel_ = wlan_hdr->stats.channel;
ssid_ = QByteArray::fromRawData((const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
QString ssid_text;
if (wlan_hdr->stats.ssid_len == 0) {
ssid_text = QObject::tr("<Broadcast>");
} else if (wlan_hdr->stats.ssid_len == 1 && wlan_hdr->stats.ssid[0] == 0) {
ssid_text = QObject::tr("<Hidden>");
} else {
gchar *str = format_text(NULL, (const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
ssid_text = str;
wmem_free(NULL, str);
}
setText(col_ssid_, ssid_text);
}
bool isMatch(const wlan_hdr_t *wlan_hdr) {
bool is_bssid_match = false;
bool is_ssid_match = false;
bool update_bssid = false;
bool update_ssid = false;
// We want (but might not have) a unicast BSSID and a named SSID. Try
// to match the current packet and update our information if possible.
if (addresses_equal(&bssid_, &wlan_hdr->bssid)) {
is_bssid_match = true;
}
if ((wlan_hdr->stats.ssid_len > 0) && (wlan_hdr->stats.ssid[0] != 0)) {
QByteArray hdr_ssid = QByteArray::fromRawData((const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
if (ssid_ == hdr_ssid) {
is_ssid_match = true;
}
}
if (is_bssid_match && is_ssid_match) return true;
// Probe requests.
if (wlan_hdr->type == MGT_PROBE_REQ) {
// Probes with visible SSIDs. Unicast or broadcast.
if (is_ssid_match) {
if (is_broadcast_ && !is_broadcast_bssid(&wlan_hdr->bssid)) {
update_bssid = true;
}
// Probes with hidden SSIDs. Unicast.
} else if ((wlan_hdr->stats.ssid_len == 1) && (wlan_hdr->stats.ssid[0] == 0)) {
if (!is_broadcast_ && addresses_equal(&bssid_, &wlan_hdr->bssid)) {
is_bssid_match = true;
update_ssid = true;
}
// Probes with no SSID. Broadcast.
} else if (ssid_.isEmpty() && wlan_hdr->stats.ssid_len < 1) {
if (is_broadcast_ && is_broadcast_bssid(&wlan_hdr->bssid)) {
return true;
}
}
// Non-probe requests (responses, beacons, etc)
} else {
if (is_ssid_match) {
if (is_broadcast_ && !is_broadcast_bssid(&wlan_hdr->bssid)) {
update_bssid = true;
}
} else if (wlan_hdr->stats.ssid_len < 1) {
// No SSID.
is_ssid_match = true;
}
if (is_bssid_match) {
if ((ssid_.isEmpty() || ssid_[0] == '\0') && (wlan_hdr->stats.ssid_len > 0) && (wlan_hdr->stats.ssid[0] != 0)) {
update_ssid = true;
}
}
}
if (update_bssid) {
updateBssid(wlan_hdr);
is_bssid_match = true;
}
if (update_ssid) {
gchar* str;
ssid_ = QByteArray::fromRawData((const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
str = format_text(NULL, (const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
setText(col_ssid_, str);
wmem_free(NULL, str);
is_ssid_match = true;
}
return is_bssid_match && is_ssid_match;
}
void update(const wlan_hdr_t *wlan_hdr) {
if (channel_ == 0 && wlan_hdr->stats.channel != 0) {
channel_ = wlan_hdr->stats.channel;
}
if (text(col_protection_).isEmpty() && wlan_hdr->stats.protection[0] != 0) {
setText(col_protection_, wlan_hdr->stats.protection);
}
if (wlan_hdr->stats.fc_retry != 0) {
retry_packet_++;
}
switch (wlan_hdr->type) {
case MGT_PROBE_REQ:
probe_req_++;
break;
case MGT_PROBE_RESP:
probe_resp_++;
break;
case MGT_BEACON:
beacon_++;
break;
case MGT_AUTHENTICATION:
auth_++;
break;
case MGT_DEAUTHENTICATION:
deauth_++;
break;
case DATA:
case DATA_CF_ACK:
case DATA_CF_POLL:
case DATA_CF_ACK_POLL:
case DATA_QOS_DATA:
case DATA_QOS_DATA_CF_ACK:
case DATA_QOS_DATA_CF_POLL:
case DATA_QOS_DATA_CF_ACK_POLL:
data_packet_++;
break;
default:
other_++;
break;
}
packets_++;
WlanStationTreeWidgetItem* sender_ws_ti = NULL;
WlanStationTreeWidgetItem* receiver_ws_ti = NULL;
foreach (QTreeWidgetItem *cur_ti, stations_) {
WlanStationTreeWidgetItem *cur_ws_ti = dynamic_cast<WlanStationTreeWidgetItem *>(cur_ti);
if (cur_ws_ti && (cur_ws_ti->isMatch(&wlan_hdr->src))) sender_ws_ti = cur_ws_ti;
if (cur_ws_ti && (cur_ws_ti->isMatch(&wlan_hdr->dst))) receiver_ws_ti = cur_ws_ti;
if (sender_ws_ti && receiver_ws_ti) break;
}
if (!sender_ws_ti) {
sender_ws_ti = new WlanStationTreeWidgetItem(&wlan_hdr->src);
stations_ << sender_ws_ti;
}
if (!receiver_ws_ti) {
receiver_ws_ti = new WlanStationTreeWidgetItem(&wlan_hdr->dst);
stations_ << receiver_ws_ti;
}
sender_ws_ti->update(wlan_hdr);
receiver_ws_ti->update(wlan_hdr);
}
void draw(int num_packets) {
if (channel_ > 0) setText(col_channel_, QString::number(channel_));
setData(col_pct_packets_, Qt::UserRole, QVariant::fromValue<double>(packets_ * 100.0 / num_packets));
setData(col_pct_retry_, Qt::UserRole, QVariant::fromValue<double>(retry_packet_ * 100.0 / packets_));
setText(col_retry_packets_, QString::number(retry_packet_));
setText(col_beacons_, QString::number(beacon_));
setText(col_data_packets_, QString::number(data_packet_));
setText(col_probe_reqs_, QString::number(probe_req_));
setText(col_probe_resps_, QString::number(probe_resp_));
setText(col_auths_, QString::number(auth_));
setText(col_deauths_, QString::number(deauth_));
setText(col_others_, QString::number(other_));
}
void addStations() {
foreach (QTreeWidgetItem *cur_ti, stations_) {
WlanStationTreeWidgetItem *cur_ws_ti = dynamic_cast<WlanStationTreeWidgetItem *>(cur_ti);
cur_ws_ti->draw(&bssid_, packets_ - beacon_);
for (int col = 0; col < treeWidget()->columnCount(); col++) {
// int QTreeWidgetItem::textAlignment(int column) const
// Returns the text alignment for the label in the given column.
// Note: This function returns an int for historical reasons. It will be corrected to return Qt::Alignment in Qt 7.
cur_ws_ti->setTextAlignment(col, static_cast<Qt::Alignment>(treeWidget()->headerItem()->textAlignment(col)));
}
}
addChildren(stations_);
stations_.clear();
}
bool operator< (const QTreeWidgetItem &other) const
{
if (other.type() != wlan_network_row_type_) return QTreeWidgetItem::operator< (other);
const WlanNetworkTreeWidgetItem *other_row = static_cast<const WlanNetworkTreeWidgetItem *>(&other);
switch (treeWidget()->sortColumn()) {
case col_bssid_:
return cmp_address(&bssid_, &other_row->bssid_) < 0;
case col_channel_:
return channel_ < other_row->channel_;
case col_ssid_:
return ssid_ < other_row->ssid_;
case col_pct_packets_:
return packets_ < other_row->packets_;
case col_beacons_:
return beacon_ < other_row->beacon_;
case col_data_packets_:
return data_packet_ < other_row->data_packet_;
case col_probe_reqs_:
return probe_req_ < other_row->probe_req_;
case col_probe_resps_:
return probe_resp_ < other_row->probe_resp_;
case col_auths_:
return auth_ < other_row->auth_;
case col_deauths_:
return deauth_ < other_row->deauth_;
case col_others_:
return other_ < other_row->other_;
case col_protection_:
default:
break;
}
return QTreeWidgetItem::operator< (other);
}
QList<QVariant> rowData() {
return QList<QVariant>()
<< address_to_qstring(&bssid_) << channel_ << text(col_ssid_)
<< data(col_pct_packets_, Qt::UserRole).toDouble()
<< data(col_pct_retry_, Qt::UserRole).toDouble()
<< retry_packet_ << beacon_ << data_packet_ << probe_req_
<< probe_resp_ << auth_ << deauth_ << other_
<< text(col_protection_);
}
const QString filterExpression() {
QString filter_expr = QString("(wlan.bssid==%1")
.arg(address_to_qstring(&bssid_));
if (!ssid_.isEmpty() && ssid_[0] != '\0') {
filter_expr += QString(" || wlan.ssid==\"%1\"")
.arg(ssid_.constData());
}
filter_expr += ")";
return filter_expr;
}
private:
address bssid_;
bool is_broadcast_;
int channel_;
QByteArray ssid_;
int beacon_;
int data_packet_;
int retry_packet_;
int probe_req_;
int probe_resp_;
int auth_;
int deauth_;
int other_;
int packets_;
// Adding items one at a time is slow. Gather up the stations in a list
// and add them all at once later.
QList<QTreeWidgetItem *>stations_;
void updateBssid(const wlan_hdr_t *wlan_hdr) {
copy_address(&bssid_, &wlan_hdr->bssid);
is_broadcast_ = is_broadcast_bssid(&bssid_);
setText(col_bssid_, address_to_qstring(&bssid_));
}
};
static const QString network_col_0_title_ = QObject::tr("BSSID");
static const QString network_col_6_title_ = QObject::tr("Beacons");
static const QString network_col_7_title_ = QObject::tr("Data Pkts");
static const QString network_col_13_title_ = QObject::tr("Protection");
static const QString node_col_0_title_ = QObject::tr("Address");
static const QString node_col_4_title_ = QObject::tr("Pkts Sent");
static const QString node_col_5_title_ = QObject::tr("Pkts Received");
static const QString node_col_11_title_ = QObject::tr("Comment");
WlanStatisticsDialog::WlanStatisticsDialog(QWidget &parent, CaptureFile &cf, const char *filter) :
TapParameterDialog(parent, cf, HELP_STATS_WLAN_TRAFFIC_DIALOG),
packet_count_(0),
cur_network_(0),
add_station_timer_(0)
{
setWindowSubtitle(tr("Wireless LAN Statistics"));
loadGeometry(parent.width() * 4 / 5, parent.height() * 3 / 4, "WlanStatisticsDialog");
QStringList header_labels = QStringList()
<< "" << tr("Channel") << tr("SSID") << tr("Percent Packets") << tr("Percent Retry")
<< tr("Retry") << "" << "" << tr("Probe Reqs") << tr("Probe Resp") << tr("Auths")
<< tr("Deauths") << tr("Other");
statsTreeWidget()->setHeaderLabels(header_labels);
updateHeaderLabels();
packets_delegate_ = new PercentBarDelegate();
statsTreeWidget()->setItemDelegateForColumn(col_pct_packets_, packets_delegate_);
retry_delegate_ = new PercentBarDelegate();
statsTreeWidget()->setItemDelegateForColumn(col_pct_retry_, retry_delegate_);
statsTreeWidget()->sortByColumn(col_bssid_, Qt::AscendingOrder);
// resizeColumnToContents doesn't work well here, so set sizes manually.
int one_em = fontMetrics().height();
for (int col = 0; col < statsTreeWidget()->columnCount() - 1; col++) {
switch (col) {
case col_bssid_:
statsTreeWidget()->setColumnWidth(col, one_em * 11);
break;
case col_ssid_:
statsTreeWidget()->setColumnWidth(col, one_em * 8);
break;
case col_pct_packets_:
case col_pct_retry_:
case col_protection_:
statsTreeWidget()->setColumnWidth(col, one_em * 6);
break;
default:
// The rest are numeric
statsTreeWidget()->setColumnWidth(col, one_em * 4);
statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
break;
}
}
addFilterActions();
if (filter) {
setDisplayFilter(filter);
}
add_station_timer_ = new QElapsedTimer();
connect(statsTreeWidget(), SIGNAL(itemSelectionChanged()),
this, SLOT(updateHeaderLabels()));
// Set handler for when display filter string is changed.
connect(this, SIGNAL(updateFilter(QString)),
this, SLOT(filterUpdated(QString)));
}
WlanStatisticsDialog::~WlanStatisticsDialog()
{
delete packets_delegate_;
delete retry_delegate_;
delete add_station_timer_;
}
void WlanStatisticsDialog::tapReset(void *ws_dlg_ptr)
{
WlanStatisticsDialog *ws_dlg = static_cast<WlanStatisticsDialog *>(ws_dlg_ptr);
if (!ws_dlg) return;
ws_dlg->statsTreeWidget()->clear();
ws_dlg->packet_count_ = 0;
}
tap_packet_status WlanStatisticsDialog::tapPacket(void *ws_dlg_ptr, _packet_info *, epan_dissect *, const void *wlan_hdr_ptr, tap_flags_t)
{
WlanStatisticsDialog *ws_dlg = static_cast<WlanStatisticsDialog *>(ws_dlg_ptr);
const wlan_hdr_t *wlan_hdr = (const wlan_hdr_t *)wlan_hdr_ptr;
if (!ws_dlg || !wlan_hdr) return TAP_PACKET_DONT_REDRAW;
guint16 frame_type = wlan_hdr->type & 0xff0;
if (!((frame_type == 0x0) || (frame_type == 0x20) || (frame_type == 0x30))
|| ((frame_type == 0x20) && DATA_FRAME_IS_NULL(wlan_hdr->type))) {
/* Not a management or non null data or extension frame; let's skip it */
return TAP_PACKET_DONT_REDRAW;
}
ws_dlg->packet_count_++;
// XXX This is very slow for large numbers of networks. We might be
// able to store networks in a cache keyed on BSSID+SSID instead.
WlanNetworkTreeWidgetItem *wn_ti = NULL;
for (int i = 0; i < ws_dlg->statsTreeWidget()->topLevelItemCount(); i++) {
QTreeWidgetItem *ti = ws_dlg->statsTreeWidget()->topLevelItem(i);
if (ti->type() != wlan_network_row_type_) continue;
WlanNetworkTreeWidgetItem *cur_wn_ti = static_cast<WlanNetworkTreeWidgetItem*>(ti);
if (cur_wn_ti->isMatch(wlan_hdr)) {
wn_ti = cur_wn_ti;
break;
}
}
if (!wn_ti) {
wn_ti = new WlanNetworkTreeWidgetItem(ws_dlg->statsTreeWidget(), wlan_hdr);
for (int col = 0; col < ws_dlg->statsTreeWidget()->columnCount(); col++) {
// int QTreeWidgetItem::textAlignment(int column) const
// Returns the text alignment for the label in the given column.
// Note: This function returns an int for historical reasons. It will be corrected to return Qt::Alignment in Qt 7.
wn_ti->setTextAlignment(col, static_cast<Qt::Alignment>(ws_dlg->statsTreeWidget()->headerItem()->textAlignment(col)));
}
}
wn_ti->update(wlan_hdr);
return TAP_PACKET_REDRAW;
}
void WlanStatisticsDialog::tapDraw(void *ws_dlg_ptr)
{
WlanStatisticsDialog *ws_dlg = static_cast<WlanStatisticsDialog *>(ws_dlg_ptr);
if (!ws_dlg) return;
for (int i = 0; i < ws_dlg->statsTreeWidget()->topLevelItemCount(); i++) {
QTreeWidgetItem *ti = ws_dlg->statsTreeWidget()->topLevelItem(i);
if (ti->type() != wlan_network_row_type_) continue;
WlanNetworkTreeWidgetItem *wn_ti = static_cast<WlanNetworkTreeWidgetItem*>(ti);
wn_ti->draw(ws_dlg->packet_count_);
}
}
const QString WlanStatisticsDialog::filterExpression()
{
QString filter_expr;
if (statsTreeWidget()->selectedItems().count() > 0) {
QTreeWidgetItem *ti = statsTreeWidget()->selectedItems()[0];
if (ti->type() == wlan_network_row_type_) {
WlanNetworkTreeWidgetItem *wn_ti = static_cast<WlanNetworkTreeWidgetItem*>(ti);
filter_expr = wn_ti->filterExpression();
} else if (ti->type() == wlan_station_row_type_) {
WlanStationTreeWidgetItem *ws_ti = static_cast<WlanStationTreeWidgetItem*>(ti);
filter_expr = ws_ti->filterExpression();
}
}
return filter_expr;
}
void WlanStatisticsDialog::fillTree()
{
if (!registerTapListener("wlan",
this,
displayFilter_.toLatin1().data(),
TL_REQUIRES_NOTHING,
tapReset,
tapPacket,
tapDraw)) {
reject();
return;
}
statsTreeWidget()->setSortingEnabled(false);
cap_file_.retapPackets();
tapDraw(this);
removeTapListeners();
statsTreeWidget()->setSortingEnabled(true);
// Don't freeze if we have a large number of stations.
cur_network_ = 0;
QTimer::singleShot(0, this, SLOT(addStationTreeItems()));
}
static const int add_station_interval_ = 5; // ms
void WlanStatisticsDialog::addStationTreeItems()
{
add_station_timer_->start();
while (add_station_timer_->elapsed() < add_station_interval_ && cur_network_ < statsTreeWidget()->topLevelItemCount()) {
QTreeWidgetItem *ti = statsTreeWidget()->topLevelItem(cur_network_);
if (ti->type() != wlan_network_row_type_) continue;
WlanNetworkTreeWidgetItem *wn_ti = static_cast<WlanNetworkTreeWidgetItem*>(ti);
wn_ti->addStations();
++cur_network_;
}
if (cur_network_ < statsTreeWidget()->topLevelItemCount()) {
QTimer::singleShot(0, this, SLOT(addStationTreeItems()));
}
}
void WlanStatisticsDialog::updateHeaderLabels()
{
if (statsTreeWidget()->selectedItems().count() > 0 && statsTreeWidget()->selectedItems()[0]->type() == wlan_station_row_type_) {
statsTreeWidget()->headerItem()->setText(col_bssid_, node_col_0_title_);
statsTreeWidget()->headerItem()->setText(col_beacons_, node_col_4_title_);
statsTreeWidget()->headerItem()->setText(col_data_packets_, node_col_5_title_);
statsTreeWidget()->headerItem()->setText(col_protection_, node_col_11_title_);
} else {
statsTreeWidget()->headerItem()->setText(col_bssid_, network_col_0_title_);
statsTreeWidget()->headerItem()->setText(col_beacons_, network_col_6_title_);
statsTreeWidget()->headerItem()->setText(col_data_packets_, network_col_7_title_);
statsTreeWidget()->headerItem()->setText(col_protection_, network_col_13_title_);
}
}
void WlanStatisticsDialog::captureFileClosing()
{
remove_tap_listener(this);
WiresharkDialog::captureFileClosing();
}
// Store filter from signal.
void WlanStatisticsDialog::filterUpdated(QString filter)
{
displayFilter_ = filter;
}
// This is how an item is represented for exporting.
QList<QVariant> WlanStatisticsDialog::treeItemData(QTreeWidgetItem *it) const
{
// Cast up to our type.
WlanNetworkTreeWidgetItem *nit = dynamic_cast<WlanNetworkTreeWidgetItem*>(it);
if (nit) {
return nit->rowData();
}
// TODO: not going to cast to WlanStationTreeWidgetItem* and do the same as
// some of the columns are different...
return QList<QVariant>();
}
// Stat command + args
static void
wlan_statistics_init(const char *args, void*) {
QStringList args_l = QString(args).split(',');
QByteArray filter;
if (args_l.length() > 2) {
filter = QStringList(args_l.mid(2)).join(",").toUtf8();
}
mainApp->emitStatCommandSignal("WlanStatistics", filter.constData(), NULL);
}
static stat_tap_ui wlan_statistics_ui = {
REGISTER_STAT_GROUP_GENERIC,
NULL,
"wlan,stat",
wlan_statistics_init,
0,
NULL
};
extern "C" {
void register_tap_listener_qt_wlan_statistics(void);
void
register_tap_listener_qt_wlan_statistics(void)
{
register_stat_tap_ui(&wlan_statistics_ui, NULL);
}
}