}"
HAVE_NL80211_SPLIT_WIPHY_DUMP
)
+ check_c_source_compiles(
+ "#include <linux/nl80211.h>
+ int main() {
+ enum nl80211_attrs x = NL80211_ATTR_VHT_CAPABILITY;
+ }"
+ HAVE_NL80211_VHT_CAPABILITY
+ )
endif()
#
int
sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar *type,
+ const gchar *center_freq1, const gchar *center_freq2,
gchar **data, gchar **primary_msg,
gchar **secondary_msg, void (*update_cb)(void))
{
argv = sync_pipe_add_arg(argv, &argc, iface);
if (type)
- opt = g_strdup_printf("%s,%s", freq, type);
+ opt = g_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2);
else
opt = g_strdup_printf("%s", freq);
/** Set wireless channel using dumpcap */
extern int
sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar *type,
+ const gchar *center_freq1, const gchar *center_freq2,
gchar **data, gchar **primary_msg,
gchar **secondary_msg, void (*update_cb)(void));
}
#endif /* NL80211_BAND_ATTR_HT_CAPA */
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+static void parse_band_vht_capa(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ guint32 chan_capa;
+ if (!tb) return;
+
+ chan_capa = (nla_get_u32(tb) >> 2) & 3;
+ if (chan_capa == 1) {
+ iface->channel_types |= 1 << WS80211_CHAN_VHT160;
+ }
+ if (chan_capa == 2) {
+ iface->channel_types |= 1 << WS80211_CHAN_VHT160;
+ iface->channel_types |= 1 << WS80211_CHAN_VHT80P80;
+ }
+ iface->channel_types |= 1 << WS80211_CHAN_VHT80;
+}
+#endif /* HAVE_NL80211_VHT_CAPABILITY */
+
static void parse_supported_iftypes(struct ws80211_interface *iface,
struct nlattr *tb)
{
#ifdef NL80211_BAND_ATTR_HT_CAPA
parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
#endif /* NL80211_BAND_ATTR_HT_CAPA */
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+ parse_band_vht_capa(iface, tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
+#endif /* HAVE_NL80211_VHT_CAPABILITY */
parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
}
}
}
if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
+ gboolean found_ch_width = FALSE;
iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
-
- if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+ if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
+ switch (nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])) {
+ case NL80211_CHAN_WIDTH_80:
+ iface_info->pub->current_chan_type = WS80211_CHAN_VHT80;
+ found_ch_width = TRUE;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ iface_info->pub->current_chan_type = WS80211_CHAN_VHT80P80;
+ found_ch_width = TRUE;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ iface_info->pub->current_chan_type = WS80211_CHAN_VHT160;
+ found_ch_width = TRUE;
+ break;
+ }
+ }
+ if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) {
+ iface_info->pub->current_center_freq1 =
+ nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]);
+ }
+ if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) {
+ iface_info->pub->current_center_freq2 =
+ nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]);
+ }
+#endif
+ if (!found_ch_width && tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
case NL80211_CHAN_NO_HT:
int i;
unsigned int j;
- struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, WS80211_FCS_ALL};
+ struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, -1, -1, WS80211_FCS_ALL};
struct __iface_info iface_info;
struct ws80211_interface *iface;
}
DIAG_ON(shorten-64-to-32)
-int ws80211_set_freq(const char *name, int freq, int chan_type)
+int ws80211_set_freq(const char *name, int freq, int chan_type, int _U_ center_freq, int _U_ center_freq2)
{
int devidx, err;
struct nl_msg *msg;
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
break;
#endif
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+ case WS80211_CHAN_VHT80:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
+ break;
+ case WS80211_CHAN_VHT80P80:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80P80);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, center_freq2);
+ break;
+
+ case WS80211_CHAN_VHT160:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_160);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
+ break;
+#endif
default:
break;
}
ret = WS80211_CHAN_HT40MINUS;
if (!strcmp(s, CHAN_HT40PLUS))
ret = WS80211_CHAN_HT40PLUS;
+ if (!strcmp(s, CHAN_VHT80))
+ ret = WS80211_CHAN_VHT80;
+ if (!strcmp(s, CHAN_VHT80P80))
+ ret = WS80211_CHAN_VHT80P80;
+ if (!strcmp(s, CHAN_VHT160))
+ ret = WS80211_CHAN_VHT160;
+
return ret;
}
return CHAN_HT40MINUS;
case WS80211_CHAN_HT40PLUS:
return CHAN_HT40PLUS;
+ case WS80211_CHAN_VHT80:
+ return CHAN_VHT80;
+ case WS80211_CHAN_VHT80P80:
+ return CHAN_VHT80P80;
+ case WS80211_CHAN_VHT160:
+ return CHAN_VHT160;
}
return NULL;
}
return 0;
}
-int ws80211_set_freq(const char *name, int freq, int chan_type)
+int ws80211_set_freq(const char *name, int freq, int chan_type, int _U_ center_freq, int _U_ center_freq2)
{
GList *airpcap_if_list;
int err;
return -1;
}
-int ws80211_set_freq(const char *name _U_, int freq _U_, int _U_ chan_type)
+int ws80211_set_freq(const char *name _U_, int freq _U_, int _U_ chan_type, int _U_ center_freq, int _U_ center_freq2)
{
return -1;
}
WS80211_CHAN_NO_HT,
WS80211_CHAN_HT20,
WS80211_CHAN_HT40MINUS,
- WS80211_CHAN_HT40PLUS
+ WS80211_CHAN_HT40PLUS,
+ WS80211_CHAN_VHT80,
+ WS80211_CHAN_VHT80P80,
+ WS80211_CHAN_VHT160
};
#define CHAN_NO_HT "NOHT"
#define CHAN_HT20 "HT20"
#define CHAN_HT40MINUS "HT40-"
#define CHAN_HT40PLUS "HT40+"
+#define CHAN_VHT80 "VHT80"
+#define CHAN_VHT80P80 "VHT80+80"
+#define CHAN_VHT160 "VHT160"
/* XXX This doesn't match AirpcapValidationType. Should it? */
enum ws80211_fcs_validation {
struct ws80211_iface_info {
int current_freq;
enum ws80211_channel_type current_chan_type;
+ int current_center_freq1;
+ int current_center_freq2;
enum ws80211_fcs_validation current_fcs_validation;
};
* @param name The interface name.
* @param freq The frequency in MHz.
* @param chan_type The HT channel type (no, 20Mhz, 40Mhz...).
+ * @param center_freq The center frequency in MHz (if 80MHz, 80+80MHz or 160MHz).
+ * @param center_freq2 The 2nd center frequency in MHz (if 80+80MHz).
* @return Zero on success, nonzero on failure.
*/
-int ws80211_set_freq(const char *name, int freq, int chan_type);
+int ws80211_set_freq(const char *name, int freq, int chan_type, int _U_ center_freq, int _U_ center_freq2);
int ws80211_str_to_chan_type(const gchar *s); /* GTK+ only? */
const gchar *ws80211_chan_type_to_str(int type); /* GTK+ only? */
/* SPLIT_WIPHY_DUMP is supported */
#cmakedefine HAVE_NL80211_SPLIT_WIPHY_DUMP 1
+/* VHT_CAPABILITY is supported */
+#cmakedefine HAVE_NL80211_VHT_CAPABILITY 1
+
/* Define to 1 if you have the <Ntddndis.h> header file. */
#cmakedefine HAVE_NTDDNDIS_H 1
[enum nl80211_protocol_features x = NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP;],
[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_NL80211_SPLIT_WIPHY_DUMP, 1, [SPLIT_WIPHY_DUMP is supported])],
[AC_MSG_RESULT(no)])
+
+ AC_MSG_CHECKING([for NL80211_VHT_CAPABILITY])
+ AC_TRY_COMPILE([#include <linux/nl80211.h>],
+ [enum nl80211_attrs x = NL80211_ATTR_VHT_CAPABILITY;],
+ [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_NL80211_VHT_CAPABILITY, 1, [VHT_CAPABILITY is supported])],
+ [AC_MSG_RESULT(no)])
;;
*)
#ifdef HAVE_BPF_IMAGE
fprintf(output, " -d print generated BPF code for capture filter\n");
#endif
- fprintf(output, " -k set channel on wifi interface <freq>,[<type>]\n");
+ fprintf(output, " -k set channel on wifi interface:\n"
+ " <freq>,[<type>],[<center_freq1>],[<center_freq2>]\n");
fprintf(output, " -S print statistics for each interface once per second\n");
fprintf(output, " -M for -D, -L, and -S, produce machine-readable output\n");
fprintf(output, "\n");
static int
set_80211_channel(const char *iface, const char *opt)
{
- int freq = 0, type, ret;
+ int freq = 0;
+ int type = -1;
+ int center_freq1 = -1;
+ int center_freq2 = -1;
+ int args;
+ int ret;
gchar **options = NULL;
- options = g_strsplit_set(opt, ",", 2);
+ options = g_strsplit_set(opt, ",", 4);
+ for (args = 0; options[args]; args++);
if (options[0])
freq = atoi(options[0]);
- if (options[1]) {
+ if (args >= 1 && options[1]) {
type = ws80211_str_to_chan_type(options[1]);
if (type == -1) {
ret = EINVAL;
goto out;
}
}
- else
- type = -1;
+
+ if (args >= 2 && options[2])
+ center_freq1 = atoi(options[2]);
+
+ if (args >= 3 && options[3])
+ center_freq2 = atoi(options[3]);
ret = ws80211_init();
if (ret) {
ret = 2;
goto out;
}
- ret = ws80211_set_freq(iface, freq, type);
+ ret = ws80211_set_freq(iface, freq, type, center_freq1, center_freq2);
if (ret) {
cmdarg_err("%d: Failed to set channel: %s\n", abs(ret), g_strerror(abs(ret)));
freq_s = g_strdup_printf("%d", freq);
type_s = ws80211_chan_type_to_str(type);
- ret = sync_interface_set_80211_chan(iface, freq_s, type_s,
+ ret = sync_interface_set_80211_chan(iface, freq_s, type_s, "-1", "-1",
&data, &primary_msg, &secondary_msg, main_window_update);
/* Parse the error msg */
if (frequency.isEmpty() || chan_type < 0) return;
- ret = sync_interface_set_80211_chan(cur_iface.toUtf8().constData(), frequency.toUtf8().constData(), chan_type_s,
+ ret = sync_interface_set_80211_chan(cur_iface.toUtf8().constData(), frequency.toUtf8().constData(),
+ chan_type_s, "-1", "-1",
&data, &primary_msg, &secondary_msg, main_window_update);
g_free(data);
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) {
+ if (ws80211_set_freq(cur_iface.toUtf8().constData(), frequency, chan_type, -1, -1) != 0) {
QString err_str = tr("Unable to set channel or offset.");
emit pushAdapterStatus(err_str);
}