From 95ff7b55dc8db048d8393d29f6a7ad118ffb2e91 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Tue, 28 Feb 2017 21:52:41 -0800 Subject: [PATCH] Spinel: Radio Source Match Support (#1371) * Add Spinel Source Match Properties * Wrap Source Match NCP code with OPENTHREAD_ENABLE_RAW_LINK_API * Update spinel docs * Handle SendPropertyUpdate errors --- doc/spinel-protocol-src/spinel-prop-mac.md | 31 ++ doc/spinel-protocol-src/spinel-prop-phy.md | 3 +- examples/drivers/windows/otLwf/command.c | 92 +++++- examples/drivers/windows/otLwf/command.h | 20 +- examples/drivers/windows/otLwf/filter.h | 6 - examples/drivers/windows/otLwf/radio.c | 250 +++++---------- examples/platforms/cc2650/radio.c | 18 ++ src/ncp/ncp_base.cpp | 357 ++++++++++++++++++++- src/ncp/ncp_base.hpp | 20 ++ src/ncp/spinel.h | 17 + 10 files changed, 611 insertions(+), 203 deletions(-) diff --git a/doc/spinel-protocol-src/spinel-prop-mac.md b/doc/spinel-protocol-src/spinel-prop-mac.md index 9018ae227..a624c37d0 100644 --- a/doc/spinel-protocol-src/spinel-prop-mac.md +++ b/doc/spinel-protocol-src/spinel-prop-mac.md @@ -124,3 +124,34 @@ Structure Parameters: * Type: Read-Write * Packed-Encoding: `b` +### PROP 4867: SPINEL_PROP_MAC_SRC_MATCH_ENABLED {#prop-mac-src-match-enabled} +* Type: Write +* Packed-Encoding: `b` + +Set to true to enable radio source matching or false to disable it. This property +is only available if the `SPINEL_CAP_MAC_RAW` capability is present. The source match +functionality is used by radios when generating ACKs. The short and extended address +lists are used for settings the Frame Pending bit in the ACKs. + +### PROP 4868: SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES {#prop-mac-src-match-short-addresses} +* Type: Write +* Packed-Encoding: `A(S)` + +Configures the list of short addresses used for source matching. This property +is only available if the `SPINEL_CAP_MAC_RAW` capability is present. + +Structure Parameters: + +* `S`: Short address for hardware generated ACKs + +### PROP 4869: SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES {#prop-mac-src-match-extended-addresses} +* Type: Write +* Packed-Encoding: `A(E)` + +Configures the list of extended addresses used for source matching. This property +is only available if the `SPINEL_CAP_MAC_RAW` capability is present. + +Structure Parameters: + +* `E`: EUI64 address for hardware generated ACKs + diff --git a/doc/spinel-protocol-src/spinel-prop-phy.md b/doc/spinel-protocol-src/spinel-prop-phy.md index 72f4514a9..d95b5854e 100644 --- a/doc/spinel-protocol-src/spinel-prop-phy.md +++ b/doc/spinel-protocol-src/spinel-prop-phy.md @@ -7,7 +7,8 @@ Set to 1 if the PHY is enabled, set to 0 otherwise. May be directly enabled to bypass higher-level packet processing -in order to implement things like packet sniffers. +in order to implement things like packet sniffers. This property +can only be written if the `SPINEL_CAP_MAC_RAW` capability is present. ### PROP 33: PROP_PHY_CHAN {#prop-phy-chan} * Type: Read-Write diff --git a/examples/drivers/windows/otLwf/command.c b/examples/drivers/windows/otLwf/command.c index 5b32fc535..4feaf2ba1 100644 --- a/examples/drivers/windows/otLwf/command.c +++ b/examples/drivers/windows/otLwf/command.c @@ -1113,6 +1113,7 @@ otLwfCmdGetProp( typedef struct _SPINEL_SET_PROP_CONTEXT { KEVENT CompletionEvent; + UINT ExpectedResultCommand; spinel_prop_key_t Key; NTSTATUS Status; } SPINEL_SET_PROP_CONTEXT; @@ -1138,11 +1139,7 @@ otLwfSetPropHandler( { CmdContext->Status = STATUS_CANCELLED; } - else if (Command != SPINEL_CMD_PROP_VALUE_IS) - { - CmdContext->Status = STATUS_INVALID_PARAMETER; - } - else if (Key == SPINEL_PROP_LAST_STATUS) + else if (Command == SPINEL_CMD_PROP_VALUE_IS && Key == SPINEL_PROP_LAST_STATUS) { spinel_status_t spinel_status = SPINEL_STATUS_OK; spinel_ssize_t packed_len = spinel_datatype_unpack(Data, DataLength, "i", &spinel_status); @@ -1157,12 +1154,18 @@ otLwfSetPropHandler( CmdContext->Status = ThreadErrorToNtstatus(errorCode); } } + else if (Command != CmdContext->ExpectedResultCommand) + { + NT_ASSERT(FALSE); + CmdContext->Status = STATUS_INVALID_PARAMETER; + } else if (Key == CmdContext->Key) { CmdContext->Status = STATUS_SUCCESS; } else { + NT_ASSERT(FALSE); CmdContext->Status = STATUS_INVALID_PARAMETER; } @@ -1174,11 +1177,12 @@ otLwfSetPropHandler( _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS -otLwfCmdSetProp( +otLwfCmdSetPropV( _In_ PMS_FILTER pFilter, + _In_ UINT Command, _In_ spinel_prop_key_t Key, - _In_ const char *pack_format, - ... + _In_opt_ const char *pack_format, + _In_opt_ va_list args ) { NTSTATUS status; @@ -1191,10 +1195,24 @@ otLwfCmdSetProp( Context.Key = Key; Context.Status = STATUS_SUCCESS; - LogFuncEntryMsg(DRIVER_DEFAULT, "Key=%u", (ULONG)Key); + LogFuncEntryMsg(DRIVER_DEFAULT, "Cmd=%u Key=%u", Command, (ULONG)Key); - va_list args; - va_start(args, pack_format); + if (Command == SPINEL_CMD_PROP_VALUE_SET) + { + Context.ExpectedResultCommand = SPINEL_CMD_PROP_VALUE_IS; + } + else if (Command == SPINEL_CMD_PROP_VALUE_INSERT) + { + Context.ExpectedResultCommand = SPINEL_CMD_PROP_VALUE_INSERTED; + } + else if (Command == SPINEL_CMD_PROP_VALUE_REMOVE) + { + Context.ExpectedResultCommand = SPINEL_CMD_PROP_VALUE_REMOVED; + } + else + { + ASSERT(FALSE); + } // Send the request transaction status = @@ -1203,7 +1221,7 @@ otLwfCmdSetProp( otLwfSetPropHandler, &Context, &tid, - SPINEL_CMD_PROP_VALUE_SET, + Command, Key, 8, pack_format, @@ -1236,14 +1254,60 @@ otLwfCmdSetProp( { Context.Status = status; } - - va_end(args); LogFuncExitNT(DRIVER_DEFAULT, Context.Status); return Context.Status; } +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdSetProp( + _In_ PMS_FILTER pFilter, + _In_ spinel_prop_key_t Key, + _In_opt_ const char *pack_format, + ... + ) +{ + va_list args; + va_start(args, pack_format); + NTSTATUS status = otLwfCmdSetPropV(pFilter, SPINEL_CMD_PROP_VALUE_SET, Key, pack_format, args); + va_end(args); + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdInsertProp( + _In_ PMS_FILTER pFilter, + _In_ spinel_prop_key_t Key, + _In_opt_ const char *pack_format, + ... + ) +{ + va_list args; + va_start(args, pack_format); + NTSTATUS status = otLwfCmdSetPropV(pFilter, SPINEL_CMD_PROP_VALUE_INSERT, Key, pack_format, args); + va_end(args); + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdRemoveProp( + _In_ PMS_FILTER pFilter, + _In_ spinel_prop_key_t Key, + _In_opt_ const char *pack_format, + ... + ) +{ + va_list args; + va_start(args, pack_format); + NTSTATUS status = otLwfCmdSetPropV(pFilter, SPINEL_CMD_PROP_VALUE_REMOVE, Key, pack_format, args); + va_end(args); + return status; +} + // // General Spinel Helpers // diff --git a/examples/drivers/windows/otLwf/command.h b/examples/drivers/windows/otLwf/command.h index f8a3aef66..bca191892 100644 --- a/examples/drivers/windows/otLwf/command.h +++ b/examples/drivers/windows/otLwf/command.h @@ -162,7 +162,25 @@ NTSTATUS otLwfCmdSetProp( _In_ PMS_FILTER pFilter, _In_ spinel_prop_key_t Key, - _In_ const char *pack_format, + _In_opt_ const char *pack_format, + ... + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdInsertProp( + _In_ PMS_FILTER pFilter, + _In_ spinel_prop_key_t Key, + _In_opt_ const char *pack_format, + ... + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdRemoveProp( + _In_ PMS_FILTER pFilter, + _In_ spinel_prop_key_t Key, + _In_opt_ const char *pack_format, ... ); diff --git a/examples/drivers/windows/otLwf/filter.h b/examples/drivers/windows/otLwf/filter.h index 7f1fb6c5f..37ca88fb8 100644 --- a/examples/drivers/windows/otLwf/filter.h +++ b/examples/drivers/windows/otLwf/filter.h @@ -111,8 +111,6 @@ typedef enum OTLWF_DEVICE_STATUS #define OT_EVENT_TIMER_RUNNING 1 #define OT_EVENT_TIMER_FIRED 2 -#define MAX_PENDING_MAC_SIZE 32 // TODO - // // Define the filter struct // @@ -245,10 +243,6 @@ typedef struct _MS_FILTER uint16_t otShortAddress; BOOLEAN otPendingMacOffloadEnabled; - uint8_t otPendingShortAddressCount; - uint16_t otPendingShortAddresses[MAX_PENDING_MAC_SIZE]; - uint8_t otPendingExtendedAddressCount; - uint64_t otPendingExtendedAddresses[MAX_PENDING_MAC_SIZE]; #if DEBUG_ALLOC // Used for tracking memory allocations diff --git a/examples/drivers/windows/otLwf/radio.c b/examples/drivers/windows/otLwf/radio.c index cbdebaaba..e9dea3c00 100644 --- a/examples/drivers/windows/otLwf/radio.c +++ b/examples/drivers/windows/otLwf/radio.c @@ -73,8 +73,6 @@ otPlatReset( pFilter->otCurrentListenChannel = 0xFF; pFilter->otPromiscuous = false; pFilter->otPendingMacOffloadEnabled = FALSE; - pFilter->otPendingShortAddressCount = 0; - pFilter->otPendingExtendedAddressCount = 0; // Reinitialize the OpenThread library pFilter->otCachedRole = kDeviceRoleDisabled; @@ -169,8 +167,6 @@ otLwfRadioInit( pFilter->otTransmitFrame.mPsdu = pFilter->otTransmitMessage; pFilter->otPendingMacOffloadEnabled = FALSE; - pFilter->otPendingShortAddressCount = 0; - pFilter->otPendingExtendedAddressCount = 0; // Cache the factory address otLwfRadioGetFactoryAddress(pFilter); @@ -569,64 +565,6 @@ otLwfRadioTransmitFrameDone( LogFuncExit(DRIVER_DATA_PATH); } -NDIS_STATUS -otPlatRadioSendPendingMacOffload( - _In_ PMS_FILTER pFilter - ) -{ - // TODO - UNREFERENCED_PARAMETER(pFilter); - return STATUS_NOT_SUPPORTED; - /*NDIS_STATUS status; - ULONG bytesProcessed; - UCHAR ShortAddressCount = pFilter->otPendingMacOffloadEnabled == TRUE ? pFilter->otPendingShortAddressCount : 0; - UCHAR ExtendedAddressCount = pFilter->otPendingMacOffloadEnabled == TRUE ? pFilter->otPendingExtendedAddressCount : 0; - USHORT OidBufferSize = COMPLETE_SIZEOF_OT_PENDING_MAC_OFFLOAD_REVISION_1(ShortAddressCount, ExtendedAddressCount); - POT_PENDING_MAC_OFFLOAD OidBuffer = (POT_PENDING_MAC_OFFLOAD)FILTER_ALLOC_MEM(pFilter->FilterHandle, OidBufferSize); - PUCHAR Offset = (PUCHAR)(OidBuffer + 1); - ULONG BufferSizeLeft = OidBufferSize - sizeof(OT_PENDING_MAC_OFFLOAD); - - OidBuffer->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; - OidBuffer->Header.Revision = OT_PENDING_MAC_OFFLOAD_REVISION_1; - OidBuffer->Header.Size = OidBufferSize; - - OidBuffer->ShortAddressCount = ShortAddressCount; - OidBuffer->ExtendedAddressCount = ExtendedAddressCount; - - if (ShortAddressCount != 0) - { - memcpy_s(Offset, BufferSizeLeft, pFilter->otPendingShortAddresses, sizeof(USHORT) * ShortAddressCount); - Offset += sizeof(USHORT) * ShortAddressCount; - BufferSizeLeft -= sizeof(USHORT) * ShortAddressCount; - } - - if (ExtendedAddressCount != 0) - { - memcpy_s(Offset, BufferSizeLeft, pFilter->otPendingExtendedAddresses, sizeof(ULONGLONG) * ExtendedAddressCount); - } - - LogInfo(DRIVER_DEFAULT, "Interface %!GUID! indicating updated Pending Mac Offload", &pFilter->InterfaceGuid); - - // Indicate to the miniport - status = - otLwfSendInternalRequest( - pFilter, - NdisRequestSetInformation, - OID_OT_PENDING_MAC_OFFLOAD, - OidBuffer, - OidBufferSize, - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) - { - LogError(DRIVER_DEFAULT, "Set for OID_OT_PENDING_MAC_OFFLOAD failed, %!NDIS_STATUS!", status); - } - - FILTER_FREE_MEM(OidBuffer); - - return status;*/ -} - void otPlatRadioEnableSrcMatch(_In_ otInstance *otCtx, bool aEnable) { NT_ASSERT(otCtx); @@ -635,9 +573,21 @@ void otPlatRadioEnableSrcMatch(_In_ otInstance *otCtx, bool aEnable) // Ignore if we are already in the correct state if (aEnable == pFilter->otPendingMacOffloadEnabled) return; - // Set the new value and update the miniport + // Cache the new value pFilter->otPendingMacOffloadEnabled = aEnable ? TRUE : FALSE; - otPlatRadioSendPendingMacOffload(pFilter); + + // Indicate to the miniport + NTSTATUS status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_ENABLED, + SPINEL_DATATYPE_BOOL_S, + (aEnable ? TRUE : FALSE) + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SRC_MATCH_ENABLED failed, %!STATUS!", status); + } } ThreadError otPlatRadioAddSrcMatchShortEntry(_In_ otInstance *otCtx, const uint16_t aShortAddress) @@ -645,34 +595,20 @@ ThreadError otPlatRadioAddSrcMatchShortEntry(_In_ otInstance *otCtx, const uint1 NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - // Check to see if it is in the list - BOOLEAN Found = false; - for (ULONG i = 0; i < pFilter->otPendingShortAddressCount; i++) + // Indicate to the miniport + NTSTATUS status = + otLwfCmdInsertProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, + SPINEL_DATATYPE_UINT16_S, + aShortAddress + ); + if (!NT_SUCCESS(status)) { - if (aShortAddress == pFilter->otPendingShortAddresses[i]) - { - Found = TRUE; - break; - } + LogError(DRIVER_DEFAULT, "Insert SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES failed, %!STATUS!", status); } - // Already in the list, return success - if (Found) return kThreadError_None; - - // Make sure we have room - if (pFilter->otPendingShortAddressCount == MAX_PENDING_MAC_SIZE) return kThreadError_NoBufs; - - // Copy to the list - pFilter->otPendingShortAddresses[pFilter->otPendingShortAddressCount] = aShortAddress; - pFilter->otPendingShortAddressCount++; - - // Update the miniport if enabled - if (pFilter->otPendingMacOffloadEnabled) - { - otPlatRadioSendPendingMacOffload(pFilter); - } - - return kThreadError_None; + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } ThreadError otPlatRadioAddSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t *aExtAddress) @@ -680,34 +616,20 @@ ThreadError otPlatRadioAddSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - // Check to see if it is in the list - BOOLEAN Found = false; - for (ULONG i = 0; i < pFilter->otPendingExtendedAddressCount; i++) + // Indicate to the miniport + NTSTATUS status = + otLwfCmdInsertProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, + SPINEL_DATATYPE_EUI64_S, + aExtAddress + ); + if (!NT_SUCCESS(status)) { - if (memcmp(aExtAddress, &pFilter->otPendingExtendedAddresses[i], sizeof(ULONGLONG)) == 0) - { - Found = TRUE; - break; - } + LogError(DRIVER_DEFAULT, "Insert SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES failed, %!STATUS!", status); } - // Already in the list, return success - if (Found) return kThreadError_None; - - // Make sure we have room - if (pFilter->otPendingExtendedAddressCount == MAX_PENDING_MAC_SIZE) return kThreadError_NoBufs; - - // Copy to the list - memcpy(&pFilter->otPendingExtendedAddresses[pFilter->otPendingExtendedAddressCount], aExtAddress, sizeof(ULONGLONG)); - pFilter->otPendingExtendedAddressCount++; - - // Update the miniport if enabled - if (pFilter->otPendingMacOffloadEnabled) - { - otPlatRadioSendPendingMacOffload(pFilter); - } - - return kThreadError_None; + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } ThreadError otPlatRadioClearSrcMatchShortEntry(_In_ otInstance *otCtx, const uint16_t aShortAddress) @@ -715,31 +637,20 @@ ThreadError otPlatRadioClearSrcMatchShortEntry(_In_ otInstance *otCtx, const uin NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - // Check to see if it is in the list - BOOLEAN Found = false; - for (ULONG i = 0; i < pFilter->otPendingShortAddressCount; i++) + // Indicate to the miniport + NTSTATUS status = + otLwfCmdRemoveProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, + SPINEL_DATATYPE_UINT16_S, + aShortAddress + ); + if (!NT_SUCCESS(status)) { - if (aShortAddress == pFilter->otPendingShortAddresses[i]) - { - // Remove it from the list - if (i + 1 != pFilter->otPendingShortAddressCount) - pFilter->otPendingShortAddresses[i] = pFilter->otPendingShortAddresses[pFilter->otPendingShortAddressCount - 1]; - pFilter->otPendingShortAddressCount--; - Found = TRUE; - break; - } + LogError(DRIVER_DEFAULT, "Remove SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES failed, %!STATUS!", status); } - // Wasn't in the list, return failure - if (Found == FALSE) return kThreadError_NotFound; - - // Update the miniport if enabled - if (pFilter->otPendingMacOffloadEnabled) - { - otPlatRadioSendPendingMacOffload(pFilter); - } - - return kThreadError_None; + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } ThreadError otPlatRadioClearSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t *aExtAddress) @@ -747,31 +658,20 @@ ThreadError otPlatRadioClearSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8 NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - // Check to see if it is in the list - BOOLEAN Found = false; - for (ULONG i = 0; i < pFilter->otPendingExtendedAddressCount; i++) + // Indicate to the miniport + NTSTATUS status = + otLwfCmdRemoveProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, + SPINEL_DATATYPE_EUI64_S, + aExtAddress + ); + if (!NT_SUCCESS(status)) { - if (memcmp(aExtAddress, &pFilter->otPendingExtendedAddresses[i], sizeof(ULONGLONG)) == 0) - { - // Remove it from the list - if (i + 1 != pFilter->otPendingExtendedAddressCount) - pFilter->otPendingExtendedAddresses[i] = pFilter->otPendingExtendedAddresses[pFilter->otPendingExtendedAddressCount - 1]; - pFilter->otPendingExtendedAddressCount--; - Found = TRUE; - break; - } - } - - // Wasn't in the list, return failure - if (Found == FALSE) return kThreadError_NotFound; - - // Update the miniport if enabled - if (pFilter->otPendingMacOffloadEnabled) - { - otPlatRadioSendPendingMacOffload(pFilter); + LogError(DRIVER_DEFAULT, "Remove SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES failed, %!STATUS!", status); } - return kThreadError_None; + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } void otPlatRadioClearSrcMatchShortEntries(_In_ otInstance *otCtx) @@ -779,12 +679,17 @@ void otPlatRadioClearSrcMatchShortEntries(_In_ otInstance *otCtx) NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - // Ignore if we are already in the correct state - if (pFilter->otPendingShortAddressCount == 0) return; - - // Set the new value and update the miniport - pFilter->otPendingShortAddressCount = 0; - otPlatRadioSendPendingMacOffload(pFilter); + // Indicate to the miniport + NTSTATUS status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, + NULL + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES failed, %!STATUS!", status); + } } void otPlatRadioClearSrcMatchExtEntries(_In_ otInstance *otCtx) @@ -792,12 +697,17 @@ void otPlatRadioClearSrcMatchExtEntries(_In_ otInstance *otCtx) NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - // Ignore if we are already in the correct state - if (pFilter->otPendingExtendedAddressCount == 0) return; - - // Set the new value and update the miniport - pFilter->otPendingExtendedAddressCount = 0; - otPlatRadioSendPendingMacOffload(pFilter); + // Indicate to the miniport + NTSTATUS status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, + NULL + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES failed, %!STATUS!", status); + } } ThreadError otPlatRadioEnergyScan(_In_ otInstance *otCtx, uint8_t aScanChannel, uint16_t aScanDuration) diff --git a/examples/platforms/cc2650/radio.c b/examples/platforms/cc2650/radio.c index 5b982c630..5cfa99004 100644 --- a/examples/platforms/cc2650/radio.c +++ b/examples/platforms/cc2650/radio.c @@ -1492,6 +1492,24 @@ exit: return error; } +/** +* Function documented in platform/radio.h +*/ +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + (void)aInstance; + // TODO - This function needs to be implemented +} + +/** +* Function documented in platform/radio.h +*/ +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + (void)aInstance; + // TODO - This function needs to be implemented +} + /** * Function documented in platform/radio.h */ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 9bd522119..121b8a5de 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -145,8 +145,8 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION, &NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA_VERSION }, { SPINEL_PROP_THREAD_LEADER_NETWORK_DATA, &NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA }, { SPINEL_PROP_THREAD_STABLE_LEADER_NETWORK_DATA, &NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA }, - { SPINEL_PROP_THREAD_LOCAL_ROUTES, &NcpBase::NcpBase::GetPropertyHandler_THREAD_LOCAL_ROUTES }, - { SPINEL_PROP_THREAD_ASSISTING_PORTS, &NcpBase::NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS }, + { SPINEL_PROP_THREAD_LOCAL_ROUTES, &NcpBase::GetPropertyHandler_THREAD_LOCAL_ROUTES }, + { SPINEL_PROP_THREAD_ASSISTING_PORTS, &NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS }, { SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE, &NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE }, { SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED, &NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED }, @@ -160,7 +160,7 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD, &NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD }, { SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY, &NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY }, { SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT, &NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT }, - { SPINEL_PROP_THREAD_ON_MESH_NETS, &NcpBase::NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS }, + { SPINEL_PROP_THREAD_ON_MESH_NETS, &NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS }, { SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING, &NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING }, { SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER, &NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER }, @@ -275,6 +275,11 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = { SPINEL_PROP_MAC_WHITELIST, &NcpBase::SetPropertyHandler_MAC_WHITELIST }, { SPINEL_PROP_MAC_WHITELIST_ENABLED, &NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED }, +#if OPENTHREAD_ENABLE_RAW_LINK_API + { SPINEL_PROP_MAC_SRC_MATCH_ENABLED, &NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED }, + { SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, &NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES }, + { SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, &NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES }, +#endif { SPINEL_PROP_THREAD_MODE, &NcpBase::SetPropertyHandler_THREAD_MODE }, { SPINEL_PROP_THREAD_CHILD_COUNT_MAX, &NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX }, { SPINEL_PROP_THREAD_CHILD_TIMEOUT, &NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT }, @@ -303,10 +308,14 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] = { - { SPINEL_PROP_IPV6_ADDRESS_TABLE, &NcpBase::NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE }, - { SPINEL_PROP_THREAD_LOCAL_ROUTES, &NcpBase::NcpBase::InsertPropertyHandler_THREAD_LOCAL_ROUTES }, - { SPINEL_PROP_THREAD_ON_MESH_NETS, &NcpBase::NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS }, - { SPINEL_PROP_THREAD_ASSISTING_PORTS, &NcpBase::NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS }, +#if OPENTHREAD_ENABLE_RAW_LINK_API + { SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, &NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES }, + { SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, &NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES }, +#endif + { SPINEL_PROP_IPV6_ADDRESS_TABLE, &NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE }, + { SPINEL_PROP_THREAD_LOCAL_ROUTES, &NcpBase::InsertPropertyHandler_THREAD_LOCAL_ROUTES }, + { SPINEL_PROP_THREAD_ON_MESH_NETS, &NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS }, + { SPINEL_PROP_THREAD_ASSISTING_PORTS, &NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS }, { SPINEL_PROP_CNTR_RESET, &NcpBase::SetPropertyHandler_CNTR_RESET }, @@ -315,10 +324,14 @@ const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] const NcpBase::RemovePropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[] = { - { SPINEL_PROP_IPV6_ADDRESS_TABLE, &NcpBase::NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE }, - { SPINEL_PROP_THREAD_LOCAL_ROUTES, &NcpBase::NcpBase::RemovePropertyHandler_THREAD_LOCAL_ROUTES }, - { SPINEL_PROP_THREAD_ON_MESH_NETS, &NcpBase::NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS }, - { SPINEL_PROP_THREAD_ASSISTING_PORTS, &NcpBase::NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS }, +#if OPENTHREAD_ENABLE_RAW_LINK_API + { SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, &NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES }, + { SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, &NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES }, +#endif + { SPINEL_PROP_IPV6_ADDRESS_TABLE, &NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE }, + { SPINEL_PROP_THREAD_LOCAL_ROUTES, &NcpBase::RemovePropertyHandler_THREAD_LOCAL_ROUTES }, + { SPINEL_PROP_THREAD_ON_MESH_NETS, &NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS }, + { SPINEL_PROP_THREAD_ASSISTING_PORTS, &NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS }, { SPINEL_PROP_MAC_WHITELIST, &NcpBase::RemovePropertyHandler_MAC_WHITELIST }, { SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS, &NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS }, }; @@ -4736,6 +4749,158 @@ ThreadError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t header, sp return errorCode; } +#if OPENTHREAD_ENABLE_RAW_LINK_API + +ThreadError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + bool isEnabled; + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_BOOL_S, + &isEnabled + ); + + if (parsedLength > 0) + { + errorCode = otLinkRawSrcMatchEnable(mInstance, isEnabled); + if (errorCode == kThreadError_None) + { + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +ThreadError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + ThreadError errorCode = kThreadError_None; + spinel_status_t errorStatus = SPINEL_STATUS_OK; + const uint8_t *data = value_ptr; + uint16_t data_len = value_len; + + // Clear the list first + errorCode = otLinkRawSrcMatchClearShortEntries(mInstance); + + VerifyOrExit(errorCode == kThreadError_None, + errorStatus = ThreadErrorToSpinelStatus(errorCode)); + + // Loop through the addresses and add them + while (data_len >= sizeof(uint16_t)) + { + spinel_ssize_t parsedLength; + uint16_t short_address; + + parsedLength = spinel_datatype_unpack( + data, + data_len, + SPINEL_DATATYPE_UINT16_S, + &short_address + ); + + VerifyOrExit(parsedLength > 0, errorStatus = SPINEL_STATUS_PARSE_ERROR); + + data += parsedLength; + data_len -= (uint16_t)parsedLength; + + errorCode = otLinkRawSrcMatchAddShortEntry(mInstance, short_address); + + VerifyOrExit(errorCode == kThreadError_None, + errorStatus = ThreadErrorToSpinelStatus(errorCode)); + } + + errorCode = + SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + value_ptr, + value_len + ); + +exit: + + if (errorStatus != SPINEL_STATUS_OK) + { + errorCode = SendLastStatus(header, errorStatus); + } + + return errorCode; +} + +ThreadError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + ThreadError errorCode = kThreadError_None; + spinel_status_t errorStatus = SPINEL_STATUS_OK; + const uint8_t *data = value_ptr; + uint16_t data_len = value_len; + + // Clear the list first + errorCode = otLinkRawSrcMatchClearExtEntries(mInstance); + + VerifyOrExit(errorCode == kThreadError_None, + errorStatus = ThreadErrorToSpinelStatus(errorCode)); + + // Loop through the addresses and add them + while (data_len >= sizeof(otExtAddress)) + { + spinel_ssize_t parsedLength; + uint8_t *ext_address; + + parsedLength = spinel_datatype_unpack( + data, + data_len, + SPINEL_DATATYPE_EUI64_S, + &ext_address + ); + + VerifyOrExit(parsedLength > 0, errorStatus = SPINEL_STATUS_PARSE_ERROR); + + data += parsedLength; + data_len -= (uint16_t)parsedLength; + + errorCode = otLinkRawSrcMatchAddExtEntry(mInstance, ext_address); + + VerifyOrExit(errorCode == kThreadError_None, + errorStatus = ThreadErrorToSpinelStatus(errorCode)); + } + + errorCode = + SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + value_ptr, + value_len + ); + +exit: + + if (errorStatus != SPINEL_STATUS_OK) + { + errorCode = SendLastStatus(header, errorStatus); + } + + return errorCode; +} + +#endif + ThreadError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { @@ -5268,6 +5433,91 @@ ThreadError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t header, s // MARK: Individual Property Inserters // ---------------------------------------------------------------------------- +#if OPENTHREAD_ENABLE_RAW_LINK_API + +ThreadError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + spinel_status_t errorStatus = SPINEL_STATUS_OK; + uint16_t short_address; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_UINT16_S, + &short_address + ); + + VerifyOrExit(parsedLength > 0, errorStatus = SPINEL_STATUS_PARSE_ERROR); + + errorCode = otLinkRawSrcMatchAddShortEntry(mInstance, short_address); + + VerifyOrExit(errorCode == kThreadError_None, + errorStatus = ThreadErrorToSpinelStatus(errorCode)); + + errorCode = + SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_INSERTED, + key, + value_ptr, + value_len + ); + +exit: + + if (errorStatus != SPINEL_STATUS_OK) + { + errorCode = SendLastStatus(header, errorStatus); + } + + return errorCode; +} + +ThreadError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + spinel_status_t errorStatus = SPINEL_STATUS_OK; + uint8_t *ext_address = NULL; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_EUI64_S, + &ext_address + ); + + VerifyOrExit(parsedLength > 0, errorStatus = SPINEL_STATUS_PARSE_ERROR); + + errorCode = otLinkRawSrcMatchAddExtEntry(mInstance, ext_address); + + VerifyOrExit(errorCode == kThreadError_None, + errorStatus = ThreadErrorToSpinelStatus(errorCode)); + + errorCode = + SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_INSERTED, + key, + value_ptr, + value_len + ); + +exit: + + if (errorStatus != SPINEL_STATUS_OK) + { + errorCode = SendLastStatus(header, errorStatus); + } + + return errorCode; +} + +#endif ThreadError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) @@ -5568,6 +5818,91 @@ ThreadError NcpBase::InsertPropertyHandler_MAC_WHITELIST(uint8_t header, spinel_ // MARK: Individual Property Removers // ---------------------------------------------------------------------------- +#if OPENTHREAD_ENABLE_RAW_LINK_API + +ThreadError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + uint16_t short_address; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_UINT16_S, + &short_address + ); + + if (parsedLength > 0) + { + errorCode = otLinkRawSrcMatchClearShortEntry(mInstance, short_address); + + if (errorCode == kThreadError_None) + { + errorCode = SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_REMOVED, + key, + value_ptr, + value_len + ); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +ThreadError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + uint8_t *ext_address; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_EUI64_S, + &ext_address + ); + + if (parsedLength > 0) + { + errorCode = otLinkRawSrcMatchClearExtEntry(mInstance, ext_address); + + if (errorCode == kThreadError_None) + { + errorCode = SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_REMOVED, + key, + value_ptr, + value_len + ); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +#endif ThreadError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index fee519997..ea0fb711c 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -467,6 +467,14 @@ private: uint16_t value_len); ThreadError SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#if OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); + ThreadError SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); + ThreadError SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); +#endif ThreadError SetPropertyHandler_THREAD_MODE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t header, spinel_prop_key_t key, @@ -518,6 +526,12 @@ private: const uint8_t *value_ptr, uint16_t value_len); #endif +#if OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); + ThreadError InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); +#endif ThreadError InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError InsertPropertyHandler_THREAD_LOCAL_ROUTES(uint8_t header, spinel_prop_key_t key, @@ -529,6 +543,12 @@ private: ThreadError InsertPropertyHandler_MAC_WHITELIST(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#if OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); + ThreadError RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); +#endif ThreadError RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError RemovePropertyHandler_THREAD_LOCAL_ROUTES(uint8_t header, spinel_prop_key_t key, diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 7cdd2444b..d1fbe8daf 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -614,6 +614,23 @@ typedef enum * Specified by Thread. Randomly-chosen, but non-volatile EUI-64. */ SPINEL_PROP_MAC_EXTENDED_ADDR = SPINEL_PROP_MAC_EXT__BEGIN + 2, + + /// MAC Source Match Enabled Flag + /** Format: `b` + */ + SPINEL_PROP_MAC_SRC_MATCH_ENABLED = SPINEL_PROP_MAC_EXT__BEGIN + 3, + + /// MAC Source Match Short Address List + /** Format: `A(S)` + */ + SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES + = SPINEL_PROP_MAC_EXT__BEGIN + 4, + + /// MAC Source Match Extended Address List + /** Format: `A(E)` + */ + SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES + = SPINEL_PROP_MAC_EXT__BEGIN + 5, SPINEL_PROP_MAC_EXT__END = 0x1400, SPINEL_PROP_NET__BEGIN = 0x40,