Merge branch 'development' of https://github.com/cyberman54/ESP32-Paxcounter into development

This commit is contained in:
Klaus K Wilting 2018-04-01 21:03:20 +02:00
commit 4b9beff3bd
11 changed files with 278 additions and 179 deletions

View File

@ -217,6 +217,11 @@ Arduino-LMIC Library
TTN OTAA Example TTN OTAA Example
https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-otaa/ https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-otaa/
and it's fork
LoraWAN-in-C library, adapted to run under the Arduino environment
https://github.com/jpmeijers/arduino-lmic
under this Licence: under this Licence:
"License "License

View File

@ -69,7 +69,9 @@ For the LoPy/LoPy4 the original Pycom firmware is not needed here, so there is n
Note: If you use this software you do this at your own risk. That means that you alone - not the authors of this software - are responsible for the legal compliance of an application using this or build from this software and/or usage of a device created using this software. You should take special care and get prior legal advice if you plan metering passengers in public areas and/or publish data drawn from doing so. Note: If you use this software you do this at your own risk. That means that you alone - not the authors of this software - are responsible for the legal compliance of an application using this or build from this software and/or usage of a device created using this software. You should take special care and get prior legal advice if you plan metering passengers in public areas and/or publish data drawn from doing so.
Disclosure: The Paxcounter code stores scanned MAC adresses in the device's RAM, and keeps it in RAM temporary for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected MAC data is erased from RAM. MAC data never is transferred to the LoRaWAN network. No kind of tracking and no persistent storing of MAC data or timestamps on the device and no other kind of analytics than counting is implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are made visible and scanned by this code. The same applies to Bluetooth MACs, if the bluetooth option in the code is enabled. # Privacy disclosure
Paxcounter generates identifiers for sniffed MAC adresses and collects them temporary in the device's RAM for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected identifiers are cleared. Identifiers are generated by salting and hashing MAC adresses. The random salt value changes after each scan cycle. Identifiers and MAC adresses are never transferred to the LoRaWAN network. No persistent storing of MAC adresses, identifiers or timestamps and no other kind of analytics than counting are implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are sniffed and processed by this code. If the bluetooth option in the code is enabled, bluetooth MACs are scanned and processed by the included BLE stack, and counted by this code.
# Payload format description # Payload format description

View File

@ -10,9 +10,9 @@
; ---> SELECT TARGET PLATFORM HERE! <--- ; ---> SELECT TARGET PLATFORM HERE! <---
[platformio] [platformio]
env_default = heltec_wifi_lora_32 ;env_default = heltec_wifi_lora_32
;env_default = ttgov1 ;env_default = ttgov1
;env_default = ttgov2 env_default = ttgov2
;env_default = lopy ;env_default = lopy
;env_default = lopy4 ;env_default = lopy4
;env_default = lolin32lite_lora ;env_default = lolin32lite_lora
@ -70,7 +70,9 @@ board = esp32dev
framework = arduino framework = arduino
monitor_baud = 115200 monitor_baud = 115200
upload_speed = 921600 upload_speed = 921600
lib_deps = U8g2 lib_deps =
U8g2
ESP32 BLE Arduino@>=0.4.9
build_flags = build_flags =
;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework ;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE

View File

@ -27,6 +27,6 @@ void BLECount() {
u8x8.clearLine(3); u8x8.clearLine(3);
u8x8.setCursor(0,3); u8x8.setCursor(0,3);
blenum=foundDevices.getCount(); blenum=foundDevices.getCount();
u8x8.printf("BLE#: %4i",blenum); u8x8.printf("BLE#: %-5i",blenum);
} }
#endif #endif

View File

