wireshark/ui/qt/wireless_frame.cpp

314 lines
10 KiB
C++

/* wireless_frame.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 "wireless_frame.h"
#include <ui_wireless_frame.h>
#include "config.h"
#include <glib.h>
#include <capchild/capture_session.h>
#include <capchild/capture_sync.h>
#include <caputils/ws80211_utils.h>
#include <ui/ui_util.h>
#include <ui/utf8_entities.h>
#include <QProcess>
// To do:
// - Disable or hide invalid channel types.
// - Push more status messages ("switched to...") to the status bar.
// - Add a "Decrypt in the driver" checkbox?
// - Check for frequency and channel type changes.
// Questions:
// - From our perspective, what's the difference between "NOHT" and "HT20"?
const int update_interval_ = 1500; // ms
WirelessFrame::WirelessFrame(QWidget *parent) :
QFrame(parent),
ui(new Ui::WirelessFrame),
interfaces_(NULL),
capture_in_progress_(false)
{
ui->setupUi(this);
ui->helperToolButton->hide();
if (ws80211_init() == 0) {
ui->stackedWidget->setEnabled(true);
ui->stackedWidget->setCurrentWidget(ui->interfacePage);
#ifdef HAVE_AIRPCAP
// We should arguably add ws80211_get_helper_name and ws80211_get_helper_tooltip.
// This works for now and is translatable.
ui->helperToolButton->setText(tr("AirPcap Control Panel"));
ui->helperToolButton->setToolTip(tr("Open the AirPcap Control Panel"));
ui->helperToolButton->show();
ui->helperToolButton->setEnabled(ws80211_get_helper_path() != NULL);
#endif
} else {
ui->stackedWidget->setEnabled(false);
ui->stackedWidget->setCurrentWidget(ui->noWirelessPage);
}
ui->fcsFilterFrame->setVisible(ws80211_has_fcs_filter());
updateWidgets();
startTimer(update_interval_);
}
WirelessFrame::~WirelessFrame()
{
delete ui;
}
void WirelessFrame::setCaptureInProgress(bool capture_in_progress)
{
capture_in_progress_ = capture_in_progress;
updateWidgets();
}
// Check to see if the ws80211 interface list matches the one in our
// combobox. Rebuild ours if necessary and select the first interface if
// the current selection goes away.
void WirelessFrame::timerEvent(QTimerEvent *)
{
ws80211_free_interfaces(interfaces_);
interfaces_ = ws80211_find_interfaces();
const QString old_iface = ui->interfaceComboBox->currentText();
guint iface_count = 0;
bool list_changed = false;
if (interfaces_ && interfaces_->len > 0) {
iface_count = interfaces_->len;
}
if ((int) iface_count != ui->interfaceComboBox->count()) {
list_changed = true;
} else {
for (guint i = 0; i < iface_count; i++) {
struct ws80211_interface *iface = g_array_index(interfaces_, struct ws80211_interface *, i);
if (ui->interfaceComboBox->itemText(i).compare(iface->ifname) != 0) {
list_changed = true;
break;
}
}
}
if (list_changed) {
ui->interfaceComboBox->clear();
for (guint i = 0; i < iface_count; i++) {
struct ws80211_interface *iface = g_array_index(interfaces_, struct ws80211_interface *, i);
ui->interfaceComboBox->addItem(iface->ifname);
if (old_iface.compare(iface->ifname) == 0) {
ui->interfaceComboBox->setCurrentIndex(ui->interfaceComboBox->count() - 1);
}
}
}
if (ui->interfaceComboBox->currentText().compare(old_iface) != 0) {
on_channelComboBox_activated(ui->interfaceComboBox->currentIndex());
}
}
Q_DECLARE_METATYPE(struct ws80211_interface *)
void WirelessFrame::updateWidgets()
{
bool enable_interface = false;
bool enable_channel = false;
bool enable_offset = false;
bool enable_show_fcs = false;
if (ui->interfaceComboBox->count() > 0) {
enable_interface = true;
enable_show_fcs = true;
}
if (enable_interface && ui->channelComboBox->count() > 0) {
enable_channel = true;
}
if (enable_channel && ui->channelTypeComboBox->count() > 1) {
enable_offset = true;
}
ui->interfaceComboBox->setEnabled(enable_interface);
ui->channelComboBox->setEnabled(enable_channel);
ui->channelTypeComboBox->setEnabled(enable_offset);
ui->fcsComboBox->setEnabled(!capture_in_progress_ && enable_show_fcs);
}
void WirelessFrame::on_helperToolButton_clicked()
{
const QString helper_path = ws80211_get_helper_path();
if (helper_path.isEmpty()) return;
QString command = QString("\"%1\"").arg(helper_path);
QProcess::startDetached(command);
}
void WirelessFrame::on_prefsToolButton_clicked()
{
emit showWirelessPreferences(QString("wlan"));
}
void WirelessFrame::on_interfaceComboBox_currentIndexChanged(const QString &cur_iface)
{
ui->channelComboBox->clear();
ui->channelTypeComboBox->clear();
if (cur_iface.isEmpty()) {
updateWidgets();
return;
}
for (guint i = 0; i < interfaces_->len; i++) {
struct ws80211_interface *iface = g_array_index(interfaces_, struct ws80211_interface *, i);
if (cur_iface.compare(iface->ifname) == 0) {
struct ws80211_iface_info iface_info;
QString units = " GHz";
ws80211_get_iface_info(iface->ifname, &iface_info);
for (guint i = 0; i < iface->frequencies->len; i++) {
guint32 frequency = g_array_index(iface->frequencies, guint32, i);
double ghz = frequency / 1000.0;
QString chan_str = QString("%1 " UTF8_MIDDLE_DOT " %2%3")
.arg(ws80211_frequency_to_channel(frequency))
.arg(ghz, 0, 'f', 3)
.arg(units);
ui->channelComboBox->addItem(chan_str, frequency);
if ((int)frequency == iface_info.current_freq) {
ui->channelComboBox->setCurrentIndex(ui->channelComboBox->count() - 1);
}
units = QString();
}
// XXX - Do we need to make a distinction between WS80211_CHAN_NO_HT
// and WS80211_CHAN_HT20? E.g. is there a driver that won't capture
// HT frames if you use WS80211_CHAN_NO_HT?
ui->channelTypeComboBox->addItem("20 MHz", WS80211_CHAN_NO_HT);
if (iface_info.current_chan_type == WS80211_CHAN_NO_HT || iface_info.current_chan_type == WS80211_CHAN_HT20) {
ui->channelTypeComboBox->setCurrentIndex(0);
}
if (iface->channel_types & (1 << WS80211_CHAN_HT40MINUS)) {
ui->channelTypeComboBox->addItem("HT 40-", WS80211_CHAN_HT40MINUS);
if (iface_info.current_chan_type == WS80211_CHAN_HT40MINUS) {
ui->channelTypeComboBox->setCurrentIndex(ui->channelTypeComboBox->count() - 1);
}
}
if (iface->channel_types & (1 << WS80211_CHAN_HT40PLUS)) {
ui->channelTypeComboBox->addItem("HT 40+", WS80211_CHAN_HT40PLUS);
if (iface_info.current_chan_type == WS80211_CHAN_HT40PLUS) {
ui->channelTypeComboBox->setCurrentIndex(ui->channelTypeComboBox->count() - 1);
}
}
if (ws80211_has_fcs_filter()) {
ui->fcsComboBox->setCurrentIndex(iface_info.current_fcs_validation);
}
}
}
updateWidgets();
}
void WirelessFrame::setChannel()
{
QString cur_iface = ui->interfaceComboBox->currentText();
int cur_chan_idx = ui->channelComboBox->currentIndex();
int cur_type_idx = ui->channelTypeComboBox->currentIndex();
if (cur_iface.isEmpty() || cur_chan_idx < 0 || cur_type_idx < 0) return;
#if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
const QString frequency = ui->channelComboBox->itemData(cur_chan_idx).toString();
int chan_type = ui->channelTypeComboBox->itemData(cur_type_idx).toInt();
const gchar *chan_type_s = ws80211_chan_type_to_str(chan_type);
gchar *data, *primary_msg, *secondary_msg;
int ret;
if (frequency.isEmpty() || chan_type < 0) return;
ret = sync_interface_set_80211_chan(cur_iface.toUtf8().constData(), frequency.toUtf8().constData(), chan_type_s,
&data, &primary_msg, &secondary_msg, main_window_update);
g_free(data);
g_free(primary_msg);
g_free(secondary_msg);
/* Parse the error msg */
if (ret) {
QString err_str = tr("Unable to set channel or offset.");
emit pushAdapterStatus(err_str);
}
#elif defined(HAVE_AIRPCAP)
int frequency = ui->channelComboBox->itemData(cur_chan_idx).toInt();
int chan_type = ui->channelTypeComboBox->itemData(cur_type_idx).toInt();
if (frequency < 0 || chan_type < 0) return;
if (ws80211_set_freq(cur_iface.toUtf8().constData(), frequency, chan_type) != 0) {
QString err_str = tr("Unable to set channel or offset.");
emit pushAdapterStatus(err_str);
}
#endif
updateWidgets();
}
void WirelessFrame::on_channelComboBox_activated(int)
{
setChannel();
}
void WirelessFrame::on_channelTypeComboBox_activated(int)
{
setChannel();
}
void WirelessFrame::on_fcsComboBox_activated(int index)
{
QString cur_iface = ui->interfaceComboBox->currentText();
if (cur_iface.isEmpty()) return;
if (ws80211_set_fcs_validation(cur_iface.toUtf8().constData(), (enum ws80211_fcs_validation) index) != 0) {
QString err_str = tr("Unable to set FCS validation behavior.");
emit pushAdapterStatus(err_str);
}
updateWidgets();
}
/*
* 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:
*/