aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/address.h19
-rw-r--r--epan/dissectors/packet-ieee80211.c16
-rw-r--r--epan/dissectors/packet-ieee80211.h17
-rw-r--r--epan/wslua/taps2
-rw-r--r--ui/gtk/wlan_stat_dlg.c24
-rw-r--r--ui/qt/CMakeLists.txt4
-rw-r--r--ui/qt/Makefile.common15
-rw-r--r--ui/qt/Wireshark.pro9
-rw-r--r--ui/qt/main_window.h3
-rw-r--r--ui/qt/main_window.ui18
-rw-r--r--ui/qt/main_window_slots.cpp16
-rw-r--r--ui/qt/multicast_statistics_dialog.cpp7
-rw-r--r--ui/qt/percent_bar_delegate.cpp94
-rw-r--r--ui/qt/percent_bar_delegate.h54
-rw-r--r--ui/qt/protocol_hierarchy_dialog.cpp55
-rw-r--r--ui/qt/protocol_hierarchy_dialog.h23
-rw-r--r--ui/qt/wlan_statistics_dialog.cpp679
-rw-r--r--ui/qt/wlan_statistics_dialog.h66
18 files changed, 1007 insertions, 114 deletions
diff --git a/epan/address.h b/epan/address.h
index c48cc7020d..5855d22641 100644
--- a/epan/address.h
+++ b/epan/address.h
@@ -143,6 +143,25 @@ addresses_equal(const address *addr1, const address *addr2) {
}
#define ADDRESSES_EQUAL(addr1, addr2) addresses_equal((addr1), (addr2))
+/** Check the data of two addresses for equality.
+ *
+ * Given two addresses, return "true" if they have the same length and,
+ * their data is equal, "false" otherwise.
+ * The address types are ignored. This can be used to compare custom
+ * address types defined with address_type_dissector_register.
+ *
+ * @param addr1 [in] The first address to compare.
+ * @param addr2 [in] The second address to compare.
+ * @return TRUE if the adresses are equal, FALSE otherwise.
+ */
+static inline gboolean
+addresses_data_equal(const address *addr1, const address *addr2) {
+ if ( addr1->len == addr2->len
+ && memcmp(addr1->data, addr2->data, addr1->len) == 0
+ ) return TRUE;
+ return FALSE;
+}
+
/** Copy an address, allocating a new buffer for the address data.
*
* @param to [in,out] The destination address.
diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c
index 53e782109a..13f36e620e 100644
--- a/epan/dissectors/packet-ieee80211.c
+++ b/epan/dissectors/packet-ieee80211.c
@@ -5177,6 +5177,11 @@ static const enum_val_t wlan_ignore_wep_options[] = {
static int wlan_address_type = -1;
static int wlan_bssid_address_type = -1;
+static address bssid_broadcast;
+gboolean is_broadcast_bssid(const address *bssid) {
+ return addresses_equal(&bssid_broadcast, bssid);
+}
+
static dissector_handle_t ieee80211_handle;
static dissector_handle_t llc_handle;
static dissector_handle_t ipx_handle;
@@ -5294,7 +5299,7 @@ static int
wlan_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
{
conv_hash_t *hash = (conv_hash_t*) pct;
- const wlan_hdr *whdr=(const wlan_hdr *)vip;
+ const wlan_hdr_t *whdr=(const wlan_hdr_t *)vip;
add_conversation_table_data(hash, &whdr->src, &whdr->dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->fd->abs_ts, &wlan_ct_dissector_info, PT_NONE);
@@ -5315,7 +5320,7 @@ static int
wlan_hostlist_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
{
conv_hash_t *hash = (conv_hash_t*) pit;
- const wlan_hdr *whdr=(const wlan_hdr *)vip;
+ const wlan_hdr_t *whdr=(const wlan_hdr_t *)vip;
/* Take two "add" passes per packet, adding for each direction, ensures that all
packets are counted properly (even if address is sending to itself)
@@ -16558,14 +16563,14 @@ dissect_ieee80211_common (tvbuff_t *tvb, packet_info *pinfo,
gint meshctl_len = 0;
guint8 mesh_flags;
guint16 meshoff = 0;
- static wlan_hdr whdrs[4];
+ static wlan_hdr_t whdrs[4];
gboolean retransmitted;
gboolean isDMG = (tree == NULL) ? FALSE : proto_tree_traverse_post_order(proto_tree_get_root(tree), is_80211ad, NULL);
volatile encap_t encap_type;
proto_tree *volatile hdr_tree = NULL;
tvbuff_t *volatile next_tvb = NULL;
- wlan_hdr *volatile whdr;
+ wlan_hdr_t *volatile whdr;
AIRPDCAP_KEY_ITEM used_key;
@@ -26923,6 +26928,8 @@ proto_register_ieee80211 (void)
module_t *wlan_module;
+ const unsigned char bssid_broadcast_data[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
memset(&wlan_stats, 0, sizeof wlan_stats);
proto_aggregate = proto_register_protocol("IEEE 802.11 wireless LAN aggregate frame",
@@ -26963,6 +26970,7 @@ proto_register_ieee80211 (void)
ether_len, ether_name_resolution_str, ether_name_resolution_len);
wlan_bssid_address_type = address_type_dissector_register("AT_ETHER_BSSID", "WLAN BSSID Address", ether_to_str, ether_str_len, wlan_bssid_col_filter_str,
ether_len, ether_name_resolution_str, ether_name_resolution_len);
+ set_address(&bssid_broadcast, wlan_bssid_address_type, 6, bssid_broadcast_data);
/* Register configuration options */
wlan_module = prefs_register_protocol(proto_wlan, init_wepkeys);
diff --git a/epan/dissectors/packet-ieee80211.h b/epan/dissectors/packet-ieee80211.h
index df63bf2e77..93fa7fcf89 100644
--- a/epan/dissectors/packet-ieee80211.h
+++ b/epan/dissectors/packet-ieee80211.h
@@ -27,6 +27,10 @@
#include "ws_symbol_export.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
WS_DLL_PUBLIC
void capture_ieee80211 (const guchar *, int, int, packet_counts *);
void capture_ieee80211_datapad (const guchar *, int, int, packet_counts *);
@@ -65,6 +69,13 @@ WS_DLL_PUBLIC const float ieee80211_float_htrates[MAX_MCS_INDEX+1][2][2];
WS_DLL_PUBLIC value_string_ext ieee80211_supported_rates_vals_ext;
+WS_DLL_PUBLIC
+gboolean is_broadcast_bssid(const address *bssid);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
/*
* Extract the protocol version from the frame control field
*/
@@ -225,12 +236,12 @@ WS_DLL_PUBLIC value_string_ext ieee80211_supported_rates_vals_ext;
*/
#define EXTENSION_DMG_BEACON 0x30 /* Extension DMG beacon */
-struct _wlan_stats {
+typedef struct _wlan_stats {
guint8 channel;
guint8 ssid_len;
guchar ssid[MAX_SSID_LEN];
gchar protection[MAX_PROTECT_LEN];
-};
+} wlan_stats_t;
typedef struct _wlan_hdr {
address bssid;
@@ -238,7 +249,7 @@ typedef struct _wlan_hdr {
address dst;
guint16 type;
struct _wlan_stats stats;
-} wlan_hdr;
+} wlan_hdr_t;
#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000
#define WLANCAP_MAGIC_COOKIE_V1 0x80211001
diff --git a/epan/wslua/taps b/epan/wslua/taps
index 56f4242a5b..eee8176bcf 100644
--- a/epan/wslua/taps
+++ b/epan/wslua/taps
@@ -76,5 +76,5 @@ smb2 ../dissectors/packet-smb2.h smb2_info_t
tcp ../dissectors/packet-tcp.h tcp_info_t
#teredo ../dissectors/packet-teredo.h teredo_info_t
#tr ../dissectors/packet-tr.h tr_info_t
-wlan ../dissectors/packet-ieee80211.h wlan_hdr
+wlan ../dissectors/packet-ieee80211.h wlan_hdr_t
#wsp ../dissectors/packet-wsp.h wsp_info_t
diff --git a/ui/gtk/wlan_stat_dlg.c b/ui/gtk/wlan_stat_dlg.c
index 672c672813..c6e16451e5 100644
--- a/ui/gtk/wlan_stat_dlg.c
+++ b/ui/gtk/wlan_stat_dlg.c
@@ -122,7 +122,6 @@ typedef struct wlan_ep {
static GtkWidget *wlanstat_dlg_w = NULL;
static GtkWidget *wlanstat_pane = NULL;
static GtkWidget *wlanstat_name_lb = NULL;
-static address broadcast;
/* used to keep track of the statistics for an entire program interface */
typedef struct _wlan_stat_t {
@@ -358,10 +357,10 @@ wlanstat_packet_details (wlan_ep_t *te, guint32 type, const address *addr, gbool
}
}
+#if 0
static gboolean
is_broadcast(const address *addr)
{
-#if 0
gboolean cmp_addr;
char* addr_str = address_to_display(NULL, addr);
@@ -370,9 +369,9 @@ is_broadcast(const address *addr)
/* doesn't work if MAC resolution is disable */
return cmp_addr;
-#endif
return ADDRESSES_EQUAL(&broadcast, addr);
}
+#endif
static gboolean
ssid_equal(const struct _wlan_stats *st1, const struct _wlan_stats *st2 )
@@ -380,7 +379,7 @@ ssid_equal(const struct _wlan_stats *st1, const struct _wlan_stats *st2 )
return ((st1->ssid_len <= sizeof(st1->ssid)) && st1->ssid_len == st2->ssid_len) && (memcmp(st1->ssid, st2->ssid, st1->ssid_len) == 0);
}
-static int
+static gboolean
wlanstat_packet (void *phs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *phi)
{
wlanstat_t *hs = (wlanstat_t *)phs;
@@ -389,19 +388,19 @@ wlanstat_packet (void *phs, packet_info *pinfo, epan_dissect_t *edt _U_, const v
guint16 frame_type = si->type & 0xff0;
if (!hs)
- return (0);
+ return FALSE;
if (!((frame_type == 0x0) || (frame_type == 0x20) || (frame_type == 0x30))
|| ((frame_type == 0x20) && DATA_FRAME_IS_NULL(si->type))) {
/* Not a management or non null data or extension frame; let's skip it */
- return (0);
+ return FALSE;
}
hs->number_of_packets++;
if (!hs->ep_list) {
hs->ep_list = alloc_wlan_ep (si, pinfo);
te = hs->ep_list;
- te->is_broadcast = is_broadcast(&si->bssid);
+ te->is_broadcast = is_broadcast_bssid(&si->bssid);
} else {
for (tmp = hs->ep_list; tmp; tmp = tmp->next) {
if ((((si->type == MGT_PROBE_REQ) && (
@@ -417,7 +416,7 @@ wlanstat_packet (void *phs, packet_info *pinfo, epan_dissect_t *edt _U_, const v
if (!te) {
te = alloc_wlan_ep (si, pinfo);
- te->is_broadcast = is_broadcast(&si->bssid);
+ te->is_broadcast = is_broadcast_bssid(&si->bssid);
te->next = hs->ep_list;
hs->ep_list = te;
}
@@ -488,7 +487,7 @@ wlanstat_packet (void *phs, packet_info *pinfo, epan_dissect_t *edt _U_, const v
wlanstat_packet_details (te, si->type, &si->src, TRUE); /* Register source */
wlanstat_packet_details (te, si->type, &si->dst, FALSE); /* Register destination */
- return (1);
+ return TRUE;
}
static void
@@ -508,8 +507,8 @@ wlanstat_draw_details(wlanstat_t *hs, wlan_ep_t *wlan_ep, gboolean clear)
hs->num_details = 0;
for (tmp = wlan_ep->details; tmp; tmp=tmp->next) {
- broadcast_flag = is_broadcast(&tmp->addr);
- basestation_flag = !broadcast_flag && !CMP_ADDRESS(&tmp->addr, &wlan_ep->bssid);
+ broadcast_flag = is_broadcast_bssid(&tmp->addr);
+ basestation_flag = !broadcast_flag && addresses_data_equal(&tmp->addr, &wlan_ep->bssid);
if ((wlan_ep->number_of_packets - wlan_ep->type[MGT_BEACON]) > 0) {
f = (float)(((float)tmp->number_of_packets * 100.0) / (wlan_ep->number_of_packets - wlan_ep->type[MGT_BEACON]));
@@ -1989,9 +1988,6 @@ wlanstat_launch (GtkAction *action _U_, gpointer user_data _U_)
void
register_tap_listener_wlanstat (void)
{
- static const unsigned char src[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
- SET_ADDRESS(&broadcast, AT_ETHER, 6, src);
}
/*
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index b43922fedb..b19093f7c0 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -92,6 +92,7 @@ set(WIRESHARK_QT_HEADERS
packet_list.h
packet_list_model.h
packet_range_group_box.h
+ percent_bar_delegate.h
preference_editor_frame.h
preferences_dialog.h
print_dialog.h
@@ -132,6 +133,7 @@ set(WIRESHARK_QT_HEADERS
wireless_frame.h
wireshark_application.h
wireshark_dialog.h
+ wlan_statistics_dialog.h
)
if(HAVE_PCAP_REMOTE)
@@ -224,6 +226,7 @@ set(WIRESHARK_QT_SRC
packet_list_model.cpp
packet_list_record.cpp
packet_range_group_box.cpp
+ percent_bar_delegate.cpp
preference_editor_frame.cpp
preferences_dialog.cpp
print_dialog.cpp
@@ -292,6 +295,7 @@ set(WIRESHARK_QT_TAP_SRC
sctp_all_assocs_dialog.cpp
sctp_assoc_analyse_dialog.cpp
stats_tree_dialog.cpp
+ wlan_statistics_dialog.cpp
)
set(WIRESHARK_QT_FILES
diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common
index 142b511444..d6232989ea 100644
--- a/ui/qt/Makefile.common
+++ b/ui/qt/Makefile.common
@@ -99,7 +99,8 @@ NODIST_GENERATED_HEADER_FILES = \
ui_traffic_table_dialog.h \
ui_uat_dialog.h \
ui_voip_calls_dialog.h \
- ui_wireless_frame.h
+ ui_wireless_frame.h \
+ ui_wlan_statistics_dialog.h
# Generated C source files that we want in the distribution.
GENERATED_C_FILES = \
@@ -206,6 +207,7 @@ MOC_HDRS = \
packet_list.h \
packet_list_model.h \
packet_range_group_box.h \
+ percent_bar_delegate.h \
preference_editor_frame.h \
preferences_dialog.h \
print_dialog.h \
@@ -248,8 +250,8 @@ MOC_HDRS = \
voip_calls_dialog.h \
wireless_frame.h \
wireshark_application.h \
- wireshark_dialog.h
-
+ wireshark_dialog.h \
+ wlan_statistics_dialog.h
#
# .ui files.
@@ -324,7 +326,8 @@ UI_FILES = \
traffic_table_dialog.ui \
uat_dialog.ui \
voip_calls_dialog.ui \
- wireless_frame.ui
+ wireless_frame.ui \
+ wlan_statistics_dialog.ui
#
# The .moc.cpp files generated from them.
@@ -444,6 +447,7 @@ WIRESHARK_QT_SRC = \
packet_list_model.cpp \
packet_list_record.cpp \
packet_range_group_box.cpp \
+ percent_bar_delegate.cpp \
preference_editor_frame.cpp \
preferences_dialog.cpp \
print_dialog.cpp \
@@ -495,7 +499,8 @@ WIRESHARK_QT_TAP_SRC = \
rtp_stream_dialog.cpp \
sctp_all_assocs_dialog.cpp \
sctp_assoc_analyse_dialog.cpp \
- stats_tree_dialog.cpp
+ stats_tree_dialog.cpp \
+ wlan_statistics_dialog.cpp
noinst_HEADERS = \
$(MOC_HDRS) \
diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro
index 627a66e8e4..8e1445cf1f 100644
--- a/ui/qt/Wireshark.pro
+++ b/ui/qt/Wireshark.pro
@@ -279,7 +279,6 @@ FORMS += \
voip_calls_dialog.ui \
wireless_frame.ui
-
HEADERS += $$HEADERS_WS_C \
about_dialog.h \
accordion_frame.h \
@@ -329,6 +328,7 @@ HEADERS += $$HEADERS_WS_C \
packet_comment_dialog.h \
packet_dialog.h \
packet_format_group_box.h \
+ percent_bar_delegate.h \
preference_editor_frame.h \
preferences_dialog.h \
print_dialog.h \
@@ -358,7 +358,8 @@ HEADERS += $$HEADERS_WS_C \
traffic_table_dialog.h \
uat_dialog.h \
voip_calls_dialog.h \
- wireless_frame.h
+ wireless_frame.h \
+ wlan_statistics_dialog.h
win32 {
OBJECTS_WS_C = $$SOURCES_WS_C
@@ -642,7 +643,7 @@ HEADERS += \
time_shift_dialog.h \
wireshark_application.h \
wireshark_dialog.h \
-
+ wlan_statistics_dialog.h
SOURCES += \
about_dialog.cpp \
@@ -718,6 +719,7 @@ SOURCES += \
packet_list_model.cpp \
packet_list_record.cpp \
packet_range_group_box.cpp \
+ percent_bar_delegate.cpp \
preference_editor_frame.cpp \
preferences_dialog.cpp \
print_dialog.cpp \
@@ -763,4 +765,5 @@ SOURCES += \
wireless_frame.cpp \
wireshark_application.cpp \
wireshark_dialog.cpp \
+ wlan_statistics_dialog.cpp \
../../wireshark-qt.cpp
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index ad17ef355d..380c9ced41 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -480,6 +480,9 @@ private slots:
void statCommandMulticastStatistics(const char *arg, void *);
void on_actionStatisticsUdpMulticastStreams_triggered();
+ void statCommandWlanStatistics(const char *arg, void *);
+ void on_actionWirelessWlanStatistics_triggered();
+
void openStatisticsTreeDialog(const gchar *abbr);
void on_actionStatistics29WestTopics_Advertisements_by_Topic_triggered();
void on_actionStatistics29WestTopics_Advertisements_by_Source_triggered();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index 75c1971388..cec6122cc4 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -576,13 +576,15 @@
<addaction name="actionEditConfigurationProfiles"/>
<addaction name="actionEditPreferences"/>
</widget>
- <widget class="QMenu" name="menuBluetooth">
+ <widget class="QMenu" name="menuWireless">
<property name="title">
- <string>&amp;Bluetooth</string>
+ <string>&amp;Wireless</string>
</property>
<addaction name="actionATT_Server_Attributes"/>
<addaction name="actionDevices"/>
<addaction name="actionHCI_Summary"/>
+ <addaction name="separator"/>
+ <addaction name="actionWirelessWlanStatistics"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
@@ -598,8 +600,8 @@
<addaction name="menuAnalyze"/>
<addaction name="menuStatistics"/>
<addaction name="menuTelephony"/>
+ <addaction name="menuWireless"/>
<addaction name="menuTools"/>
- <addaction name="menuBluetooth"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
@@ -2385,7 +2387,7 @@
</action>
<action name="actionATT_Server_Attributes">
<property name="text">
- <string>ATT Server Attributes</string>
+ <string>Bluetooth ATT Server Attributes</string>
</property>
</action>
<action name="actionDevices">
@@ -2646,6 +2648,14 @@
<string>Show UTP multicast stream statistics.</string>
</property>
</action>
+ <action name="actionWirelessWlanStatistics">
+ <property name="text">
+ <string>WLAN Traffic</string>
+ </property>
+ <property name="toolTip">
+ <string>Show IEEE 802.11 wireless LAN statistics.</string>
+ </property>
+ </action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index 25b6030e8f..05d0d550e1 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -98,6 +98,7 @@
#if HAVE_EXTCAP
#include "extcap_options_dialog.h"
#endif
+#include "filter_action.h"
#include "filter_dialog.h"
#include "funnel_statistics.h"
#include "gsm_map_summary_dialog.h"
@@ -130,7 +131,7 @@
#include "multicast_statistics_dialog.h"
#include "voip_calls_dialog.h"
#include "wireshark_application.h"
-#include "filter_action.h"
+#include "wlan_statistics_dialog.h"
#include <QClipboard>
#include <QFileInfo>
@@ -2571,6 +2572,19 @@ void MainWindow::on_actionSCTPFilterThisAssociation_triggered()
}
}
+void MainWindow::statCommandWlanStatistics(const char *arg, void *)
+{
+ WlanStatisticsDialog *wlan_stats_dlg = new WlanStatisticsDialog(*this, capture_file_, arg);
+ connect(wlan_stats_dlg, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
+ this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
+ wlan_stats_dlg->show();
+}
+
+void MainWindow::on_actionWirelessWlanStatistics_triggered()
+{
+ statCommandWlanStatistics(NULL, NULL);
+}
+
void MainWindow::statCommandExpertInfo(const char *, void *)
{
ExpertInfoDialog *expert_dialog = new ExpertInfoDialog(*this, capture_file_);
diff --git a/ui/qt/multicast_statistics_dialog.cpp b/ui/qt/multicast_statistics_dialog.cpp
index 4b4da27446..c818ce4e3f 100644
--- a/ui/qt/multicast_statistics_dialog.cpp
+++ b/ui/qt/multicast_statistics_dialog.cpp
@@ -306,10 +306,6 @@ void MulticastStatisticsDialog::tapDraw(void *mti_ptr)
ms_ti->updateStreamInfo(stream_info);
cur_row++;
}
-
- for (int col = 0; col < ms_dlg->statsTreeWidget()->columnCount() - 1; col++) {
- ms_dlg->statsTreeWidget()->resizeColumnToContents(col);
- }
}
const QString MulticastStatisticsDialog::filterExpression()
@@ -442,6 +438,9 @@ void MulticastStatisticsDialog::fillTree()
tapDraw(tapinfo_);
foreach (QWidget *w, disable_widgets) w->setEnabled(true);
+ for (int col = 0; col < statsTreeWidget()->columnCount() - 1; col++) {
+ statsTreeWidget()->resizeColumnToContents(col);
+ }
updateWidgets();
}
diff --git a/ui/qt/percent_bar_delegate.cpp b/ui/qt/percent_bar_delegate.cpp
new file mode 100644
index 0000000000..06ee6f422c
--- /dev/null
+++ b/ui/qt/percent_bar_delegate.cpp
@@ -0,0 +1,94 @@
+/* percent_bar_delegate.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "percent_bar_delegate.h"
+
+#include "color_utils.h"
+
+#include <QApplication>
+#include <QPainter>
+
+static const int bar_em_width_ = 8;
+static const double bar_blend_ = 0.15;
+
+void PercentBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QStyleOptionViewItemV4 optv4 = option;
+ QStyledItemDelegate::initStyleOption(&optv4, index);
+ double value = index.data(Qt::UserRole).toDouble();
+
+ QStyledItemDelegate::paint(painter, option, index);
+
+ painter->save();
+
+ if (QApplication::style()->objectName().contains("vista")) {
+ // QWindowsVistaStyle::drawControl does this internally. Unfortunately there
+ // doesn't appear to be a more general way to do this.
+ optv4.palette.setColor(QPalette::All, QPalette::HighlightedText,
+ optv4.palette.color(QPalette::Active, QPalette::Text));
+ }
+
+ QColor bar_color = ColorUtils::alphaBlend(optv4.palette.windowText(),
+ optv4.palette.window(), bar_blend_);
+ QPalette::ColorGroup cg = optv4.state & QStyle::State_Enabled
+ ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(optv4.state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+ if (optv4.state & QStyle::State_Selected) {
+ painter->setPen(optv4.palette.color(cg, QPalette::HighlightedText));
+ bar_color = ColorUtils::alphaBlend(optv4.palette.color(cg, QPalette::Window),
+ optv4.palette.color(cg, QPalette::Highlight),
+ bar_blend_);
+ } else {
+ painter->setPen(optv4.palette.color(cg, QPalette::Text));
+ }
+
+ QRect pct_rect = option.rect;
+ pct_rect.adjust(1, 1, -1, -1);
+ pct_rect.setWidth(((pct_rect.width() * value) / 100.0) + 0.5);
+ painter->fillRect(pct_rect, bar_color);
+
+ QString pct_str = QString::number(value, 'f', 1);
+ painter->drawText(option.rect, Qt::AlignCenter, pct_str);
+
+ painter->restore();
+}
+
+QSize PercentBarDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ return QSize(option.fontMetrics.height() * bar_em_width_,
+ QStyledItemDelegate::sizeHint(option, index).height());
+}
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/percent_bar_delegate.h b/ui/qt/percent_bar_delegate.h
new file mode 100644
index 0000000000..4bd2473e86
--- /dev/null
+++ b/ui/qt/percent_bar_delegate.h
@@ -0,0 +1,54 @@
+/* percent_bar_delegate.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef PERCENTBARDELEGATE_H
+#define PERCENTBARDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class PercentBarDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ PercentBarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) { }
+protected:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+};
+
+#endif // PERCENTBARDELEGATE_H
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/protocol_hierarchy_dialog.cpp b/ui/qt/protocol_hierarchy_dialog.cpp
index 61f65de72e..05a498003d 100644
--- a/ui/qt/protocol_hierarchy_dialog.cpp
+++ b/ui/qt/protocol_hierarchy_dialog.cpp
@@ -27,12 +27,10 @@
#include "ui/proto_hier_stats.h"
#include "ui/utf8_entities.h"
-#include "color_utils.h"
#include "qt_ui_utils.h"
#include "wireshark_application.h"
#include <QClipboard>
-#include <QPainter>
#include <QPushButton>
#include <QTextStream>
#include <QTreeWidgetItemIterator>
@@ -58,59 +56,6 @@ const int end_packets_col_ = 6;
const int end_bytes_col_ = 7;
const int end_bandwidth_col_ = 8;
-const int bar_em_width_ = 8;
-const double bar_blend_ = 0.15;
-void PercentBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
- const QModelIndex &index) const
-{
- QStyleOptionViewItemV4 optv4 = option;
- QStyledItemDelegate::initStyleOption(&optv4, index);
- double value = index.data(Qt::UserRole).toDouble();
-
- QStyledItemDelegate::paint(painter, option, index);
-
- painter->save();
-
- if (QApplication::style()->objectName().contains("vista")) {
- // QWindowsVistaStyle::drawControl does this internally. Unfortunately there
- // doesn't appear to be a more general way to do this.
- optv4.palette.setColor(QPalette::All, QPalette::HighlightedText,
- optv4.palette.color(QPalette::Active, QPalette::Text));
- }
-
- QColor bar_color = ColorUtils::alphaBlend(optv4.palette.windowText(),
- optv4.palette.window(), bar_blend_);
- QPalette::ColorGroup cg = optv4.state & QStyle::State_Enabled
- ? QPalette::Normal : QPalette::Disabled;
- if (cg == QPalette::Normal && !(optv4.state & QStyle::State_Active))
- cg = QPalette::Inactive;
- if (optv4.state & QStyle::State_Selected) {
- painter->setPen(optv4.palette.color(cg, QPalette::HighlightedText));
- bar_color = ColorUtils::alphaBlend(optv4.palette.color(cg, QPalette::Window),
- optv4.palette.color(cg, QPalette::Highlight),
- bar_blend_);
- } else {
- painter->setPen(optv4.palette.color(cg, QPalette::Text));
- }
-
- QRect pct_rect = option.rect;
- pct_rect.adjust(1, 1, -1, -1);
- pct_rect.setWidth(((pct_rect.width() * value) / 100.0) + 0.5);
- painter->fillRect(pct_rect, bar_color);
-
- QString pct_str = QString::number(value, 'f', 1);
- painter->drawText(option.rect, Qt::AlignCenter, pct_str);
-
- painter->restore();
-}
-
-QSize PercentBarDelegate::sizeHint(const QStyleOptionViewItem &option,
- const QModelIndex &index) const
-{
- return QSize(option.fontMetrics.height() * bar_em_width_,
- QStyledItemDelegate::sizeHint(option, index).height());
-}
-
Q_DECLARE_METATYPE(ph_stats_t*)
class ProtocolHierarchyTreeWidgetItem : public QTreeWidgetItem
diff --git a/ui/qt/protocol_hierarchy_dialog.h b/ui/qt/protocol_hierarchy_dialog.h
index 1c0fb47c59..b3963cd4df 100644
--- a/ui/qt/protocol_hierarchy_dialog.h
+++ b/ui/qt/protocol_hierarchy_dialog.h
@@ -22,11 +22,12 @@
#ifndef PROTOCOL_HIERARCHY_DIALOG_H
#define PROTOCOL_HIERARCHY_DIALOG_H
+#include <QMenu>
+
#include "filter_action.h"
+#include "percent_bar_delegate.h"
#include "wireshark_dialog.h"
-#include <QMenu>
-
class QPushButton;
class QTreeWidgetItem;
@@ -34,24 +35,6 @@ namespace Ui {
class ProtocolHierarchyDialog;
}
-#include <QStyledItemDelegate>
-
-class PercentBarDelegate : public QStyledItemDelegate
-{
-public:
- PercentBarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) { }
-// void clear();
-// void addRelatedFrame(int frame_num);
-// void setConversationSpan(int first_frame, int last_frame);
-protected:
- void paint(QPainter *painter, const QStyleOptionViewItem &option,
- const QModelIndex &index) const;
- QSize sizeHint(const QStyleOptionViewItem &option,
- const QModelIndex &index) const;
-
-private:
-};
-
class ProtocolHierarchyDialog : public WiresharkDialog
{
Q_OBJECT
diff --git a/ui/qt/wlan_statistics_dialog.cpp b/ui/qt/wlan_statistics_dialog.cpp
new file mode 100644
index 0000000000..181001a6ed
--- /dev/null
+++ b/ui/qt/wlan_statistics_dialog.cpp
@@ -0,0 +1,679 @@
+/* wlan_statistics_dialog.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "wlan_statistics_dialog.h"
+
+#include <epan/packet.h>
+#include <epan/strutil.h>
+#include <epan/tap.h>
+
+#include <epan/dissectors/packet-ieee80211.h>
+
+#include <QMessageBox>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+
+#include "percent_bar_delegate.h"
+#include "qt_ui_utils.h"
+#include "wireshark_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_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(address *addr) :
+ QTreeWidgetItem (wlan_station_row_type_),
+ packets_(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(address *addr) {
+ return (addresses_equal(&addr_, addr)) == TRUE;
+ }
+ void update(wlan_hdr_t *wlan_hdr) {
+ bool is_sender = addresses_equal(&addr_, &wlan_hdr->src) == TRUE;
+
+ // 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) {
+ setData(col_pct_packets_, Qt::UserRole, QVariant::fromValue<double>(packets_ * 100.0 / num_packets));
+ setText(col_beacons_, QString::number(sent_));
+ setText(col_data_packets_, QString::number(received_));
+ 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_;
+ default:
+ break;
+ }
+
+ return QTreeWidgetItem::operator< (other);
+ }
+ QList<QVariant> rowData() {
+ return QList<QVariant>()
+ << address_to_qstring(&addr_)
+ << data(col_pct_packets_, Qt::UserRole).toDouble()
+ << 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 sent_;
+ int received_;
+ int probe_req_;
+ int probe_resp_;
+ int auth_;
+ int deauth_;
+ int other_;
+};
+
+class WlanNetworkTreeWidgetItem : public QTreeWidgetItem
+{
+public:
+ WlanNetworkTreeWidgetItem(QTreeWidget *parent, wlan_hdr_t *wlan_hdr) :
+ QTreeWidgetItem (parent, wlan_network_row_type_),
+ beacon_(0),
+ data_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 {
+ ssid_text = format_text(wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
+ }
+
+ setText(col_ssid_, ssid_text);
+ }
+
+ bool isMatch(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) {
+ ssid_ = QByteArray::fromRawData((const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len);
+ setText(col_ssid_, format_text(wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len));
+ is_ssid_match = true;
+ }
+
+ return is_bssid_match && is_ssid_match;
+ }
+
+ void update(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);
+ }
+ 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->isMatch(&wlan_hdr->src)) sender_ws_ti = cur_ws_ti;
+ if (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));
+ 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++) {
+ cur_ws_ti->setTextAlignment(col, 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()
+ << 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_mgt.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 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(wlan_hdr_t *wlan_hdr) {
+ copy_address(&bssid_, &wlan_hdr->bssid);
+ is_broadcast_ = is_broadcast_bssid(&bssid_) == TRUE;
+ setText(col_bssid_, address_to_qstring(&bssid_));
+ }
+};
+
+static const QString network_col_0_title_ = QObject::tr("BSSID");
+static const QString network_col_4_title_ = QObject::tr("Beacons");
+static const QString network_col_5_title_ = QObject::tr("Data Pkts");
+static const QString network_col_11_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 = NULL) :
+ TapParameterDialog(parent, cf, HELP_STATS_WLAN_TRAFFIC_DIALOG)
+{
+ setWindowSubtitle(tr("Wireless LAN Statistics"));
+
+ // XXX Use recent settings instead
+ resize(parent.width() * 4 / 5, parent.height() * 3 / 4);
+
+ QStringList header_labels = QStringList()
+ << "" << tr("Channel") << tr("SSID") << tr("Percent Packets") << "" << ""
+ << tr("Probe Reqs") << tr("Probe Resp") << tr("Auths")
+ << tr("Deauths") << tr("Other");
+ statsTreeWidget()->setHeaderLabels(header_labels);
+ updateHeaderLabels();
+ statsTreeWidget()->setItemDelegateForColumn(col_pct_packets_, new PercentBarDelegate());
+ 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_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();
+
+ connect(statsTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
+ this, SLOT(updateHeaderLabels()));
+}
+
+WlanStatisticsDialog::~WlanStatisticsDialog()
+{
+}
+
+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;
+}
+
+gboolean WlanStatisticsDialog::tapPacket(void *ws_dlg_ptr, _packet_info *, epan_dissect *, const void *wlan_hdr_ptr)
+{
+ WlanStatisticsDialog *ws_dlg = static_cast<WlanStatisticsDialog *>(ws_dlg_ptr);
+ wlan_hdr_t *wlan_hdr = (wlan_hdr_t *)wlan_hdr_ptr;
+ if (!ws_dlg || !wlan_hdr) return FALSE;
+
+ 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 FALSE;
+ }
+
+ ws_dlg->packet_count_++;
+
+ 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++) {
+ wn_ti->setTextAlignment(col, ws_dlg->statsTreeWidget()->headerItem()->textAlignment(col));
+ }
+ }
+
+ wn_ti->update(wlan_hdr);
+ return TRUE;
+}
+
+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()
+{
+ GString *error_string = register_tap_listener("wlan",
+ this,
+ NULL,
+ TL_REQUIRES_NOTHING,
+ tapReset,
+ tapPacket,
+ tapDraw);
+ if (error_string) {
+ QMessageBox::warning(this, tr("Endpoint expert failed to register tap listener"),
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ reject();
+ return;
+ }
+
+ cap_file_.retapPackets();
+ tapDraw(this);
+ remove_tap_listener(this);
+
+ for (int i = 0; i < statsTreeWidget()->topLevelItemCount(); i++) {
+ QTreeWidgetItem *ti = statsTreeWidget()->topLevelItem(i);
+ if (ti->type() != wlan_network_row_type_) continue;
+
+ WlanNetworkTreeWidgetItem *wn_ti = static_cast<WlanNetworkTreeWidgetItem*>(ti);
+ wn_ti->addStations();
+ }
+}
+
+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_4_title_);
+ statsTreeWidget()->headerItem()->setText(col_data_packets_, network_col_5_title_);
+ statsTreeWidget()->headerItem()->setText(col_protection_, network_col_11_title_);
+ }
+}
+
+void WlanStatisticsDialog::captureFileClosing()
+{
+ remove_tap_listener(this);
+ updateWidgets();
+}
+
+// Stat command + args
+
+static void
+wlan_statistics_init(const char *, void*) {
+ wsApp->emitStatCommandSignal("WlanStatistics", NULL, 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)
+{
+ register_stat_tap_ui(&wlan_statistics_ui, NULL);
+}
+}
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/wlan_statistics_dialog.h b/ui/qt/wlan_statistics_dialog.h
new file mode 100644
index 0000000000..e39f4b6427
--- /dev/null
+++ b/ui/qt/wlan_statistics_dialog.h
@@ -0,0 +1,66 @@
+/* wlan_statistics_dialog.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef WLANSTATISTICSDIALOG_H
+#define WLANSTATISTICSDIALOG_H
+
+#include "tap_parameter_dialog.h"
+
+class WlanStatisticsDialog : public TapParameterDialog
+{
+ Q_OBJECT
+
+public:
+ WlanStatisticsDialog(QWidget &parent, CaptureFile &cf, const char *filter);
+ ~WlanStatisticsDialog();
+
+protected:
+
+private:
+ int packet_count_;
+
+ // Callbacks for register_tap_listener
+ static void tapReset(void *ws_dlg_ptr);
+ static gboolean tapPacket(void *ws_dlg_ptr, struct _packet_info *, struct epan_dissect *, const void *wlan_hdr_ptr);
+ static void tapDraw(void *ws_dlg_ptr);
+
+ virtual const QString filterExpression();
+
+private slots:
+ virtual void fillTree();
+ void updateHeaderLabels();
+ void captureFileClosing();
+};
+
+#endif // WLANSTATISTICSDIALOG_H
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */