From a0cb35706c0c864c886c1206e6e6846273770753 Mon Sep 17 00:00:00 2001 From: Marcel Schulz Date: Fri, 15 Dec 2017 13:55:09 +0100 Subject: [PATCH] Changed the library to not use AutoAcknowledge so that an analysis of the network can not be done by a simple trying to ping a device/master. The master must be paired to a device before he sends any ACK package or must enable new slaves to answer to a MASTER_SEARCH Request. The AutoAcknowledge feature would automatically send an ACK package which makes the master and any other device directly visible. Be aware that this feature does not prevent a devices for being detected by sniffing the radio traffic, because the normal data traffic is still there and not encrypted in any way. An Encryption would hide the sender address. This would make it again more difficult to copy a sender address and simulate a paired device. (This is stikk possible now). But again, this will come later, maybe! The best solution is to implement an encryption feature at a higher communication layer. --- src/Device.cpp | 32 +++++++ src/SBDevice.h | 33 +------ src/SBNetwork.cpp | 192 ++++++++++++++++++++++------------------- src/SBNetwork.h | 14 ++- src/SBNetwork_config.h | 18 ++-- src/SBTypes.h | 2 + 6 files changed, 163 insertions(+), 128 deletions(-) create mode 100644 src/Device.cpp diff --git a/src/Device.cpp b/src/Device.cpp new file mode 100644 index 0000000..6012e6b --- /dev/null +++ b/src/Device.cpp @@ -0,0 +1,32 @@ +#include "SBDevice.h" + +SBMasterStorage SBMasterStorage::initialize() { + SBMasterStorage storage; +#if defined(ESP8266) + EEPROM.begin(SB_NETWORK_FLASH_SIZE); +#endif + EEPROM.get(0 + sizeof(SBNetworkDevice), storage); + if (storage.ID[0] != 'M' || storage.ID[1] != 'S') { + // We have to create a new one + storage.ID[0] = 'M'; + storage.ID[1] = 'S'; + Serial.println("Creating new Master Storage"); + EEPROM.put(0 + sizeof(SBNetworkDevice), storage); +#if defined(ESP8266) + EEPROM.commit(); + EEPROM.end(); +#endif + } + return storage; +} + +void SBMasterStorage::save() { +#if defined(ESP8266) + EEPROM.begin(SB_NETWORK_FLASH_SIZE); +#endif + EEPROM.put(sizeof(SBNetworkDevice), *this); +#if defined(ESP8266) + EEPROM.commit(); + EEPROM.end(); +#endif +} \ No newline at end of file diff --git a/src/SBDevice.h b/src/SBDevice.h index e67e1a9..05218fd 100644 --- a/src/SBDevice.h +++ b/src/SBDevice.h @@ -18,36 +18,11 @@ public: char ID[2] = { 'M', 'S' }; // MS stands for master storage SBMacAddress Slaves[MAX_CLIENTS]; - static SBMasterStorage initialize(){ - SBMasterStorage storage; -#if defined(ESP8266) - EEPROM.begin(FLASH_SIZE); -#endif - EEPROM.get(0 + sizeof(SBNetworkDevice), storage); - if (storage.ID[0] != 'M' || storage.ID[1] != 'S'){ - // We have to create a new one - storage.ID[0] = 'M'; - storage.ID[1] = 'S'; - Serial.println("Creating new Master Storage"); - EEPROM.put(0 + sizeof(SBNetworkDevice), storage); -#if defined(ESP8266) - EEPROM.commit(); - EEPROM.end(); -#endif - } - return storage; - } + static SBMasterStorage initialize(); - void save(){ -#if defined(ESP8266) - EEPROM.begin(FLASH_SIZE); -#endif - EEPROM.put(0 + sizeof(SBNetworkDevice), *this); -#if defined(ESP8266) - EEPROM.commit(); - EEPROM.end(); -#endif - } + void save(); }; +#define SB_NETWORK_FLASH_SIZE (sizeof(SBNetworkDevice) + sizeof(SBMasterStorage)) + #endif \ No newline at end of file diff --git a/src/SBNetwork.cpp b/src/SBNetwork.cpp index 0157e63..4281ad6 100644 --- a/src/SBNetwork.cpp +++ b/src/SBNetwork.cpp @@ -62,7 +62,7 @@ void SBNetwork::initialize(SBMacAddress mac){ this->radio.enableDynamicPayloads(); //this->radio.enableDynamicAck(); - this->radio.setAutoAck(true); + this->radio.setAutoAck(false); // We use our own ack handling //this->radio.enableAckPayload(); this->radio.setRetries(40, 5); @@ -89,7 +89,7 @@ void SBNetwork::initialize(SBMacAddress mac){ void SBNetwork::initializeNetworkDevice(SBNetworkDevice &device, SBMacAddress mac){ Serial.print(F("Try to read device config from internal flash...")); #if defined(ESP8266) - EEPROM.begin(FLASH_SIZE); + EEPROM.begin(SB_NETWORK_FLASH_SIZE); #endif EEPROM.get(0, device); // The first two bytes of a storage must always be 'D' 'S' ID to identifiy, that the device was already initiated if (device.ID[0] == 'D' && device.ID[1] == 'S'){ @@ -121,9 +121,9 @@ void SBNetwork::initializeNetworkDevice(SBNetworkDevice &device, SBMacAddress ma void SBNetwork::resetData(){ Serial.print(F("Erasing device configuration data...")); #if defined(ESP8266) - EEPROM.begin(FLASH_SIZE); + EEPROM.begin(SB_NETWORK_FLASH_SIZE); #endif - for(uint16_t i = 0; i < FLASH_SIZE; i++){ + for(uint16_t i = 0; i < SB_NETWORK_FLASH_SIZE; i++){ EEPROM.write(i, 0); } #if defined(ESP8266) @@ -147,7 +147,6 @@ bool SBNetwork::sendToDevice(SBMacAddress mac, void* message, uint8_t messageSiz frame.Header = header; uint8_t maxPackageSize = MAX_PACKAGE_SIZE; if (messageSize <= maxPackageSize){ - //Serial.print(" with no fragmentation"); // We can send directly without fragmentation frame.Header.FragmentNr = 0; frame.Header.FragmentCount = 1; @@ -166,15 +165,11 @@ bool SBNetwork::sendToDevice(SBMacAddress mac, void* message, uint8_t messageSiz return bSuccess; } else{ - //Serial.print(" with fragmentation "); // We have to send it in fragments uint8_t fragmentCount = messageSize / maxPackageSize; if ((fragmentCount * maxPackageSize) < messageSize){ fragmentCount++; } - //Serial.println(F("Have to send fragments")); - //Serial.print(F("Fragment count = ")); - //Serial.println(fragmentCount, DEC); for (uint8_t i = 0; i < fragmentCount; i++){ #if defined(_DEBUG) Serial.print("."); @@ -196,7 +191,7 @@ bool SBNetwork::sendToDevice(SBMacAddress mac, void* message, uint8_t messageSiz bool bSuccess = this->sendToDevice(frame); if (!bSuccess){ #if defined(_DEBUG) - Serial.println(" Failed"); + Serial.println(" Failed "); #endif return false; } @@ -208,23 +203,74 @@ bool SBNetwork::sendToDevice(SBMacAddress mac, void* message, uint8_t messageSiz } } -bool SBNetwork::sendToDevice(SBNetworkFrame frame){ +bool SBNetwork::sendToDeviceInternal(SBNetworkFrame frame, bool waitForAck) { uint8_t bufferSize = sizeof(SBNetworkHeader) + frame.MessageSize; uint8_t buffer[32]; // = (uint8_t*)malloc(bufferSize); memcpy(buffer, &frame.Header, sizeof(SBNetworkHeader)); - if (frame.MessageSize > 0){ + if (frame.MessageSize > 0) { memcpy(buffer + sizeof(SBNetworkHeader), frame.Message, frame.MessageSize); } - // Send to broadcast - radio.stopListening(); - radio.openWritingPipe(frame.Header.ToAddress); - bool bSuccess = radio.write(buffer, bufferSize); - //free(buffer); - radio.openReadingPipe(0, this->NetworkDevice.MAC); - radio.startListening(); + bool bSuccess = false; + uint8_t iCounter = 0; + while (!bSuccess && iCounter < RETRY_COUNT) { + // Send to broadcast + radio.stopListening(); + radio.openWritingPipe(frame.Header.ToAddress); + bSuccess = radio.write(buffer, bufferSize); + radio.openReadingPipe(0, this->NetworkDevice.MAC); + radio.startListening(); + if (bSuccess) { + bSuccess = waitForAck ? waitForAckFrom(frame.Header.ToAddress) : true; + } + delay(40); // Waittime between two sendings + iCounter++; + } return bSuccess; } +bool SBNetwork::sendToDevice(SBNetworkFrame frame){ + return sendToDeviceInternal(frame, true); +} + +bool SBNetwork::waitForAckFrom(SBMacAddress mac) { +#if defined(_DEBUG) + Serial.print(F("Wait for Ack... ")); +#endif + long lNow = millis(); + // We need the counter in case of the unoccationally case, that during the wait, the timer overflows ans starts with 0 + uint16_t iCounter = 1; + SBNetworkFrame frame; + while (lNow + ACK_WAIT > millis() && iCounter) { + if (this->receiveInternal(&frame)) { + if (frame.Header.FromAddress.isEquals(mac)) { + if (frame.Header.CommandType == SB_COMMAND_ACK) { +#if defined(_DEBUG) + Serial.print(F("Done - Counter = ")); Serial.println(iCounter); +#endif + return true; + } + } + } + iCounter++; + } +#if defined(_DEBUG) + Serial.print(F("Failed - Counter = ")); Serial.println(iCounter); +#endif + return false; +} + +bool SBNetwork::sendAckTo(SBMacAddress mac) { + SBNetworkFrame frame; + frame.Header.ToAddress = mac; + frame.Header.FromAddress = this->NetworkDevice.MAC; + frame.Header.FragmentCount = 1; + frame.Header.FragmentNr = 0; + frame.Header.PackageId = millis(); + frame.Header.CommandType = SB_COMMAND_ACK; + frame.MessageSize = 0; + return sendToDeviceInternal(frame, false); +} + bool SBNetwork::receiveInternal(SBNetworkFrame *frame) { uint8_t pipe = -1; if (radio.available(&pipe)) { @@ -278,20 +324,17 @@ bool SBNetwork::receiveMessage(void **message, uint8_t *messageSize, SBMacAddres return true; } else if (frame.Header.FragmentNr == 0) { + //Serial.print(frame.Header.FragmentNr + 1); Serial.print("/"); Serial.println(frame.Header.FragmentCount); // We have to receive more packages - //uint8_t *buffer = (uint8_t*)malloc((frame.MessageSize * frame.Header.FragmentCount)); memcpy(_ReadBuffer, frame.Message, maxPackageSize); - //free(frame.Message); - delay(10); + delay(50); // We need a delay here, because the opposite needs time to send the next package while (radio.available()) { bReceive = this->receive(&frame); if (!bReceive) { - //free(buffer); return false; } else { memcpy(_ReadBuffer + (frame.Header.FragmentNr * maxPackageSize), frame.Message, frame.MessageSize); - //free(frame.Message); if (frame.Header.FragmentNr == (frame.Header.FragmentCount - 1)) { // Last fragment received *message = _ReadBuffer; @@ -302,14 +345,9 @@ bool SBNetwork::receiveMessage(void **message, uint8_t *messageSize, SBMacAddres delay(10); } } - - //free(buffer); return false; } else { - if (frame.Message != NULL) { - //free(frame.Message); - } return false; } } @@ -339,7 +377,7 @@ bool SBNetwork::connectToNetwork(){ frame.Header = header; frame.Message = NULL; frame.MessageSize = 0; - bool bMasterAck = this->sendToDevice(frame); + bool bMasterAck = this->sendToDeviceInternal(frame, false); unsigned long started_waiting_at = millis(); boolean timeout = false; while (!this->receive(&frame)) { @@ -375,7 +413,7 @@ bool SBNetwork::connectToNetwork(){ conFrame.Header.PackageId = millis(); conFrame.Header.ToAddress = frame.Header.FromAddress; conFrame.MessageSize = 0; - if (!this->sendToDevice(conFrame)) { + if (!this->sendToDeviceInternal(conFrame, false)) { Serial.println(F("Failed - Sending pairing request")); } else { @@ -415,7 +453,7 @@ bool SBNetwork::connectToNetwork(){ } } -bool SBNetwork::pingDeviceInternal(SBMacAddress mac, bool waitForAck) { +bool SBNetwork::pingDevice(SBMacAddress mac){ SBNetworkHeader header; header.ToAddress = mac; header.FromAddress = this->NetworkDevice.MAC; @@ -431,35 +469,14 @@ bool SBNetwork::pingDeviceInternal(SBMacAddress mac, bool waitForAck) { bool bSend = this->sendToDevice(frame); if (bSend) { - if (waitForAck) { - long lNow = millis(); - SBNetworkFrame pingAckFrame; - while ((lNow + 100) > millis()) { - if (this->receiveInternal(&pingAckFrame)) { - if (pingAckFrame.Header.CommandType == SB_COMMAND_PING) { - Serial.println(F("Done - Device available")); - return true; - } - } - } -#if defined(_DEBUG) - Serial.println(F("Failed - Device not responding")); -#endif - return false; - } + Serial.println(F("Done - Device available")); } -#if defined(_DEBUG) else { Serial.println("Failed - Device not responding"); } -#endif return bSend; } -bool SBNetwork::pingDevice(SBMacAddress mac){ - return pingDeviceInternal(mac, true); -} - bool SBNetwork::handleCommandPackage(SBNetworkFrame *frame){ if (!this->RunAsClient) { // First check, if the device is listed in the storage @@ -472,81 +489,74 @@ bool SBNetwork::handleCommandPackage(SBNetworkFrame *frame){ } } - if (!bFound) { - // If an unknown device was detected, then never handle the network control traffic and never handle the messages -#ifdef _DEBUG - Serial.print(F("Unknown device detected with MAC: ")); - printAddress(frame->Header.FromAddress); - Serial.println(); -#endif - //return false; - } + // Look, if we must handle a command package switch (frame->Header.CommandType) { case SB_COMMAND_PING: { #ifdef _DEBUG Serial.println(F("Received 'PING'")); #endif + // Only, when the device is a paired slave, send a ping back if (bFound) { - pingDeviceInternal(frame->Header.FromAddress, false); + sendAckTo(frame->Header.FromAddress); } break; } case SB_COMMAND_SEARCH_MASTER: { -#ifdef _DEBUG - Serial.print(F("Received 'SEARCH_MASTER' Package. ")); -#endif + Serial.print(F("Received 'SEARCH_MASTER'. ")); + // When automatic Client adding is activated if (_EnableAutomaticClientAdding) { -#ifdef _DEBUG - Serial.println(F("Send MasterACK...")); -#endif + Serial.print(F("Send MasterACK...")); delay(20); bool bSend = sendMasterAck(frame->Header.FromAddress); if (bSend) { - return false; + Serial.println(F("Done")); + } + else { + Serial.println(F("Failed")); } - Serial.println(F("Done")); } -#if defined(_DEBUG) else { Serial.println(F("AutomaticClientAdding is deactivaed. Ignoring package.")); } -#endif break; } case SB_COMMAND_REQUEST_PAIRING: { -#ifdef _DEBUG - Serial.print(F("Received 'PAIRING_REQUEST' Package. ")); -#endif + Serial.print(F("Received 'PAIRING_REQUEST'. ")); + // When automatic Client adding is activated if (_EnableAutomaticClientAdding) { -#ifdef _DEBUG - Serial.println(F("Send MasterACK...")); -#endif + Serial.print(F("Send PairingACK... ")); delay(20); - // This is the point where we could stop orpcessing and wait for an user input on the controller to let the new device access the network + // This is the point where we could stop prpcessing and wait for an user input on the controller to let the new device access the network bool bSend = sendPairingAck(frame->Header.FromAddress); + // If sending was successfull, then add the new slave if (bSend) { + Serial.println(F("Done")); + Serial.print(F("Storing new MAC to MasterStorage... ")); addMac(frame->Header.FromAddress); + Serial.println(F("Done")); + } + else { + Serial.println(F("Failed")); } } -#if defined(_DEBUG) else { Serial.println(F("AutomaticClientAdding is deactivaed. Ignoring package.")); } -#endif break; } case SB_COMMAND_NO_COMMAND: - default: { - //Serial.println("No Command received. Passing through transport layer."); - return bFound; - break; - } +#ifdef _DEBUG + Serial.println(F("Received 'NO_COMMAND'")); +#endif + if (bFound) { + return sendAckTo(frame->Header.FromAddress); + } } // Package was handled by handleCommandPackage(); return false; } else { - return true; + return sendAckTo(frame->Header.FromAddress); } } @@ -563,7 +573,7 @@ bool SBNetwork::sendMasterAck(SBMacAddress mac){ frame.Header = header; frame.Message = (uint8_t*)&(this->NetworkDevice.NetworkKey); frame.MessageSize = sizeof(uint32_t); - return this->sendToDevice(frame); + return this->sendToDeviceInternal(frame, false); } else { return false; @@ -584,7 +594,7 @@ bool SBNetwork::sendPairingAck(SBMacAddress mac){ frame.Header = header; frame.Message = NULL; frame.MessageSize = 0; - return this->sendToDevice(frame); + return this->sendToDeviceInternal(frame, false); } else { return false; diff --git a/src/SBNetwork.h b/src/SBNetwork.h index ec16068..a14d3fe 100644 --- a/src/SBNetwork.h +++ b/src/SBNetwork.h @@ -65,6 +65,8 @@ class SBNetwork{ void initializeNetworkDevice(SBNetworkDevice &device, SBMacAddress mac); + bool sendToDeviceInternal(SBNetworkFrame frame, bool waitForAck); + bool sendToDevice(SBNetworkFrame frame); // Return false, if the package was handled internally and if it is not relevant for the end user @@ -80,7 +82,9 @@ class SBNetwork{ bool receiveMessage(void **message, uint8_t *messageSize, SBMacAddress *mac); - bool pingDeviceInternal(SBMacAddress mac, bool waitForAck); + bool waitForAckFrom(SBMacAddress mac); + + bool sendAckTo(SBMacAddress mac); public: /* @@ -183,5 +187,13 @@ public: return _EnableAutomaticClientAdding; } + /* + Returns the count of bytes that are reserved for SBNetworkLib in the internal flash. + If you want to use the internal flash, get shure not writing into the storage of SBNetwork. + */ + uint16_t getFlashOffset() { + return SB_NETWORK_FLASH_SIZE; + } + }; #endif diff --git a/src/SBNetwork_config.h b/src/SBNetwork_config.h index d0ea475..6337550 100644 --- a/src/SBNetwork_config.h +++ b/src/SBNetwork_config.h @@ -2,19 +2,23 @@ #ifndef _SB_NETWORK_CONFIG_ #define _SB_NETWORK_CONFIG_ -// Uncomment the following line, to compile the library for a master device. -//#define RUN_AS_MASTER - +// Generates details debug messages about sending and receiving data packages //#define _DEBUG -#define MASTER_CHECK_INTERVAL 0 // All slaves will ping the master every xxx milliseconds. if set to 0, they will not ping the master +// All slaves will ping the master every xxx milliseconds. if set to 0, they will not ping the master +#define MASTER_CHECK_INTERVAL 0 #define MAX_CLIENTS 10 -#define CLIENT_TIMEOUT 20000 +#define CLIENT_TIMEOUT 60000 -#define FLASH_SIZE 512 +// Waittime for an ACK package +#define ACK_WAIT 50 -#define ACK_WAIT 100 +// Count of trys to send a data package +#define RETRY_COUNT 10 + +// Milliseconds to wait between two retries +#define RETRY_DALY 40 #endif diff --git a/src/SBTypes.h b/src/SBTypes.h index cf86706..e83d2c5 100644 --- a/src/SBTypes.h +++ b/src/SBTypes.h @@ -15,6 +15,8 @@ #define SB_COMMAND_REQUEST_PAIRING 4 // Will be sent from the master after successfule adding a new client #define SB_COMMAND_PAIRING_ACK 5 +// Will always be sent, when packages are received and the other device is a known device +#define SB_COMMAND_ACK 6 class SBMacAddress{ public: