Repository: thomasfla/Linux-ESPNOW Branch: master Commit: 7ca8af0b1cb5 Files: 28 Total size: 60.1 KB Directory structure: gitextract_42a6adbu/ ├── .gitignore ├── ESP32-Test/ │ ├── ESP32-Test.ino │ ├── PYTHON_serial/ │ │ └── serial_logger.py │ ├── p_histogram.ino │ ├── t_callbacks.ino │ └── z_setup_loop.ino ├── ESP8266-Test/ │ ├── ESP8266-Test.ino │ └── serial_logger.py ├── ESP8266_Echo/ │ └── ESP8266_Echo.ino ├── ESPNOW_lib/ │ ├── Makefile │ ├── README.MD │ └── src/ │ ├── ESPNOW_manager.cpp │ ├── ESPNOW_types.cpp │ ├── Includes/ │ │ ├── ESPNOW_manager.h │ │ └── ESPNOW_types.h │ └── main.cpp ├── LICENSE ├── Lab/ │ └── EspNowPacket/ │ ├── EspNowPacket.c │ └── Makefile ├── README.md ├── wifiRawEcho/ │ ├── Includes/ │ │ └── ESPNOW_packet.h │ ├── Makefile │ └── src/ │ ├── ESPNOW_packet.c │ └── main.c ├── wifiRawReceiver/ │ ├── Makefile │ └── main.c └── wifiRawSender/ ├── Makefile └── main.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app wifiRawReceiver/bin/ wifiRawEcho/bin/ ESPNOW_lib/bin/ ESP32-Test/PYTHON_serial/test\.txt *.txt *.pyc *.png *.pcapng ESP32-Test/PYTHON_serial/channel_study\.py ESP32-Test/PYTHON_serial/datarate_study\.py ESP32-Test/PYTHON_serial/trash ================================================ FILE: ESP32-Test/ESP32-Test.ino ================================================ #include #include #include #include //Ticker Library #define CHANNEL 9 #define DATARATE WIFI_PHY_RATE_24M #define N_BATCH 1000 static byte dest_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; //broadcast //static byte dest_mac[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b}; //computers //static byte dest_mac[6] ={0x84, 0xF3, 0xEB, 0x73, 0x55, 0x1E}; //ESP8266 (2) Echo mode esp_now_peer_info_t peer; wifi_config_t wifi_config; Ticker blinker; #define DATA_LEN 127 uint8_t txData[DATA_LEN]; void init_data() { for(int i=0;i> \033[33m" + line + "\033[0m") try : raw_input("Press [enter] to continue.") except: pass ================================================ FILE: ESP32-Test/p_histogram.ino ================================================ #define HISTO_INF 0 #define HISTO_SUP 10000 #define HISTO_N_STEP 100 #define recv_list_len N_BATCH/6 #define packet_received(p) recv_list[p/6] |= 1<= HISTO_N_STEP) { histogram_higher++; } else if(index < 0) { histogram_lower++; } else { histogram[index]++; } packet_received(packet_nb); receiveNb++; avg += value; } void print_histo() { Serial.println("----------"); Serial.printf("Units :\tus"); Serial.println(); Serial.printf("Bounds :\t%d\t%d", HISTO_INF, HISTO_SUP); Serial.println(); Serial.printf("Nb_values :\t%d", HISTO_N_STEP); Serial.println(); for(int i=0;isizeof(sendTime)) { memcpy(&sendTime, rxData, sizeof(sendTime)); memcpy(&packet_nb, rxData+sizeof(sendTime), sizeof(packet_nb)); if(sendTime>batchStart) { fill_histo(receiveTime - sendTime, packet_nb); } } else { error_recv++; } } ================================================ FILE: ESP32-Test/z_setup_loop.ino ================================================ #define TRY_ESP_ACTION(action, name) if(action == ESP_OK) {Serial.println("\t+ "+String(name));} else {Serial.println("----------Error while " + String(name) + " !---------------");} void setup() { Serial.begin(115200); WiFi.disconnect(); //Set device in STA mode to begin with WiFi.mode(WIFI_STA); Serial.println("ESPNow/Basic/Master Example"); // This is the mac address of the Master in Station Mode Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); TRY_ESP_ACTION( esp_wifi_stop(), "stop WIFI"); TRY_ESP_ACTION( esp_wifi_deinit(), "De init"); wifi_init_config_t my_config = WIFI_INIT_CONFIG_DEFAULT(); my_config.ampdu_tx_enable = 0; TRY_ESP_ACTION( esp_wifi_init(&my_config), "Disable AMPDU"); TRY_ESP_ACTION( esp_wifi_start(), "Restart WiFi"); TRY_ESP_ACTION( esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE), "Set channel"); TRY_ESP_ACTION( esp_wifi_internal_set_fix_rate(ESP_IF_WIFI_STA, true, DATARATE), "Fixed rate set up"); TRY_ESP_ACTION( esp_now_init(), "ESPNow Init"); TRY_ESP_ACTION( esp_now_register_send_cb(OnDataSent), "Attach send callback"); TRY_ESP_ACTION( esp_now_register_recv_cb(OnDataRecv), "Attach recv callback"); memset(&peer, 0, sizeof(peer)); for (int ii = 0; ii < 6; ++ii ) { peer.peer_addr[ii] = (uint8_t) dest_mac[ii]; } peer.channel = CHANNEL; // pick a channel peer.encrypt = 0; // no encryption TRY_ESP_ACTION( esp_now_add_peer(&peer), "Add peer"); n_sent = 0; init_data(); blinker.attach(0.001, sendData); } void loop() { if(n_sent >= N_BATCH) { delay(2000); print_histo(); init_histo(); n_sent=0; batchStart = micros(); } else { yield(); } } ================================================ FILE: ESP8266-Test/ESP8266-Test.ino ================================================ /* 19/02/2019 Mac adress modified : Dell laptop Master/Server: Sends a 100Byte ESPNOW data block, and awaits a response SLAVE ADDRESS[84:F3:EB:B3:66:CC] SELF=84:F3:EB:73:55:0D */ #include extern "C" { #include } #include //Ticker Library Ticker blinker; #define WIFI_CHANNEL 1 //byte selfmac[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b}; byte selfmac[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D}; #define NB_TRIES 1000 #define HISTO_INF 0 #define HISTO_SUP 10000 #define HISTO_N_STEP 10 int histogram[HISTO_N_STEP]; int histogram_higher; int histogram_lower; int error_nb; int receiveNb; double avg; long batchStart =0; bool sendNew = true; //MAC ADDRESS OF THE DEVICE YOU ARE SENDING TO //byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0xB3, 0x66, 0xCC}; //byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D}; //byte remoteDevice[6] = {0x00, 0x21, 0x6A, 0xAA, 0xC9, 0x8C}; ///byte remoteDevice[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b}; //computer //byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x1E}; //Deuxieme ESP8266 byte remoteDevice[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const byte dataLength = 250; byte txData[dataLength]; unsigned long n_sent; int error; void init_histo() { for(int i=0;i= HISTO_N_STEP) { histogram_higher++; } else if(index < 0) { histogram_lower++; } else { histogram[index]++; } receiveNb++; avg += value; } void print_histo() { Serial.printf("Bounds\t%d\tµs\t%d\tµs", HISTO_INF, HISTO_SUP); Serial.println(); Serial.printf("Nb out of bounds :"); Serial.println(); Serial.printf("Higher :\t%d\tLower :\t%d", histogram_higher, histogram_lower); Serial.println(); Serial.printf("Histo :"); Serial.println(); for(int i=0;isizeof(sendTime)) { memcpy(&sendTime, data, sizeof(sendTime)); if(sendTime>batchStart) { fill_histo(receiveTime - sendTime); } } else { error_nb++; } sendNew = true; }); esp_now_register_send_cb([](uint8_t* mac, uint8_t sendStatus) { sendNew = sendStatus != 0; }); Serial.println(error);// if ==0 is OK n_sent = 0; blinker.attach(0.01, send_test); } void loop() { yield(); } ================================================ FILE: ESP8266-Test/serial_logger.py ================================================ import serial import time import csv import sys assert len(sys.argv)==3 ser = serial.Serial(sys.argv[1], 115200) ser.flushInput() print "Serial opened : " + str(sys.argv[1]) while True: try: ser_bytes = ser.readline() #print(ser_bytes) with open(sys.argv[2],"a") as f: f.write(ser_bytes) except: print("Keyboard Interrupt") break ================================================ FILE: ESP8266_Echo/ESP8266_Echo.ino ================================================ /* 19/02/2019 Mac adress modified : Dell laptop Master/Server: Sends a 100Byte ESPNOW data block, and awaits a response SLAVE ADDRESS[84:F3:EB:B3:66:CC] SELF=84:F3:EB:73:55:0D */ #include extern "C" { #include } #include //Ticker Library Ticker blinker; #define WIFI_CHANNEL 1 //byte selfmac[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b}; byte selfmac[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x1E}; //MAC ADDRESS OF THE DEVICE YOU ARE SENDING TO //byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0xB3, 0x66, 0xCC}; //byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D}; //byte remoteDevice[6] = {0x00, 0x21, 0x6A, 0xAA, 0xC9, 0x8C}; ///byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D}; //byte remoteDevice[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //broadcast byte remoteDevice[6] {0xB4,0xE6,0x2D,0xB5,0x9F,0x85}; //ESP32 const byte dataLength = 250; byte txData[dataLength]; int error; void send_echo(byte *rxpacket) { memcpy(txData, rxpacket, 8); esp_now_send(remoteDevice, txData, dataLength); } void setup() { for (int i = 0; i < dataLength; i++) { txData[i] = 0x13; } wifi_set_macaddr(STATION_IF,selfmac); Serial.begin(115200); while(!Serial) {delay(1);} Serial.print("\r\n\r\nDevice MAC: "); WiFi.mode(WIFI_STA); WiFi.begin(); Serial.println(WiFi.macAddress()); Serial.println("\r\nESP_Now Dual Mode Transmitter + Receiver [MASTER].\r\n"); esp_now_init(); delay(10); esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); //esp_now_add_peer(remoteDevice, ESP_NOW_ROLE_CONTROLLER, WIFI_CHANNEL, NULL, 0); esp_now_add_peer(NULL, ESP_NOW_ROLE_CONTROLLER, WIFI_CHANNEL, NULL, 0); error = esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len) { if(len>8) { send_echo(data); } }); Serial.println(error);// if ==0 is OK } void loop() { yield(); } ================================================ FILE: ESPNOW_lib/Makefile ================================================ CC = g++ CFLAGS = -g -Wall -std=c++11 INCLUDES = -I src/Includes/ default: all %.o: src/%.cpp mkdir -p bin $(CC) $(CFLAGS) $(INCLUDES) -o bin/$@ -c $^ app: main.o ESPNOW_manager.o ESPNOW_types.o $(CC) $(CFLAGS) -o bin/exec $(addprefix bin/,$^) -pthread all: clear clean app clean: $(RM) bin/* clear: clear ================================================ FILE: ESPNOW_lib/README.MD ================================================ # Before using this code Do not forget to turn on monitor mode and choose the right channel on your wireless interface card. Here is a exmaple on how to do it : ``` sudo ifconfig wlp5s0 down sudo iwconfig wlp5s0 mode monitor sudo ifconfig wlp5s0 up sudo iwconfig wlp5s0 channel 1 ``` ================================================ FILE: ESPNOW_lib/src/ESPNOW_manager.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include "ESPNOW_manager.h" #include "ESPNOW_types.h" #define MAC_2_MSBytes(MAC) MAC == NULL ? 0 : (MAC[0] << 8) | MAC[1] #define MAC_4_LSBytes(MAC) MAC == NULL ? 0 : (((((MAC[2] << 8) | MAC[3]) << 8) | MAC[4]) << 8) | MAC[5] void ESPNOW_manager::set_interface(char* interface) { this->interface = (char*) malloc(strlen(interface)*sizeof(char)); strcpy(this->interface, interface); } void ESPNOW_manager::set_recv_callback(void (*callback)(uint8_t src_mac[6], uint8_t *data, int len)) { recv_thread_params.callback = callback; } void ESPNOW_manager::unset_filter() { if(this->bpf.filter != NULL) { free(this->bpf.filter); this->bpf.filter = NULL; } this->bpf.len = 0; } void ESPNOW_manager::set_filter(uint8_t *src_mac, uint8_t *dst_mac) { //sudo tcpdump -i wlp5s0 'type 0 subtype 0xd0 and wlan[24:4]=0x7f18fe34 and wlan[32]=221 and wlan[33:4]&0xffffff = 0x18fe34 and wlan[37]=0x4 and wlan dst 11:22:33:44:55:66 and wlan src 77:88:99:aa:bb:cc' -dd unset_filter(); this->bpf.len = 53; uint32_t MSB_dst = MAC_2_MSBytes(dst_mac); uint32_t LSB_dst = MAC_4_LSBytes(dst_mac); uint32_t MSB_src = MAC_2_MSBytes(src_mac); uint32_t LSB_src = MAC_4_LSBytes(src_mac); uint8_t jeq_dst = dst_mac == NULL ? 0x30 : 0x15; //0x30 jump if >=. 0x15 jump if ==. uint8_t jeq_src = src_mac == NULL ? 0x30 : 0x15; struct sock_filter temp_code[this->bpf.len] = { { 0x30, 0, 0, 0x00000003 }, { 0x64, 0, 0, 0x00000008 }, { 0x7, 0, 0, 0x00000000 }, { 0x30, 0, 0, 0x00000002 }, { 0x4c, 0, 0, 0x00000000 }, { 0x2, 0, 0, 0x00000000 }, { 0x7, 0, 0, 0x00000000 }, { 0x50, 0, 0, 0x00000000 }, { 0x54, 0, 0, 0x000000fc }, { 0x15, 0, 42, 0x000000d0 }, { 0x40, 0, 0, 0x00000018 }, { 0x15, 0, 40, 0x7f18fe34 }, { 0x50, 0, 0, 0x00000020 }, { 0x15, 0, 38, 0x000000dd }, { 0x40, 0, 0, 0x00000021 }, { 0x54, 0, 0, 0x00ffffff }, { 0x15, 0, 35, 0x0018fe34 }, { 0x50, 0, 0, 0x00000025 }, { 0x15, 0, 33, 0x00000004 }, { 0x50, 0, 0, 0x00000000 }, { 0x45, 31, 0, 0x00000004 }, { 0x45, 0, 21, 0x00000008 }, { 0x50, 0, 0, 0x00000001 }, { 0x45, 0, 4, 0x00000001 }, { 0x40, 0, 0, 0x00000012 }, { jeq_dst, 0, 26, LSB_dst }, { 0x48, 0, 0, 0x00000010 }, { jeq_dst, 4, 24, MSB_dst }, { 0x40, 0, 0, 0x00000006 }, { jeq_dst, 0, 22, LSB_dst }, { 0x48, 0, 0, 0x00000004 }, { jeq_dst, 0, 20, MSB_dst }, { 0x50, 0, 0, 0x00000001 }, { 0x45, 0, 13, 0x00000002 }, { 0x45, 0, 4, 0x00000001 }, { 0x40, 0, 0, 0x0000001a }, { jeq_src, 0, 15, LSB_src }, { 0x48, 0, 0, 0x00000018 }, { jeq_src, 12, 13, MSB_src }, { 0x40, 0, 0, 0x00000012 }, { jeq_src, 0, 11, LSB_src }, { 0x48, 0, 0, 0x00000010 }, { jeq_src, 8, 9, MSB_src }, { 0x40, 0, 0, 0x00000006 }, { jeq_dst, 0, 7, LSB_dst }, { 0x48, 0, 0, 0x00000004 }, { jeq_dst, 0, 5, MSB_dst }, { 0x40, 0, 0, 0x0000000c }, { jeq_src, 0, 3, LSB_src }, { 0x48, 0, 0, 0x0000000a }, { jeq_src, 0, 1, MSB_src }, { 0x6, 0, 0, 0x00040000 }, { 0x6, 0, 0, 0x00000000 } }; this->bpf.filter = (sock_filter*) malloc(sizeof(sock_filter)*this->bpf.len); memcpy(this->bpf.filter, temp_code, sizeof(struct sock_filter) * this->bpf.len); } void ESPNOW_manager::start() { struct sockaddr_ll s_dest_addr; struct ifreq ifr; int fd, //file descriptor ioctl_errno, //ioctl errno bind_errno, //bind errno filter_errno, //attach filter errno priority_errno; //Set priority errno bzero(&s_dest_addr, sizeof(s_dest_addr)); bzero(&ifr, sizeof(ifr)); fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); assert(fd != -1); strncpy((char *)ifr.ifr_name, this->interface, IFNAMSIZ); //interface ioctl_errno = ioctl(fd, SIOCGIFINDEX, &ifr); assert(ioctl_errno >= 0); //abort if error s_dest_addr.sll_family = PF_PACKET; s_dest_addr.sll_protocol = htons(ETH_P_ALL); s_dest_addr.sll_ifindex = ifr.ifr_ifindex; bind_errno = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr)); assert(bind_errno >= 0); //abort if error if(bpf.len > 0) { filter_errno = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &(this->bpf), sizeof(bpf)); assert(filter_errno >= 0); } priority_errno = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &(this->socket_priority), sizeof(this->socket_priority)); assert(priority_errno ==0); this->sock_fd = fd; this->recv_thread_params.sock_fd = this->sock_fd; pthread_create (&recv_thd_id, NULL, &(ESPNOW_manager::sock_recv_thread), &recv_thread_params); } void ESPNOW_manager::stop() { if(recv_thd_id) { pthread_cancel(recv_thd_id); } if (this->sock_fd > 0) { close(this->sock_fd); } } void ESPNOW_manager::end() { stop(); if(this->interface != NULL) { free(this->interface); this->interface = NULL; } if(this->bpf.filter != NULL) { free(this->bpf.filter); this->bpf.filter = NULL; } } void* ESPNOW_manager::sock_recv_thread (void *p_arg) { int raw_bytes_len; uint8_t raw_bytes[LEN_RAWBYTES_MAX]; uint8_t* res_mac; uint8_t* res_payload; int res_len; struct thread_args params = * ((struct thread_args *)p_arg); if(params.callback == NULL) { printf ("No callback for receive, receive thread exited\n"); return EXIT_SUCCESS; }; while(1) { raw_bytes_len = recvfrom (params.sock_fd, raw_bytes, LEN_RAWBYTES_MAX, MSG_TRUNC, NULL, 0); if( -1 == raw_bytes_len ) { perror ("Socket receive failed"); break; } else if( raw_bytes_len < 0 ) { perror ("Socket receive, error "); } else { res_mac = ESPNOW_packet::get_src_mac(raw_bytes,raw_bytes_len); res_payload = ESPNOW_packet::get_payload(raw_bytes, raw_bytes_len); res_len = ESPNOW_packet::get_payload_len(raw_bytes, raw_bytes_len); if(res_mac != NULL && res_payload != NULL && res_len > 0) { params.callback(res_mac, res_payload, res_len); } } } printf ("Receive thread exited \n"); return EXIT_SUCCESS; } /* int ESPNOW_manager::send(ESPNOW_packet p) { uint8_t raw_bytes[LEN_RAWBYTES_MAX]; int len = p.toBytes(raw_bytes, LEN_RAWBYTES_MAX); return sendto(this->sock_fd, raw_bytes, len, 0, NULL, 0); } */ int ESPNOW_manager::send(uint8_t *payload, int len) { uint8_t raw_bytes[LEN_RAWBYTES_MAX]; //Not the most fastest way to do this : // copy the payload in the packet array and then copy it back into the buffer... this->mypacket.wlan.actionframe.content.set_length(len); memcpy(this->mypacket.wlan.actionframe.content.payload, payload, len); int raw_len = mypacket.toBytes(raw_bytes, LEN_RAWBYTES_MAX); return sendto(this->sock_fd, raw_bytes, raw_len, 0, NULL, 0); } int ESPNOW_manager::send() { uint8_t raw_bytes[LEN_RAWBYTES_MAX]; int raw_len = mypacket.toBytes(raw_bytes, LEN_RAWBYTES_MAX); return sendto(this->sock_fd, raw_bytes, raw_len, 0, NULL, 0); } ================================================ FILE: ESPNOW_lib/src/ESPNOW_types.cpp ================================================ #include "ESPNOW_types.h" #include #include #include #include void ESPNOW_packet::set_channel(uint16_t channel_freq) { this->radiotap.channel_freq = channel_freq; } void ESPNOW_packet::set_datarate(uint8_t datarate) { this->radiotap.datarate = datarate; } void ESPNOW_packet::set_src_mac(uint8_t my_mac[6]) { memcpy(this->wlan.sa, my_mac, sizeof(uint8_t)*6); } void ESPNOW_packet::set_dst_mac(uint8_t dst_mac[6]) { memcpy(this->wlan.da, dst_mac, sizeof(uint8_t)*6); memcpy(this->wlan.bssid, dst_mac, sizeof(uint8_t)*6); } int ESPNOW_packet::toBytes(uint8_t *bytes, int max_len) { int correct_len = sizeof(ESPNOW_packet) + this->wlan.actionframe.content.length - 0xff; assert(correct_len <= max_len); memcpy(bytes, this, correct_len); memcpy(bytes + correct_len - sizeof(this->wlan.fcs), &(this->wlan.fcs), sizeof(this->wlan.fcs)); return correct_len; } int ESPNOW_packet::get_radiotap_len(uint8_t *raw_bytes, int len) { if(len < 4) return -1; return (int)raw_bytes[2] + ((int)raw_bytes[3] << 8); } uint8_t* ESPNOW_packet::get_src_mac(uint8_t *raw_bytes, int len) { int radiotap_len = get_radiotap_len(raw_bytes, len); if(len < radiotap_len + 10 + 6) return NULL; return raw_bytes + radiotap_len + 10; } int ESPNOW_packet::get_payload_len(uint8_t *raw_bytes, int len) { int radiotap_len = get_radiotap_len(raw_bytes, len); if(len < radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + 1) return -1; return raw_bytes[radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + 1] - 5; } uint8_t* ESPNOW_packet::get_payload(uint8_t *raw_bytes, int len) { int radiotap_len = get_radiotap_len(raw_bytes, len); if(len < radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + VENDORSPECIFIC_CONTENT_LEN) return NULL; return raw_bytes + radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + VENDORSPECIFIC_CONTENT_LEN; } ================================================ FILE: ESPNOW_lib/src/Includes/ESPNOW_manager.h ================================================ #ifndef ESPNOW_manager_H #define ESPNOW_manager_H #include #include #include #include #include #include #include "ESPNOW_types.h" #define LEN_RAWBYTES_MAX 512 struct thread_args { int sock_fd; void (*callback)(uint8_t src_mac[6], uint8_t *data, int len); }; class ESPNOW_manager { public: ESPNOW_manager() { default_values(); } ESPNOW_manager(char* interface) { default_values(); set_interface(interface); } ESPNOW_manager(char* interface, uint8_t datarate, uint16_t channel_freq, uint8_t src_mac[6], uint8_t dst_mac[6], bool filterOn) { default_values(); set_interface(interface); set_channel(channel_freq); set_datarate(datarate); set_src_mac(src_mac); set_dst_mac(dst_mac); if(filterOn) { set_filter(dst_mac, src_mac); } else { set_filter(NULL, NULL); } } void unset_filter(); void set_filter(uint8_t *src_mac, uint8_t *dst_mac); void set_interface(char* interface); void set_recv_callback(void (*callback)(uint8_t src_mac[6], uint8_t *data, int len)); void start(); void stop(); void end(); //int send(ESPNOW_packet p); int send(uint8_t *payload, int len); int send(); void set_channel(uint16_t channel_freq) { mypacket.set_channel(channel_freq); } void set_datarate(uint8_t datarate) { mypacket.set_datarate(datarate); } void set_src_mac(uint8_t src_mac[6]) { mypacket.set_src_mac(src_mac); } void set_dst_mac(uint8_t dst_mac[6]) { mypacket.set_dst_mac(dst_mac); } ESPNOW_packet mypacket; private: int sock_fd; struct sock_fprog bpf; int socket_priority; char* interface; pthread_t recv_thd_id; struct thread_args recv_thread_params; static void* sock_recv_thread (void *p_arg); void default_values() { bpf.len = 0; socket_priority = 7; //Priority recv_thread_params.callback = NULL; } }; #endif ================================================ FILE: ESPNOW_lib/src/Includes/ESPNOW_types.h ================================================ #ifndef ESPNOW_TYPES_H #define ESPNOW_TYPES_H #include #include #define DATARATE_1Mbps 0x02 #define DATARATE_2Mbps 0x04 #define DATARATE_6Mbps 0x0c #define DATARATE_9Mbps 0x12 #define DATARATE_12Mbps 0x18 #define DATARATE_18Mbps 0x24 #define DATARATE_24Mbps 0x30 #define DATARATE_36Mbps 0x48 #define DATARATE_48Mbps 0x60 #define DATARATE_54Mbps 0x6c #define CHANNEL_freq_1 2412 #define CHANNEL_freq_2 2417 #define CHANNEL_freq_3 2422 #define CHANNEL_freq_4 2427 #define CHANNEL_freq_5 2432 #define CHANNEL_freq_6 2437 #define CHANNEL_freq_7 2442 #define CHANNEL_freq_8 2447 #define CHANNEL_freq_9 2452 #define CHANNEL_freq_10 2457 #define CHANNEL_freq_11 2462 #define CHANNEL_freq_12 2467 #define CHANNEL_freq_13 2472 #define WLAN_LEN 24 #define ACTIONFRAME_HEADER_LEN 8 #define VENDORSPECIFIC_CONTENT_LEN 7 struct IEEE80211_radiotap { uint8_t version; uint8_t pad; uint16_t length; uint32_t present; uint8_t flags; uint8_t datarate; uint16_t channel_freq; uint16_t channel_flags_quarter; //Default values for ESPNOW IEEE80211_radiotap() { this->version = 0; this->pad = 0; this->length = sizeof(IEEE80211_radiotap); this->present = 0x0000000e; this->flags = 0x10; this->datarate = DATARATE_6Mbps; this->channel_freq = CHANNEL_freq_1; this->channel_flags_quarter = 0x00c0; } } __attribute__((__packed__)); struct IEEE80211_vendorspecific { uint8_t elementID; uint8_t length; uint8_t OUI[3]; uint8_t type; uint8_t version; uint8_t payload[250]; //Default values for ESPNOW IEEE80211_vendorspecific() { this->elementID = 0xdd; this->OUI[0] = 0x18; this->OUI[1] = 0xfe; this->OUI[2] = 0x34; this->type = 0x04; this->version = 0x01; } void set_length(int length) {this->length = length + 5;} } __attribute__((__packed__)); struct IEEE80211_actionframe { uint8_t category_code; uint8_t OUI[3]; uint8_t unknown_bytes[4]; struct IEEE80211_vendorspecific content; //Default values for ESPNOW IEEE80211_actionframe() { this->category_code = 0x7f; this->OUI[0] = 0x18; this->OUI[1] = 0xfe; this->OUI[2] = 0x34; bzero(this->unknown_bytes, 4); } } __attribute__((__packed__)); struct IEEE80211_wlan { uint8_t type; uint8_t flags; uint16_t duration; uint8_t da[6]; uint8_t sa[6]; uint8_t bssid[6]; uint16_t seq; struct IEEE80211_actionframe actionframe; uint32_t fcs; //Default values for ESPNOW IEEE80211_wlan() { this->type = 0xd0; this->flags = 0x00; this->duration = 0x0000; //Will be recalculated by the hardware... this->seq = 0x0280; this->fcs = 0x00000000; //Will be recalculated by the hardware... } } __attribute__((__packed__)); typedef struct { struct IEEE80211_radiotap radiotap; struct IEEE80211_wlan wlan; void set_channel(uint16_t channel_freq); void set_datarate(uint8_t datarate); void set_src_mac(uint8_t my_mac[6]); void set_dst_mac(uint8_t dst_mac[6]); int toBytes(uint8_t *bytes, int max_len); static int get_radiotap_len(uint8_t *raw_bytes, int len); static uint8_t* get_src_mac(uint8_t *raw_bytes, int len); static int get_payload_len(uint8_t *raw_bytes, int len); static uint8_t* get_payload(uint8_t *raw_bytes, int len); } __attribute__((__packed__)) ESPNOW_packet; #endif ================================================ FILE: ESPNOW_lib/src/main.cpp ================================================ /* Etienne Arlaud */ #include #include #include #include #include #include #include "ESPNOW_manager.h" #include "ESPNOW_types.h" using namespace std; static uint8_t my_mac[6] = {0xF8, 0x1A, 0x67, 0xb7, 0xEB, 0x0B}; static uint8_t dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t ESP_mac[6] = {0xB4,0xE6,0x2D,0xB5,0x9F,0x85}; ESPNOW_manager *handler; uint8_t payload[127]; void callback(uint8_t src_mac[6], uint8_t *data, int len) { handler->mypacket.wlan.actionframe.content.length = 127 + 5; memcpy(handler->mypacket.wlan.actionframe.content.payload, data, 6); //handler->set_dst_mac(dest_mac); handler->send(); } int main(int argc, char **argv) { assert(argc > 1); nice(-20); handler = new ESPNOW_manager(argv[1], DATARATE_24Mbps, CHANNEL_freq_9, my_mac, dest_mac, false); handler->set_filter(ESP_mac, dest_mac); handler->set_recv_callback(&callback); handler->start(); while(1) { std::this_thread::yield(); } handler->end(); } ================================================ FILE: LICENSE ================================================ BSD 2-Clause License Copyright (c) 2019, thomasfla All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Lab/EspNowPacket/EspNowPacket.c ================================================ /* Florenc Caminade Thomas FLayols Send ESP-NOW vendor specific action frame example https://hackaday.io/project/161896 https://github.com/thomasfla/Linux-ESPNOW Adapted from : https://stackoverflow.com/questions/10824827/raw-sockets-communication-over-wifi-receiver-not-able-to-receive-packets 1/Find your wifi interface: $ iwconfig 2/Setup your interface in monitor mode : $ sudo ifconfig wlp5s0 down $ sudo iwconfig wlp5s0 mode monitor $ sudo ifconfig wlp5s0 up 3/Run this code as root */ #include #include #include #include #include #include #include #include #include #include int packetSetUp(uint8_t* packet, uint8_t* mac_dest, uint8_t* mac_src, uint8_t* payload, int len ); static uint8_t mac_src[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t mac_dest[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D}; static uint8_t gu8a_dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t payload[20] = {0}; static int len = 20; uint8_t esppacket[400] = {0}; int create_raw_socket(char *dev) { struct sockaddr_ll s_dest_addr; //code from sender struct ifreq ifr; int fd, ifi, rb; bzero(&s_dest_addr, sizeof(s_dest_addr)); bzero(&ifr, sizeof(ifr)); (void)memset(&s_dest_addr, 0, sizeof(s_dest_addr)); fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); assert(fd != -1); //abort if error strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ); ifi = ioctl(fd, SIOCGIFINDEX, &ifr); assert(ifi != -1); //abort if error s_dest_addr.sll_family = PF_PACKET; //we don't use a protocol above ethernet layer, just use anything here s_dest_addr.sll_protocol = htons(ETH_P_ALL); s_dest_addr.sll_ifindex = ifr.ifr_ifindex; s_dest_addr.sll_hatype = ARPHRD_ETHER; s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING s_dest_addr.sll_halen = ETH_ALEN; //MAC - begin s_dest_addr.sll_addr[0] = gu8a_dest_mac[0]; s_dest_addr.sll_addr[1] = gu8a_dest_mac[1]; s_dest_addr.sll_addr[2] = gu8a_dest_mac[2]; s_dest_addr.sll_addr[3] = gu8a_dest_mac[3]; s_dest_addr.sll_addr[4] = gu8a_dest_mac[4]; s_dest_addr.sll_addr[5] = gu8a_dest_mac[5]; //MAC - end s_dest_addr.sll_addr[6] = 0x00; //not used s_dest_addr.sll_addr[7] = 0x00; //not used rb = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr)); assert(rb != -1); //abort if error return fd; } int main(int argc, char **argv) { char *dev = argv[1]; int sock_fd = -1; int32_t s32_res = -1; sock_fd = create_raw_socket(dev); /* Creating the raw socket */ if (-1 == sock_fd) { perror("Could not create the socket"); goto LABEL_CLEAN_EXIT; } printf("Socket created\n"); fflush(stdout); sleep(1); printf("******Sending data using raw socket over %s \n", dev); while (1) { int length = packetSetUp(esppacket,mac_dest,mac_src,payload,len); s32_res = sendto(sock_fd,esppacket,length,0,NULL,0); if (-1 == s32_res) { perror("Socket send failed"); goto LABEL_CLEAN_EXIT; } int i = 0; for (i = 0; i < length; i++) printf("%x ", esppacket[i]); printf("\n\n"); usleep(100); } LABEL_CLEAN_EXIT: if (sock_fd > 0) { close(sock_fd); } printf("***** Raw Socket test- end\n"); return EXIT_SUCCESS; } struct ieee80211_radiotap_header { uint8_t radiotap_version; //= 0; uint8_t radiotap_pad; //= 0; uint16_t radiotap_lenght; //= 0x00,0x26; uint32_t radiotap_present_1; //= {0x2f, 0x40, 0x00, 0xa0}; uint32_t radiotap_present_2; //= {0x20, 0x08, 0x00, 0xa0}; uint32_t radiotap_present_3; //= {0x20, 0x08, 0x00, 0x00}; uint8_t radiotap_flags; //= 10; uint8_t radiotap_datarate; //0x0c uint16_t radiotap_channel_freq; //0x6c, 0x09 uint16_t radiotap_channel_flags_quarter; //0xc0, 0x00 } __attribute__((__packed__)); struct ieee80211_wlan { uint8_t wlan_fc_subtype; //0xd0 uint8_t wlan_fc_order; //0x00 uint16_t wlan_duration; //0x3a, 0x01 uint8_t wlan_da[6]; //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d uint8_t wlan_sa[6]; //0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b uint8_t wlan_bssid[6]; //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d uint16_t wlan_seq; //0x70, 0x51 uint8_t wlan_fiwed_category_code; //0x7f uint8_t wlan_tag_oui[3]; //0x18,0xfe, 0x34 uint8_t espheader[11]; uint8_t payload[261]; uint32_t wlan_fcs; //0x1c, 0xd5, 0x35, 0xd3 } __attribute__((__packed__)); typedef struct { struct ieee80211_radiotap_header rtap_header; struct ieee80211_wlan mypayload; } espPacket; int packetSetUp(uint8_t* packet, uint8_t* mac_dest, uint8_t* mac_src, uint8_t* payload, int len ) { /// packet should be at least x long todo calculate x check/// espPacket mypacket; ///to do chage pypacket to packet_header mypacket.rtap_header.radiotap_version = 0; mypacket.rtap_header.radiotap_pad = 0; mypacket.rtap_header.radiotap_lenght = sizeof(mypacket.rtap_header); mypacket.rtap_header.radiotap_present_1 = 0xfe; mypacket.rtap_header.radiotap_flags = 0x10; mypacket.rtap_header.radiotap_datarate = 0x0c; mypacket.rtap_header.radiotap_channel_freq = 0x096c; mypacket.rtap_header.radiotap_channel_flags_quarter = 0x00c0; mypacket.mypayload.wlan_fc_subtype = 0xd0; mypacket.mypayload.wlan_fc_order = 0x00; mypacket.mypayload.wlan_duration = 0x013a; memcpy(mypacket.mypayload.wlan_da,mac_dest,6); memcpy(mypacket.mypayload.wlan_sa,mac_src,6); memcpy(mypacket.mypayload.wlan_bssid,mac_dest,6); mypacket.mypayload.wlan_seq = 0x5170; mypacket.mypayload.wlan_fiwed_category_code = 0x7f; mypacket.mypayload.wlan_tag_oui[0] = 0x18; mypacket.mypayload.wlan_tag_oui[1] = 0xfe; mypacket.mypayload.wlan_tag_oui[2] = 0x34; mypacket.mypayload.espheader[0] = 0xa2;//element ID mypacket.mypayload.espheader[1] = 0x03;//length of Organization Identifier mypacket.mypayload.espheader[2] = 0x92; mypacket.mypayload.espheader[3] = 0xb0; mypacket.mypayload.espheader[4] = 0xdd; mypacket.mypayload.espheader[5] = 0xff; mypacket.mypayload.espheader[6] = 0x18;//Organization ID mypacket.mypayload.espheader[7] = 0xfe;//Organization ID mypacket.mypayload.espheader[8] = 0x34;//Organization ID mypacket.mypayload.espheader[9] = 0x04;//type (should be 4) mypacket.mypayload.espheader[10] = 0x1;//version field memcpy(packet,&mypacket,sizeof(mypacket)); memcpy(packet + sizeof(mypacket),payload,len); mypacket.mypayload.wlan_fcs = 0x00000000; printf("%lu\n", sizeof(mypacket.rtap_header)); return sizeof(mypacket)+len; } ================================================ FILE: Lab/EspNowPacket/Makefile ================================================ test: mkdir -p bin gcc EspNowPacket.c -Wall -o bin/main clean: rm -r bin ================================================ FILE: README.md ================================================ # Linux-ESPNOW An attempt at implementing a direct link between a linux station and an ESP module using ESPNOW protocol for real time robot control Project description here: https://hackaday.io/project/161896 ================================================ FILE: wifiRawEcho/Includes/ESPNOW_packet.h ================================================ #ifndef ESPNOW_PACKET_H #define ESPNOW_PACKET_H #include #include struct IEEE80211_radiotap { uint8_t version; //= 0; uint8_t pad; //= 0; uint16_t length; //= 0x00,0x26; uint32_t present_1; //= {0x2f, 0x40, 0x00, 0xa0}; uint8_t flags; //= 10; uint8_t datarate; //0x0c uint16_t channel_freq; //0x6c, 0x09 uint16_t channel_flags_quarter; //0xc0, 0x00 } __attribute__((__packed__)); struct IEEE80211_vendorspecific { uint8_t elementID; //0xdd uint8_t length; //0xff uint8_t OUI[3]; //0x18,0xfe, 0x34 uint8_t type; //0x04 uint8_t version; //0x01 uint8_t payload[127]; } __attribute__((__packed__)); struct IEEE80211_actionframe { uint8_t category_code; //0x7f uint8_t OUI[3]; //0x18,0xfe, 0x34 uint8_t unknown_bytes[4]; struct IEEE80211_vendorspecific content; } __attribute__((__packed__)); struct IEEE80211_wlan { uint8_t type; //0xd0 uint8_t flags; //0x00 uint16_t duration; //0x3a, 0x01 uint8_t da[6]; //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d uint8_t sa[6]; //0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b uint8_t bssid[6]; //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d uint16_t seq; //0x70, 0x51 struct IEEE80211_actionframe actionframe; uint32_t fcs; //Random values : will be recalculated by the hrdw. } __attribute__((__packed__)); typedef struct { struct IEEE80211_radiotap radiotap; struct IEEE80211_wlan wlan; } __attribute__((__packed__)) ESPNOW_packet; void init_ESPNOW_packet(ESPNOW_packet *packet); int packet_to_bytes(uint8_t *bytes, int max_length, ESPNOW_packet packet); void print_raw_packet(uint8_t *data, int len); #endif ================================================ FILE: wifiRawEcho/Makefile ================================================ CC = gcc CFLAGS = -g -Wall --std=c99 INCLUDES = -I Includes/ default: all %.o: src/%.c $(CC) $(CFLAGS) $(INCLUDES) -o bin/$@ -c $^ app: main.o ESPNOW_packet.o $(CC) $(CFLAGS) -o bin/exec $(addprefix bin/,$^) all: clear clean app clean: $(RM) bin/* clear: clear ================================================ FILE: wifiRawEcho/src/ESPNOW_packet.c ================================================ #include "ESPNOW_packet.h" #include #include #include #include void init_ESPNOW_packet(ESPNOW_packet *packet) { //radiotap header packet->radiotap.version = 0x00; packet->radiotap.pad = 0x00; packet->radiotap.present_1 = 0x0000000e; packet->radiotap.flags = 0x10; packet->radiotap.datarate = 0x6c; packet->radiotap.channel_freq = 0x096c; packet->radiotap.channel_flags_quarter = 0x00c0; packet->radiotap.length = sizeof(packet->radiotap); //Wlan packet->wlan.type = 0xd0; packet->wlan.flags = 0x00; packet->wlan.duration = 0x3a01; packet->wlan.seq = 0x0280;//0x7051; //action frame packet->wlan.actionframe.category_code = 0x7f; packet->wlan.actionframe.OUI[0] = 0x18; packet->wlan.actionframe.OUI[1] = 0xfe; packet->wlan.actionframe.OUI[2] = 0x34; //vendor specific packet->wlan.actionframe.content.elementID = 0xdd; packet->wlan.actionframe.content.length = 0x80;//0xff; packet->wlan.actionframe.content.OUI[0] = 0x18; packet->wlan.actionframe.content.OUI[1] = 0xfe; packet->wlan.actionframe.content.OUI[2] = 0x34; packet->wlan.actionframe.content.type = 0x04; packet->wlan.actionframe.content.version = 0x01; //payload for(int i=0;i<127;i++) { packet->wlan.actionframe.content.payload[i] = 0x13; } } int packet_to_bytes(uint8_t *bytes, int max_length, ESPNOW_packet packet) { int len = sizeof(packet); assert(max_length > len); memcpy(bytes, &packet, len); return len; } void print_raw_packet(uint8_t *data, int len) { printf("----------------------new packet (len : %d)---------------------------\n", len); int i; for (i = 0; i < len; i++) { if (i % 16 == 0) printf("\n"); else if(i % 8 == 0) printf(" "); printf("0x%02x, ", data[i]); } printf("\n\n"); } ================================================ FILE: wifiRawEcho/src/main.c ================================================ /* Etienne Arlaud */ #include #include #include #include #include #include #include #include #include #include #include #include #define PRIORITY_LVL -20 #define SOCKET_PRIORITY 7 #include "ESPNOW_packet.h" #define MY_MAC 0xffffffffffff//0xf81a67b7eb0b static uint8_t broadcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t src_mac[6] = {0xF8, 0x1A, 0x67, 0xb7, 0xEB, 0x0B}; //static uint8_t dest_mac[6] = {0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d}; //ESP8266 static uint8_t dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//{0xB4, 0xE6, 0x2D, 0xB5, 0x9F, 0x85};// ESP32 #define MAX_PACKET_LEN 1000 #define FILTER_LENGTH 53//34 #define MAC_2_MSBytes(MAC) ((uint64_t) MAC & (uint64_t) 0xffff00000000)>>(8*4) #define MAC_4_LSBytes(MAC) (uint64_t) MAC & (((uint64_t) 1<<(4*8))-1) //generated with tcpdump -i wlp5s0 'type 0 subtype 0xd0 and wlan[24:4]=0x7f18fe34 and wlan[32]=221 and wlan[33:4]&0xffffff = 0x18fe34 and wlan[37]=0x4 and wlan dst f8:1a:67:b7:eb:0b' -dd static struct sock_filter bpfcode[FILTER_LENGTH] = { { 0x30, 0, 0, 0x00000003 }, { 0x64, 0, 0, 0x00000008 }, { 0x7, 0, 0, 0x00000000 }, { 0x30, 0, 0, 0x00000002 }, { 0x4c, 0, 0, 0x00000000 }, { 0x2, 0, 0, 0x00000000 }, { 0x7, 0, 0, 0x00000000 }, { 0x50, 0, 0, 0x00000000 }, { 0x54, 0, 0, 0x000000fc }, { 0x15, 0, 42, 0x000000d0 }, { 0x40, 0, 0, 0x00000018 }, { 0x15, 0, 40, 0x7f18fe34 }, { 0x50, 0, 0, 0x00000020 }, { 0x15, 0, 38, 0x000000dd }, { 0x40, 0, 0, 0x00000021 }, { 0x54, 0, 0, 0x00ffffff }, { 0x15, 0, 35, 0x0018fe34 }, { 0x50, 0, 0, 0x00000025 }, { 0x15, 0, 33, 0x00000004 }, { 0x50, 0, 0, 0x00000000 }, { 0x45, 31, 0, 0x00000004 }, { 0x45, 0, 21, 0x00000008 }, { 0x50, 0, 0, 0x00000001 }, { 0x45, 0, 4, 0x00000001 }, { 0x40, 0, 0, 0x00000012 }, { 0x15, 0, 26, 0xffffffff }, { 0x48, 0, 0, 0x00000010 }, { 0x15, 4, 24, 0x0000ffff }, { 0x40, 0, 0, 0x00000006 }, { 0x15, 0, 22, 0xffffffff }, { 0x48, 0, 0, 0x00000004 }, { 0x15, 0, 20, 0x0000ffff }, { 0x50, 0, 0, 0x00000001 }, { 0x45, 0, 13, 0x00000002 }, { 0x45, 0, 4, 0x00000001 }, { 0x40, 0, 0, 0x0000001a }, { 0x15, 0, 15, 0x2db59f85 }, { 0x48, 0, 0, 0x00000018 }, { 0x15, 12, 13, 0x0000b4e6 }, { 0x40, 0, 0, 0x00000012 }, { 0x15, 0, 11, 0x2db59f85 }, { 0x48, 0, 0, 0x00000010 }, { 0x15, 8, 9, 0x0000b4e6 }, { 0x40, 0, 0, 0x00000006 }, { 0x15, 0, 7, 0xffffffff }, { 0x48, 0, 0, 0x00000004 }, { 0x15, 0, 5, 0x0000ffff }, { 0x40, 0, 0, 0x0000000c }, { 0x15, 0, 3, 0x2db59f85 }, { 0x48, 0, 0, 0x0000000a }, { 0x15, 0, 1, 0x0000b4e6 }, { 0x6, 0, 0, 0x00040000 }, { 0x6, 0, 0, 0x00000000 }, /* { 0x30, 0, 0, 0x00000003 }, { 0x64, 0, 0, 0x00000008 }, { 0x7, 0, 0, 0x00000000 }, { 0x30, 0, 0, 0x00000002 }, { 0x4c, 0, 0, 0x00000000 }, { 0x2, 0, 0, 0x00000000 }, { 0x7, 0, 0, 0x00000000 }, { 0x50, 0, 0, 0x00000000 }, { 0x54, 0, 0, 0x000000fc }, { 0x15, 0, 23, 0x000000d0 }, { 0x40, 0, 0, 0x00000018 }, { 0x15, 0, 21, 0x7f18fe34 }, { 0x50, 0, 0, 0x00000020 }, { 0x15, 0, 19, 0x000000dd }, { 0x40, 0, 0, 0x00000021 }, { 0x54, 0, 0, 0x00ffffff }, { 0x15, 0, 16, 0x0018fe34 }, { 0x50, 0, 0, 0x00000025 }, { 0x15, 0, 14, 0x00000004 }, { 0x50, 0, 0, 0x00000000 }, { 0x45, 12, 0, 0x00000004 }, { 0x45, 0, 6, 0x00000008 }, { 0x50, 0, 0, 0x00000001 }, { 0x45, 0, 4, 0x00000001 }, { 0x40, 0, 0, 0x00000012 }, { 0x15, 0, 7, 0x67b7eb0b }, { 0x48, 0, 0, 0x00000010 }, { 0x15, 4, 5, 0x0000f81a }, { 0x40, 0, 0, 0x00000006 }, { 0x15, 0, 3, MAC_4_LSBytes(MY_MAC) }, { 0x48, 0, 0, 0x00000004 }, { 0x15, 0, 1, MAC_2_MSBytes(MY_MAC) }, { 0x6, 0, 0, 0x00040000 }, { 0x6, 0, 0, 0x00000000 }, */ }; ESPNOW_packet echo_packet; uint8_t raw_bytes[400]; int create_raw_socket(char *dev, struct sock_fprog *bpf) { struct sockaddr_ll s_dest_addr; struct ifreq ifr; int priority; int fd, //file descriptor ioctl_errno, //ioctl errno bind_errno, //bind errno filter_errno, //attach filter errno priority_errno; //Set priority errno bzero(&s_dest_addr, sizeof(s_dest_addr)); bzero(&ifr, sizeof(ifr)); fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); assert(fd != -1); //abort if error strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ); //interface ioctl_errno = ioctl(fd, SIOCGIFINDEX, &ifr); assert(ioctl_errno >= 0); //abort if error s_dest_addr.sll_family = PF_PACKET; //we don't use a protocol above ethernet layer, just use anything here s_dest_addr.sll_protocol = htons(ETH_P_ALL); s_dest_addr.sll_ifindex = ifr.ifr_ifindex; s_dest_addr.sll_hatype = ARPHRD_ETHER; s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING s_dest_addr.sll_halen = ETH_ALEN; memcpy(&(s_dest_addr.sll_addr),dest_mac, sizeof(*src_mac)*6); //MAC bind_errno = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr)); assert(bind_errno >= 0); //abort if error filter_errno = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(*bpf)); assert(filter_errno >= 0); priority = SOCKET_PRIORITY; priority_errno = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); assert(priority_errno ==0); return fd; } int main(int argc, char **argv) { assert(argc == 2); nice(PRIORITY_LVL); char *dev = argv[1]; int packets_received = 0; uint8_t buff[MAX_PACKET_LEN] = {0}; int sock_fd = -1; int s32_res = -1; struct sock_fprog bpf = {FILTER_LENGTH, bpfcode}; sock_fd = create_raw_socket(dev, &bpf); /* Creating the raw socket */ if (sock_fd < 0) { perror("Could not create the socket"); goto LABEL_CLEAN_EXIT; } else { printf("Socket created\n"); } fflush(stdout); sleep(1); //init answer packet init_ESPNOW_packet(&echo_packet); memcpy(echo_packet.wlan.da, dest_mac, sizeof(uint8_t)*6); memcpy(echo_packet.wlan.sa, src_mac, sizeof(uint8_t)*6); memcpy(echo_packet.wlan.bssid, dest_mac, sizeof(uint8_t)*6); while (1) { int len = recvfrom(sock_fd, buff, MAX_PACKET_LEN, MSG_TRUNC, NULL, 0); if (len < 0) { perror("Socket receive failed or error"); goto LABEL_CLEAN_EXIT; } else if(len > 77) { //printf("Receive packet number : %d\n", ++packets_received); //print_raw_packet(buff, len); //generate echo memcpy(echo_packet.wlan.actionframe.content.payload, buff+77, 16); int mypacket_len = packet_to_bytes(raw_bytes, 400, echo_packet); s32_res = sendto(sock_fd, raw_bytes, mypacket_len,0,NULL,0); if (-1 == s32_res) { perror("Socket send failed"); goto LABEL_CLEAN_EXIT; } else { //printf("Echo sent\n\n\n"); } } } LABEL_CLEAN_EXIT: if (sock_fd > 0) { close(sock_fd); } printf("***** Raw Socket test- end\n"); return EXIT_SUCCESS; } ================================================ FILE: wifiRawReceiver/Makefile ================================================ test: mkdir -p bin gcc main.c -Wall -o bin/receiver clean: rm -r bin ================================================ FILE: wifiRawReceiver/main.c ================================================ /* Florenc Caminade Thomas FLayols Etienne Arlaud Receive raw 802.11 packet and filter ESP-NOW vendor specific action frame using BPF filters. https://hackaday.io/project/161896 https://github.com/thomasfla/Linux-ESPNOW Adapted from : https://stackoverflow.com/questions/10824827/raw-sockets-communication-over-wifi-receiver-not-able-to-receive-packets 1/Find your wifi interface: $ iwconfig 2/Setup your interface in monitor mode : $ sudo ifconfig wlp5s0 down $ sudo iwconfig wlp5s0 mode monitor $ sudo ifconfig wlp5s0 up 3/Run this code as root */ #include #include #include #include #include #include #include #include #include #include #include #define PACKET_LENGTH 400 //Approximate #define MYDATA 18 //0x12 #define MAX_PACKET_LEN 1000 /*our MAC address*/ //{0xF8, 0x1A, 0x67, 0xB7, 0xeB, 0x0B}; /*ESP8266 host MAC address*/ //{0x84,0xF3,0xEB,0x73,0x55,0x0D}; //filter action frame packets //Equivalent for tcp dump : //type 0 subtype 0xd0 and wlan[24:4]=0x7f18fe34 and wlan[32]=221 and wlan[33:4]&0xffffff = 0x18fe34 and wlan[37]=0x4 //NB : There is no filter on source or destination addresses, so this code will 'receive' the action frames sent by this computer... #define FILTER_LENGTH 20 static struct sock_filter bpfcode[FILTER_LENGTH] = { { 0x30, 0, 0, 0x00000003 }, // ldb [3] // radiotap header length : MS byte { 0x64, 0, 0, 0x00000008 }, // lsh #8 // left shift it { 0x7, 0, 0, 0x00000000 }, // tax // 'store' it in X register { 0x30, 0, 0, 0x00000002 }, // ldb [2] // radiotap header length : LS byte { 0x4c, 0, 0, 0x00000000 }, // or x // combine A & X to get radiotap header length in A { 0x7, 0, 0, 0x00000000 }, // tax // 'store' it in X { 0x50, 0, 0, 0x00000000 }, // ldb [x + 0] // right after radiotap header is the type and subtype { 0x54, 0, 0, 0x000000fc }, // and #0xfc // mask the interesting bits, a.k.a 0b1111 1100 { 0x15, 0, 10, 0x000000d0 }, // jeq #0xd0 jt 9 jf 19 // compare the types (0) and subtypes (0xd) { 0x40, 0, 0, 0x00000018 }, // Ld [x + 24] // 24 bytes after radiotap header is the end of MAC header, so it is category and OUI (for action frame layer) { 0x15, 0, 8, 0x7f18fe34 }, // jeq #0x7f18fe34 jt 11 jf 19 // Compare with category = 127 (Vendor specific) and OUI 18:fe:34 { 0x50, 0, 0, 0x00000020 }, // ldb [x + 32] // Begining of Vendor specific content + 4 ?random? bytes : element id { 0x15, 0, 6, 0x000000dd }, // jeq #0xdd jt 13 jf 19 // element id should be 221 (according to the doc) { 0x40, 0, 0, 0x00000021 }, // Ld [x + 33] // OUI (again!) on 3 LS bytes { 0x54, 0, 0, 0x00ffffff }, // and #0xffffff // Mask the 3 LS bytes { 0x15, 0, 3, 0x0018fe34 }, // jeq #0x18fe34 jt 16 jf 19 // Compare with OUI 18:fe:34 { 0x50, 0, 0, 0x00000025 }, // ldb [x + 37] // Type { 0x15, 0, 1, 0x00000004 }, // jeq #0x4 jt 18 jf 19 // Compare type with type 0x4 (corresponding to ESP_NOW) { 0x6, 0, 0, 0x00040000 }, // ret #262144 // return 'True' { 0x6, 0, 0, 0x00000000 }, // ret #0 // return 'False' }; void print_packet(uint8_t *data, int len) { printf("----------------------------new packet-----------------------------------\n"); int i; for (i = 0; i < len; i++) { if (i % 16 == 0) printf("\n"); printf("0x%02x, ", data[i]); } printf("\n\n"); } int create_raw_socket(char *dev, struct sock_fprog *bpf) { struct sockaddr_ll sll; struct ifreq ifr; int fd, ifi, rb, attach_filter; bzero(&sll, sizeof(sll)); bzero(&ifr, sizeof(ifr)); fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); assert(fd != -1); strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ); ifi = ioctl(fd, SIOCGIFINDEX, &ifr); assert(ifi != -1); sll.sll_protocol = htons(ETH_P_ALL); sll.sll_family = PF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_pkttype = PACKET_OTHERHOST; rb = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); assert(rb != -1); attach_filter = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(*bpf)); assert(attach_filter != -1); return fd; } int main(int argc, char **argv) { assert(argc == 2); uint8_t buff[MAX_PACKET_LEN] = {0}; int sock_fd; char *dev = argv[1]; struct sock_fprog bpf = {FILTER_LENGTH, bpfcode}; sock_fd = create_raw_socket(dev, &bpf); /* Creating the raw socket */ printf("\n Waiting to receive packets ........ \n"); while (1) { int len = recvfrom(sock_fd, buff, MAX_PACKET_LEN, MSG_TRUNC, NULL, 0); if (len < 0) { perror("Socket receive failed or error"); break; } else { printf("len:%d\n", len); print_packet(buff, len); } } close(sock_fd); return 0; } ================================================ FILE: wifiRawSender/Makefile ================================================ test: mkdir -p bin gcc main.c -Wall -o bin/sender clean: rm -r bin ================================================ FILE: wifiRawSender/main.c ================================================ /* Florenc Caminade Thomas FLayols Send ESP-NOW vendor specific action frame example https://hackaday.io/project/161896 https://github.com/thomasfla/Linux-ESPNOW Adapted from : https://stackoverflow.com/questions/10824827/raw-sockets-communication-over-wifi-receiver-not-able-to-receive-packets 1/Find your wifi interface: $ iwconfig 2/Setup your interface in monitor mode : $ sudo ifconfig wlp5s0 down $ sudo iwconfig wlp5s0 mode monitor $ sudo ifconfig wlp5s0 up 3/Run this code as root */ #include #include #include #include #include #include #include #include #include #include static uint8_t gu8a_dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; int create_raw_socket(char *dev) { struct sockaddr_ll s_dest_addr; //code from sender struct ifreq ifr; int fd, ifi, rb; bzero(&s_dest_addr, sizeof(s_dest_addr)); bzero(&ifr, sizeof(ifr)); (void)memset(&s_dest_addr, 0, sizeof(s_dest_addr)); fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); assert(fd != -1); //abort if error strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ); ifi = ioctl(fd, SIOCGIFINDEX, &ifr); assert(ifi != -1); //abort if error s_dest_addr.sll_family = PF_PACKET; //we don't use a protocol above ethernet layer, just use anything here s_dest_addr.sll_protocol = htons(ETH_P_ALL); s_dest_addr.sll_ifindex = ifr.ifr_ifindex; s_dest_addr.sll_hatype = ARPHRD_ETHER; s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING s_dest_addr.sll_halen = ETH_ALEN; //MAC - begin s_dest_addr.sll_addr[0] = gu8a_dest_mac[0]; s_dest_addr.sll_addr[1] = gu8a_dest_mac[1]; s_dest_addr.sll_addr[2] = gu8a_dest_mac[2]; s_dest_addr.sll_addr[3] = gu8a_dest_mac[3]; s_dest_addr.sll_addr[4] = gu8a_dest_mac[4]; s_dest_addr.sll_addr[5] = gu8a_dest_mac[5]; //MAC - end s_dest_addr.sll_addr[6] = 0x00; //not used s_dest_addr.sll_addr[7] = 0x00; //not used rb = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr)); assert(rb != -1); //abort if error return fd; } int main(int argc, char **argv) { char *dev = argv[1]; int sock_fd = -1; int32_t s32_res = -1; sock_fd = create_raw_socket(dev); /* Creating the raw socket */ if (-1 == sock_fd) { perror("Could not create the socket"); goto LABEL_CLEAN_EXIT; } printf("Socket created\n"); fflush(stdout); sleep(1); printf("******Sending data using raw socket over %s \n", dev); while (1) { uint8_t data[331] = { 0x00, 0x00, 0x26, 0x00, 0x2f, 0x40, 0x00, 0xa0, 0x20, 0x08, 0x00, 0xa0, 0x20, 0x08, 0x00, 0x00, 0xdf, 0x32, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0c, 0x6c, 0x09, 0xc0, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd3, 0x00, 0xc7, 0x01, 0xd0, 0x00, 0x3a, 0x01, 0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d, 0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b, 0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d, 0x70, 0x51, 0x7f, 0x18, 0xfe, 0x34, 0xa2, 0x03, 0x92, 0xb0, 0xdd, 0xff, 0x18, 0xfe, 0x34, 0x04, 0x01, 0x29, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x1c, 0xd5, 0x35, 0xd3}; //FROM TLINK TO ESP s32_res = sendto(sock_fd,data,331,0,NULL,0); if (-1 == s32_res) { perror("Socket send failed"); goto LABEL_CLEAN_EXIT; } int i = 0; for (i = 0; i < 331; i++) printf("%x ", data[i]); printf("\n\n"); usleep(100); } LABEL_CLEAN_EXIT: if (sock_fd > 0) { close(sock_fd); } printf("***** Raw Socket test- end\n"); return EXIT_SUCCESS; }