Fix stale EZSP v14+ command and callback schemas - #750
Open
zigpy-review-bot wants to merge 1 commit into
Open
zigpy-review-bot wants to merge 1 commit into
zigpy-review-bot wants to merge 1 commit into
Conversation
The v14 command table copies every v13 command it doesn't override and only swaps `EmberStatus`/`EzspStatus` for `sl_Status`. Commands whose layout changed in any other way at v14 (or later) kept their old schemas, and v16-v19 inherit them. None of these are called by bellows, so nothing broke visibly, but they would misparse if used, and callbacks are parsed whenever the NCP sends them. Checked against the Silicon Labs EZSP host encoders/decoders (GSDK 4.3.0 and 4.4.6, SiSDK 2024.6.0, 2024.12.0, 2025.6.0, 2025.6.2, 2025.12.3, 2026.6.x) and the NCP handlers where available: - v14: status moved first or a context was added in the key export/import responses (`exportLinkKeyByEui`, `exportTransientKeyByIndex`/`ByEui`, `getApsKeyInfo`, `importKey`), `findAndRejoinNetwork` gained `reason` and `nodeType`, and `setAddressTableRemoteEui64` became `setAddressTableInfo`. - v14: `setPowerDescriptor` and `clearStoredBeacons` gained an `sl_Status` response, while `sendPanIdUpdate`, `readAttribute`, and `writeAttribute` keep their one-byte response that the global replacement had widened. - v14: callbacks that replaced `lastHopLqi`/`lastHopRssi` with `sl_zigbee_rx_packet_info_t`, and `rawTransmitCompleteHandler`, which now carries the message. - v14: drop commands the SDK removed. Several of their frame IDs were reused (0x0004, 0x0037, 0x003A right away; 0x003D, 0x005D, 0x005F, 0x0062 in later versions, which collided with commands bellows added for v17 and v18). - v18: `getTokenCount` returns a `uint32_t`, and `macFilterMatchMessageHandler` also carries `sl_zigbee_rx_packet_info_t`. - v19: `getTokenInfo`'s token size is a `uint32_t` (widened in SiSDK 2025.12 without an EZSP version bump, so v18 is left as-is). - v12/v13: `checkKeyContext` was defined with `setPassiveAckConfig`'s arguments; it takes a security manager context and returns `sl_Status`.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #750 +/- ##
=======================================
Coverage 99.55% 99.55%
=======================================
Files 64 64
Lines 4269 4290 +21
=======================================
+ Hits 4250 4271 +21
Misses 19 19 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
bellows' EZSP v14 command table copies every v13 command it doesn't override and only swaps
EmberStatus/EzspStatusforsl_Status, and v16–v19 inherit that table. Commands whose layout changed in any other way kept their old schemas. bellows never calls any of the commands fixed here, and it only logs leftover bytes at DEBUG level, so nothing visibly broke. But callbacks are parsed whenever the NCP sends them, and several stale entries shared a frame ID with a newer command in the same table. This PR fixes the rest of the outdated definitions from the audit on #747, re-checked against the Silicon Labs sources.Changes
Requests and responses (v14, SiSDK 2024.6.0):
exportLinkKeyByEui,exportTransientKeyByIndex,exportTransientKeyByEui: the status now comes first, followed by the context, the key, and the key metadata.getApsKeyInfo: returns the status, the key metadata, and the context (it used to return the EUI64, the metadata, and the status).importKey: the response now also contains the context.findAndRejoinNetwork: takes two new arguments,reasonandnodeType.setAddressTableRemoteEui64(0x005C) becamesetAddressTableInfo, which also takes the node ID. It's renamed the same waygetAddressTableInfoalready was.setPowerDescriptorandclearStoredBeacons: now return ansl_Status.sendPanIdUpdate,readAttribute,writeAttribute: still return a single byte (aboolor a ZCL status), but the globalsl_Statusreplacement had widened it to 4 bytes.Callbacks (v14):
macPassthroughMessageHandler,macFilterMatchMessageHandler,incomingBootloadMessageHandler,zllNetworkFoundHandler,zllAddressAssignmentHandler:lastHopLqi/lastHopRssiwere replaced withsl_zigbee_rx_packet_info_t(t.SlRxPacketInfo).rawTransmitCompleteHandler: now carries the message, followed by ansl_Status.Removed commands (v14):
getNextBeacon(0x0004 is nowgetStoredBeacon),proxyBroadcast(0x0037 is nowsetNumBeaconsToStore),sendMulticastWithAlias(0x003A is nowsetupDelayedJoin).setAddressTableRemoteNodeId(0x005D) andgetAddressTableRemoteNodeId(0x005F) with v17'sgpProxyTableRemoveEntryandgpClearProxyTable,incomingSenderEui64Handler(0x0062) with v17'smuxInvalidRxHandler, andgetFirstBeacon(0x003D) with v18'ssetPendingNetworkUpdateChannel. Incoming frames already resolved to the newer command, but callinggetAddressTableRemoteNodeId()on v17+ would have sent thegpClearProxyTableframe ID.sendRawMessage(0x0096; the SDK now uses that name for 0x0051, which bellows callssendRawMessageExtended),setLongUpTime,setHubConnectivity,isUpTimeLong,isHubConnected,setParentClassificationEnabled,getParentClassificationEnabled.Later versions:
getTokenCountreturns auint32_t. The existing v18macFilterMatchMessageHandleroverride also getspacketInfo.sizeingetTokenInfois auint32_t(newSlZigbeeTokenInfostruct). SiSDK 2025.12 widened it without an EZSP version bump, so v18 firmware sends either width depending on its SDK. v18 is left as-is, with a note.Older definition (v12/v13):
checkKeyContexthad been defined withsetPassiveAckConfig's arguments since v12. It takes a security manager context and returns ansl_Statusin every SDK since v12. It's fixed in v12 and overridden in v13 with the v13 context, like the other security manager commands there.New tests decode and encode SDK-layout bytes through every affected v14+ table with no bytes left over. They also check that the removed commands are gone and that no v14+ table has duplicate frame IDs. 183 of the 210 new test cases fail on
dev.Not included
gpepIncomingMessageHandler, which Fix gpepIncomingMessageHandler schema for EZSP v13+ #746 and Fix and forward gpepIncomingMessageHandler for Green Power support #713 cover.getExtendedTimeoutandlookupNodeIdByEui64are fixed in Fix EZSP v14+getExtendedTimeoutandlookupNodeIdByEui64response parsing #748, andleaveNetworkandsetManufacturerCodein Fix EZSP v14+leaveNetworkandsetManufacturerCodeschemas #749. This PR merges cleanly with both.importTransientKeydropped itsflagsargument: bellows still sends the byte, and the NCP never reads it.launchStandaloneBootloaderreturns a 4-bytesl_status_t, but bellows deliberately reads one byte. It gets the low byte, which holds the status, and three bytes are left over.Verification
EZSP_PROTOCOL_VERSIONinezsp-protocol.h: v12 = GSDK 4.3.x, v13 = GSDK 4.4.x, v14 = SiSDK 2024.6.0–2024.6.2, v16 = 2024.6.3 and 2024.12.x, v17 = 2025.6.0–2025.6.1, v18 = 2025.6.2–2025.6.3 and 2025.12.x, v19 = 2026.6.x.command-functions.h, expanded thefetch_*/append_*helpers fromezsp-frame-utilities.c/.h, and took frame IDs fromezsp-enum.h. I compared field widths and order against each bellows table. Sources: GSDK 4.3.0 and 4.4.6 and SiSDK 2024.6.0, 2024.12.0, 2025.6.0, 2025.6.2, and 2025.6.3 from GitHub, plus full SiSDK 2025.12.3, 2026.6.0, and 2026.6.1 installs.app/em260/command-handlers-*-generated.c(2025.12.3) for the security, networking, messaging, and token commands. ForlaunchStandaloneBootloader, and to confirm that extra trailing bytes are ignored, I readprocessEzspCommandfrom the 2026.6.1 NCP library's LTO dump.command-functions.hand unchanged through 2026.6.1. The frame ID reuse is inezsp-enum.h(0x0004/0x0037/0x003A in 2024.6.0, 0x005D/0x005F/0x0062 in 2025.6.0, 0x003D in 2025.12.3).getTokenCountis in 2025.6.2command-functions.h. ThegetTokenInfosize isfetchInt8u()in 2025.6.3 andfetchInt32u()in 2025.12.3ezsp-frame-utilities.c.checkKeyContextis in GSDK 4.3.0 and 4.4.6command-functions.h.getExtendedTimeoutandlookupNodeIdByEui64response parsing #748, and Fix EZSP v14+leaveNetworkandsetManufacturerCodeschemas #749, every command and callback whose layout the SDK changed between v13 and v19 matches bellows' tables. The exceptions are the GP commands,importTransientKey,launchStandaloneBootloader, and v18'sgetTokenInfo.Related: #747
🤖 Generated with Claude Code