#define WLAN_CAPABILITY_QOS (1<<9)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
#define WLAN_CAPABILITY_APSD (1<<11)
+#define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
+#define WLAN_CAPABILITY_DEL_BACK (1<<14)
+#define WLAN_CAPABILITY_IMM_BACK (1<<15)
+/* DMG (60gHz) 802.11ad */
+/* type - bits 0..1 */
+#define WLAN_CAPABILITY_DMG_TYPE_MASK (3<<0)
+
+#define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */
+#define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */
+#define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */
+
+#define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2)
+#define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3)
+#define WLAN_CAPABILITY_DMG_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_DMG_ECPAC (1<<5)
+
+#define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
+#define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
static int handle_scan(struct nl80211_state *state,
struct nl_cb *cb,
struct nl_msg *msg,
- int argc, char **argv)
+ int argc, char **argv,
+ enum id_input id)
{
struct nl_msg *ssids = NULL, *freqs = NULL;
char *eptr;
bool passive = false, have_ssids = false, have_freqs = false;
size_t tmp;
unsigned char *ies;
+ int flags = 0;
ssids = nlmsg_alloc();
if (!ssids)
} else if (strcmp(argv[i], "ies") == 0) {
parse = IES;
break;
+ } else if (strcmp(argv[i], "lowpri") == 0) {
+ parse = NONE;
+ flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+ break;
+ } else if (strcmp(argv[i], "flush") == 0) {
+ parse = NONE;
+ flags |= NL80211_SCAN_FLAG_FLUSH;
+ break;
+ } else if (strcmp(argv[i], "ap-force") == 0) {
+ parse = NONE;
+ flags |= NL80211_SCAN_FLAG_AP;
+ break;
} else if (strcmp(argv[i], "ssid") == 0) {
parse = SSID;
have_ssids = true;
if (have_freqs)
nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+ if (flags)
+ NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
err = 0;
nla_put_failure:
printf("\n");
}
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
{
int i;
for (i = 0; i < len; i++) {
int r = data[i] & 0x7f;
- printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
+
+ if (r == BSS_MEMBERSHIP_SELECTOR_VHT_PHY && data[i] & 0x80)
+ printf("VHT");
+ else if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
+ printf("HT");
+ else
+ printf("%d.%d", r/2, 5*(r&1));
+
+ printf("%s ", data[i] & 0x80 ? "*" : "");
}
printf("\n");
}
case 6:
printf("AES-128-CMAC");
break;
+ case 8:
+ printf("GCMP");
+ break;
default:
printf("%.02x-%.02x-%.02x:%d",
data[0], data[1] ,data[2], data[3]);
print_ht_mcs(data + 3);
}
+static const char *ht_secondary_offset[4] = {
+ "no secondary",
+ "above",
+ "[reserved!]",
+ "below",
+};
+
static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data)
{
- static const char *offset[4] = {
- "no secondary",
- "above",
- "[reserved!]",
- "below",
- };
static const char *protection[4] = {
"no",
"nonmember",
printf("\n");
printf("\t\t * primary channel: %d\n", data[0]);
printf("\t\t * secondary channel offset: %s\n",
- offset[data[1] & 0x3]);
+ ht_secondary_offset[data[1] & 0x3]);
printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
else
first = false;
+#define CAPA(bit, name) case bit: printf(" " name); break
+
switch (bit + base) {
- case 0:
- printf(" HT Information Exchange Supported");
- break;
- case 1:
- printf(" On-demand Beacon");
- break;
- case 2:
- printf(" Extended Channel Switching");
- break;
- case 3:
- printf(" Wave Indication");
- break;
- case 4:
- printf(" PSMP Capability");
- break;
- case 5:
- printf(" Service Interval Granularity");
- break;
- case 6:
- printf(" S-PSMP Capability");
- break;
+ CAPA(0, "HT Information Exchange Supported");
+ CAPA(1, "reserved (On-demand Beacon)");
+ CAPA(2, "Extended Channel Switching");
+ CAPA(3, "reserved (Wave Indication)");
+ CAPA(4, "PSMP Capability");
+ CAPA(5, "reserved (Service Interval Granularity)");
+ CAPA(6, "S-PSMP Capability");
+ CAPA(7, "Event");
+ CAPA(8, "Diagnostics");
+ CAPA(9, "Multicast Diagnostics");
+ CAPA(10, "Location Tracking");
+ CAPA(11, "FMS");
+ CAPA(12, "Proxy ARP Service");
+ CAPA(13, "Collocated Interference Reporting");
+ CAPA(14, "Civic Location");
+ CAPA(15, "Geospatial Location");
+ CAPA(16, "TFS");
+ CAPA(17, "WNM-Sleep Mode");
+ CAPA(18, "TIM Broadcast");
+ CAPA(19, "BSS Transition");
+ CAPA(20, "QoS Traffic Capability");
+ CAPA(21, "AC Station Count");
+ CAPA(22, "Multiple BSSID");
+ CAPA(23, "Timing Measurement");
+ CAPA(24, "Channel Usage");
+ CAPA(25, "SSID List");
+ CAPA(26, "DMS");
+ CAPA(27, "UTC TSF Offset");
+ CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
+ CAPA(29, "TDLS Peer PSM Support");
+ CAPA(30, "TDLS channel switching");
+ CAPA(31, "Interworking");
+ CAPA(32, "QoS Map");
+ CAPA(33, "EBR");
+ CAPA(34, "SSPN Interface");
+ CAPA(35, "Reserved");
+ CAPA(36, "MSGCF Capability");
+ CAPA(37, "TDLS Support");
+ CAPA(38, "TDLS Prohibited");
+ CAPA(39, "TDLS Channel Switching Prohibited");
+ CAPA(40, "Reject Unadmitted Frame");
+ CAPA(44, "Identifier Location");
+ CAPA(45, "U-APSD Coexistence");
+ CAPA(46, "WNM-Notification");
+ CAPA(47, "Reserved");
+ CAPA(48, "UTF-8 SSID");
default:
printf(" %d", bit);
break;
}
+#undef CAPA
}
}
printf("\n");
}
+static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+ printf("\n");
+ print_vht_info(data[0] | (data[1] << 8) |
+ (data[2] << 16) | (data[3] << 24),
+ data + 4);
+}
+
+static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+ const char *chandwidths[] = {
+ [0] = "20 or 40 MHz",
+ [1] = "80 MHz",
+ [3] = "80+80 MHz",
+ [2] = "160 MHz",
+ };
+
+ printf("\n");
+ printf("\t\t * channel width: %d (%s)\n", data[0],
+ data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
+ printf("\t\t * center freq segment 1: %d\n", data[1]);
+ printf("\t\t * center freq segment 2: %d\n", data[2]);
+ printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
+}
+
+static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+ printf("\n");
+ printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
+ printf("\t\t * active dwell: %d TUs\n", (data[3] << 8) | data[2]);
+ printf("\t\t * channel width trigger scan interval: %d s\n", (data[5] << 8) | data[4]);
+ printf("\t\t * scan passive total per channel: %d TUs\n", (data[7] << 8) | data[6]);
+ printf("\t\t * scan active total per channel: %d TUs\n", (data[9] << 8) | data[8]);
+ printf("\t\t * BSS width channel transition delay factor: %d\n", (data[11] << 8) | data[10]);
+ printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
+ ((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100);
+}
+
+static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+ if (data[0] < ARRAY_SIZE(ht_secondary_offset))
+ printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
+ else
+ printf(" %d\n", data[0]);
+}
+
+static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+ printf("\n");
+ printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
+ printf("\t\t * channel utilisation: %d/255\n", data[2]);
+ printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]);
+}
+
struct ie_print {
const char *name;
void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
[3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
[5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
[7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
+ [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
[32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
[42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
[45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+ [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
[61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
+ [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
+ [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
+ [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
[48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
[50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
+ [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
[127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
};
for (i = 0; i < 4; i++) {
printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
- if (data[4] & 0x10)
+ if (data[0] & 0x10)
printf(" acm");
printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1,
(1 << (data[1] >> 4)) - 1);
}
}
+static void print_capa_dmg(__u16 capa)
+{
+ switch (capa & WLAN_CAPABILITY_DMG_TYPE_MASK) {
+ case WLAN_CAPABILITY_DMG_TYPE_AP:
+ printf(" DMG_ESS");
+ break;
+ case WLAN_CAPABILITY_DMG_TYPE_PBSS:
+ printf(" DMG_PCP");
+ break;
+ case WLAN_CAPABILITY_DMG_TYPE_IBSS:
+ printf(" DMG_IBSS");
+ break;
+ }
+
+ if (capa & WLAN_CAPABILITY_DMG_CBAP_ONLY)
+ printf(" CBAP_Only");
+ if (capa & WLAN_CAPABILITY_DMG_CBAP_SOURCE)
+ printf(" CBAP_Src");
+ if (capa & WLAN_CAPABILITY_DMG_PRIVACY)
+ printf(" Privacy");
+ if (capa & WLAN_CAPABILITY_DMG_ECPAC)
+ printf(" ECPAC");
+ if (capa & WLAN_CAPABILITY_DMG_SPECTRUM_MGMT)
+ printf(" SpectrumMgmt");
+ if (capa & WLAN_CAPABILITY_DMG_RADIO_MEASURE)
+ printf(" RadioMeasure");
+}
+
+static void print_capa_non_dmg(__u16 capa)
+{
+ if (capa & WLAN_CAPABILITY_ESS)
+ printf(" ESS");
+ if (capa & WLAN_CAPABILITY_IBSS)
+ printf(" IBSS");
+ if (capa & WLAN_CAPABILITY_CF_POLLABLE)
+ printf(" CfPollable");
+ if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
+ printf(" CfPollReq");
+ if (capa & WLAN_CAPABILITY_PRIVACY)
+ printf(" Privacy");
+ if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ printf(" ShortPreamble");
+ if (capa & WLAN_CAPABILITY_PBCC)
+ printf(" PBCC");
+ if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
+ printf(" ChannelAgility");
+ if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ printf(" SpectrumMgmt");
+ if (capa & WLAN_CAPABILITY_QOS)
+ printf(" QoS");
+ if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ printf(" ShortSlotTime");
+ if (capa & WLAN_CAPABILITY_APSD)
+ printf(" APSD");
+ if (capa & WLAN_CAPABILITY_RADIO_MEASURE)
+ printf(" RadioMeasure");
+ if (capa & WLAN_CAPABILITY_DSSS_OFDM)
+ printf(" DSSS-OFDM");
+ if (capa & WLAN_CAPABILITY_DEL_BACK)
+ printf(" DelayedBACK");
+ if (capa & WLAN_CAPABILITY_IMM_BACK)
+ printf(" ImmediateBACK");
+}
+
static int print_bss_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
};
struct scan_params *params = arg;
int show = params->show_both_ie_sets ? 2 : 1;
+ bool is_dmg = false;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
(tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
}
- if (bss[NL80211_BSS_FREQUENCY])
- printf("\tfreq: %d\n",
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
+ if (bss[NL80211_BSS_FREQUENCY]) {
+ int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ printf("\tfreq: %d\n", freq);
+ if (freq > 45000)
+ is_dmg = true;
+ }
if (bss[NL80211_BSS_BEACON_INTERVAL])
printf("\tbeacon interval: %d\n",
nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
if (bss[NL80211_BSS_CAPABILITY]) {
__u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
printf("\tcapability:");
- if (capa & WLAN_CAPABILITY_ESS)
- printf(" ESS");
- if (capa & WLAN_CAPABILITY_IBSS)
- printf(" IBSS");
- if (capa & WLAN_CAPABILITY_PRIVACY)
- printf(" Privacy");
- if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
- printf(" ShortPreamble");
- if (capa & WLAN_CAPABILITY_PBCC)
- printf(" PBCC");
- if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
- printf(" ChannelAgility");
- if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
- printf(" SpectrumMgmt");
- if (capa & WLAN_CAPABILITY_QOS)
- printf(" QoS");
- if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
- printf(" ShortSlotTime");
- if (capa & WLAN_CAPABILITY_APSD)
- printf(" APSD");
- if (capa & WLAN_CAPABILITY_DSSS_OFDM)
- printf(" DSSS-OFDM");
+ if (is_dmg)
+ print_capa_dmg(capa);
+ else
+ print_capa_non_dmg(capa);
printf(" (0x%.4x)\n", capa);
}
if (bss[NL80211_BSS_SIGNAL_MBM]) {
int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
printf("\tlast seen: %d ms ago\n", age);
}
-
+
if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
if (bss[NL80211_BSS_BEACON_IES])
printf("\tInformation elements from Probe Response "
static int handle_scan_dump(struct nl80211_state *state,
struct nl_cb *cb,
struct nl_msg *msg,
- int argc, char **argv)
+ int argc, char **argv,
+ enum id_input id)
{
if (argc > 1)
return 1;
static int handle_scan_combined(struct nl80211_state *state,
struct nl_cb *cb,
struct nl_msg *msg,
- int argc, char **argv)
+ int argc, char **argv,
+ enum id_input id)
{
char **trig_argv;
static char *dump_argv[] = {
int i;
for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
- err = handle_cmd(state, II_NETDEV, trig_argc, trig_argv);
+ err = handle_cmd(state, id, trig_argc, trig_argv);
free(trig_argv);
if (err)
return err;
}
dump_argv[0] = argv[0];
- return handle_cmd(state, II_NETDEV, dump_argc, dump_argv);
+ return handle_cmd(state, id, dump_argc, dump_argv);
}
-TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive]", 0, 0,
+TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]", 0, 0,
CIB_NETDEV, handle_scan_combined,
"Scan on the given frequencies and probe for the given SSIDs\n"
"(or wildcard if not given) unless passive scanning is requested.\n"
NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
"Dump the current scan results. If -u is specified, print unknown\n"
"data in scan results.");
-COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive]",
+COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]",
NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
"Trigger a scan on the given frequencies with probing for the given\n"
"SSIDs (or wildcard if not given) unless passive scanning is requested.");