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.
This commit is contained in:
Marcel Schulz 2017-12-15 13:55:09 +01:00
parent 21e31893f2
commit a0cb35706c
6 changed files with 163 additions and 128 deletions

32
src/Device.cpp Normal file
View File

@ -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
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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: