Skip to content

Commit e2d08e8

Browse files
committed
Overwrite the entire NWK_SEC_MATERIAL_TABLE table when setting the FC
1 parent c2a3c58 commit e2d08e8

File tree

2 files changed

+20
-60
lines changed

2 files changed

+20
-60
lines changed

tests/tools/test_network_backup_restore.py

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -330,26 +330,13 @@ async def test_tc_frame_counter_zstack30(make_connected_znp):
330330
assert (await security.read_tc_frame_counter(znp)) == 0x00000001
331331

332332
# If we change the EPID, the generic entry will be used
333-
old_nwk_info = znp.network_info
334333
znp.network_info = znp.network_info.replace(
335334
extended_pan_id=t.EUI64.convert("11:22:33:44:55:66:77:88")
336335
)
337336
assert (await security.read_tc_frame_counter(znp)) == 0x00000002
338337

339-
# Changing the frame counter will always change the global entry in this case
340338
await security.write_tc_frame_counter(znp, 0xAABBCCDD)
341339
assert (await security.read_tc_frame_counter(znp)) == 0xAABBCCDD
342-
assert znp_server._nvram[ExNvIds.LEGACY][
343-
OsalNvIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + 2
344-
].startswith(t.uint32_t(0xAABBCCDD).serialize())
345-
346-
# Global entry is ignored if the EPID matches
347-
znp.network_info = old_nwk_info
348-
assert (await security.read_tc_frame_counter(znp)) == 0x00000001
349-
await security.write_tc_frame_counter(znp, 0xABCDABCD)
350-
assert znp_server._nvram[ExNvIds.LEGACY][
351-
OsalNvIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START + 1
352-
].startswith(t.uint32_t(0xABCDABCD).serialize())
353340

354341

355342
@pytest.mark.asyncio
@@ -375,7 +362,6 @@ async def test_tc_frame_counter_zstack33(make_connected_znp):
375362
assert (await security.read_tc_frame_counter(znp)) == 0x00000002
376363

377364
# If we change the EPID, the generic entry will be used. It doesn't exist.
378-
old_nwk_info = znp.network_info
379365
znp.network_info = znp.network_info.replace(
380366
extended_pan_id=t.EUI64.convert("11:22:33:44:55:66:77:88")
381367
)
@@ -386,19 +372,11 @@ async def test_tc_frame_counter_zstack33(make_connected_znp):
386372
# Writes similarly will fail
387373
old_nvram_state = repr(znp_server._nvram)
388374

389-
with pytest.raises(ValueError):
390-
await security.write_tc_frame_counter(znp, 0x98765432)
391-
392375
# And the NVRAM will be untouched
393376
assert repr(znp_server._nvram) == old_nvram_state
394377

395-
# The correct entry will be updated
396-
znp.network_info = old_nwk_info
397-
assert (await security.read_tc_frame_counter(znp)) == 0x00000002
398-
await security.write_tc_frame_counter(znp, 0xABCDABCD)
399-
assert znp_server._nvram[ExNvIds.NWK_SEC_MATERIAL_TABLE][0x0001].startswith(
400-
t.uint32_t(0xABCDABCD).serialize()
401-
)
378+
await security.write_tc_frame_counter(znp, 0x98765432)
379+
assert (await security.read_tc_frame_counter(znp)) == 0x98765432
402380

403381

404382
def ieee_and_key(text):

zigpy_znp/znp/security.py

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -117,48 +117,30 @@ async def write_tc_frame_counter(znp: ZNP, counter: t.uint32_t) -> None:
117117

118118
return
119119

120+
entry = t.NwkSecMaterialDesc(
121+
FrameCounter=counter,
122+
ExtendedPanID=znp.network_info.extended_pan_id,
123+
)
124+
125+
fill_entry = t.NwkSecMaterialDesc(
126+
FrameCounter=0x00000000,
127+
ExtendedPanID=t.EUI64.convert("00:00:00:00:00:00:00:00"),
128+
)
129+
130+
# The security material tables are quite small (4 values) so it's simpler to just
131+
# write them completely when updating the frame counter.
120132
if znp.version == 3.0:
121-
address = OsalNvIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START
122-
entries = znp.nvram.osal_read_table(
133+
await znp.nvram.osal_write_table(
123134
start_nvid=OsalNvIds.LEGACY_NWK_SEC_MATERIAL_TABLE_START,
124135
end_nvid=OsalNvIds.LEGACY_NWK_SEC_MATERIAL_TABLE_END,
125-
item_type=t.NwkSecMaterialDesc,
136+
values=[entry],
137+
fill_value=fill_entry,
126138
)
127139
else:
128-
address = 0x0000
129-
entries = znp.nvram.read_table(
130-
item_id=ExNvIds.NWK_SEC_MATERIAL_TABLE,
131-
item_type=t.NwkSecMaterialDesc,
132-
)
133-
134-
best_entry = None
135-
best_address = None
136-
137-
async for entry in entries:
138-
if entry.ExtendedPanID == znp.network_info.extended_pan_id:
139-
best_entry = entry
140-
best_address = address
141-
break
142-
elif best_entry is None and entry.ExtendedPanID == t.EUI64.convert(
143-
"FF:FF:FF:FF:FF:FF:FF:FF"
144-
):
145-
best_entry = entry
146-
best_address = address
147-
148-
address += 0x0001
149-
150-
if best_entry is None:
151-
raise ValueError("Failed to find open slot for security material entry")
152-
153-
best_entry.FrameCounter = counter
154-
155-
if znp.version == 3.0:
156-
await znp.nvram.osal_write(best_address, best_entry)
157-
else:
158-
await znp.nvram.write(
140+
await znp.nvram.write_table(
159141
item_id=ExNvIds.NWK_SEC_MATERIAL_TABLE,
160-
sub_id=best_address,
161-
value=best_entry,
142+
values=[entry],
143+
fill_value=fill_entry,
162144
)
163145

164146

0 commit comments

Comments
 (0)