use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveSecurityCommandClass in project openhab1-addons by openhab.
the class ZWaveNode method setSecuredClasses.
/**
* Invoked by {@link ZWaveSecurityCommandClass} when a
* {@link ZWaveSecurityCommandClass#SECURITY_SUPPORTED_REPORT} is received.
*
* @param data the class id for each class which must be encrypted in transmission
*/
public void setSecuredClasses(byte[] data) {
logger.info("NODE {}: Setting secured command classes for node with {}", this.getNodeId(), SerialMessage.bb2hex(data));
boolean afterMark = false;
// reset the existing list
securedCommandClasses.clear();
for (final byte aByte : data) {
// TODO: DB support extended commandClass format by checking for 0xF1 - 0xFF
if (ZWaveSecurityCommandClass.bytesAreEqual(aByte, ZWaveSecurityCommandClass.COMMAND_CLASS_MARK)) {
/**
* Marks the end of the list of supported command classes. The remaining classes are those
* that can be controlled by the device. These classes are created without values.
* Messages received cause notification events instead.
*/
afterMark = true;
continue;
}
// Check if this is a commandClass that is already registered with the node
final CommandClass commandClass = CommandClass.getCommandClass((aByte & 0xFF));
if (commandClass == null) {
// Not supported by OpenHab
logger.error("NODE {}: setSecuredClasses requested secure " + "class NOT supported by OpenHab: {} afterMark={}", this.getNodeId(), commandClass, afterMark);
} else {
// can't be set that way since it's the one doing the encryption work So ignore that.
if (commandClass == CommandClass.SECURITY) {
continue;
} else if (afterMark) {
// Nothing to do, we don't track devices that control other devices
logger.info("NODE {}: is after mark for commandClass {}", this.getNodeId(), commandClass);
break;
} else {
if (!this.supportsCommandClass(commandClass)) {
logger.info("NODE {}: Adding secured command class to supported that wasn't in original list {}", this.getNodeId(), commandClass.getLabel());
final ZWaveCommandClass classInstance = ZWaveCommandClass.getInstance((aByte & 0xFF), this, controller);
if (classInstance != null) {
addCommandClass(classInstance);
}
}
securedCommandClasses.add(commandClass);
logger.info("NODE {}: (Secured) {}", this.getNodeId(), commandClass.getLabel());
}
}
}
if (logger.isInfoEnabled()) {
// show which classes are still insecure after the update
final StringBuilder buf = new StringBuilder("NODE " + this.getNodeId() + ": After update, INSECURE command classes are: ");
for (final ZWaveCommandClass zwCommandClass : this.getCommandClasses()) {
if (!securedCommandClasses.contains(zwCommandClass.getCommandClass())) {
buf.append(zwCommandClass.getCommandClass() + ", ");
}
}
logger.info(buf.toString().substring(0, buf.toString().length() - 1));
}
}
use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveSecurityCommandClass in project openhab1-addons by openhab.
the class ApplicationCommandMessageClass method handleRequest.
@Override
public boolean handleRequest(ZWaveController zController, SerialMessage lastSentMessage, SerialMessage incomingMessage) {
logger.trace("Handle Message Application Command Request");
int nodeId = incomingMessage.getMessagePayloadByte(1);
ZWaveNode node = zController.getNode(nodeId);
if (node == null) {
logger.warn("NODE {}: Not initialized yet, ignoring message.", nodeId);
return false;
}
logger.debug("NODE {}: Application Command Request ({}:{})", nodeId, node.getNodeState().toString(), node.getNodeInitializationStage().toString());
// If the node is DEAD, but we've just received a message from it, then it's not dead!
if (node.isDead()) {
node.setNodeState(ZWaveNodeState.ALIVE);
}
node.resetResendCount();
node.incrementReceiveCount();
int commandClassCode = incomingMessage.getMessagePayloadByte(3);
ZWaveCommandClass zwaveCommandClass = resolveZWaveCommandClass(node, commandClassCode, zController);
if (zwaveCommandClass == null) {
// Error message was logged in resolveZWaveCommandClass
return false;
}
final int commandByte = incomingMessage.getMessagePayloadByte(4);
if (zwaveCommandClass instanceof ZWaveSecurityCommandClass && (ZWaveSecurityCommandClass.bytesAreEqual(ZWaveSecurityCommandClass.SECURITY_MESSAGE_ENCAP, commandByte) || ZWaveSecurityCommandClass.bytesAreEqual(ZWaveSecurityCommandClass.SECURITY_MESSAGE_ENCAP_NONCE_GET, commandByte))) {
boolean isEncapNonceGet = ZWaveSecurityCommandClass.bytesAreEqual(ZWaveSecurityCommandClass.SECURITY_MESSAGE_ENCAP_NONCE_GET, commandByte);
// Intercept security encapsulated messages here and decrypt them.
ZWaveSecurityCommandClass zwaveSecurityCommandClass = (ZWaveSecurityCommandClass) zwaveCommandClass;
logger.trace("NODE {}: Preparing to decrypt security encapsulated message, messagePayload={}", nodeId, SerialMessage.bb2hex(incomingMessage.getMessagePayload()));
int toDecryptLength = incomingMessage.getMessageBuffer().length - 9;
byte[] toDecrypt = new byte[toDecryptLength];
System.arraycopy(incomingMessage.getMessageBuffer(), 8, toDecrypt, 0, toDecryptLength);
byte[] decryptedBytes = zwaveSecurityCommandClass.decryptMessage(toDecrypt, 0);
if (decryptedBytes == null) {
logger.error("NODE {}: Failed to decrypt message out of {} .", nodeId, incomingMessage);
} else {
// call handleApplicationCommandRequest with the decrypted message. Note that we do NOT set
// incomingMessage as that needs to be processed below with the original security encapsulated message
final SerialMessage decryptedMessage = new SerialMessage(incomingMessage.getMessageClass(), incomingMessage.getMessageType(), incomingMessage.getExpectedReply(), incomingMessage.getPriority());
decryptedMessage.setMessagePayload(decryptedBytes);
// Get the new command class with the decrypted contents
zwaveCommandClass = resolveZWaveCommandClass(node, decryptedBytes[1], zController);
// Use a flag bc we need to handle isEncapNonceGet either way
boolean failed = false;
if (zwaveCommandClass == null) {
// Error message was logged in resolveZWaveCommandClass
failed = true;
} else {
// Note that we do not call node.doesMessageRequireSecurityEncapsulation since it was encapsulated.
// Messages that are not required to be are allowed to be, just not the other way around
logger.debug("NODE {}: After decrypt, found Command Class {}, passing to handleApplicationCommandRequest", nodeId, zwaveCommandClass.getCommandClass().getLabel());
zwaveCommandClass.handleApplicationCommandRequest(decryptedMessage, 2, 0);
}
if (isEncapNonceGet) {
// the device also needs another nonce; send it regardless of the success/failure of decryption
zwaveSecurityCommandClass.sendNonceReport();
}
if (failed) {
return false;
}
}
} else {
// Message does not require decryption
if (node.doesMessageRequireSecurityEncapsulation(incomingMessage)) {
// Should have been security encapsulation but wasn't!
logger.error("NODE {}: Command Class {} {} was required to be security encapsulation but it wasn't! Dropping message.", nodeId, zwaveCommandClass.getCommandClass().getKey(), zwaveCommandClass.getCommandClass().getLabel());
// do not call zwaveCommandClass.handleApplicationCommandRequest();
} else {
logger.trace("NODE {}: Found Command Class {}, passing to handleApplicationCommandRequest", nodeId, zwaveCommandClass.getCommandClass().getLabel());
zwaveCommandClass.handleApplicationCommandRequest(incomingMessage, 4, 0);
}
}
if (node.getNodeId() == lastSentMessage.getMessageNode()) {
checkTransactionComplete(lastSentMessage, incomingMessage);
} else {
logger.debug("NODE {}: Transaction not completed: node address inconsistent. lastSent={}, incoming={}", lastSentMessage.getMessageNode(), lastSentMessage.getMessageNode(), incomingMessage.getMessageNode());
}
return true;
}
use of org.openhab.binding.zwave.internal.protocol.commandclass.ZWaveSecurityCommandClass in project openhab1-addons by openhab.
the class ZWaveController method enqueue.
/**
* Enqueues a message for sending on the send queue.
*
* @param serialMessage the serial message to enqueue.
*/
public void enqueue(SerialMessage serialMessage) {
// Sanity check!
if (serialMessage == null) {
return;
}
// First try and get the node
// If we're sending to a node, then this obviously isn't to the controller, and we should
// queue anything to a battery node (ie a node supporting the WAKEUP class)!
ZWaveNode node = this.getNode(serialMessage.getMessageNode());
if (node != null) {
// Does this message need to be security encapsulated?
if (node.doesMessageRequireSecurityEncapsulation(serialMessage)) {
ZWaveSecurityCommandClass securityCommandClass = (ZWaveSecurityCommandClass) node.getCommandClass(CommandClass.SECURITY);
securityCommandClass.queueMessageForEncapsulationAndTransmission(serialMessage);
// so we discard this one without putting it on the queue
return;
}
// Keep track of the number of packets sent to this device
node.incrementSendCount();
// If the device isn't listening, queue the message if it supports the wakeup class
if (!node.isListening() && !node.isFrequentlyListening()) {
ZWaveWakeUpCommandClass wakeUpCommandClass = (ZWaveWakeUpCommandClass) node.getCommandClass(CommandClass.WAKE_UP);
// If it's a battery operated device, check if it's awake or place in wake-up queue.
if (wakeUpCommandClass != null && !wakeUpCommandClass.processOutgoingWakeupMessage(serialMessage)) {
return;
}
}
}
// Add the message to the queue
this.sendQueue.add(serialMessage);
if (logger.isTraceEnabled()) {
logger.debug("Enqueueing message. Queue length = {}, Queue = {}", this.sendQueue.size(), this.sendQueue);
} else {
logger.debug("Enqueueing message. Queue length = {}", this.sendQueue.size());
}
}
Aggregations