spinel_status_t spinel_datatype_iter_open_container(const spinel_datatype_iter_t* iter, spinel_datatype_iter_t* subiter) { spinel_status_t ret = SPINEL_STATUS_PARSE_ERROR; int depth = 0; spinel_ssize_t block_len; require(iter->data_len > 2, bail); if ((spinel_datatype_t)*iter->pack_format == SPINEL_DATATYPE_ARRAY_C) { ret = SPINEL_STATUS_UNIMPLEMENTED; goto bail; } if ((spinel_datatype_t)*iter->pack_format != SPINEL_DATATYPE_STRUCT_C) { ret = SPINEL_STATUS_PARSE_ERROR; goto bail; } *subiter = *iter; require(subiter->pack_format[1] == '(', bail); subiter->container = iter->pack_format[0]; subiter->pack_format += 2; do { switch(subiter->pack_format[1]) { case '(': depth++; break; case ')': depth++; break; case 0: depth = 0; break; } } while(depth > 0); require(subiter->pack_format[1] == ')', bail); subiter->pack_format += 2; block_len = spinel_datatype_unpack( subiter->data_ptr, subiter->data_len, SPINEL_DATATYPE_DATA_WLEN_S, &subiter->data_ptr, &subiter->data_len ); require(block_len > 0, bail); ret = SPINEL_STATUS_OK; bail: return ret; }
_Use_decl_annotations_ NDIS_STATUS FilterRestart( NDIS_HANDLE FilterModuleContext, PNDIS_FILTER_RESTART_PARAMETERS RestartParameters ) /*++ Routine Description: Filter restart routine. Start the datapath - begin sending and receiving NBLs. Arguments: FilterModuleContext - pointer to the filter context stucture. RestartParameters - additional information about the restart operation. Return Value: NDIS_STATUS_SUCCESS: if filter restarts successfully NDIS_STATUS_XXX: Otherwise. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PVOID SpinelCapsDataBuffer = NULL; const uint8_t* SpinelCapsPtr = NULL; spinel_size_t SpinelCapsLen = 0; NL_INTERFACE_KEY key = {0}; NL_INTERFACE_RW interfaceRw; ULONG ThreadOnHost = TRUE; PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", FilterModuleContext); NT_ASSERT(pFilter->State == FilterPaused); NdisRestartAttributes = RestartParameters->RestartAttributes; // // If NdisRestartAttributes is not NULL, then the filter can modify generic // attributes and add new media specific info attributes at the end. // Otherwise, if NdisRestartAttributes is NULL, the filter should not try to // modify/add attributes. // if (NdisRestartAttributes != NULL) { ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES); NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data; // // Check to see if we need to change any attributes. For example, the // driver can change the current MAC address here. Or the driver can add // media specific info attributes. // NdisGeneralAttributes->LookaheadSize = 128; } // Initialize the Spinel command processing NdisStatus = otLwfCmdInitialize(pFilter); if (NdisStatus != NDIS_STATUS_SUCCESS) { LogError(DRIVER_DEFAULT, "otLwfCmdInitialize failed, %!NDIS_STATUS!", NdisStatus); goto exit; } // Query the device capabilities NtStatus = otLwfCmdGetProp(pFilter, SpinelCapsDataBuffer, SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, &SpinelCapsPtr, &SpinelCapsLen); if (!NT_SUCCESS(NtStatus)) { NdisStatus = NDIS_STATUS_NOT_SUPPORTED; LogError(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_CAPS, %!STATUS!", NtStatus); goto exit; } // Iterate and process returned capabilities while (SpinelCapsLen > 0) { ULONG SpinelCap = 0; spinel_ssize_t len = spinel_datatype_unpack(SpinelCapsPtr, SpinelCapsLen, SPINEL_DATATYPE_UINT_PACKED_S, &SpinelCap); if (len < 1) break; SpinelCapsLen -= (spinel_size_t)len; switch (SpinelCap) { case SPINEL_CAP_MAC_RAW: pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO; pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT; pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN; break; case SPINEL_CAP_NET_THREAD_1_0: pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_THREAD_1_0; break; default: break; } } // Set the state indicating where we should be running the Thread logic (Host or Device). if (!NT_SUCCESS(GetRegDWORDValue(pFilter, L"RunOnHost", &ThreadOnHost))) { // Default to running on the host if the key isn't present ThreadOnHost = TRUE; SetRegDWORDValue(pFilter, L"RunOnHost", ThreadOnHost); } LogInfo(DRIVER_DEFAULT, "Filter: %p initializing ThreadOnHost=%d", FilterModuleContext, ThreadOnHost); // Initialize the processing logic if (ThreadOnHost) { // Ensure the device has the capabilities to support raw radio commands if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO) == 0) { LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support raw radio commands"); NdisStatus = NDIS_STATUS_NOT_SUPPORTED; goto exit; } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_RADIO_MODE; NtStatus = otLwfInitializeThreadMode(pFilter); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "otLwfInitializeThreadMode failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; goto exit; } } else { // Ensure the device has the capabilities to support Thread commands if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_THREAD_1_0) == 0) { LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support thread commands"); NdisStatus = NDIS_STATUS_NOT_SUPPORTED; goto exit; } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_THREAD_MODE; NtStatus = otLwfTunInitialize(pFilter); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "otLwfInitializeTunnelMode failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; goto exit; } } // // Disable DAD and Neighbor advertisements // key.Luid = pFilter->InterfaceLuid; NlInitializeInterfaceRw(&interfaceRw); interfaceRw.DadTransmits = 0; interfaceRw.SendUnsolicitedNeighborAdvertisementOnDad = FALSE; NtStatus = NsiSetAllParameters( NsiActive, NsiSetDefault, &NPI_MS_IPV6_MODULEID, NlInterfaceObject, &key, sizeof(key), &interfaceRw, sizeof(interfaceRw)); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "NsiSetAllParameters (NlInterfaceObject) failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; goto exit; } // // Enable the external references to the filter // ExReInitializeRundownProtection(&pFilter->ExternalRefs); // // If everything is OK, set the filter in running state. // pFilter->State = FilterRunning; // when successful otLwfNotifyDeviceAvailabilityChange(pFilter, TRUE); LogInfo(DRIVER_DEFAULT, "Interface %!GUID! arrival, Filter=%p", &pFilter->InterfaceGuid, pFilter); exit: // // Ensure the state is Paused if restart failed. // if (NdisStatus != NDIS_STATUS_SUCCESS) { pFilter->State = FilterPaused; if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) { otLwfUninitializeThreadMode(pFilter); } else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) { otLwfTunUninitialize(pFilter); } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; // Clean up Spinel command processing otLwfCmdUninitialize(pFilter); } // Free the buffer for the capabilities we queried if (SpinelCapsDataBuffer != NULL) { FILTER_FREE_MEM(SpinelCapsDataBuffer); } LogFuncExitNDIS(DRIVER_DEFAULT, NdisStatus); return NdisStatus; }
spinel_status_t spinel_datatype_iter_next(spinel_datatype_iter_t* iter) { spinel_status_t ret = SPINEL_STATUS_PARSE_ERROR; spinel_datatype_iter_t scratchpad = *iter; const char* next_pack_format; if (!iter->data_ptr || !iter->data_len || !iter->pack_format) { ret = SPINEL_STATUS_EMPTY; goto bail; } next_pack_format = spinel_next_packed_datatype(scratchpad.pack_format); switch ((spinel_datatype_t)*scratchpad.pack_format) { case SPINEL_DATATYPE_INT8_C: case SPINEL_DATATYPE_UINT8_C: require(scratchpad.data_len >= sizeof(uint8_t), bail); scratchpad.data_ptr += sizeof(uint8_t); scratchpad.data_len -= sizeof(uint8_t); break; case SPINEL_DATATYPE_INT16_C: case SPINEL_DATATYPE_UINT16_C: require(scratchpad.data_len >= sizeof(uint16_t), bail); scratchpad.data_ptr += sizeof(uint16_t); scratchpad.data_len -= sizeof(uint16_t); break; case SPINEL_DATATYPE_INT32_C: case SPINEL_DATATYPE_UINT32_C: require(scratchpad.data_len >= sizeof(uint32_t), bail); scratchpad.data_ptr += sizeof(uint32_t); scratchpad.data_len -= sizeof(uint32_t); break; case SPINEL_DATATYPE_IPv6ADDR_C: require(scratchpad.data_len >= sizeof(spinel_ipv6addr_t), bail); scratchpad.data_ptr += sizeof(spinel_ipv6addr_t); scratchpad.data_len -= sizeof(spinel_ipv6addr_t); break; case SPINEL_DATATYPE_EUI64_C: require(scratchpad.data_len >= sizeof(spinel_eui64_t), bail); scratchpad.data_ptr += sizeof(spinel_eui64_t); scratchpad.data_len -= sizeof(spinel_eui64_t); break; case SPINEL_DATATYPE_EUI48_C: require(scratchpad.data_len >= sizeof(spinel_eui48_t), bail); scratchpad.data_ptr += sizeof(spinel_eui48_t); scratchpad.data_len -= sizeof(spinel_eui48_t); break; case SPINEL_DATATYPE_UINT_PACKED_C: { spinel_ssize_t pui_len = spinel_packed_uint_decode(scratchpad.data_ptr, scratchpad.data_len, NULL); require(pui_len > 0, bail); scratchpad.data_ptr += pui_len; scratchpad.data_len -= pui_len; } break; case SPINEL_DATATYPE_UTF8_C: { size_t str_len = strnlen((const char*)scratchpad.data_ptr, scratchpad.data_len) + 1; scratchpad.data_ptr += str_len; scratchpad.data_len -= str_len; } break; case SPINEL_DATATYPE_ARRAY_C: case SPINEL_DATATYPE_DATA_C: if ( (scratchpad.pack_format[1] == ')') || (next_pack_format == 0) ) { // Special case: This type is size of the rest of the buffer! scratchpad.data_ptr += scratchpad.data_len; scratchpad.data_len -= scratchpad.data_len; break; } // Fall through to length-prepended... case SPINEL_DATATYPE_STRUCT_C: case SPINEL_DATATYPE_DATA_WLEN_C: { spinel_ssize_t block_len = spinel_datatype_unpack( scratchpad.data_ptr, scratchpad.data_len, SPINEL_DATATYPE_STRUCT_S("") ); require(block_len > 0, bail); require(block_len < SPINEL_FRAME_MAX_SIZE, bail); require(scratchpad.data_len >= block_len, bail); scratchpad.data_ptr += block_len; scratchpad.data_len -= block_len; } break; default: // Unsupported Type! goto bail; } scratchpad.pack_format = next_pack_format; while (scratchpad.pack_format[0] == SPINEL_DATATYPE_VOID_C) { scratchpad.pack_format++; } if ((*scratchpad.pack_format == ')') || (*scratchpad.pack_format == 0) || (scratchpad.data_len == 0) ) { ret = SPINEL_STATUS_EMPTY; } else { ret = SPINEL_STATUS_OK; } if (iter->container == SPINEL_DATATYPE_ARRAY_C) { iter->data_ptr = scratchpad.data_ptr; iter->data_len = scratchpad.data_len; } else { *iter = scratchpad; } bail: return ret; }