Skip to content

Commit

Permalink
Bridge Firmware Support - #2126 and #2127
Browse files Browse the repository at this point in the history
  • Loading branch information
Fishwaldo committed Feb 24, 2020
1 parent 079c8b5 commit 15d6c95
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 58 deletions.
2 changes: 2 additions & 0 deletions cpp/src/Defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ namespace OpenZWave
#define FUNC_ID_ZW_SET_SLAVE_LEARN_MODE 0xA4 // Enter slave learn mode
#define FUNC_ID_ZW_GET_VIRTUAL_NODES 0xA5 // Return all virtual nodes
#define FUNC_ID_ZW_IS_VIRTUAL_NODE 0xA6 // Virtual node test
#define FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE 0xA8 // Bridge Version of FUNC_ID_APPLICATION_COMMAND_HANDLER
#define FUNC_ID_ZW_SEND_DATA_BRIDGE 0xA9 // Bridge Version of FUNC_ID_SEND_DATA
#define FUNC_ID_ZW_SET_PROMISCUOUS_MODE 0xD0 // Set controller into promiscuous mode to listen to all frames
#define FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER 0xD1

Expand Down
149 changes: 101 additions & 48 deletions cpp/src/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@ bool Driver::WriteMsg(string const &msg)
{
node->m_sentCnt++;
node->m_sentTS.SetTime();
if (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER)
if ( (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER) || (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE) )
{
Internal::CC::CommandClass *cc = node->GetCommandClass(m_expectedCommandClassId);
if (cc != NULL)
Expand Down Expand Up @@ -1770,6 +1770,21 @@ bool Driver::ReadMsg()
return true;
}

bool checkReplyForCommandHandler(uint8 expectedReply, uint8 reply) {
if ( ( expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER) || (expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE) ) {
if (reply == FUNC_ID_APPLICATION_COMMAND_HANDLER) {
return true;
} else if (reply == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE) {
return true;
}
return false;
} else if (expectedReply == reply) {
return true;
}
return false;
}


//-----------------------------------------------------------------------------
// <Driver::ProcessMsg>
// Process data received from the Z-Wave PC interface
Expand All @@ -1778,58 +1793,79 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
{
bool handleCallback = true;
bool wasencrypted = false;
//uint8 nodeId = GetNodeNumber( m_currentMsg );
uint8 node;
uint8 cc;
uint8 cccmd;
uint8 startdata;
uint8 pktlength;

if (_data[1] == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE) {
node = _data[4];
cc = _data[6];
cccmd = _data[7];
startdata = 8;
pktlength = 5;

} else {
node = _data[3];
cc = _data[5];
cccmd = _data[6];
startdata = 7;
pktlength = 4;
}

if ((REQUEST == _data[0]) && FUNC_ID_APPLICATION_COMMAND_HANDLER == _data[1] && (Internal::CC::Security::StaticGetCommandClassId() == _data[5]))


if ((REQUEST == _data[0]) && ( ( FUNC_ID_APPLICATION_COMMAND_HANDLER == _data[1] ) || ( FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE == _data[1] ) ) && (Internal::CC::Security::StaticGetCommandClassId() == cc))
{
/* if this message is a NONCE Report - Then just Trigger the Encrypted Send */
if (Internal::CC::SecurityCmd_NonceReport == _data[6])
if (Internal::CC::SecurityCmd_NonceReport == cccmd)
{
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_NonceReport from node %d", _data[3]);
Log::Write(LogLevel_Info, node, "Received SecurityCmd_NonceReport from node %d", node);

/* handle possible resends of NONCE_REPORT messages.... See Issue #931 */
if (!m_currentMsg)
{
Log::Write(LogLevel_Warning, _data[3], "Received a NonceReport from node, but no pending messages. Dropping..");
Log::Write(LogLevel_Warning, node, "Received a NonceReport from node, but no pending messages. Dropping..");
return;
}

// No Need to triger a WriteMsg here - It should be handled automatically
m_currentMsg->setNonce(&_data[7]);
m_currentMsg->setNonce(&_data[startdata]);
this->SendEncryptedMessage();
return;

/* if this is a NONCE Get - Then call to the CC directly, process it, and then bail out. */
}
else if (Internal::CC::SecurityCmd_NonceGet == _data[6])
else if (Internal::CC::SecurityCmd_NonceGet == cccmd)
{
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_NonceGet from node %d", _data[3]);
Log::Write(LogLevel_Info, node, "Received SecurityCmd_NonceGet from node %d", node);
{
uint8 *nonce = NULL;
Internal::LockGuard LG(m_nodeMutex);
Node* node = GetNode(_data[3]);
Node* nodeobj = GetNode(node);
if (node)
{
nonce = node->GenerateNonceKey();
nonce = nodeobj->GenerateNonceKey();
}
else
{
Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]);
Log::Write(LogLevel_Warning, node, "Couldn't Generate Nonce Key for Node %d", node);
return;
}

SendNonceKey(_data[3], nonce);
SendNonceKey(node, nonce);

}
/* don't continue processing */
return;

/* if this message is encrypted, decrypt it first */
}
else if ((Internal::CC::SecurityCmd_MessageEncap == _data[6]) || (Internal::CC::SecurityCmd_MessageEncapNonceGet == _data[6]))
else if ((Internal::CC::SecurityCmd_MessageEncap == cccmd) || (Internal::CC::SecurityCmd_MessageEncapNonceGet == cccmd))
{
uint8 _newdata[256];
uint8 SecurityCmd = _data[6];
uint8 SecurityCmd = cccmd;
uint8 *_nonce;

/* clear out NONCE Report tracking */
Expand All @@ -1839,51 +1875,58 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
/* make sure the Node Exists, and it has the Security CC */
{
Internal::LockGuard LG(m_nodeMutex);
Node* node = GetNode(_data[3]);
if (node)
Node* nodeobj = GetNode(node);
if (nodeobj)
{
_nonce = node->GetNonceKey(_data[_data[4] - 4]);
uint8 nonceid;
if (_data[1] == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE)
nonceid = _data[_data[pktlength]-3];
else
nonceid = _data[_data[pktlength]-4];
_nonce = nodeobj->GetNonceKey(nonceid);
if (!_nonce)
{
Log::Write(LogLevel_Warning, _data[3], "Could Not Retrieve Nonce for Node %d", _data[3]);
Log::Write(LogLevel_Warning, node, "Could Not Retrieve Nonce for Node %d", node);
return;
}
}
else
{
Log::Write(LogLevel_Warning, _data[3], "Can't Find Node %d for Encrypted Message", _data[3]);
Log::Write(LogLevel_Warning, node, "Can't Find Node %d for Encrypted Message", node);
return;
}
}
if (Internal::DecryptBuffer(&_data[5], _data[4] + 1, this, _data[3], this->GetControllerNodeId(), _nonce, &_newdata[0]))
/* StartData - 2 as we start at the CC ID */
if (Internal::DecryptBuffer(&_data[startdata-2], _data[pktlength]+1, this, node, this->GetControllerNodeId(), _nonce, &_newdata[0]))
{
/* Ok - _newdata now contains the decrypted packet */
/* copy it back to the _data packet for processing */
/* New Length - See Decrypt Packet for why these numbers*/
_data[4] = _data[4] - 8 - 8 - 2 - 2;
_data[pktlength] = _data[pktlength] - 8 - 8 - 2 - 2;

/* now copy the decrypted packet */
memcpy(&_data[5], &_newdata[1], _data[4]);
memcpy(&_data[pktlength+1], &_newdata[1], _data[pktlength]);
//PrintHex("Decrypted Packet", _data, _data[4]+5);

/* if the Node has something else to send, it will encrypt a message and send it as a MessageEncapNonceGet */
if (Internal::CC::SecurityCmd_MessageEncapNonceGet == SecurityCmd)
{
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", _data[3]);
Log::Write(LogLevel_Info, node, "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", node);
Internal::LockGuard LG(m_nodeMutex);
Node* node = GetNode(_data[3]);
if (node)
Node* nodeobj = GetNode(node);
if (nodeobj)
{
_nonce = node->GenerateNonceKey();
_nonce = nodeobj->GenerateNonceKey();
}
else
{
Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]);
Log::Write(LogLevel_Warning, node, "Couldn't Generate Nonce Key for Node %d", node);
return;
}
SendNonceKey(_data[3], _nonce);
SendNonceKey(node, _nonce);
}

/* reset our CC as its now decrypted */
cc = _data[1] == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE ? _data[6] : _data[5];
wasencrypted = true;

}
Expand All @@ -1892,19 +1935,19 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
/* if the Node has something else to send, it will encrypt a message and send it as a MessageEncapNonceGet */
if (Internal::CC::SecurityCmd_MessageEncapNonceGet == SecurityCmd)
{
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", _data[3]);
Log::Write(LogLevel_Info, node, "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", node);
Internal::LockGuard LG(m_nodeMutex);
Node* node = GetNode(_data[3]);
Node* nodeobj = GetNode(node);
if (node)
{
_nonce = node->GenerateNonceKey();
_nonce = nodeobj->GenerateNonceKey();
}
else
{
Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]);
Log::Write(LogLevel_Warning, node, "Couldn't Generate Nonce Key for Node %d", node);
return;
}
SendNonceKey(_data[3], _nonce);
SendNonceKey(node, _nonce);
}
/* it failed for some reason, lets just move on */
m_expectedReply = 0;
Expand Down Expand Up @@ -2177,6 +2220,7 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
switch (_data[1])
{
case FUNC_ID_APPLICATION_COMMAND_HANDLER:
case FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE:
{
Log::Write(LogLevel_Detail, "");
HandleApplicationCommandHandlerRequest(_data, wasencrypted);
Expand Down Expand Up @@ -2358,15 +2402,20 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
return;
}
}

