void sendSketchInfo(const char *name, const char *version, bool enableAck) { if (name != NULL) { _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); } if (version != NULL) { _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); } }
// Helper to process nonce request mesages static bool signerInternalProcessNonceRequest(MyMessage &msg) { #if defined(MY_SIGNING_FEATURE) #if defined(MY_NODE_LOCK_FEATURE) nof_nonce_requests++; SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) { _nodeLock("TMNR"); //Too many nonces requested } #endif // MY_NODE_LOCK_FEATURE if (signerBackendGetNonce(msg)) { if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); } else { SIGN_DEBUG(PSTR("Transmitted nonce\n")); } } else { SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); } #else // not MY_SIGNING_FEATURE (void)msg; SIGN_DEBUG(PSTR("Received nonce request, but signing is not supported (message ignored)\n")); #endif // MY_SIGNING_FEATURE return true; // No need to further process I_NONCE_REQUEST }
bool signerSignMsg(MyMessage &msg) { bool ret; #if defined(MY_SIGNING_FEATURE) // If destination is known to require signed messages and we are the sender, // sign this message unless it is identified as an exception if (DO_SIGN(msg.destination) && msg.sender == getNodeId()) { if (skipSign(msg)) { ret = true; } else { // Send nonce-request _signingNonceStatus=SIGN_WAITING_FOR_NONCE; if (!_sendRoute(build(_msgSign, msg.destination, msg.sensor, C_INTERNAL, I_NONCE_REQUEST).set(""))) { SIGN_DEBUG(PSTR("Failed to transmit nonce request!\n")); ret = false; } else { SIGN_DEBUG(PSTR("Nonce requested from %d. Waiting...\n"), msg.destination); // We have to wait for the nonce to arrive before we can sign our original message // Other messages could come in-between. We trust _process() takes care of them unsigned long enter = hwMillis(); _msgSign = msg; // Copy the message to sign since message buffer might be touched in _process() while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { _process(); } if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { SIGN_DEBUG(PSTR("Timeout waiting for nonce!\n")); ret = false; } else { if (_signingNonceStatus == SIGN_OK) { // process() received a nonce and signerProcessInternal successfully signed the message msg = _msgSign; // Write the signed message back SIGN_DEBUG(PSTR("Message to send has been signed\n")); ret = true; // After this point, only the 'last' member of the message structure is allowed to be altered if the // message has been signed, or signature will become invalid and the message rejected by the receiver } else { SIGN_DEBUG(PSTR("Message to send could not be signed!\n")); ret = false; } } } } } else if (getNodeId() == msg.sender) { mSetSigned(msg, 0); // Message is not supposed to be signed, make sure it is marked unsigned SIGN_DEBUG(PSTR("Will not sign message for destination %d as it does not require it\n"), msg.destination); ret = true; } else { SIGN_DEBUG(PSTR("Will not sign message since it was from %d and we are %d\n"), msg.sender, getNodeId()); ret = true; } #else (void)msg; ret = true; #endif // MY_SIGNING_FEATURE return ret; }
// Message delivered through _msg void _processInternalMessages() { bool isMetric; uint8_t type = _msg.type; #if !defined(MY_DISABLE_REMOTE_RESET) if (type == I_REBOOT) { // Requires MySensors or other bootloader with watchdogs enabled hwReboot(); } else #endif if (type == I_CONFIG) { // Pick up configuration from controller (currently only metric/imperial) // and store it in eeprom if changed if (_msg.getString() == NULL) { isMetric = true; } else { isMetric = _msg.getString()[0] == 'M'; } _cc.isMetric = isMetric; hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); } else if (type == I_PRESENTATION) { if (!mGetAck(_msg)) { // Re-send node presentation to controller #if defined(MY_RADIO_FEATURE) transportPresentNode(); #endif if (presentation) presentation(); } } else if (type == I_HEARTBEAT) { sendHeartbeat(); } else if (type == I_TIME) { // Deliver time to callback if (receiveTime) receiveTime(_msg.getULong()); } #if defined(MY_REPEATER_FEATURE) if (type == I_CHILDREN) { if (_msg.getString()[0] == 'C') { // Clears child relay data for this node debug(PSTR("clear routing table\n")); uint8_t i = 255; do { hwWriteConfig(EEPROM_ROUTES_ADDRESS+i, BROADCAST_ADDRESS); } while (i--); // Clear parent node id & distance to gw hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, AUTO); hwWriteConfig(EEPROM_DISTANCE_ADDRESS, DISTANCE_INVALID); // Find parent node transportFindParentNode(); _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); } } #endif }
void nodeLock(const char* str) { // Make sure EEPROM is updated to locked status hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0); while (1) { debug(PSTR("Node is locked. Ground pin %d and reset to unlock.\n"), MY_NODE_UNLOCK_PIN); #if defined(MY_GATEWAY_ESP8266) yield(); #endif _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_LOCKED, false).set(str)); #if defined(MY_RADIO_FEATURE) transportPowerDown(); #endif (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message } }
void signerPresentation(MyMessage &msg, uint8_t destination) { prepareSigningPresentation(msg, destination); #if defined(MY_SIGNING_REQUEST_SIGNATURES) msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; SIGN_DEBUG(PSTR("Signing required\n")); #endif #if defined(MY_SIGNING_NODE_WHITELISTING) msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; SIGN_DEBUG(PSTR("Whitelisting required\n")); #endif if (!_sendRoute(msg)) { SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } if (destination == GATEWAY_ADDRESS) { SIGN_DEBUG(PSTR("Waiting for GW to send signing preferences...\n")); wait(2000, C_INTERNAL, I_SIGNING_PRESENTATION); } }
// Helper to process presentation mesages static bool signerInternalProcessPresentation(MyMessage &msg) { const uint8_t sender = msg.sender; #if defined(MY_SIGNING_FEATURE) if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); return true; // Just drop this presentation message } // We only handle version 1 here... if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { // We received an indicator that the sender require us to sign all messages we send to it SIGN_DEBUG(PSTR("Mark node %d as one that require signed messages\n"), sender); SET_SIGN(sender); } else { // We received an indicator that the sender does not require us to sign all messages we send to it SIGN_DEBUG(PSTR("Mark node %d as one that do not require signed messages\n"), sender); CLEAR_SIGN(sender); } if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { // We received an indicator that the sender require us to salt signatures with serial SIGN_DEBUG(PSTR("Mark node %d as one that require whitelisting\n"), sender); SET_WHITELIST(sender); } else { // We received an indicator that the sender does not require us to sign all messages we send to it SIGN_DEBUG(PSTR("Mark node %d as one that do not require whitelisting\n"), sender); CLEAR_WHITELIST(sender); } // Save updated tables hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, sizeof(_doWhitelist)); // Inform sender about our preference if we are a gateway, but only require signing if the sender // required signing unless we explicitly configure it to #if defined(MY_GATEWAY_FEATURE) prepareSigningPresentation(msg, sender); #if defined(MY_SIGNING_REQUEST_SIGNATURES) #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; #else if (DO_SIGN(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; } #endif #endif // MY_SIGNING_REQUEST_SIGNATURES #if defined(MY_SIGNING_NODE_WHITELISTING) #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; #else if (DO_WHITELIST(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; } #endif #endif // MY_SIGNING_NODE_WHITELISTING if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), sender); } else { SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), sender); } if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), sender); } else { SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), sender); } if (!_sendRoute(msg)) { SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } #endif // MY_GATEWAY_FEATURE #else // not MY_SIGNING_FEATURE #if defined(MY_GATEWAY_FEATURE) // If we act as gateway and do not have the signing feature and receive a signing request we still // need to do make sure the requester does not believe the gateway still require signatures prepareSigningPresentation(msg, sender); SIGN_DEBUG( PSTR("Informing node %d that we do not require signatures because we do not support it\n"), sender); if (!_sendRoute(msg)) { SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } #else // not MY_GATEWAY_FEATURE // If we act as a node and do not have the signing feature then we just silently drop any signing // presentation messages received (void)msg; (void)sender; SIGN_DEBUG(PSTR("Received signing presentation, but signing is not supported (message ignored)\n")); #endif // not MY_GATEWAY_FEATURE #endif // not MY_SIGNING_FEATURE return true; // No need to further process I_SIGNING_PRESENTATION }
void requestTime() { _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); }
void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { _sendRoute(build(_msg, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); }
void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); }
void sendHeartbeat(void) { _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(_heartbeat)); }
void sendBatteryLevel(uint8_t value, bool enableAck) { _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); }
bool send(MyMessage &message, bool enableAck) { message.sender = _nc.nodeId; mSetCommand(message,C_SET); mSetRequestAck(message,enableAck); return _sendRoute(message); }