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:
parent
21e31893f2
commit
a0cb35706c
32
src/Device.cpp
Normal file
32
src/Device.cpp
Normal 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
|
||||
}
|
@ -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
|
@ -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(".");
|
||||
@ -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) {
|
||||
memcpy(buffer + sizeof(SBNetworkHeader), frame.Message, frame.MessageSize);
|
||||
}
|
||||
bool bSuccess = false;
|
||||
uint8_t iCounter = 0;
|
||||
while (!bSuccess && iCounter < RETRY_COUNT) {
|
||||
// Send to broadcast
|
||||
radio.stopListening();
|
||||
radio.openWritingPipe(frame.Header.ToAddress);
|
||||
bool bSuccess = radio.write(buffer, bufferSize);
|
||||
//free(buffer);
|
||||
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;
|
||||
}
|
||||
}
|
||||
#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"));
|
||||
}
|
||||
#if defined(_DEBUG)
|
||||
else {
|
||||
Serial.println(F("Failed"));
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user