if (m_expectedReply)
{
if (m_expectedReply == _data[1])
/* if m_expectedReply was FUNC_ID_APPLICATION_COMMAND_HANDLER then the actual reply can either be
* FUNC_ID_APPLICATION_COMMAND_HANDLER - For Static Controllers or
* FUNC_ID_APPLICATION_COMMAND_HANDLER || FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE for Bridge Controllers
*/
if ( checkReplyForCommandHandler(m_expectedReply, _data[1]) )
{
if (m_expectedCommandClassId && (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER))
if (m_expectedCommandClassId && ( ( m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER) || ( m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE) ) )
{
if (m_expectedCallbackId == 0 && m_expectedCommandClassId == _data[5] && m_expectedNodeId == _data[3])
if (m_expectedCallbackId == 0 && m_expectedCommandClassId == cc && m_expectedNodeId == node)
{
Log::Write(LogLevel_Detail, _data[3], " Expected reply and command class was received");
Log::Write(LogLevel_Detail, node, " Expected reply and command class was received");
m_waitingForAck = false;
m_expectedReply = 0;
m_expectedCommandClassId = 0;
Expand All @@ -2375,7 +2424,7 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
}
else
{
if (IsExpectedReply(_data[3]))
if (IsExpectedReply(node))

{
Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), " Expected reply was received");
Expand Down Expand Up @@ -2403,6 +2452,7 @@ void Driver::ProcessMsg(uint8* _data, uint8 _length)
}
}


//-----------------------------------------------------------------------------
// <Driver::HandleGetVersionResponse>
// Process a response from the Z-Wave PC interface
Expand All @@ -2418,10 +2468,10 @@ void Driver::HandleGetVersionResponse(uint8* _data)
}
Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_GET_VERSION:");
Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " %s library, version %s", m_libraryTypeName.c_str(), m_libraryVersion.c_str());
if (!((m_libraryType == ZW_LIB_CONTROLLER_STATIC) || (m_libraryType == ZW_LIB_CONTROLLER)))
if (!((m_libraryType == ZW_LIB_CONTROLLER_STATIC) || (m_libraryType == ZW_LIB_CONTROLLER) || (m_libraryType == ZW_LIB_CONTROLLER_BRIDGE) ))
{
Log::Write(LogLevel_Fatal, GetNodeNumber(m_currentMsg), "Z-Wave Interface is not a Supported Library Type: %s", m_libraryTypeName.c_str());
Log::Write(LogLevel_Fatal, GetNodeNumber(m_currentMsg), "Z-Wave Interface should be a Static Controller Library Type");
Log::Write(LogLevel_Fatal, GetNodeNumber(m_currentMsg), "Z-Wave Interface should be a Static or Bridge Controller Library Type");

{
Notification* notification = new Notification(Notification::Type_UserAlerts);
Expand Down Expand Up @@ -2550,7 +2600,6 @@ void Driver::HandleGetSerialAPICapabilitiesResponse(uint8* _data)
}

SendMsg(new Internal::Msg("FUNC_ID_SERIAL_API_GET_INIT_DATA", 0xff, REQUEST, FUNC_ID_SERIAL_API_GET_INIT_DATA, false), MsgQueue_Command);
if (!IsBridgeController())
{
Internal::Msg* msg = new Internal::Msg("FUNC_ID_SERIAL_API_SET_TIMEOUTS", 0xff, REQUEST, FUNC_ID_SERIAL_API_SET_TIMEOUTS, false);
msg->Append( ACK_TIMEOUT / 10);
Expand All @@ -2565,9 +2614,9 @@ void Driver::HandleGetSerialAPICapabilitiesResponse(uint8* _data)
/* get a list of Advertised Command Classes */
list<uint8> advertisedCommandClasses = Internal::CC::CommandClasses::GetAdvertisedCommandClasses();
msg->Append((uint8) advertisedCommandClasses.size()); // Length
for (list<uint8>::iterator it = advertisedCommandClasses.begin(); it != advertisedCommandClasses.end(); ++it)
for (list<uint8>::iterator it = advertisedCommandClasses.begin(); it != advertisedCommandClasses.end(); ++it) {
msg->Append(*it);

}
SendMsg(msg, MsgQueue_Command);
}

Expand Down Expand Up @@ -3553,8 +3602,9 @@ void Driver::HandleApplicationCommandHandlerRequest(uint8* _data, bool encrypted
{

uint8 status = _data[2];
uint8 nodeId = _data[3];
uint8 nodeId = this->IsBridgeController() ? _data[4] : _data[3];
uint8 classId = _data[5];
uint8 lengthbyte = this->IsBridgeController() ? _data[5] : _data[4];
Node* node = GetNodeUnsafe(nodeId);

if ((status & RECEIVE_STATUS_ROUTED_BUSY) != 0)
Expand All @@ -3580,7 +3630,7 @@ void Driver::HandleApplicationCommandHandlerRequest(uint8* _data, bool encrypted
memcpy(node->m_lastReceivedMessage, _data, sizeof(node->m_lastReceivedMessage));
}
node->m_receivedTS.SetTime();
if (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER && m_expectedNodeId == nodeId)
if ( ( ( m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER ) || ( m_expectedReply = FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE) ) && ( m_expectedNodeId == nodeId ) )
{
// Need to confirm this is the correct response to the last sent request.
// At least ignore any received messages prior to the send data request.
Expand Down Expand Up @@ -3615,7 +3665,7 @@ void Driver::HandleApplicationCommandHandlerRequest(uint8* _data, bool encrypted
{
if (m_controllerReplication && m_currentControllerCommand && (ControllerCommand_ReceiveConfiguration == m_currentControllerCommand->m_controllerCommand))
{
m_controllerReplication->HandleMsg(&_data[6], _data[4]);
m_controllerReplication->HandleMsg(&_data[6], _data[lengthbyte]);

UpdateControllerState(ControllerState_InProgress);
}
Expand Down Expand Up @@ -6426,6 +6476,9 @@ uint8 Driver::NodeFromMessage(uint8 const* buffer)
case FUNC_ID_APPLICATION_COMMAND_HANDLER:
nodeId = buffer[5];
break;
case FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE:
nodeId = buffer[6];
break;
case FUNC_ID_ZW_APPLICATION_UPDATE:
nodeId = buffer[5];
break;
Expand Down
Loading

0 comments on commit 15d6c95

Please sign in to comment.