Skip to content

Instantly share code, notes, and snippets.

@zgoda
Created September 6, 2016 11:29
Show Gist options
  • Save zgoda/a6854e12d987d727efc68a8fb0860a1c to your computer and use it in GitHub Desktop.
Save zgoda/a6854e12d987d727efc68a8fb0860a1c to your computer and use it in GitHub Desktop.
Basic ESP8266 WiFi frame capture
extern "C" {
#include <user_interface.h>
}
#include <Arduino.h>
/*
802.11 Frame Control on 2 bytes
*/
struct FrameControl {
uint8_t version:2;
uint8_t type:2;
uint8_t subtype:4;
uint8_t toDS:1;
uint8_t fromDS:1;
uint8_t MF:1;
uint8_t retry:1;
uint8_t pwr:1;
uint8_t more:1;
uint8_t w:1;
uint8_t o:1;
};
/*
Following structs taken literally from Espressif SDK docs
*/
struct RxControl {
signed rssi:8; // signal intensity of packet
unsigned rate:4;
unsigned is_group:1;
unsigned:1;
unsigned sig_mode:2; // 0:is 11n packet; 1:is not 11n packet;
unsigned legacy_length:12; // if not 11n packet, shows length of packet.
unsigned damatch0:1;
unsigned damatch1:1;
unsigned bssidmatch0:1;
unsigned bssidmatch1:1;
unsigned MCS:7; // if is 11n packet, shows the modulation and code used (range from 0 to 76)
unsigned CWB:1; // if is 11n packet, shows if is HT40 packet or not
unsigned HT_length:16;// if is 11n packet, shows length of packet.
unsigned Smoothing:1;
unsigned Not_Sounding:1;
unsigned:1;
unsigned Aggregation:1;
unsigned STBC:2;
unsigned FEC_CODING:1; // if is 11n packet, shows if is LDPC packet or not.
unsigned SGI:1;
unsigned rxend_state:8;
unsigned ampdu_cnt:8;
unsigned channel:4; //which channel this packet in.
unsigned:12;
};
struct LenSeq{
u16 len; // length of packet
u16 seq; // serial number of packet, the high 12bits are serial number, low 14 bits are Fragment number (usually be 0)
u8 addr3[6]; // the third address in packet
};
struct sniffer_buf{
struct RxControl rx_ctrl;
u8 buf[36]; // head of ieee80211 packet
u16 cnt; // number count of packet
struct LenSeq lenseq[1]; //length of packet
};
struct sniffer_buf2 {
struct RxControl rx_ctrl;
u8 buf[112];
u16 cnt;
u16 len; //length of packet
};
static const char MAC_FMT[] = "%02X:%02X:%02X:%02X:%02X:%02X";
static const uint8_t MAC1_BEGIN = 4;
static const uint8_t MAC2_BEGIN = 10;
static const uint8_t MAC3_BEGIN = 16;
static const uint8_t MAC_SIZE = 6;
/*
POC packet sniffer and parser, we process only 100% valid frames that have all
required data (incomplete frames can be parsed if verified valid)
*/
static void ICACHE_FLASH_ATTR handle_pkt(uint8_t* buf, uint16_t len) {
if (len <= 12) {
return; // packet is invalid
}
if (len == 128) {
char mStr[20];
sniffer_buf2 *data = (sniffer_buf2 *)buf;
Serial.print(F("RSSI: "));
Serial.println(data->rx_ctrl.rssi);
FrameControl *fc = (FrameControl *)data->buf;
sprintf(mStr, "t: %d; s: %d", fc->type, fc->subtype);
Serial.println(mStr);
if (fc->type == 0 && fc->subtype == 4) {
/*
type 0 - management frame
subtype 4 - probe request
*/
uint8_t mac1[6];
for (size_t i = MAC1_BEGIN; i < MAC1_BEGIN + MAC_SIZE; i++) {
mac1[i - MAC1_BEGIN] = data->buf[i];
}
sprintf(mStr, MAC_FMT, mac1[0], mac1[1], mac1[2], mac1[3], mac1[4], mac1[5]);
Serial.print(F("MAC1: "));
Serial.println(mStr);
uint8_t mac2[6];
for (size_t i = MAC2_BEGIN; i < MAC2_BEGIN + MAC_SIZE; i++) {
mac2[i - MAC2_BEGIN] = data->buf[i];
}
sprintf(mStr, MAC_FMT, mac2[0], mac2[1], mac2[2], mac2[3], mac2[4], mac2[5]);
Serial.print(F("MAC2: "));
Serial.println(mStr);
uint8_t mac3[6];
for (size_t i = MAC3_BEGIN; i < MAC3_BEGIN + MAC_SIZE; i++) {
mac3[i - MAC3_BEGIN] = data->buf[i];
}
sprintf(mStr, MAC_FMT, mac3[0], mac3[1], mac3[2], mac3[3], mac3[4], mac3[5]);
Serial.print(F("MAC3: "));
Serial.println(mStr);
}
}
}
void setup() {
Serial.begin(115200);
delay(10);
wifi_set_opmode(STATION_MODE);
wifi_set_channel(1);
wifi_set_promiscuous_rx_cb(handle_pkt);
delay(10);
wifi_promiscuous_enable(1);
}
void loop() {
yield();
}
@aminbaig
Copy link

aminbaig commented Mar 25, 2017

Hi Jarek,

I like what you have done with the script. I am a beginner and was hoping if you could help me with elaborating this script a bit more. Basically I want to print the SSID, MAC address and date and time.

@zgoda
Copy link
Author

zgoda commented Apr 12, 2017

You don't have any ssid in promiscuous mode. The device is just listening to what flies in the air.

@alexgrauer
Copy link

Hi @zgoda,

Is there a way of getting more than 112 bytes of the data? When I capture the probe request with Wireshark, the data in there is bigger than 112.
Do you know if thats an ESP's restriction?

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment