Back to Nodemcu Firmware

WiFi.monitor Module

docs/modules/wifi_monitor.md

latest13.7 KB
Original Source

WiFi.monitor Module

SinceOrigin / ContributorMaintainerSource
2017-12-20Philip GladstonePhilip Gladstonewifi_monitor.c

This is an optional module that is only included if LUA_USE_MODULES_WIFI_MONITOR is defined in the user_modules.h file. This module provides access to the monitor mode features of the ESP8266 chipset. In particular, it provides access to received WiFi management frames.

This module is not for casual use -- it requires an understanding of IEEE802.11 management protocols.

wifi.monitor.start()

This registers a callback function to be called whenever a management frame is received. Note that this can be at quite a high rate, so some limited filtering is provided before the callback is invoked. Only the first 110 bytes or so of the frame are returned -- this is an SDK restriction. Any connected AP/station will be disconnected. Calling this function sets the channel back to 1.

Syntax

wifi.monitor.start([filter parameters,] mgmt_frame_callback)

Parameters

  • filter parameters. This is a byte offset (1 based) into the underlying data structure, a value to match against, and an optional mask to use for matching. The data structure used for filtering is 12 bytes of radio header, and then the actual frame. The first byte of the frame is therefore numbered 13. The filter values of 13, 0x80 will just extract beacon frames.
  • mgmt_frame_callback is a function which is invoked with a single argument which is a wifi.packet object which has many methods and attributes.

Returns

nothing.

Example

wifi.monitor.start(13, 0x80, function(pkt)
    print ('Beacon: ' .. pkt.bssid_hex .. " '" .. pkt[0] .. "' ch " .. pkt[3]:byte(1))
end)
wifi.monitor.channel(6)

wifi.monitor.stop()

This disables the monitor mode and returns to normal operation. There are no parameters and no return value.

Syntax

wifi.monitor.stop()

wifi.monitor.channel()

This sets the channel number to monitor. Note that in many applications you will want to step through the channel numbers at regular intervals. Beacon frames (in particular) are typically sent every 102 milliseconds, so a switch time of (say) 150 milliseconds seems to work well. Note that this function should be called after starting to monitor, since wifi.monitor.start resets the channel back to 1.

Syntax

wifi.monitor.channel(channel)

Parameters

  • channel sets the channel number in the range 1 to 15.

Returns

nothing.

wifi.packet object

This object provides access to the raw packet data and also many methods to extract data from the packet in a simple way.

packet:radio_byte()

This is like the string.byte method, except that it gives access to the bytes of the radio header.

Syntax

packet:radio_byte(n)

Parameters

  • n the byte number (1 based) to get from the radio header portion of the packet

Returns

0-255 as the value of the byte nothing if the offset is not within the radio header.

packet:frame_byte()

This is like the string.byte method, except that it gives access to the bytes of the received frame.

Syntax

packet:frame_byte(n)

Parameters

  • n the byte number (1 based) to get from the received frame.

Returns

0-255 as the value of the byte nothing if the offset is not within the received frame.

packet:radio_sub()

This is like the string.sub method, except that it gives access to the bytes of the radio header.

Syntax

packet:radio_sub(start, end)

Parameters

Same rules as for string.sub except that it operates on the radio header.

Returns

A string according to the string.sub rules.

packet:frame_sub()

This is like the string.sub method, except that it gives access to the bytes of the received frame.

Syntax

packet:frame_sub(start, end)

Parameters

Same rules as for string.sub except that it operates on the received frame.

Returns

A string according to the string.sub rules.

packet:radio_subhex()

This is like the string.sub method, except that it gives access to the bytes of the radio header. It also converts them into hex efficiently.

Syntax

packet:radio_subhex(start, end [, seperator])

Parameters

Same rules as for string.sub except that it operates on the radio header.

  • seperator is an optional sting which is placed between the individual hex pairs returned.

Returns

A string according to the string.sub rules, converted into hex with possible inserted spacers.

packet:frame_sub()

This is like the string.sub method, except that it gives access to the bytes of the received frame.

Syntax

packet:frame_subhex(start, end [, seperator])

Parameters

Same rules as for string.sub except that it operates on the received frame.

  • seperator is an optional sting which is placed between the individual hex pairs returned.

Returns

A string according to the string.sub rules, converted into hex with possible inserted spacers.

packet:ie_table()

This returns a table of the information elements from the management frame. The table keys values are the information element numbers (0 - 255). Note that IE0 is the SSID. This method is mostly only useful if you need to determine which information elements were in the management frame.

Syntax

packet:ie_table()

Parameters

None.

Returns

A table with all the information elements in it.

Example

print ("SSID", packet:ie_table()[0])

Note that this is possibly the worst way of getting the SSID.

Alternative

The packet object itself can be indexed to extract the information elements.

Example

print ("SSID", packet[0])

This is more efficient than the above approach, but requires you to remember that IE0 is the SSID.

packet.<attribute>

The packet object has many attributes on it. These allow easy access to all the fields, though not an easy way to enumerate them. All integers are unsigned except where noted. Information Elements are only returned if they are completely within the captured frame. This can mean that for some frames, some of the information elements can be missing.

When a string is returned as the value of a field, it can (and often is) be a binary string with embedded nulls. All information elements are returned as strings even if they are only one byte long and look like a number in the specification. This is purely to make the interface consistent. Note that even SSIDs can contain embedded nulls.

Attribute nameType
aggregationInteger
ampdu_cntInteger
association_idInteger
authentication_algorithmInteger
authentication_transactionInteger
beacon_intervalInteger
beacon_intervalInteger
bssidString
bssid_hexString
bssidmatch0Integer
bssidmatch1Integer
capabilityInteger
channelInteger
current_apString
cwbInteger
dmatch0Integer
dmatch1Integer
dstmacString
dstmac_hexString
durationInteger
fec_codingInteger
frameString (the entire received frame)
frame_hexString
fromdsInteger
headerString (the fixed part of the management frame)
ht_lengthInteger
ie_20_40_bss_coexistenceString
ie_20_40_bss_intolerant_channel_reportString
ie_advertisement_protocolString
ie_aidString
ie_antennaString
ie_ap_channel_reportString
ie_authenticated_mesh_peering_exchangeString
ie_beacon_timingString
ie_bss_ac_access_delayString
ie_bss_available_admission_capacityString
ie_bss_average_access_delayString
ie_bss_loadString
ie_bss_max_idle_periodString
ie_cf_parameter_setString
ie_challenge_textString
ie_channel_switch_announcementString
ie_channel_switch_timingString
ie_channel_switch_wrapperString
ie_channel_usageString
ie_collocated_interference_reportString
ie_congestion_notificationString
ie_countryString
ie_destination_uriString
ie_diagnostic_reportString
ie_diagnostic_requestString
ie_dms_requestString
ie_dms_responseString
ie_dse_registered_locationString
ie_dsss_parameter_setString
ie_edca_parameter_setString
ie_emergency_alart_identifierString
ie_erp_informationString
ie_event_reportString
ie_event_requestString
ie_expedited_bandwidth_requestString
ie_extended_bss_loadString
ie_extended_capabilitiesString
ie_extended_channel_switch_announcementString
ie_extended_supported_ratesString
ie_fast_bss_transitionString
ie_fh_parameter_setString
ie_fms_descriptorString
ie_fms_requestString
ie_fms_responseString
ie_gannString
ie_he_capabilitiesString
ie_hopping_pattern_parametersString
ie_hopping_pattern_tableString
ie_ht_capabilitiesString
ie_ht_operationString
ie_ibss_dfsString
ie_ibss_parameter_setString
ie_interworkingString
ie_link_identifierString
ie_location_parametersString
ie_management_micString
ie_mccaopString
ie_mccaop_advertisementString
ie_mccaop_advertisement_overviewString
ie_mccaop_setup_replyString
ie_mccaop_setup_requestString
ie_measurement_pilot_transmissionString
ie_measurement_reportString
ie_measurement_requestString
ie_mesh_awake_windowString
ie_mesh_channel_switch_parametersString
ie_mesh_configurationString
ie_mesh_idString
ie_mesh_link_metric_reportString
ie_mesh_peering_managementString
ie_micString
ie_mobility_domainString
ie_multiple_bssidString
ie_multiple_bssid_indexString
ie_neighbor_reportString
ie_nontransmitted_bssid_capabilityString
ie_operating_mode_notificationString
ie_overlapping_bss_scan_parametersString
ie_perrString
ie_power_capabilityString
ie_power_constraintString
ie_prepString
ie_preqString
ie_proxy_updateString
ie_proxy_update_confirmationString
ie_pti_controlString
ie_qos_capabilityString
ie_qos_map_setString
ie_qos_traffic_capabilityString
ie_quietString
ie_quiet_channelString
ie_rannString
ie_rcpiString
ie_requestString
ie_ric_dataString
ie_ric_descriptorString
ie_rm_enabled_capacitiesString
ie_roaming_consortiumString
ie_rsnString
ie_rsniString
ie_scheduleString
ie_secondary_channel_offsetString
ie_ssidString
ie_ssid_listString
ie_supported_channelsString
ie_supported_operating_classesString
ie_supported_ratesString
ie_tclasString
ie_tclas_processingString
ie_tfs_requestString
ie_tfs_responseString
ie_timString
ie_tim_broadcast_requestString
ie_tim_broadcast_responseString
ie_time_advertisementString
ie_time_zoneString
ie_timeout_intervalString
ie_tpc_reportString
ie_tpc_requestString
ie_tpu_buffer_statusString
ie_ts_delayString
ie_tspecString
ie_uapsd_coexistenceString
ie_vendor_specificString
ie_vht_capabilitiesString
ie_vht_operationString
ie_vht_transmit_power_envelopeString
ie_wakeup_scheduleString
ie_wide_bandwidth_channel_switchString
ie_wnm_sleep_modeString
is_groupInteger
legacy_lengthInteger
listen_intervalInteger
mcsInteger
moredataInteger
moreflagInteger
not_coundingInteger
numberInteger
orderInteger
protectedframeInteger
protocolInteger
pwrmgmtInteger
radioString (the entire radio header)
rateInteger
reasonInteger
retryInteger
rssiSigned Integer
rxend_stateInteger
sgiInteger
sig_modeInteger
smoothingInteger
srcmacString
srcmac_hexString
statusInteger
stbcInteger
subtypeInteger
timestampString
todsInteger
typeInteger

