Skip to content

Commit 2c9dc8d

Browse files
authored
Merge branch 'ripplebiz:dev' into dev
2 parents a6c8dc4 + 6a6221f commit 2c9dc8d

File tree

18 files changed

+288
-92
lines changed

18 files changed

+288
-92
lines changed

examples/companion_radio/DataStore.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
154154
file.read((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
155155
file.read((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
156156
file.read((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
157-
file.read((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
157+
file.read(pad, 1); // 62
158158
file.read((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
159159
file.read((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
160160
file.read((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
@@ -163,7 +163,8 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
163163
file.read((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
164164
file.read((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
165165
file.read((uint8_t *)&_prefs.advert_loc_policy, sizeof(_prefs.advert_loc_policy)); // 76
166-
file.read(pad, 3); // 77
166+
file.read((uint8_t *)&_prefs.multi_acks, sizeof(_prefs.multi_acks)); // 77
167+
file.read(pad, 2); // 78
167168
file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
168169

169170
file.close();
@@ -184,7 +185,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
184185
file.write((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
185186
file.write((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
186187
file.write((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
187-
file.write((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
188+
file.write(pad, 1); // 62
188189
file.write((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
189190
file.write((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
190191
file.write((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
@@ -193,7 +194,8 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
193194
file.write((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
194195
file.write((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
195196
file.write((uint8_t *)&_prefs.advert_loc_policy, sizeof(_prefs.advert_loc_policy)); // 76
196-
file.write(pad, 3); // 77
197+
file.write((uint8_t *)&_prefs.multi_acks, sizeof(_prefs.multi_acks)); // 77
198+
file.write(pad, 2); // 78
197199
file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
198200

199201
file.close();

examples/companion_radio/MyMesh.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
210210
return (int)((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time);
211211
}
212212

213+
uint8_t MyMesh::getExtraAckTransmitCount() const {
214+
return _prefs.multi_acks;
215+
}
216+
213217
void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) {
214218
if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) {
215219
int i = 0;
@@ -719,7 +723,7 @@ void MyMesh::handleCmdFrame(size_t len) {
719723
i += 4;
720724
memcpy(&out_frame[i], &lon, 4);
721725
i += 4;
722-
out_frame[i++] = 0; // reserved
726+
out_frame[i++] = _prefs.multi_acks; // new v7+
723727
out_frame[i++] = _prefs.advert_loc_policy;
724728
out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) |
725729
(_prefs.telemetry_mode_base); // v5+
@@ -1050,6 +1054,9 @@ void MyMesh::handleCmdFrame(size_t len) {
10501054

10511055
if (len >= 4) {
10521056
_prefs.advert_loc_policy = cmd_frame[3];
1057+
if (len >= 5) {
1058+
_prefs.multi_acks = cmd_frame[4];
1059+
}
10531060
}
10541061
}
10551062
savePrefs();

examples/companion_radio/MyMesh.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
9797
float getAirtimeBudgetFactor() const override;
9898
int getInterferenceThreshold() const override;
9999
int calcRxDelay(float score, uint32_t air_time) const override;
100+
uint8_t getExtraAckTransmitCount() const override;
100101

101102
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
102103
bool isAutoAddEnabled() const override;

examples/companion_radio/NodePrefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct NodePrefs { // persisted to file
1414
float freq;
1515
uint8_t sf;
1616
uint8_t cr;
17-
uint8_t reserved1;
17+
uint8_t multi_acks;
1818
uint8_t manual_add_contacts;
1919
float bw;
2020
uint8_t tx_power_dbm;

examples/companion_radio/UITask.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,12 @@ void UITask::handleButtonQuadruplePress() {
408408
if (strcmp(_sensors->getSettingName(i), "gps") == 0) {
409409
if (strcmp(_sensors->getSettingValue(i), "1") == 0) {
410410
_sensors->setSettingValue("gps", "0");
411+
soundBuzzer(UIEventType::ack);
412+
sprintf(_alert, "GPS: Disabled");
411413
} else {
412414
_sensors->setSettingValue("gps", "1");
415+
soundBuzzer(UIEventType::ack);
416+
sprintf(_alert, "GPS: Enabled");
413417
}
414418
break;
415419
}

examples/simple_repeater/main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
339339
int getAGCResetInterval() const override {
340340
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
341341
}
342+
uint8_t getExtraAckTransmitCount() const override {
343+
return _prefs.multi_acks;
344+
}
342345

343346
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override {
344347
if (packet->getPayloadType() == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin client (unknown at this stage)

examples/simple_room_server/main.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
424424
int getAGCResetInterval() const override {
425425
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
426426
}
427+
uint8_t getExtraAckTransmitCount() const override {
428+
return _prefs.multi_acks;
429+
}
427430

428431
bool allowPacketForward(const mesh::Packet* packet) override {
429432
if (_prefs.disable_fwd) return false;
@@ -578,15 +581,22 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
578581

579582
uint32_t delay_millis;
580583
if (send_ack) {
581-
mesh::Packet* ack = createAck(ack_hash);
582-
if (ack) {
583-
if (client->out_path_len < 0) {
584-
sendFlood(ack, TXT_ACK_DELAY);
585-
} else {
586-
sendDirect(ack, client->out_path, client->out_path_len, TXT_ACK_DELAY);
584+
if (client->out_path_len < 0) {
585+
mesh::Packet* ack = createAck(ack_hash);
586+
if (ack) sendFlood(ack, TXT_ACK_DELAY);
587+
delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS;
588+
} else {
589+
uint32_t d = TXT_ACK_DELAY;
590+
if (getExtraAckTransmitCount() > 0) {
591+
mesh::Packet* a1 = createMultiAck(ack_hash, 1);
592+
if (a1) sendDirect(a1, client->out_path, client->out_path_len, d);
593+
d += 300;
587594
}
595+
596+
mesh::Packet* a2 = createAck(ack_hash);
597+
if (a2) sendDirect(a2, client->out_path, client->out_path_len, d);
598+
delay_millis = d + REPLY_DELAY_MILLIS;
588599
}
589-
delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS;
590600
} else {
591601
delay_millis = 0;
592602
}

examples/simple_sensor/SensorMesh.cpp

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ static uint8_t putFloat(uint8_t * dest, float value, uint8_t size, uint32_t mult
243243
uint8_t SensorMesh::handleRequest(uint8_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len) {
244244
memcpy(reply_data, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag')
245245

246-
if (req_type == REQ_TYPE_GET_TELEMETRY_DATA && (perms & PERM_GET_TELEMETRY) != 0) {
246+
if (req_type == REQ_TYPE_GET_TELEMETRY_DATA) { // allow all
247247
telemetry.reset();
248248
telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
249249
// query other sensors -- target specific
@@ -254,7 +254,7 @@ uint8_t SensorMesh::handleRequest(uint8_t perms, uint32_t sender_timestamp, uint
254254
memcpy(&reply_data[4], telemetry.getBuffer(), tlen);
255255
return 4 + tlen; // reply_len
256256
}
257-
if (req_type == REQ_TYPE_GET_AVG_MIN_MAX && (perms & PERM_GET_OTHER_STATS) != 0) {
257+
if (req_type == REQ_TYPE_GET_AVG_MIN_MAX && (perms & PERM_ACL_ROLE_MASK) >= PERM_ACL_READ_ONLY) {
258258
uint32_t start_secs_ago, end_secs_ago;
259259
memcpy(&start_secs_ago, &payload[0], 4);
260260
memcpy(&end_secs_ago, &payload[4], 4);
@@ -288,13 +288,14 @@ uint8_t SensorMesh::handleRequest(uint8_t perms, uint32_t sender_timestamp, uint
288288
}
289289
return ofs;
290290
}
291-
if (req_type == REQ_TYPE_GET_ACCESS_LIST && (perms & PERM_ACL_ROLE_MASK) == PERM_ACL_LEVEL3) {
291+
if (req_type == REQ_TYPE_GET_ACCESS_LIST && (perms & PERM_ACL_ROLE_MASK) == PERM_ACL_ADMIN) {
292292
uint8_t res1 = payload[0]; // reserved for future (extra query params)
293293
uint8_t res2 = payload[1];
294294
if (res1 == 0 && res2 == 0) {
295295
uint8_t ofs = 4;
296296
for (int i = 0; i < num_contacts && ofs + 7 <= sizeof(reply_data) - 4; i++) {
297297
auto c = &contacts[i];
298+
if (c->permissions == 0) continue; // skip deleted entries
298299
memcpy(&reply_data[ofs], c->id.pub_key, 6); ofs += 6; // just 6-byte pub_key prefix
299300
reply_data[ofs++] = c->permissions;
300301
}
@@ -315,7 +316,14 @@ mesh::Packet* SensorMesh::createSelfAdvert() {
315316
return createAdvert(self_id, app_data, app_data_len);
316317
}
317318

318-
ContactInfo* SensorMesh::putContact(const mesh::Identity& id) {
319+
ContactInfo* SensorMesh::getContact(const uint8_t* pubkey, int key_len) {
320+
for (int i = 0; i < num_contacts; i++) {
321+
if (memcmp(pubkey, contacts[i].id.pub_key, key_len) == 0) return &contacts[i]; // already known
322+
}
323+
return NULL; // not found
324+
}
325+
326+
ContactInfo* SensorMesh::putContact(const mesh::Identity& id, uint8_t init_perms) {
319327
uint32_t min_time = 0xFFFFFFFF;
320328
ContactInfo* oldest = &contacts[MAX_CONTACTS - 1];
321329
for (int i = 0; i < num_contacts; i++) {
@@ -333,22 +341,35 @@ ContactInfo* SensorMesh::putContact(const mesh::Identity& id) {
333341
c = oldest; // evict least active contact
334342
}
335343
memset(c, 0, sizeof(*c));
344+
c->permissions = init_perms;
336345
c->id = id;
337346
c->out_path_len = -1; // initially out_path is unknown
338347
return c;
339348
}
340349

341-
void SensorMesh::applyContactPermissions(const uint8_t* pubkey, uint8_t perms) {
342-
mesh::Identity id(pubkey);
343-
auto c = putContact(id);
344-
350+
bool SensorMesh::applyContactPermissions(const uint8_t* pubkey, int key_len, uint8_t perms) {
351+
ContactInfo* c;
345352
if ((perms & PERM_ACL_ROLE_MASK) == PERM_ACL_GUEST) { // guest role is not persisted in contacts
346-
memset(c, 0, sizeof(*c));
353+
c = getContact(pubkey, key_len);
354+
if (c == NULL) return false; // partial pubkey not found
355+
356+
num_contacts--; // delete from contacts[]
357+
int i = c - contacts;
358+
while (i < num_contacts) {
359+
contacts[i] = contacts[i + 1];
360+
i++;
361+
}
347362
} else {
363+
if (key_len < PUB_KEY_SIZE) return false; // need complete pubkey when adding/modifying
364+
365+
mesh::Identity id(pubkey);
366+
c = putContact(id, 0);
367+
348368
c->permissions = perms; // update their permissions
349369
self_id.calcSharedSecret(c->shared_secret, pubkey);
350370
}
351371
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); // trigger saveContacts()
372+
return true;
352373
}
353374

354375
void SensorMesh::sendAlert(ContactInfo* c, Trigger* t) {
@@ -434,32 +455,43 @@ int SensorMesh::getAGCResetInterval() const {
434455
}
435456

436457
uint8_t SensorMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data) {
437-
if (strcmp((char *) data, _prefs.password) != 0) { // check for valid password
438-
#if MESH_DEBUG
439-
MESH_DEBUG_PRINTLN("Invalid password: %s", &data[4]);
440-
#endif
441-
return 0;
442-
}
458+
ContactInfo* client;
459+
if (data[0] == 0) { // blank password, just check if sender is in ACL
460+
client = getContact(sender.pub_key, PUB_KEY_SIZE);
461+
if (client == NULL) {
462+
#if MESH_DEBUG
463+
MESH_DEBUG_PRINTLN("Login, sender not in ACL");
464+
#endif
465+
return 0;
466+
}
467+
} else {
468+
if (strcmp((char *) data, _prefs.password) != 0) { // check for valid admin password
469+
#if MESH_DEBUG
470+
MESH_DEBUG_PRINTLN("Invalid password: %s", &data[4]);
471+
#endif
472+
return 0;
473+
}
443474

444-
auto client = putContact(sender); // add to contacts (if not already known)
445-
if (sender_timestamp <= client->last_timestamp) {
446-
MESH_DEBUG_PRINTLN("Possible login replay attack!");
447-
return 0; // FATAL: client table is full -OR- replay attack
448-
}
475+
client = putContact(sender, PERM_RECV_ALERTS_HI | PERM_RECV_ALERTS_LO); // add to contacts (if not already known)
476+
if (sender_timestamp <= client->last_timestamp) {
477+
MESH_DEBUG_PRINTLN("Possible login replay attack!");
478+
return 0; // FATAL: client table is full -OR- replay attack
479+
}
449480

450-
MESH_DEBUG_PRINTLN("Login success!");
451-
client->last_timestamp = sender_timestamp;
452-
client->last_activity = getRTCClock()->getCurrentTime();
453-
client->permissions = PERM_ACL_LEVEL3 | PERM_RECV_ALERTS_HI | PERM_RECV_ALERTS_LO; // initially opt-in to receive alerts (can opt out)
454-
memcpy(client->shared_secret, secret, PUB_KEY_SIZE);
481+
MESH_DEBUG_PRINTLN("Login success!");
482+
client->last_timestamp = sender_timestamp;
483+
client->last_activity = getRTCClock()->getCurrentTime();
484+
client->permissions |= PERM_ACL_ADMIN;
485+
memcpy(client->shared_secret, secret, PUB_KEY_SIZE);
455486

456-
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
487+
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
488+
}
457489

458490
uint32_t now = getRTCClock()->getCurrentTimeUnique();
459491
memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp
460492
reply_data[4] = RESP_SERVER_LOGIN_OK;
461493
reply_data[5] = 0; // NEW: recommended keep-alive interval (secs / 16)
462-
reply_data[6] = 1; // 1 = is admin
494+
reply_data[6] = client->isAdmin() ? 1 : 0;
463495
reply_data[7] = client->permissions;
464496
getRNG()->random(&reply_data[8], 4); // random blob to help packet-hash uniqueness
465497

@@ -484,16 +516,20 @@ void SensorMesh::handleCommand(uint32_t sender_timestamp, char* command, char* r
484516
if (memcmp(command, "setperm ", 8) == 0) { // format: setperm {pubkey-hex} {permissions-int8}
485517
char* hex = &command[8];
486518
char* sp = strchr(hex, ' '); // look for separator char
487-
if (sp == NULL || sp - hex != PUB_KEY_SIZE*2) {
488-
strcpy(reply, "Err - bad pubkey len");
519+
if (sp == NULL) {
520+
strcpy(reply, "Err - bad params");
489521
} else {
490522
*sp++ = 0; // replace space with null terminator
491523

492524
uint8_t pubkey[PUB_KEY_SIZE];
493-
if (mesh::Utils::fromHex(pubkey, PUB_KEY_SIZE, hex)) {
525+
int hex_len = min(sp - hex, PUB_KEY_SIZE*2);
526+
if (mesh::Utils::fromHex(pubkey, hex_len / 2, hex)) {
494527
uint8_t perms = atoi(sp);
495-
applyContactPermissions(pubkey, perms);
496-
strcpy(reply, "OK");
528+
if (applyContactPermissions(pubkey, hex_len / 2, perms)) {
529+
strcpy(reply, "OK");
530+
} else {
531+
strcpy(reply, "Err - invalid params");
532+
}
497533
} else {
498534
strcpy(reply, "Err - bad pubkey");
499535
}
@@ -502,6 +538,7 @@ void SensorMesh::handleCommand(uint32_t sender_timestamp, char* command, char* r
502538
Serial.println("ACL:");
503539
for (int i = 0; i < num_contacts; i++) {
504540
auto c = &contacts[i];
541+
if (c->permissions == 0) continue; // skip deleted entries
505542

506543
Serial.printf("%02X ", c->permissions);
507544
mesh::Utils::printHex(Serial, c->id.pub_key, PUB_KEY_SIZE);
@@ -569,7 +606,7 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
569606
memcpy(&timestamp, data, 4);
570607

571608
if (timestamp > from.last_timestamp) { // prevent replay attacks
572-
uint8_t reply_len = handleRequest(from.isAdmin() ? 0xFFFF : from.permissions, timestamp, data[4], &data[5], len - 5);
609+
uint8_t reply_len = handleRequest(from.isAdmin() ? 0xFF : from.permissions, timestamp, data[4], &data[5], len - 5);
573610
if (reply_len == 0) return; // invalid command
574611

575612
from.last_timestamp = timestamp;

examples/simple_sensor/SensorMesh.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525

2626
#define PERM_ACL_ROLE_MASK 3 // lower 2 bits
2727
#define PERM_ACL_GUEST 0
28-
#define PERM_ACL_LEVEL1 1
29-
#define PERM_ACL_LEVEL2 2
30-
#define PERM_ACL_LEVEL3 3 // admin
31-
32-
#define PERM_GET_TELEMETRY (1 << 2)
33-
#define PERM_GET_OTHER_STATS (1 << 3)
34-
#define PERM_RESERVED1 (1 << 4)
35-
#define PERM_RESERVED2 (1 << 5)
28+
#define PERM_ACL_READ_ONLY 1
29+
#define PERM_ACL_READ_WRITE 2
30+
#define PERM_ACL_ADMIN 3
31+
32+
#define PERM_RESERVED1 (1 << 2)
33+
#define PERM_RESERVED2 (1 << 3)
34+
#define PERM_RESERVED3 (1 << 4)
35+
#define PERM_RESERVED4 (1 << 5)
3636
#define PERM_RECV_ALERTS_LO (1 << 6) // low priority alerts
3737
#define PERM_RECV_ALERTS_HI (1 << 7) // high priority alerts
3838

@@ -45,7 +45,7 @@ struct ContactInfo {
4545
uint32_t last_timestamp; // by THEIR clock (transient)
4646
uint32_t last_activity; // by OUR clock (transient)
4747

48-
bool isAdmin() const { return (permissions & PERM_ACL_ROLE_MASK) == PERM_ACL_LEVEL3; }
48+
bool isAdmin() const { return (permissions & PERM_ACL_ROLE_MASK) == PERM_ACL_ADMIN; }
4949
};
5050

5151
#ifndef FIRMWARE_BUILD_DATE
@@ -160,8 +160,9 @@ class SensorMesh : public mesh::Mesh, public CommonCLICallbacks {
160160
uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data);
161161
uint8_t handleRequest(uint8_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len);
162162
mesh::Packet* createSelfAdvert();
163-
ContactInfo* putContact(const mesh::Identity& id);
164-
void applyContactPermissions(const uint8_t* pubkey, uint8_t perms);
163+
ContactInfo* getContact(const uint8_t* pubkey, int key_len);
164+
ContactInfo* putContact(const mesh::Identity& id, uint8_t init_perms);
165+
bool applyContactPermissions(const uint8_t* pubkey, int key_len, uint8_t perms);
165166

166167
void sendAlert(ContactInfo* c, Trigger* t);
167168

0 commit comments

Comments
 (0)