@ -12,7 +12,6 @@
#include <hal/hal.h> #include <hal/hal.h>
// Struct holding devices's runtime configuration // Struct holding devices's runtime configuration
typedef struct { typedef struct {
int8_t lorasf; // 7-12, lora spreadfactor int8_t lorasf; // 7-12, lora spreadfactor
int8_t txpower; // 2-15, lora tx power int8_t txpower; // 2-15, lora tx power
@ -33,9 +32,10 @@ extern configData_t cfg;
extern uint8_t mydata[]; extern uint8_t mydata[];
extern uint64_t uptimecounter; extern uint64_t uptimecounter;
extern osjob_t sendjob; extern osjob_t sendjob;
extern int macnum, blenum, countermode, screensaver, adrmode, lorasf, txpower, rlim; extern uint16_t macnum, blenum, salt;
extern int countermode, screensaver, adrmode, lorasf, txpower, rlim;
extern bool joinstate; extern bool joinstate;
extern std::set<uint64_t, std::greater <uint64_t> > macs; extern std::set<uint16_t> macs;
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY
extern HAS_DISPLAY u8x8; extern HAS_DISPLAY u8x8;

View File

@ -79,10 +79,10 @@ void printKeys(void) {
#endif // VERBOSE #endif // VERBOSE
void do_send(osjob_t* j){ void do_send(osjob_t* j){
mydata[0] = (macnum & 0x0000ff00) >> 8; mydata[0] = (macnum & 0xff00) >> 8;
mydata[1] = macnum & 0x000000ff; mydata[1] = macnum & 0x00ff;
mydata[2] = (blenum & 0x0000ff00) >> 8; mydata[2] = (blenum & 0xff00) >> 8;
mydata[3] = blenum & 0x000000ff; mydata[3] = blenum & 0x00ff;
// Check if there is not a current TX/RX job running // Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) { if (LMIC.opmode & OP_TXRXPEND) {

View File

@ -25,9 +25,6 @@ Refer to LICENSE.txt file in repository for more details.
#include "main.h" #include "main.h"
#include "globals.h" #include "globals.h"
// std::set for unified array functions
#include <set>
// OLED driver // OLED driver
#include <U8x8lib.h> #include <U8x8lib.h>
@ -45,11 +42,11 @@ configData_t cfg; // struct holds current device configuration
osjob_t sendjob, initjob; // LMIC osjob_t sendjob, initjob; // LMIC
// Initialize global variables // Initialize global variables
int macnum = 0, blenum = 0; uint16_t macnum = 0, blenum = 0, salt;
uint64_t uptimecounter = 0; uint64_t uptimecounter = 0;
bool joinstate = false; bool joinstate = false;
std::set<uint64_t, std::greater <uint64_t> > macs; // storage holds MAC frames std::set<uint16_t> macs; // associative container holds filtered MAC adresses
// this variable will be changed in the ISR, and read in main loop // this variable will be changed in the ISR, and read in main loop
static volatile bool ButtonTriggered = false; static volatile bool ButtonTriggered = false;
@ -70,16 +67,29 @@ void eraseConfig(void);
void saveConfig(void); void saveConfig(void);
void loadConfig(void); void loadConfig(void);
/* begin LMIC specific parts ------------------------------------------------------------ */ /* begin LMIC specific parts ------------------------------------------------------------ */
// LMIC enhanced Pin mapping
const lmic_pinmap lmic_pins = {
.mosi = PIN_SPI_MOSI,
.miso = PIN_SPI_MISO,
.sck = PIN_SPI_SCK,
.nss = PIN_SPI_SS,
.rxtx = LMIC_UNUSED_PIN,
.rst = RST,
.dio = {DIO0, DIO1, DIO2}
};
// defined in lorawan.cpp // defined in lorawan.cpp
void gen_lora_deveui(uint8_t * pdeveui); void gen_lora_deveui(uint8_t * pdeveui);
void RevBytes(unsigned char* b, size_t c); void RevBytes(unsigned char* b, size_t c);
#ifdef VERBOSE #ifdef VERBOSE
void printKeys(void); void printKeys(void);
#endif // VERBOSE #endif
// LMIC functions
void onEvent(ev_t ev);
void do_send(osjob_t* j);
// LMIC callback functions // LMIC callback functions
void os_getDevKey (u1_t *buf) { void os_getDevKey (u1_t *buf) {
@ -102,21 +112,6 @@ void os_getDevEui (u1_t* buf) {
gen_lora_deveui(buf); // generate DEVEUI from device's MAC gen_lora_deveui(buf); // generate DEVEUI from device's MAC
} }
// LMIC enhanced Pin mapping
const lmic_pinmap lmic_pins = {
.mosi = PIN_SPI_MOSI,
.miso = PIN_SPI_MISO,
.sck = PIN_SPI_SCK,
.nss = PIN_SPI_SS,
.rxtx = LMIC_UNUSED_PIN,
.rst = RST,
.dio = {DIO0, DIO1, DIO2}
};
// LMIC functions
void onEvent(ev_t ev);
void do_send(osjob_t* j);
// LoRaWAN Initjob // LoRaWAN Initjob
static void lora_init (osjob_t* j) { static void lora_init (osjob_t* j) {
// reset MAC state // reset MAC state
@ -193,7 +188,7 @@ void wifi_sniffer_loop(void * pvParameters) {
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
uint8_t channel = 1; uint8_t channel = 1;
int nloop=0, lorawait=0; int nloop=0, lorawait=0;
while (true) { while (true) {
nloop++; nloop++;
vTaskDelay(cfg.wifichancycle*10 / portTICK_PERIOD_MS); vTaskDelay(cfg.wifichancycle*10 / portTICK_PERIOD_MS);
@ -208,20 +203,21 @@ void wifi_sniffer_loop(void * pvParameters) {
// execute BLE count if BLE function is enabled // execute BLE count if BLE function is enabled
#ifdef BLECOUNTER #ifdef BLECOUNTER
if ( cfg.blescan ) if (cfg.blescan)
BLECount(); BLECount();
#endif #endif
// Prepare and execute LoRaWAN data upload // Prepare and execute LoRaWAN data upload
u8x8.setCursor(0,4); u8x8.setCursor(0,4);
u8x8.printf("MAC#: %4i", macnum); u8x8.printf("MAC#: %-5i", macnum);
do_send(&sendjob); // send payload do_send(&sendjob); // send payload
vTaskDelay(500/portTICK_PERIOD_MS); vTaskDelay(500/portTICK_PERIOD_MS);
yield(); yield();
// clear counter if not in cumulative counter mode // clear counter if not in cumulative counter mode
if ( cfg.countermode != 1 ) { if (cfg.countermode != 1) {
macs.erase(macs.begin(), macs.end()); // clear RAM macs.clear(); // clear macs container
salt = random(65536); // get new 16bit random for salting hashes
macnum = 0; macnum = 0;
u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter
} }
@ -384,11 +380,14 @@ void setup() {
antenna_init(); antenna_init();
#endif #endif
// initialize salt value using esp_random() called by random in arduino-esp32 core
salt = random(65536); // get new 16bit random for salting hashes
// initialize display // initialize display
init_display(PROGNAME, PROGVERSION); init_display(PROGNAME, PROGVERSION);
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
u8x8.setCursor(0,5); u8x8.setCursor(0,5);
u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %4i", cfg.rssilimit); u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %4i", cfg.rssilimit);
u8x8.drawString(0,6,"Join Wait "); u8x8.drawString(0,6,"Join Wait ");
// output LoRaWAN keys to console // output LoRaWAN keys to console

View File

@ -1,106 +1,108 @@
// program version // program version
#define PROGVERSION "1.2.5" // use max 10 chars here! #define PROGVERSION "1.2.62" // use max 10 chars here!
#define PROGNAME "PAXCNT" #define PROGNAME "PAXCNT"
// Verbose enables serial output // Verbose enables serial output
#define VERBOSE 1 // comment out to silence the device, for mute use build option #define VERBOSE 1 // comment out to silence the device, for mute use build option
// set this to include BLE counting and vendor filter functions // set this to include BLE counting and vendor filter functions
#define VENDORFILTER 1 // comment out if you want to count things, not people #define VENDORFILTER 1 // comment out if you want to count things, not people
#define BLECOUNTER 1 // comment out if you don't want BLE count #define BLECOUNTER 1 // comment out if you don't want BLE count
// BLE scan time // BLE scan time
#define BLESCANTIME 30 // [seconds] #define BLESCANTIME 30 // [seconds]
// WiFi Sniffer cycle interval // WiFi Sniffer cycle interval
#define SEND_SECS 120 // [seconds/2] -> 240 sec. #define SEND_SECS 120 // [seconds/2] -> 240 sec.
// WiFi sniffer config // WiFi sniffer config
#define WIFI_CHANNEL_MAX 13 #define WIFI_CHANNEL_MIN 1 // start channel number where scan begings
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec. #define WIFI_CHANNEL_MAX 13 // total channel number to scan
#define WIFI_MY_COUNTRY "EU" // for Wifi RF settings
// Default LoRa Spreadfactor #define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
#define LORASFDEFAULT 9 // 7 ... 12
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy // Default LoRa Spreadfactor
#define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands #define LORASFDEFAULT 9 // 7 ... 12
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
// LMIC settings #define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands
// define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored
// define hardware specifics settings in platformio.ini as build_flag for hardware environment // LMIC settings
// define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored
// Select frequency band here according to national regulations // define hardware specifics settings in platformio.ini as build_flag for hardware environment
#define CFG_eu868 1
//#define CFG_us915 1 // Select frequency band here according to national regulations
#define CFG_eu868 1
// This is the SX1272/SX1273 radio, which is also used on the HopeRF //#define CFG_us915 1
// RFM92 boards.
//#define CFG_sx1272_radio 1 // This is the SX1272/SX1273 radio, which is also used on the HopeRF
// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on // RFM92 boards.
// the HopeRF RFM95 boards. //#define CFG_sx1272_radio 1
//#define CFG_sx1276_radio 1 // This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on
// the HopeRF RFM95 boards.
// 16 μs per tick //#define CFG_sx1276_radio 1
// LMIC requires ticks to be 15.5μs - 100 μs long
#define US_PER_OSTICK_EXPONENT 4 // 16 μs per tick
#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT) // LMIC requires ticks to be 15.5μs - 100 μs long
#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK) #define US_PER_OSTICK_EXPONENT 4
#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT)
// Set this to 1 to enable some basic debug output (using printf) about #define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK)
// RF settings used during transmission and reception. Set to 2 to
// enable more verbose output. Make sure that printf is actually // Set this to 1 to enable some basic debug output (using printf) about
// configured (e.g. on AVR it is not by default), otherwise using it can // RF settings used during transmission and reception. Set to 2 to
// cause crashing. // enable more verbose output. Make sure that printf is actually
//#define LMIC_DEBUG_LEVEL 1 // configured (e.g. on AVR it is not by default), otherwise using it can
// cause crashing.
// Enable this to allow using printf() to print to the given serial port //#define LMIC_DEBUG_LEVEL 1
// (or any other Print object). This can be easy for debugging. The
// current implementation only works on AVR, though. // Enable this to allow using printf() to print to the given serial port
//#define LMIC_PRINTF_TO Serial // (or any other Print object). This can be easy for debugging. The
// current implementation only works on AVR, though.
// Any runtime assertion failures are printed to this serial port (or //#define LMIC_PRINTF_TO Serial
// any other Print object). If this is unset, any failures just silently
// halt execution. // Any runtime assertion failures are printed to this serial port (or
#define LMIC_FAILURE_TO Serial // any other Print object). If this is unset, any failures just silently
// halt execution.
// Uncomment this to disable all code related to joining #define LMIC_FAILURE_TO Serial
//#define DISABLE_JOIN
// Uncomment this to disable all code related to ping // Uncomment this to disable all code related to joining
#define DISABLE_PING //#define DISABLE_JOIN
// Uncomment this to disable all code related to beacon tracking. // Uncomment this to disable all code related to ping
// Requires ping to be disabled too #define DISABLE_PING
#define DISABLE_BEACONS // Uncomment this to disable all code related to beacon tracking.
// Requires ping to be disabled too
// Uncomment these to disable the corresponding MAC commands. #define DISABLE_BEACONS
// Class A
//#define DISABLE_MCMD_DCAP_REQ // duty cycle cap // Uncomment these to disable the corresponding MAC commands.
//#define DISABLE_MCMD_DN2P_SET // 2nd DN window param // Class A
//#define DISABLE_MCMD_SNCH_REQ // set new channel //#define DISABLE_MCMD_DCAP_REQ // duty cycle cap
// Class B //#define DISABLE_MCMD_DN2P_SET // 2nd DN window param
//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING //#define DISABLE_MCMD_SNCH_REQ // set new channel
//#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatical disabled by DISABLE_BEACON // Class B
//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING
// In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the //#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatical disabled by DISABLE_BEACON
// same on RX. This ensures that gateways can talk to nodes and vice
// versa, but gateways will not hear other gateways and nodes will not // In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the
// hear other nodes. By uncommenting this macro, this inversion is // same on RX. This ensures that gateways can talk to nodes and vice
// disabled and this node can hear other nodes. If two nodes both have // versa, but gateways will not hear other gateways and nodes will not
// this macro set, they can talk to each other (but they can no longer // hear other nodes. By uncommenting this macro, this inversion is
// hear gateways). This should probably only be used when debugging // disabled and this node can hear other nodes. If two nodes both have
// and/or when talking to the radio directly (e.g. like in the "raw" // this macro set, they can talk to each other (but they can no longer
// example). // hear gateways). This should probably only be used when debugging
//#define DISABLE_INVERT_IQ_ON_RX // and/or when talking to the radio directly (e.g. like in the "raw"
// example).
// This allows choosing between multiple included AES implementations. //#define DISABLE_INVERT_IQ_ON_RX
// Make sure exactly one of these is uncommented.
// // This allows choosing between multiple included AES implementations.
// This selects the original AES implementation included LMIC. This // Make sure exactly one of these is uncommented.
// implementation is optimized for speed on 32-bit processors using //
// fairly big lookup tables, but it takes up big amounts of flash on the // This selects the original AES implementation included LMIC. This
// AVR architecture. // implementation is optimized for speed on 32-bit processors using
// #define USE_ORIGINAL_AES // fairly big lookup tables, but it takes up big amounts of flash on the
// // AVR architecture.
// This selects the AES implementation written by Ideetroon for their // #define USE_ORIGINAL_AES
// own LoRaWAN library. It also uses lookup tables, but smaller //
// byte-oriented ones, making it use a lot less flash space (but it is // This selects the AES implementation written by Ideetroon for their
// also about twice as slow as the original). // own LoRaWAN library. It also uses lookup tables, but smaller
#define USE_IDEETRON_AES // byte-oriented ones, making it use a lot less flash space (but it is
// also about twice as slow as the original).
#define USE_IDEETRON_AES

View File

@ -67,8 +67,9 @@ void set_reset(int val) {
break; break;
case 1: // reset MAC counter case 1: // reset MAC counter
ESP_LOGI(TAG, "Remote command: reset MAC counter"); ESP_LOGI(TAG, "Remote command: reset MAC counter");
macs.erase(macs.begin(), macs.end()); // clear RAM macs.clear(); // clear macs container
macnum = 0; macnum = 0;
salt = random(65536); // get new 16bit random for salting hashes
u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter
u8x8.clearLine(5); u8x8.clearLine(5);
u8x8.setCursor(0, 5); u8x8.setCursor(0, 5);

83
src/rokkithash.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* RokkitHash - Arduino port for Paul Hsieh's "SuperFastHash"
*
* A very quick hash function, (c) Paul Hsieh
*
* See http://www.azillionmonkeys.com/qed/hash.html for more information
* about its inner workings
*
* - Initial Arduino version: 2014 Alex K
* - 8-bit improvements: robtillaart
* - Current maintainer: SukkoPera <software@sukkology.net>
*
* See http://forum.arduino.cc/index.php?topic=226686.0 for some talk
* about the various improvements.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <inttypes.h>
uint32_t rokkit(const char * data, int len) {
uint32_t hash, tmp;
int rem;
if (len <= 0 || data == 0) return 0;
hash = len;
rem = len & 3;
len >>= 2;
/* Main loop */
while (len > 0) {
hash += *((uint16_t*)data);
tmp = (*((uint16_t*)(data+2)) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*2;
hash += hash >> 11;
len--;
}
/* Handle end cases */
switch (rem) {
case 3: hash += *((uint16_t*)data);
hash ^= hash << 16;
hash ^= ((signed char)data[2]) << 18;
hash += hash >> 11;
break;
case 2: hash += *((uint16_t*)data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += (signed char)*data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}

View File

@ -14,7 +14,10 @@
// Local logging tag // Local logging tag
static const char *TAG = "wifisniffer"; static const char *TAG = "wifisniffer";
static wifi_country_t wifi_country = {.cc="EU", .schan=1, .nchan=13, .policy=WIFI_COUNTRY_POLICY_AUTO}; // function defined in rokkithash.cpp
uint32_t rokkit(const char * , int );
static wifi_country_t wifi_country = {.cc=WIFI_MY_COUNTRY, .schan=WIFI_CHANNEL_MIN, .nchan=WIFI_CHANNEL_MAX, .policy=WIFI_COUNTRY_POLICY_MANUAL};
typedef struct { typedef struct {
unsigned frame_ctrl:16; unsigned frame_ctrl:16;
@ -37,17 +40,15 @@ extern void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t
void wifi_sniffer_init(void) { void wifi_sniffer_init(void) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
cfg.nvs_enable = 0; // we don't want wifi settings from NVRAM cfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country)); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) ); ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country)); // set locales for RF and channels
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL) ); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
//ESP_ERROR_CHECK(esp_wifi_start()); // not sure if we need this in this application? ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
//ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(-128)); // we don't need to TX, so we use lowest power level to save energy ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler)); ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
} }
void wifi_sniffer_set_channel(uint8_t channel) { void wifi_sniffer_set_channel(uint8_t channel) {
@ -58,36 +59,40 @@ void wifi_sniffer_packet_handler(void* buff, wifi_promiscuous_pkt_type_t type) {
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff; const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload; const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload;
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr; const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
char counter [10]; char counter [6]; // uint16_t -> 2 byte -> 5 decimals + '0' terminator -> 6 chars
char macbuf [21]; // uint64_t -> 8 byte -> 20 decimals + '0' terminator -> 21 chars
uint64_t addr2int;
uint32_t vendor2int;
uint16_t hashedmac;
std::pair<std::set<uint16_t>::iterator, bool> newmac;
if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value
uint64_t addr2int = ( (uint64_t)hdr->addr2[0] ) | ( (uint64_t)hdr->addr2[1] << 8 ) | ( (uint64_t)hdr->addr2[2] << 16 ) | \ addr2int = ( (uint64_t)hdr->addr2[0] ) | ( (uint64_t)hdr->addr2[1] << 8 ) | ( (uint64_t)hdr->addr2[2] << 16 ) | \
( (uint64_t)hdr->addr2[3] << 24 ) | ( (uint64_t)hdr->addr2[4] << 32 ) | ( (uint64_t)hdr->addr2[5] << 40 ); ( (uint64_t)hdr->addr2[3] << 24 ) | ( (uint64_t)hdr->addr2[4] << 32 ) | ( (uint64_t)hdr->addr2[5] << 40 );
#ifdef VENDORFILTER #ifdef VENDORFILTER // uses vendor array with prefiltered OUIs (no local nd no group MACs, bits 0+1 in 1st byte of OUI)
uint32_t vendor2int = ( (uint32_t)hdr->addr2[2] ) | ( (uint32_t)hdr->addr2[1] << 8 ) | ( (uint32_t)hdr->addr2[0] << 16 ); vendor2int = ( (uint32_t)hdr->addr2[2] ) | ( (uint32_t)hdr->addr2[1] << 8 ) | ( (uint32_t)hdr->addr2[0] << 16 );
if ( std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() ) { if ( std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() ) {
#endif #endif
macs.insert(addr2int); // salt and hash MAC, and if new unique one, store identifier in container and increment counter on display
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
// INFO: RSSI when adding MAC
ESP_LOGI(TAG, "WiFi RSSI: %02d", ppkt->rx_ctrl.rssi); addr2int |= (uint64_t) salt << 48; // prepend 12 bit salt to 48 bit MAC
itoa(addr2int, macbuf, 10); // convert 64 bit MAC to base 10 decimal string
// if new unique MAC logged increment counter on display hashedmac = rokkit(macbuf, 5); // hash MAC, use 5 chars to fit hash in uint16_t container
if ( macs.size() > macnum ) { newmac = macs.insert(hashedmac); // store hashed MAC if new unique
macnum = macs.size(); if (newmac.second) { // first time seen MAC
itoa(macnum, counter, 10); macnum++; // increment MAC counter
itoa(macnum, counter, 10); // base 10 decimal counter value
u8x8.draw2x2String(0, 0, counter); u8x8.draw2x2String(0, 0, counter);
ESP_LOGI(TAG, "MAC counter: %4i", macnum); ESP_LOGI(TAG, "#%05i: RSSI %04d -> Salt %04x -> Hash %04x", macnum, ppkt->rx_ctrl.rssi, salt, hashedmac);
} }
#ifdef VENDORFILTER #ifdef VENDORFILTER
} }
#endif #endif
} else { } else
ESP_LOGI(TAG, "Ignoring RSSI %02d (limit: %i)", ppkt->rx_ctrl.rssi, cfg.rssilimit ); ESP_LOGI(TAG, "RSSI %04d -> ignoring (limit: %i)", ppkt->rx_ctrl.rssi, cfg.rssilimit);
}
yield(); yield();
} }