If you don't know what some of the attributes are, then you probably need to read the IEEE 802.11 specifications and other supporting material.

Example

print ("SSID", packet.ie_ssid)

The Radio Header

The Radio Header has been mentioned above as a 12 byte structure. The layout is shown below. The only comments are in Chinese.

struct {
    signed rssi:8;//表示该包的信号强度
    unsigned rate:4;
    unsigned is_group:1;
    unsigned:1;
    unsigned sig_mode:2;//表示该包是否是11n 的包,0 表示非11n,非0 表示11n
    unsigned legacy_length:12;//如果不是11n 的包,它表示包的长度
    unsigned damatch0:1;
    unsigned damatch1:1;
    unsigned bssidmatch0:1;
    unsigned bssidmatch1:1;
    unsigned MCS:7;//如果是11n 的包,它表示包的调制编码序列,有效值:0-76
    unsigned CWB:1;//如果是11n 的包,它表示是否为HT40 的包
    unsigned HT_length:16;//如果是11n 的包,它表示包的长度
    unsigned Smoothing:1;
    unsigned Not_Sounding:1;
    unsigned:1;
    unsigned Aggregation:1;
    unsigned STBC:2;
    unsigned FEC_CODING:1;//如果是11n 的包,它表示是否为LDPC 的包
    unsigned SGI:1;
    unsigned rxend_state:8;
    unsigned ampdu_cnt:8;
    unsigned channel:4;//表示该包所在的信道
    unsigned:12;
}