diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index 12062b340..931df9e4d 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -14,7 +14,7 @@ jobs: matrix: configuration: [Debug, Release] platform: [x64, arm64] - runs-on: windows-2019 + runs-on: windows-2022 env: Solution_Path: general\echo\kmdf\kmdfecho.sln steps: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68b46552d..4c07460a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: matrix: configuration: [Debug, Release] platform: [x64, arm64] - runs-on: windows-2019 + runs-on: windows-2022 env: Solution_Path: general\echo\kmdf\kmdfecho.sln steps: diff --git a/network/wwan/cxwmbclass/README.md b/network/wwan/cxwmbclass/README.md new file mode 100644 index 000000000..d0b049782 --- /dev/null +++ b/network/wwan/cxwmbclass/README.md @@ -0,0 +1,14 @@ +--- +page_type: sample +description: "Demonstrates use of the cxwmbclass driver." +languages: +- c +products: +- windows +- windows-wdk +--- + +# cxwmbclass samples + +This sample demonstrates use of the cxwmbclass. + diff --git a/network/wwan/cxwmbclass/adapter.cpp b/network/wwan/cxwmbclass/adapter.cpp new file mode 100644 index 000000000..ed60b427d --- /dev/null +++ b/network/wwan/cxwmbclass/adapter.cpp @@ -0,0 +1,197 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +#include "device.h" +#include "txqueue.h" +#include "rxqueue.h" + +_Use_decl_annotations_ NTSTATUS WmbClassAdapterStart(NETADAPTER netAdapter) +{ + NTSTATUS status = STATUS_SUCCESS; + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = WmbClassGetNetAdapterContext(netAdapter); + PWMBCLASS_DEVICE_CONTEXT deviceContext = netAdapterContext->WmbDeviceContext; + + ULONG64 maxXmitLinkSpeed = MBB_MEDIA_MAX_SPEED; + ULONG64 maxRcvLinkSpeed = MBB_MEDIA_MAX_SPEED; + DWORD maxPowerFilterSize = 0; + + NET_ADAPTER_LINK_LAYER_CAPABILITIES linkLayerCapabilities; + NET_ADAPTER_LINK_LAYER_CAPABILITIES_INIT(&linkLayerCapabilities, maxXmitLinkSpeed, maxRcvLinkSpeed); + + NetAdapterSetLinkLayerCapabilities(netAdapter, &linkLayerCapabilities); + + if (deviceContext->BusParams.IsErrataDevice) + { + NetAdapterSetLinkLayerMtuSize(netAdapter, deviceContext->BusParams.MTU); + } + else + { + NetAdapterSetLinkLayerMtuSize(netAdapter, deviceContext->BusParams.MaxSegmentSize); + } + + if (deviceContext->BusParams.PowerFiltersSupported > 0) + { + NET_ADAPTER_WAKE_BITMAP_CAPABILITIES bitmapCapabilities; + NET_ADAPTER_WAKE_BITMAP_CAPABILITIES_INIT(&bitmapCapabilities); + + bitmapCapabilities.BitmapPattern = TRUE; + bitmapCapabilities.MaximumPatternCount = deviceContext->BusParams.PowerFiltersSupported; + + if (deviceContext->BusParams.IsErrataDevice) + { + // For errata devices we will report the device specific max pattern size. + // 192 bytes is the maximum power filter size as per the MBIM spec. + // If a device reports more than 192 bytes as the power filter size, we + // normalize it here to 192 bytes. This will prevent erroneous devices + // from indicating arbitrary pattern size. This needs to change with any + // MBIM spec revision. + + if (deviceContext->BusParams.MaxPowerFilterSize > WMBCLASS_MAX_MBIM_WOL_PATTERN) + { + maxPowerFilterSize = WMBCLASS_MAX_MBIM_WOL_PATTERN; + } + else + { + maxPowerFilterSize = deviceContext->BusParams.MaxPowerFilterSize; + } + } + else + { + // To maintain backward compatibility with Win8 devices, we continue + // reporting 256 bytes as the wake pattern size. + maxPowerFilterSize = WMBCLASS_MAX_WOL_PATTERN; + } + + bitmapCapabilities.MaximumPatternSize = maxPowerFilterSize; + + NetAdapterWakeSetBitmapCapabilities(netAdapter, &bitmapCapabilities); + } + + NET_ADAPTER_WAKE_MEDIA_CHANGE_CAPABILITIES wakeMediaChangeCapabilities; + NET_ADAPTER_WAKE_MEDIA_CHANGE_CAPABILITIES_INIT(&wakeMediaChangeCapabilities); + + wakeMediaChangeCapabilities.MediaConnect = TRUE; + wakeMediaChangeCapabilities.MediaDisconnect = TRUE; + + NetAdapterWakeSetMediaChangeCapabilities(netAdapter, &wakeMediaChangeCapabilities); + + if (deviceContext->BusParams.SelectiveSuspendSupported) + { + NET_ADAPTER_WAKE_PACKET_FILTER_CAPABILITIES wakePacketFilterCapabilities; + NET_ADAPTER_WAKE_PACKET_FILTER_CAPABILITIES_INIT(&wakePacketFilterCapabilities); + wakePacketFilterCapabilities.PacketFilterMatch = TRUE; + + NetAdapterWakeSetPacketFilterCapabilities(netAdapter, &wakePacketFilterCapabilities); + } + + NET_ADAPTER_TX_CAPABILITIES txCapabilities; + NET_ADAPTER_TX_CAPABILITIES_INIT(&txCapabilities, 1); + NET_ADAPTER_RX_CAPABILITIES rxCapabilities; + NET_ADAPTER_RX_CAPABILITIES_INIT_DRIVER_MANAGED(&rxCapabilities, EvtAdapterReturnRxBuffer, MBB_MAX_PACKET_SIZE, 1); + + NetAdapterSetDataPathCapabilities(netAdapter, &txCapabilities, &rxCapabilities); + + status = NetAdapterStart(netAdapter); + + return status; +} + +NTSTATUS +EvtAdapterCreateTxQueue(_In_ NETADAPTER netAdapter, _Inout_ NETTXQUEUE_INIT* txQueueInit) +{ + NTSTATUS status = STATUS_SUCCESS; + PMBB_TXQUEUE_CONTEXT txQueueContext = NULL; + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = WmbClassGetNetAdapterContext(netAdapter); + PWMBCLASS_DEVICE_CONTEXT deviceContext = netAdapterContext->WmbDeviceContext; + WDF_OBJECT_ATTRIBUTES txAttributes; + NET_EXTENSION_QUERY extension; + + WDF_OBJECT_ATTRIBUTES_INIT(&txAttributes); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&txAttributes, MBB_TXQUEUE_CONTEXT); + + txAttributes.EvtDestroyCallback = EvtTxQueueDestroy; + + NET_PACKET_QUEUE_CONFIG queueConfig; + NET_PACKET_QUEUE_CONFIG_INIT(&queueConfig, EvtTxQueueAdvance, EvtTxQueueSetNotificationEnabled, EvtTxQueueCancel); + + NETPACKETQUEUE txQueue; + status = NetTxQueueCreate(txQueueInit, &txAttributes, &queueConfig, &txQueue); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + txQueueContext = MbbGetTxQueueContext(txQueue); + + + txQueueContext->NetAdapterContext = netAdapterContext; + txQueueContext->DatapathDescriptor = NetTxQueueGetRingCollection(txQueue); + + // Try to use MaxOutDatagrams parameter as the tx completion batch size, but limit to half of the packet ring buffer + auto maxBatchSize = NetRingCollectionGetPacketRing(txQueueContext->DatapathDescriptor)->NumberOfElements / 2; + txQueueContext->CompletionBatchSize = min(deviceContext->BusParams.MaxOutDatagrams, maxBatchSize); + + NET_EXTENSION_QUERY_INIT(&extension, NET_FRAGMENT_EXTENSION_MDL_NAME, NET_FRAGMENT_EXTENSION_MDL_VERSION_1, NetExtensionTypeFragment); + + NetTxQueueGetExtension(txQueue, &extension, &txQueueContext->MdlExtension); + + netAdapterContext->TxQueue = txQueue; +Exit: + return status; +} + +void EvtRxQueueStart(_In_ NETPACKETQUEUE rxQueue) +{ + MbbGetRxQueueContext(rxQueue)->NetAdapterContext->AllowRxTraffic = TRUE; +} + +NTSTATUS +EvtAdapterCreateRxQueue(_In_ NETADAPTER netAdapter, _Inout_ NETRXQUEUE_INIT* rxQueueInit) +{ + NTSTATUS status = STATUS_SUCCESS; + + PMBB_RXQUEUE_CONTEXT rxQueueContext = NULL; + WDF_OBJECT_ATTRIBUTES rxAttributes; + NET_EXTENSION_QUERY extension; + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = WmbClassGetNetAdapterContext(netAdapter); + + NET_PACKET_QUEUE_CONFIG rxConfig; + NET_PACKET_QUEUE_CONFIG_INIT(&rxConfig, EvtRxQueueAdvance, EvtRxQueueSetNotificationEnabled, EvtRxQueueCancel); + rxConfig.EvtStart = EvtRxQueueStart; + + WDF_OBJECT_ATTRIBUTES_INIT(&rxAttributes); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&rxAttributes, MBB_RXQUEUE_CONTEXT); + rxAttributes.EvtDestroyCallback = EvtRxQueueDestroy; + + NETPACKETQUEUE rxQueue; + status = NetRxQueueCreate(rxQueueInit, &rxAttributes, &rxConfig, &rxQueue); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + rxQueueContext = MbbGetRxQueueContext(rxQueue); + + NET_EXTENSION_QUERY_INIT(&extension, NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_NAME, NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_VERSION_1, NetExtensionTypeFragment); + + NetRxQueueGetExtension(rxQueue, &extension, &rxQueueContext->VirtualAddressExtension); + + rxQueueContext->NetAdapterContext = netAdapterContext; + rxQueueContext->DatapathDescriptor = NetRxQueueGetRingCollection(rxQueue); + + NET_EXTENSION_QUERY_INIT(&extension, NET_FRAGMENT_EXTENSION_RETURN_CONTEXT_NAME, NET_FRAGMENT_EXTENSION_RETURN_CONTEXT_VERSION_1, NetExtensionTypeFragment); + + NetRxQueueGetExtension(rxQueue, &extension, &rxQueueContext->ReturnContextExtension); + + // Set netAdapterContext->RxQueue to mean EvtAdapterCreateRxQueue completed successfully + netAdapterContext->RxQueue = rxQueue; + +Exit: + + return status; +} diff --git a/network/wwan/cxwmbclass/businit.cpp b/network/wwan/cxwmbclass/businit.cpp new file mode 100644 index 000000000..a4109adab --- /dev/null +++ b/network/wwan/cxwmbclass/businit.cpp @@ -0,0 +1,1906 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include + +#pragma pack(push, 1) + +typedef struct _USB_DESCRIPTOR_HEADER +{ + + BYTE bLength; + BYTE bDescriptorType; + +} USB_DESCRIPTOR_HEADER, * PUSB_DESCRIPTOR_HEADER; + +#pragma pack(pop) + +NTSTATUS +MbbParseConfigDescriptor( + WDFUSBDEVICE WdfUsbDevice, + PUSHORT MaxSegmentSize, + PUCHAR NcmCaps, + PUCHAR PowerFiltersSupported, + PUCHAR MaxPowerFilterSize, + PUCHAR CommunicationClassInterface, + PUCHAR DataClassInterface, + PUSHORT MaxControlMessage, + PUCHAR AltCommunicationClassSetting, + PUCHAR AltDataClassSetting, + PUSHORT BulkInDataClassPacketSize, + PUSHORT MTU, + PUSHORT MbimVersion, + PUSHORT MbimExtendedVersion); + +NTSTATUS +GetNtbParameters(WDFUSBDEVICE WdfUsbDevice, PNCM_NTB_PARAMETER NcmNtb); + +NTSTATUS +GetDeviceString(__in WDFUSBDEVICE UsbDevice, __in UCHAR Index, __out PWSTR* String); + +VOID FreeBusObject(_In_ __drv_freesMem(Mem) PBUS_OBJECT BusObject); + +NTSTATUS +SetActivityIdForRequest(__in WDFREQUEST Request, __in LPGUID ActivityId); + +void ResetDataPipeWorkItem(_In_ WDFWORKITEM WorkItem); + +EVT_WDF_USB_READER_COMPLETION_ROUTINE InterruptPipeReadComplete; +EVT_WDF_USB_READERS_FAILED InterruptPipeReadError; + +NTSTATUS +MbbBusInitializeByWdf( + _In_ WDFDEVICE WdfDevice, + _In_ MBB_BUS_RESPONSE_AVAILABLE_CALLBACK ResponseAvailableCallback, + _In_ MBB_BUS_DATA_RECEIVE_CALLBACK ReceiveDataCallback, + _In_ MBB_BUS_SS_IDLE_CONFIRM_CALLBACK IdleConfirmCallback, + _In_ MBB_BUS_SS_IDLE_NOTIFICATION_COMPLETE_CALLBACK IdleNotificationComplete, + _In_ MBB_PROTOCOL_HANDLE ProtocolHandle, + _Outptr_ MBB_BUS_HANDLE* BusHandle, + _Inout_opt_ MBB_BUS_HANDLE preAllocatedBusObject) +{ + NTSTATUS Status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + PWDF_USB_INTERFACE_SETTING_PAIR settingPairs = NULL; + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS SettingParams; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + WDFUSBINTERFACE UsbInterface = NULL; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + WDF_USB_DEVICE_CREATE_CONFIG Config; + + WDF_WORKITEM_CONFIG workitemConfig; + WDF_OBJECT_ATTRIBUTES workitemAttributes; + + UCHAR numInterfaces; + UCHAR interfaceIndex; + UCHAR i; + USHORT DescriptorSize = 0; + UCHAR CurrentSetting; + USHORT BulkInPacketSize = 0; + WDF_USB_CONTINUOUS_READER_CONFIG ReaderConfig; + + PIRP UsbSsIrp = NULL; + + PBUS_OBJECT BusObject = NULL; + + USB_CAP_DEVICE_INFO usbCapDeviceInfo = { USB_CAP_DEVICE_TYPE_MAXIMUM, 0, 0, 0 }; + ULONG capResultLength = 0; + + WDF_USB_DEVICE_INFORMATION deviceInformation; + + *BusHandle = NULL; + + if (preAllocatedBusObject == NULL) + { + + BusObject = (PBUS_OBJECT)ALLOCATE_NONPAGED_POOL(sizeof(BUS_OBJECT)); + + if (BusObject == NULL) + { + Status = STATUS_NO_MEMORY; + goto Cleanup; + } + + RtlZeroMemory(BusObject, sizeof(*BusObject)); + + BusObject->Fdo = WdfDeviceWdmGetDeviceObject(WdfDevice); + + INITIALIZE_PASSIVE_LOCK(&BusObject->Lock); + BusObject->State = BUS_STATE_CLOSED; + + BusObject->ProtocolHandle = ProtocolHandle; + BusObject->ResponseAvailableCallback = ResponseAvailableCallback; + BusObject->ReceiveDataCallback = ReceiveDataCallback; + BusObject->IdleConfirmCallback = IdleConfirmCallback; + BusObject->IdleNotificationComplete = IdleNotificationComplete; + + } + else + { + BusObject = (PBUS_OBJECT)preAllocatedBusObject; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, USB_DEVICE_CONTEXT); + + WDF_USB_DEVICE_CREATE_CONFIG_INIT(&Config, USBD_CLIENT_CONTRACT_VERSION_602); + + Status = WdfUsbTargetDeviceCreateWithParameters(WdfDevice, &Config, &attributes, &BusObject->WdfUsbDevice); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + usbDeviceContext->BulkPipeResetFlag = FALSE; + usbDeviceContext->BulkPipeResetWorkitem = NULL; + + // + // create a work item to reset data pipe + // + ExInitializeRundownProtection(&usbDeviceContext->BulkPipeResetRundown); + + WDF_OBJECT_ATTRIBUTES_INIT(&workitemAttributes); + workitemAttributes.ParentObject = BusObject->WdfUsbDevice; + WDF_WORKITEM_CONFIG_INIT(&workitemConfig, ResetDataPipeWorkItem); + + Status = WdfWorkItemCreate(&workitemConfig, &workitemAttributes, &usbDeviceContext->BulkPipeResetWorkitem); + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + // + // create a lock + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = BusObject->WdfUsbDevice; + + Status = WdfWaitLockCreate(&attributes, &usbDeviceContext->PipeStateLock); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = BusObject->WdfUsbDevice; + + Status = WdfCollectionCreate(&attributes, &usbDeviceContext->WriteRequestCollection); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = BusObject->WdfUsbDevice; + + Status = WdfSpinLockCreate(&attributes, &usbDeviceContext->WriteCollectionLock); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + // + // see if the bus driver supports chained mdl's + // + Status = WdfUsbTargetDeviceQueryUsbCapability(BusObject->WdfUsbDevice, (PGUID)&GUID_USB_CAPABILITY_CHAINED_MDLS, 0, NULL, NULL); + + if (NT_SUCCESS(Status)) + { + // + // request work, the stack supports chained mdl's + // + BusObject->ChainedMdlsSupported = TRUE; + } + else + { + } + + // see what USB device type the bus driver is supporting + // + Status = WdfUsbTargetDeviceQueryUsbCapability( + BusObject->WdfUsbDevice, (PGUID)&GUID_USB_CAPABILITY_DEVICE_TYPE, sizeof(USB_CAP_DEVICE_INFO), (PVOID)&usbCapDeviceInfo, &capResultLength); + + if (NT_SUCCESS(Status)) + { + // + // request work, the stack returns USB device type + // + if (IsUsbCapDeviceInfoValid(usbCapDeviceInfo, capResultLength)) + { + BusObject->UsbCapDeviceInfo = usbCapDeviceInfo; + } + } + + WdfUsbTargetDeviceGetDeviceDescriptor(BusObject->WdfUsbDevice, &DeviceDescriptor); + + Status = GetDeviceString(BusObject->WdfUsbDevice, DeviceDescriptor.iManufacturer, &BusObject->Manufacturer); + + Status = GetDeviceString(BusObject->WdfUsbDevice, DeviceDescriptor.iProduct, &BusObject->Model); + + WDF_USB_DEVICE_INFORMATION_INIT(&deviceInformation); + Status = WdfUsbTargetDeviceRetrieveInformation(BusObject->WdfUsbDevice, &deviceInformation); + if (NT_SUCCESS(Status)) + { + BusObject->RemoteWakeCapable = IS_USB_DEVICE_REMOTE_WAKE_CAPABLE(deviceInformation); + } + + Status = MbbParseConfigDescriptor( + BusObject->WdfUsbDevice, + &BusObject->MaxSegmentSize, + &BusObject->NcmParams, + &BusObject->PowerFiltersSupported, + &BusObject->MaxPowerFilterSize, + &usbDeviceContext->UsbCommunicationInterfaceIndex, + &usbDeviceContext->UsbDataInterfaceIndex, + &BusObject->MaxControlChannelSize, + &usbDeviceContext->UsbCommunicationInterfaceSetting, + &usbDeviceContext->UsbDataInterfaceSetting, + &BulkInPacketSize, + &BusObject->MTU, + &BusObject->MbimVersion, + &BusObject->MbimExtendedVersion); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + if (BusObject->MaxControlChannelSize < MIN_CONTROL_MESSAGE_SIZE) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + if (BulkInPacketSize == 0) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + numInterfaces = WdfUsbTargetDeviceGetNumInterfaces(BusObject->WdfUsbDevice); + + settingPairs = (PWDF_USB_INTERFACE_SETTING_PAIR)ALLOCATE_NONPAGED_POOL(sizeof(WDF_USB_INTERFACE_SETTING_PAIR) * numInterfaces); + + if (settingPairs == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + for (interfaceIndex = 0; interfaceIndex < numInterfaces; interfaceIndex++) + { + settingPairs[interfaceIndex].UsbInterface = WdfUsbTargetDeviceGetInterface(BusObject->WdfUsbDevice, interfaceIndex); + + // + // Select alternate setting zero on all interfaces. + // + settingPairs[interfaceIndex].SettingIndex = 0; + } + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&configParams, numInterfaces, settingPairs); + + Status = WdfUsbTargetDeviceSelectConfig(BusObject->WdfUsbDevice, NULL, &configParams); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + if (configParams.Types.MultiInterface.NumberOfConfiguredInterfaces < 2) + { + Status = STATUS_NO_SUCH_DEVICE; + goto Cleanup; + } + + + usbDeviceContext->WdfCommunicationInterfaceIndex = 0xff; + usbDeviceContext->WdfDataInterfaceIndex = 0xff; + + for (i = 0; i < configParams.Types.MultiInterface.NumberOfConfiguredInterfaces; i++) + { + UsbInterface = WdfUsbTargetDeviceGetInterface(BusObject->WdfUsbDevice, i); + CurrentSetting = WdfUsbInterfaceGetConfiguredSettingIndex(UsbInterface); + WdfUsbInterfaceGetDescriptor(UsbInterface, CurrentSetting, &InterfaceDescriptor); + if ((InterfaceDescriptor.bInterfaceNumber == usbDeviceContext->UsbCommunicationInterfaceIndex)) + { + if (usbDeviceContext->WdfCommunicationInterfaceIndex == 0xff) + { + usbDeviceContext->WdfCommunicationInterfaceIndex = i; + } + } + + if ((InterfaceDescriptor.bInterfaceNumber == usbDeviceContext->UsbDataInterfaceIndex)) + { + if (usbDeviceContext->WdfDataInterfaceIndex == 0xff) + { + usbDeviceContext->WdfDataInterfaceIndex = i; + } + } + } + + if ((usbDeviceContext->WdfCommunicationInterfaceIndex == 0xff) || (usbDeviceContext->WdfDataInterfaceIndex == 0xff)) + { + Status = STATUS_NO_SUCH_DEVICE; + goto Cleanup; + } + + // + // get interrupt pipe handles + // + { + BYTE ConfiguredPipes = 0; + UsbInterface = WdfUsbTargetDeviceGetInterface(BusObject->WdfUsbDevice, usbDeviceContext->WdfCommunicationInterfaceIndex); + + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&SettingParams, usbDeviceContext->UsbCommunicationInterfaceSetting); + + Status = WdfUsbInterfaceSelectSetting(UsbInterface, WDF_NO_OBJECT_ATTRIBUTES, &SettingParams); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + ConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(UsbInterface); + + if (ConfiguredPipes != 1) + { + Status = STATUS_NO_SUCH_DEVICE; + goto Cleanup; + } + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + UsbInterface, + 0, // index 0 + &pipeInfo); + + if (WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) + { + usbDeviceContext->InterruptPipe = pipe; + usbDeviceContext->InterruptPipeIoTarget = WdfUsbTargetPipeGetIoTarget(pipe); + + usbDeviceContext->InterruptPipeMaxPacket = pipeInfo.MaximumPacketSize; + } + else + { + Status = STATUS_NO_SUCH_DEVICE; + goto Cleanup; + } + } + + BusObject->SyncInterruptReadBuffer = (PUCHAR)ALLOCATE_NONPAGED_POOL(usbDeviceContext->InterruptPipeMaxPacket); + + if (BusObject->SyncInterruptReadBuffer == NULL) + { + Status = STATUS_NO_MEMORY; + goto Cleanup; + } + + // + // Configure the continous reader now + // + + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&ReaderConfig, InterruptPipeReadComplete, BusObject, usbDeviceContext->InterruptPipeMaxPacket); + + ReaderConfig.NumPendingReads = 1; + ReaderConfig.EvtUsbTargetPipeReadersFailed = InterruptPipeReadError; + + Status = WdfUsbTargetPipeConfigContinuousReader(usbDeviceContext->InterruptPipe, &ReaderConfig); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = GetNtbParameters(BusObject->WdfUsbDevice, &BusObject->NtbParam); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + if (!BusObject->ChainedMdlsSupported) + { + // + // chained mdl's not supported, create a lookaside list to hold the buffers + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = BusObject->WdfUsbDevice; + // + // TODO : For testing + // + // BusObject->NtbParam.dwNtbOutMaxSize = 512; + + Status = WdfLookasideListCreate( + &attributes, BusObject->NtbParam.dwNtbOutMaxSize, NonPagedPoolNx, WDF_NO_OBJECT_ATTRIBUTES, 'CBMW', &usbDeviceContext->LookasideList); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + } + + if (BusObject->UsbCapDeviceInfo.DeviceInfoHeader.DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM) + { + BusObject->MaxBulkInTransfer = BusObject->NtbParam.dwNtbInMaxSize < MAX_HOST_NTB_SIZE_FOR_UDE_MBIM + ? BusObject->NtbParam.dwNtbInMaxSize + : MAX_HOST_NTB_SIZE_FOR_UDE_MBIM; + } + else + { + BusObject->MaxBulkInTransfer = + BusObject->NtbParam.dwNtbInMaxSize < MAX_HOST_NTB_SIZE ? BusObject->NtbParam.dwNtbInMaxSize : MAX_HOST_NTB_SIZE; + } + + // + // round down the transfer size so it is a multiple of maxpacket size for the builk in pipe + // + BusObject->MaxBulkInTransfer = (BusObject->MaxBulkInTransfer / BulkInPacketSize) * BulkInPacketSize; + + BusObject->BulkInHeaderSize = + ROUND_UP_COUNT((ULONG)MmSizeOfMdl(NULL, ROUND_UP_COUNT(BusObject->MaxBulkInTransfer + PAGE_SIZE, ALIGN_QUAD)), ALIGN_QUAD); + + if ((BusObject->NtbParam.bmNtbFormatSupported & NCM_NTB_FORMAT_32_BIT) == NCM_NTB_FORMAT_32_BIT) + { + // + // device supports 32 bit mode + // + if ((BusObject->NtbParam.dwNtbInMaxSize > 0xffff) || (BusObject->NtbParam.dwNtbOutMaxSize > 0xffff)) + { + // + // the device can actually handle a transfer larger than 16bit, change to 32 bit + // + BusObject->NtbFormat32Bit = TRUE; + } + } + + // + // put the device back into a known state + // + Status = MbbBusResetDeviceAndSetParms(BusObject); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + *BusHandle = BusObject; + usbDeviceContext->BusObject = BusObject; + BusObject = NULL; + +Cleanup: + + if (settingPairs != NULL) + { + FREE_POOL(settingPairs); + settingPairs = NULL; + } + + if (BusObject != NULL && preAllocatedBusObject == NULL) + { + FreeBusObject(BusObject); + BusObject = NULL; + } + + return Status; +} + +VOID FreeBusObject(_In_ __drv_freesMem(Mem) PBUS_OBJECT BusObject) + +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + if (BusObject->WdfUsbDevice != NULL) + { + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + if (usbDeviceContext->InterruptPipeIoTarget != NULL) + { + WdfIoTargetStop(usbDeviceContext->InterruptPipeIoTarget, WdfIoTargetCancelSentIo); + } + + usbDeviceContext->BusObject = NULL; + } + + if (BusObject->Manufacturer != NULL) + { + FREE_POOL(BusObject->Manufacturer); + BusObject->Manufacturer = NULL; + } + + if (BusObject->Model != NULL) + { + FREE_POOL(BusObject->Model); + BusObject->Model = NULL; + } + + if (BusObject->WdfDevice != NULL) + { + WdfObjectDelete(BusObject->WdfDevice); + } + + if (BusObject->UsbSsIrp != NULL) + { + IoCancelIrp(BusObject->UsbSsIrp); + + + KeWaitForSingleObject(&BusObject->UsbSsIrpComplete, Executive, KernelMode, FALSE, NULL); + + + IoFreeIrp(BusObject->UsbSsIrp); + BusObject->UsbSsIrp = NULL; + } + + if (BusObject->SyncInterruptReadBuffer != NULL) + { + FREE_POOL(BusObject->SyncInterruptReadBuffer); + BusObject->SyncInterruptReadBuffer = NULL; + } + + FREE_POOL(BusObject); + BusObject = NULL; + + return; +} + +VOID MbbBusCleanup(__in MBB_BUS_HANDLE BusHandle) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + + FreeBusObject(BusObject); + BusObject = NULL; + + return; +} + +NTSTATUS +MbbParseConfigDescriptor( + WDFUSBDEVICE WdfUsbDevice, + PUSHORT MaxSegmentSize, + PUCHAR NcmCaps, + PUCHAR PowerFiltersSupported, + PUCHAR MaxPowerFilterSize, + PUCHAR CommunicationClassInterface, + PUCHAR DataClassInterface, + PUSHORT MaxControlMessage, + PUCHAR AltCommunicationClassSetting, + PUCHAR AltDataClassSetting, + PUSHORT BulkInDataClassPacketSize, + PUSHORT MTU, + PUSHORT MbimVersion, + PUSHORT MbimExtendedVersion) + +{ + + NTSTATUS Status; + + BYTE* ConfigDescriptorBuffer = NULL; + PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor = NULL; + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor = NULL; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor = NULL; + PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR IadDescriptor = NULL; + PUSB_CS_DESCRIPTOR CsDescriptor = NULL; + PUSB_CS_ECM_DESCRIPTOR EcmDescriptor = NULL; + PUSB_CS_NCM_DESCRIPTOR NcmDescriptor = NULL; + PUSB_CS_MBB_DESCRIPTOR MbbDescriptor = NULL; + PUSB_CS_MBB_DESCRIPTOR_EXTENDED MbbDescriptorExtended = NULL; + PUSB_CS_CDC_DESCRIPTOR CdcDescriptor = NULL; + + BYTE* Current = NULL; + USHORT DescriptorSize = 0; + + BOOLEAN GotEcmDesc = FALSE; + BOOLEAN GotNcmDesc = FALSE; + BOOLEAN GotMbbDesc = FALSE; + BYTE CurrentInterface = 0; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + *CommunicationClassInterface = 0xff; + *DataClassInterface = 0xff; + *AltCommunicationClassSetting = 0; + *AltDataClassSetting = 0; + *BulkInDataClassPacketSize = 0; + *MTU = 0; + *MbimVersion = 0x0100; // Default to MBIM 1.0 Version + *MbimExtendedVersion = 0x0100; + + usbDeviceContext = GetUsbDeviceContext(WdfUsbDevice); + + Status = WdfUsbTargetDeviceRetrieveConfigDescriptor(WdfUsbDevice, NULL, &DescriptorSize); + + if (Status != STATUS_BUFFER_TOO_SMALL) + { + + goto Cleanup; + } + + ConfigDescriptorBuffer = (BYTE*)ALLOCATE_NONPAGED_POOL(DescriptorSize); + + if (ConfigDescriptorBuffer == NULL) + { + Status = STATUS_NO_MEMORY; + goto Cleanup; + } + + Status = WdfUsbTargetDeviceRetrieveConfigDescriptor(WdfUsbDevice, ConfigDescriptorBuffer, &DescriptorSize); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + Current = ConfigDescriptorBuffer; + + while (Current + sizeof(USB_DESCRIPTOR_HEADER) <= ConfigDescriptorBuffer + DescriptorSize) + { + PUSB_DESCRIPTOR_HEADER Header = (PUSB_DESCRIPTOR_HEADER)Current; + + if (Current + Header->bLength > ConfigDescriptorBuffer + DescriptorSize) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + switch (Header->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + + ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Current; + + break; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + + InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current; + + CurrentInterface = InterfaceDescriptor->bInterfaceNumber; + + if ((InterfaceDescriptor->bInterfaceClass == MBIM_CC_INTERFACE_CLASS) && + ((InterfaceDescriptor->bInterfaceSubClass == MBIM_CC_INTERFACE_SUBCLASS)) && + (InterfaceDescriptor->bInterfaceProtocol == MBIM_CC_INTERFACE_PROTOCOL || + InterfaceDescriptor->bInterfaceProtocol == MBIM_CC_INTERFACE_NBL_PROTOCOL || + InterfaceDescriptor->bInterfaceProtocol == MBIM_CC_INTERFACE_NETPACKET_PROTOCOL)) + { + + *CommunicationClassInterface = InterfaceDescriptor->bInterfaceNumber; + *AltCommunicationClassSetting = InterfaceDescriptor->bAlternateSetting; + } + + if ((InterfaceDescriptor->bInterfaceClass == MBIM_DC_INTERFACE_CLASS) && + (InterfaceDescriptor->bInterfaceSubClass == MBIM_DC_INTERFACE_SUBCLASS) && + (InterfaceDescriptor->bInterfaceProtocol == MBIM_DC_INTERFACE_PROTOCOL)) + { + *DataClassInterface = InterfaceDescriptor->bInterfaceNumber; + *AltDataClassSetting = InterfaceDescriptor->bAlternateSetting; + } + + break; + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + + if ((Header->bLength != sizeof(*EndpointDescriptor))) + { + + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Current; + + + if (CurrentInterface == *DataClassInterface) + { + // + // this endpoint is for the data interface + // + if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress) && (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_BULK)) + { + // + // bulk in endpoint + // + *BulkInDataClassPacketSize = EndpointDescriptor->wMaxPacketSize & 0x7ff; + + } + } + + break; + + case USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE: + + + break; + + case USB_CDC_CS_DESCRIPTOR_TYPE: + + CsDescriptor = (PUSB_CS_DESCRIPTOR)Current; + + switch (CsDescriptor->bSubType) + { + case USB_CDC_CS_ECM_DESCRIPTOR_SUBTYPE: + + EcmDescriptor = (PUSB_CS_ECM_DESCRIPTOR)Current; + + + break; + + case USB_CDC_CS_NCM_DESCRIPTOR_SUBTYPE: + + NcmDescriptor = (PUSB_CS_NCM_DESCRIPTOR)Current; + + break; + + case USB_CDC_CS_DESCRIPTOR_SUBTYPE: + + if ((CsDescriptor->bLength != sizeof(*CdcDescriptor))) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + CdcDescriptor = (PUSB_CS_CDC_DESCRIPTOR)Current; + + break; + + case USB_CDC_CS_MBB_DESCRIPTOR_SUBTYPE: + + if ((CsDescriptor->bLength != sizeof(*MbbDescriptor))) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + MbbDescriptor = (PUSB_CS_MBB_DESCRIPTOR)Current; + + if (MbbDescriptor->wMbbVersion < MBIM_MBB_FUNCDESC_MIN_VERSION) + { + + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + if (MbbDescriptor->wMaxSegmentSize < MBIM_MIN_SEGMENT_SIZE) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + if (MbbDescriptor->bMaxFilterSize > MBIM_MAX_PACKET_FILTER_SIZE) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + if (MbbDescriptor->bNumberPowerFilters < MBIM_MIN_NUMBER_OF_PACKET_FILTERS) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + *MaxSegmentSize = MbbDescriptor->wMaxSegmentSize; + *PowerFiltersSupported = MbbDescriptor->bNumberPowerFilters; + *MaxPowerFilterSize = MbbDescriptor->bMaxFilterSize; + *NcmCaps = MbbDescriptor->bmNetworkCapabilities; + *MaxControlMessage = MbbDescriptor->wMaxControlMessage; + GotMbbDesc = TRUE; + *MbimVersion = MbbDescriptor->wMbbVersion; + + break; + + case USB_CDC_CS_MBB_DESCRIPTOR_EXTENDED_SUBTYPE: + + // MBIM 1.0 - 6.5: If MBIM Extended Functional Descriptor is provided, it must appear after MBIM Functional Descriptor. + if (!GotMbbDesc) + { + Status = STATUS_UNRECOGNIZED_MEDIA; + + goto Cleanup; + } + + if ((CsDescriptor->bLength != sizeof(*MbbDescriptorExtended))) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + + MbbDescriptorExtended = (PUSB_CS_MBB_DESCRIPTOR_EXTENDED)Current; + + if (MbbDescriptorExtended->wMbbVersion < MBIM_MBB_FUNCDESC_EXTENDED_MIN_VERSION) + { + + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + if (MbbDescriptorExtended->wMTU < MBIM_MIN_MTU_SIZE) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + // If the Extended MTU comes in as larger than the MaxSegmentSize, we set the MTU to MaxSegmentSize + if (MbbDescriptorExtended->wMTU > *MaxSegmentSize) + { + // Check if the MaxSegmentSize is not less than the Minimum MTU size, if it is then bail + if (*MaxSegmentSize < MBIM_MIN_MTU_SIZE) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + else + { + MbbDescriptorExtended->wMTU = *MaxSegmentSize; + } + } + + *MTU = MbbDescriptorExtended->wMTU; + *MbimExtendedVersion = MbbDescriptorExtended->wMbbVersion; + + break; + + default: + + + break; + } + + break; + + default: + + + break; + } + + Current += Header->bLength; + } + + Status = STATUS_SUCCESS; + +Cleanup: + + if (ConfigDescriptorBuffer != NULL) + { + FREE_POOL(ConfigDescriptorBuffer); + ConfigDescriptorBuffer = NULL; + } + + if (!(GotMbbDesc)) + { + + Status = STATUS_UNRECOGNIZED_MEDIA; + } + + if ((*CommunicationClassInterface == 0xff) || (*DataClassInterface == 0xff)) + { + + Status = STATUS_UNRECOGNIZED_MEDIA; + } + + return Status; +} + +NTSTATUS +GetNtbParameters(WDFUSBDEVICE WdfUsbDevice, PNCM_NTB_PARAMETER NcmNtb) + +{ + + NTSTATUS Status; + ULONG BytesTransfered = 0; + + Status = SendSyncControlCommand( + WdfUsbDevice, BmRequestDeviceToHost, BmRequestToInterface, GET_NTB_PARAMETERS, 0, (PUCHAR)NcmNtb, sizeof(*NcmNtb), &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + if (BytesTransfered < sizeof(*NcmNtb)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + } + else + { + goto Cleanup; + } + + if ((NcmNtb->bmNtbFormatSupported & NCM_NTB_FORMAT_16_BIT) != NCM_NTB_FORMAT_16_BIT) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + if (NcmNtb->wNdpInPayloadRemainder >= NcmNtb->wNdpInDivisor) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + if ((NcmNtb->wNdpInPayloadRemainder > NcmNtb->dwNtbInMaxSize) || (NcmNtb->wNdpInDivisor > NcmNtb->dwNtbInMaxSize)) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + if ((NcmNtb->wNdpInAlignment < 4) || (NcmNtb->wNdpInAlignment > NcmNtb->dwNtbInMaxSize) || + ((NcmNtb->wNdpInAlignment - 1) & NcmNtb->wNdpInAlignment) != 0) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + if (NcmNtb->wNdpOutPayloadRemainder >= NcmNtb->wNdpOutDivisor) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + if ((NcmNtb->wNdpOutPayloadRemainder > NcmNtb->dwNtbOutMaxSize) || (NcmNtb->wNdpOutDivisor > NcmNtb->dwNtbOutMaxSize)) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + if ((NcmNtb->wNdpOutAlignment < 4) || (NcmNtb->wNdpOutAlignment > NcmNtb->dwNtbOutMaxSize) || + ((NcmNtb->wNdpOutAlignment - 1) & NcmNtb->wNdpOutAlignment) != 0) + { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + +Cleanup: + + return Status; +} + +NTSTATUS +SetActivityIdForRequest(__in WDFREQUEST Request, __in LPGUID ActivityId) +{ + NTSTATUS Status = STATUS_SUCCESS; + PIRP Irp = NULL; + + do + { + GUID zeroGuid = { 0 }; + + if (ActivityId == NULL || IsEqualGUID(*ActivityId, zeroGuid)) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + Irp = WdfRequestWdmGetIrp(Request); + + if (Irp == NULL) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + // set the activity id of the IRP + Status = IoSetActivityIdIrp(Irp, ActivityId); + } while (FALSE); + + return Status; +} + +EVT_WDF_REQUEST_COMPLETION_ROUTINE SendCompletionRoutine; + +VOID SendCompletionRoutine(__in WDFREQUEST Request, __in WDFIOTARGET Target, __in PWDF_REQUEST_COMPLETION_PARAMS Params, __in WDFCONTEXT Context) + +{ + PREQUEST_CONTEXT ReqContext = NULL; + + ReqContext = GetRequestContext(Request); + + (ReqContext->Callback.Send)(ReqContext->ProtocolHandle, ReqContext->CallbackContext, Params->IoStatus.Status); + + WdfObjectDelete(Request); +} + +NTSTATUS +MbbBusSendMessageFragment( + __in MBB_BUS_HANDLE BusHandle, + __in MBB_REQUEST_HANDLE RequestHandle, + __in PVOID MessageFragment, + __in ULONG FragmentLength, + __in LPGUID ActivityId, + __in MBB_BUS_SEND_COMPLETION_CALLBACK SendCompletionCallback) + + /* + Description + The protocol layer call this routine to request the bus layer to + send a message fragment. Fragmentation / Reassembly is handled by + the protocol layer and it will only handle fragments that are within + the maximum transfer size of the bus. + + This routine is asynchronous and returns immediately after queueing + the transfer. The caller is notified of the completion through the + callback. + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + __in MBB_REQUEST_HANDLE RequestHandle, + Identifies the request. + + __in PVOID MessageFragment, + The data payload that needs to be sent. + + __in ULONG FragmentLength, + Length of the data payload. This will not be greater than the + maximum transfer size supported by the bus. + + __in LPGUID ActivityId, + The activity Id to be associated with this fragment transfer. + This activity Id will also be used by USB for logging USB events. + + __in MBB_BUS_SEND_COMPLETION_CALLBACK SendCompletionCallback + The completion callback routine that will be called by the bus + when the transfer is complete. + + Return Value + + NTSTATUS_SUCCESS + The transfer has completed successfully. SendCompletionCallback will NOT be called. + + NTSTATUS_PENDING + The transfer was queued. SendCompletionCallback will be called on completion. + + Other failure code + The transfer could not be queued. SendCompletionCallback will NOT be called. + */ + +{ + + WDF_USB_CONTROL_SETUP_PACKET packet; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + WDFMEMORY memHandle = NULL; + WDFREQUEST request = NULL; + BOOLEAN SentToDevice = FALSE; + PREQUEST_CONTEXT Context = NULL; + WDF_REQUEST_SEND_OPTIONS SendOptions; + + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); + attributes.ParentObject = BusObject->WdfUsbDevice; + + status = WdfRequestCreate(&attributes, WdfUsbTargetDeviceGetIoTarget(BusObject->WdfUsbDevice), &request); + + if (!NT_SUCCESS(status)) + { + + goto Cleanup; + } + + Context = GetRequestContext(request); + + Context->CallbackContext = RequestHandle; + Context->Callback.Send = SendCompletionCallback; + Context->ProtocolHandle = BusObject->ProtocolHandle; + Context->UsbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = request; + + status = WdfMemoryCreatePreallocated(&attributes, MessageFragment, FragmentLength, &memHandle); + + if (!NT_SUCCESS(status)) + { + + goto Cleanup; + } + + WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS( + &packet, BmRequestHostToDevice, BmRequestToInterface, SEND_ENCAPSULATE_COMMAND, 0, Context->UsbDeviceContext->UsbCommunicationInterfaceIndex); + + status = WdfUsbTargetDeviceFormatRequestForControlTransfer(BusObject->WdfUsbDevice, request, &packet, memHandle, NULL); + + if (!NT_SUCCESS(status)) + { + + goto Cleanup; + } + + WdfRequestSetCompletionRoutine(request, SendCompletionRoutine, NULL); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(10)); + + // Set the activity Id of the IRP associated with the request. + // Ignore any failures + SetActivityIdForRequest(request, ActivityId); + + if (FragmentLength >= sizeof(MBB_COMMAND_HEADER)) + { + PMBB_COMMAND_HEADER CommandHeader = (PMBB_COMMAND_HEADER)MessageFragment; + } + + SentToDevice = WdfRequestSend(request, WdfUsbTargetDeviceGetIoTarget(BusObject->WdfUsbDevice), &SendOptions); + + status = STATUS_PENDING; + + if (!SentToDevice) + { + + status = WdfRequestGetStatus(request); + + } + +Cleanup: + + if (!NT_SUCCESS(status)) + { + if (request != NULL) + { + WdfObjectDelete(request); + request = NULL; + } + } + + return status; +} + +EVT_WDF_REQUEST_COMPLETION_ROUTINE ReceiveCompletionRoutine; + +VOID ReceiveCompletionRoutine(__in WDFREQUEST Request, __in WDFIOTARGET Target, __in PWDF_REQUEST_COMPLETION_PARAMS Params, __in WDFCONTEXT Context) + +{ + PREQUEST_CONTEXT ReqContext = NULL; + GUID ActivityId = { 0 }; + PIRP Irp = NULL; + NTSTATUS Status = STATUS_INVALID_PARAMETER; + + ReqContext = GetRequestContext(Request); + + // Get the IRP + Irp = WdfRequestWdmGetIrp(Request); + + if (Irp != NULL) + { + // Get the activity Id + Status = IoGetActivityIdIrp(Irp, &ActivityId); + } + + if (NT_SUCCESS(Params->IoStatus.Status) && (Params->IoStatus.Information >= sizeof(MBB_COMMAND_DONE_HEADER))) + { + + PMBB_COMMAND_DONE_HEADER CommandHeader = (PMBB_COMMAND_DONE_HEADER)ReqContext->Buffer; + } + + (*ReqContext->Callback.Receive)( + ReqContext->ProtocolHandle, ReqContext->CallbackContext, Params->IoStatus.Status, (ULONG)Params->IoStatus.Information); + + WdfObjectDelete(Request); +} + +NTSTATUS +MbbBusReceiveMessageFragment( + _In_ MBB_BUS_HANDLE BusHandle, + _In_ MBB_REQUEST_HANDLE RequestHandle, + _In_ __drv_aliasesMem PVOID MessageFragment, + _In_ ULONG FragmentLength, + _In_ LPGUID ActivityId, + _In_ MBB_BUS_RECEIVE_COMPLETION_CALLBACK ReceiveCompletionCallback) + /* + Description + + Parameters + + + Return Value + + NTSTATUS_SUCCESS + Initialization was successful. + + Other failure code + */ + /* + Description + The protocol layer call this routine to request the bus layer to + receive data from the device. Reassembly is handled by the protocol layer. + + This routine is asynchronous and returns immediately after queueing + the transfer. The caller is notified of the completion through the + callback. + + Parameters + _In_ MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + _In_ MBB_REQUEST_HANDLE RequestHandle, + Identifies the request. + + _In_ __drv_aliasesMem PVOID MessageFragment, + The data buffer that would be filled with the received data. + + _In_ ULONG FragmentLength, + Length of the data requested from the device. This will not be + greater than the maximum transfer size supported by the bus. + + _In_ LPGUID ActivityId, + The activity Id to be associated with this fragment transfer. + This activity Id will also be used by USB for logging USB events. + + _In_ MBB_BUS_RECEIVE_COMPLETION_CALLBACK ReceiveCompletionCallback + The completion callback routine that will be called by the bus + when the transfer is complete. + + Return Value + + NTSTATUS_SUCCESS + The transfer has completed successfully. ReceiveCompletionCallback will NOT be called. + + NTSTATUS_PENDING + The transfer was queued. ReceiveCompletionCallback will be called on completion. + + Other failure code + The transfer could not be queued. ReceiveCompletionCallback will NOT be called. + */ + +{ + WDF_USB_CONTROL_SETUP_PACKET packet; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + WDFMEMORY memHandle = NULL; + WDFREQUEST request = NULL; + BOOLEAN SentToDevice = FALSE; + PREQUEST_CONTEXT Context = NULL; + WDF_REQUEST_SEND_OPTIONS SendOptions; + PIRP Irp = NULL; + + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); + + attributes.ParentObject = BusObject->WdfUsbDevice; + + status = WdfRequestCreate(&attributes, WdfUsbTargetDeviceGetIoTarget(BusObject->WdfUsbDevice), &request); + + if (!NT_SUCCESS(status)) + { + + goto Cleanup; + } + + Context = GetRequestContext(request); + + Context->CallbackContext = RequestHandle; + Context->Callback.Receive = ReceiveCompletionCallback; + Context->ProtocolHandle = BusObject->ProtocolHandle; + Context->UsbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + Context->Buffer = MessageFragment; + Context->BufferLength = FragmentLength; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = request; + + status = WdfMemoryCreatePreallocated(&attributes, MessageFragment, FragmentLength, &memHandle); + + if (!NT_SUCCESS(status)) + { + + goto Cleanup; + } + + WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS( + &packet, BmRequestDeviceToHost, BmRequestToInterface, GET_ENCAPSULATE_RESPONSE, 0, Context->UsbDeviceContext->UsbCommunicationInterfaceIndex); + + status = WdfUsbTargetDeviceFormatRequestForControlTransfer(BusObject->WdfUsbDevice, request, &packet, memHandle, NULL); + + if (!NT_SUCCESS(status)) + { + + goto Cleanup; + } + + WdfRequestSetCompletionRoutine(request, ReceiveCompletionRoutine, NULL); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(10)); + + // Set the activity Id of the IRP associated with the request. + // Ignore any failures + SetActivityIdForRequest(request, ActivityId); + + SentToDevice = WdfRequestSend(request, WdfUsbTargetDeviceGetIoTarget(BusObject->WdfUsbDevice), &SendOptions); + + status = STATUS_PENDING; + + if (!SentToDevice) + { + + status = WdfRequestGetStatus(request); + + } + +Cleanup: + + if (!NT_SUCCESS(status)) + { + if (request != NULL) + { + WdfObjectDelete(request); + request = NULL; + } + } + + return status; +} + +VOID InterruptPipeReadComplete(__in WDFUSBPIPE Pipe, __in WDFMEMORY Memory, __in size_t NumBytesTransfered, __in WDFCONTEXT Context) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)Context; + PVOID Buffer = NULL; + PUSB_CDC_NOTIFICATION CdcNotification = NULL; + PUSB_CDC_NOTIFICATION_SPEED_CHANGE CdcSpeedChangeNotification = NULL; + ULONG TempBytesTransfered = (ULONG)NumBytesTransfered; + UCHAR IndicateBuffer[INTERRUPT_REASSEMBLY_BUFFER_SIZE]; + ULONG BufferLength = 0; + + + Buffer = WdfMemoryGetBuffer(Memory, NULL); + + // + // process this fragment, the function will return a non-zero value if a complete message is returned. + // + BufferLength = ProcessInterruptPipeRead(BusObject, (PCUCHAR)Buffer, NumBytesTransfered, IndicateBuffer, sizeof(IndicateBuffer)); + + if (BufferLength >= sizeof(*CdcNotification)) + { + CdcNotification = (PUSB_CDC_NOTIFICATION)&IndicateBuffer[0]; + + switch (CdcNotification->bNotificationCode) + { + case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE: (BusObject->ResponseAvailableCallback)(BusObject->ProtocolHandle); break; + + case USB_CDC_NOTIFICATION_NETWORK_CONNECTION: + case USB_CDC_NOTIFICATION_CONNECTION_SPEED_CHANGE: + default: break; + } + } + + return; +} + +BOOLEAN +InterruptPipeReadError(__in WDFUSBPIPE Pipe, __in NTSTATUS Status, __in USBD_STATUS UsbdStatus) + +{ + return TRUE; +} + +NTSTATUS +MbbBusQueryBusParameters(__in MBB_BUS_HANDLE BusHandle, __out PMBB_BUS_PARAMETERS BusParameters) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + + RtlZeroMemory(BusParameters, sizeof(*BusParameters)); + + BusParameters->FragmentSize = BusObject->MaxControlChannelSize; + + BusParameters->MaxSegmentSize = BusObject->MaxSegmentSize; + + BusParameters->Ntb32BitSupported = (BusObject->NtbParam.bmNtbFormatSupported & NCM_NTB_FORMAT_32_BIT) == NCM_NTB_FORMAT_32_BIT; + BusParameters->MaxOutNtb = BusObject->NtbParam.dwNtbOutMaxSize; + + if ((BusObject->NtbParam.wNtbOutMaxDatagrams == 0) || (BusObject->NtbParam.wNtbOutMaxDatagrams > MAX_OUT_DATAGRAMS)) + { + // + // Zero means unlimited, impose a limit so the driver can preallocated the contexts it needs + // + BusParameters->MaxOutDatagrams = MAX_OUT_DATAGRAMS; + } + else + { + BusParameters->MaxOutDatagrams = BusObject->NtbParam.wNtbOutMaxDatagrams; + } + + BusParameters->NdpOutDivisor = BusObject->NtbParam.wNdpOutDivisor; + BusParameters->NdpOutRemainder = BusObject->NtbParam.wNdpOutPayloadRemainder; + BusParameters->NdpOutAlignment = BusObject->NtbParam.wNdpOutAlignment; + // + // TODO: Read the current value from the bus object when SetNtb is implemented + // + BusParameters->CurrentMode32Bit = BusObject->NtbFormat32Bit; + BusParameters->SelectiveSuspendSupported = TRUE; + + BusParameters->PowerFiltersSupported = BusObject->PowerFiltersSupported; + BusParameters->MaxPowerFilterSize = BusObject->MaxPowerFilterSize; + BusParameters->RemoteWakeCapable = BusObject->RemoteWakeCapable; + + if (BusObject->Manufacturer != NULL) + { + RtlStringCbCopyW(BusParameters->Manufacturer, sizeof(BusParameters->Manufacturer), BusObject->Manufacturer); + } + + if (BusObject->Model != NULL) + { + RtlStringCbCopyW(BusParameters->Model, sizeof(BusParameters->Model), BusObject->Model); + } + + BusParameters->MTU = BusObject->MTU; + if (BusObject->MTU != 0) + { + BusParameters->IsErrataDevice = TRUE; + } + else + { + BusParameters->IsErrataDevice = FALSE; + } + + BusParameters->MbimVersion = BusObject->MbimVersion; + BusParameters->MbimExtendedVersion = BusObject->MbimExtendedVersion; + + return STATUS_SUCCESS; +} + +NTSTATUS MbbBusHandshake(_In_ PBUS_OBJECT BusObject, _In_ ULONG TransactionId, _In_opt_ PVOID FastIOSendNetBufferListsComplete, _In_opt_ PVOID FastIOIndicateReceiveNetBufferLists) +{ + NTSTATUS Status; + ULONG BytesTransferred = 0; + UCHAR ReadBuffer[256]; + ULONG RetryCount = 0; + MBB_OPEN_MESSAGE OpenMessage; + PMBB_OPEN_DONE OpenDoneMessage = NULL; + MBB_OPEN_MESSAGE_FASTIO OpenMessageFastIO; + PMBB_OPEN_DONE_FASTIO OpenDoneMessageFastIO = NULL; + + RtlZeroMemory(&OpenMessage, sizeof(OpenMessage)); + + OpenMessage.MessageHeader.MessageType = MBB_MESSAGE_TYPE_OPEN; + OpenMessage.MessageHeader.MessageLength = sizeof(OpenMessage); + OpenMessage.MessageHeader.MessageTransactionId = TransactionId; + OpenMessage.MaximumControlTransfer = + BusObject->MaxControlChannelSize < MAX_CONTROL_MESSAGE_SIZE ? BusObject->MaxControlChannelSize : MAX_CONTROL_MESSAGE_SIZE; + + do + { + RetryCount++; + + Status = TransactControlChannel( + BusObject, RetryCount * INITIAL_OPEN_TIMEOUT, (PUCHAR)&OpenMessage, sizeof(OpenMessage), (PUCHAR)&ReadBuffer[0], sizeof(ReadBuffer), &BytesTransferred); + } while ((Status == STATUS_IO_TIMEOUT) && (RetryCount < MAX_OPEN_RETRY_ATTEMPTS)); + + if (NT_SUCCESS(Status)) + { + if (BytesTransferred < sizeof(*OpenDoneMessage)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + if (NT_SUCCESS(Status)) + { + OpenDoneMessage = (PMBB_OPEN_DONE)&ReadBuffer[0]; + + if ((OpenDoneMessage->MessageHeader.MessageType != MBB_MESSAGE_TYPE_OPEN_DONE) || + (OpenDoneMessage->MessageHeader.MessageLength < sizeof(*OpenDoneMessage)) || + (OpenDoneMessage->MessageHeader.MessageTransactionId != OpenMessage.MessageHeader.MessageTransactionId)) + { + Status = STATUS_NDIS_INVALID_DATA; + } + else if (OpenDoneMessage->MbbStatus != STATUS_SUCCESS) + { + Status = STATUS_OPEN_FAILED; + } + } + return Status; +} + +NTSTATUS +MbbBusStart(_In_ MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + BOOLEAN FailOpen = FALSE; + + BOOLEAN AltSettingSet = FALSE; + + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + if (BusObject->State != BUS_STATE_CLOSED) + { + FailOpen = TRUE; + } + else + { + BusObject->State = BUS_STATE_OPENING; + } + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + + if (FailOpen) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + Status = MbbBusResetDeviceAndSetParms(BusObject); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = MbbBusSelectDataAltSetting(BusObject, ALT_DATA_SETTING_1); + + if (NT_ERROR(Status)) + { + goto Cleanup; + } + + AltSettingSet = TRUE; + + // + // start the continouse reader now + // + Status = WdfIoTargetStart(usbDeviceContext->InterruptPipeIoTarget); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + Status = STATUS_SUCCESS; + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + BusObject->State = BUS_STATE_OPENED; + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + +Cleanup: + + if (!NT_SUCCESS(Status)) + { + // + // stop the pipe reader + // + WdfIoTargetStop(usbDeviceContext->InterruptPipeIoTarget, WdfIoTargetCancelSentIo); + + // + // set the data pipes back to alt seeting 0 + // + if (AltSettingSet) + { + MbbBusSelectDataAltSetting(BusObject, ALT_DATA_SETTING_0); + } + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + BusObject->State = BUS_STATE_CLOSED; + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + } + + return Status; +} + +NTSTATUS +MbbBusStop(__in MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + // + // stop the interrupt pipe so the continuous reader will stop and we can do sync reads + // + WdfIoTargetStop(usbDeviceContext->InterruptPipeIoTarget, WdfIoTargetCancelSentIo); + + Status = STATUS_SUCCESS; + + MbbBusSelectDataAltSetting(BusObject, ALT_DATA_SETTING_0); + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + BusObject->State = BUS_STATE_CLOSED; + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + + + return Status; +} + +BOOLEAN +MbbBusIsStoped(_In_ MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + return BusObject->State == BUS_STATE_CLOSED; +} + +NTSTATUS +MbbBusOpen(_In_ MBB_BUS_HANDLE BusHandle, _In_ ULONG TransactionId, _In_opt_ PVOID FastIOSendNetBufferListsComplete, _In_opt_ PVOID FastIOIndicateReceiveNetBufferLists) +/* + Description + + Opens the session with the device + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + BOOLEAN FailOpen = FALSE; + + PUSB_CDC_NOTIFICATION Notification = NULL; + BOOLEAN AltSettingSet = FALSE; + + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + if (BusObject->State != BUS_STATE_CLOSED) + { + FailOpen = TRUE; + } + else + { + BusObject->State = BUS_STATE_OPENING; + } + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + + if (FailOpen) + { + Status = STATUS_UNSUCCESSFUL; + + + goto Cleanup; + } + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + + Status = MbbBusResetDeviceAndSetParms(BusObject); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = MbbBusSelectDataAltSetting(BusObject, ALT_DATA_SETTING_1); + + if (NT_ERROR(Status)) + { + goto Cleanup; + } + + AltSettingSet = TRUE; + + Status = MbbBusHandshake(BusObject, TransactionId, FastIOSendNetBufferListsComplete, FastIOIndicateReceiveNetBufferLists); + if (NT_ERROR(Status)) + { + goto Cleanup; + } + + // + // start the continouse reader now + // + Status = WdfIoTargetStart(usbDeviceContext->InterruptPipeIoTarget); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = STATUS_SUCCESS; + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + BusObject->State = BUS_STATE_OPENED; + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + +Cleanup: + + if (!NT_SUCCESS(Status)) + { + // + // stop the pipe reader + // + WdfIoTargetStop(usbDeviceContext->InterruptPipeIoTarget, WdfIoTargetCancelSentIo); + + // + // set the data pipes back to alt seeting 0 + // + if (AltSettingSet) + { + MbbBusSelectDataAltSetting(BusObject, ALT_DATA_SETTING_0); + } + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + BusObject->State = BUS_STATE_CLOSED; + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + } + + return Status; +} + +NTSTATUS +MbbBusClose(__in MBB_BUS_HANDLE BusHandle, __in ULONG TransactionId, __in BOOLEAN ForceClose) +/* + Description + + Opens the session with the device + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + BOOLEAN FailClose = FALSE; + + ULONG BytesTransfered = 0; + PUSB_CDC_NOTIFICATION Notification = NULL; + MBB_CLOSE_MESSAGE CloseMessage; + PMBB_CLOSE_DONE CloseDoneMessage = NULL; + UCHAR ReadBuffer[256]; + + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + if (!ForceClose) + { + if (BusObject->State != BUS_STATE_OPENED) + { + FailClose = TRUE; + } + } + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + + if (FailClose) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + // + // stop the interrupt pipe so the continuous reader will stop and we can do sync reads + // + WdfIoTargetStop(usbDeviceContext->InterruptPipeIoTarget, WdfIoTargetCancelSentIo); + + RtlZeroMemory(&CloseMessage, sizeof(CloseMessage)); + + CloseMessage.MessageHeader.MessageType = MBB_MESSAGE_TYPE_CLOSE; + CloseMessage.MessageHeader.MessageLength = sizeof(CloseMessage); + CloseMessage.MessageHeader.MessageTransactionId = TransactionId; + + Status = TransactControlChannel( + BusObject, DEFAULT_IO_TIMEOUT, (PUCHAR)&CloseMessage, sizeof(CloseMessage), (PUCHAR)&ReadBuffer[0], sizeof(ReadBuffer), &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + if (BytesTransfered < sizeof(*CloseDoneMessage)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + CloseDoneMessage = (PMBB_CLOSE_DONE)&ReadBuffer[0]; + + if ((CloseDoneMessage->MessageHeader.MessageType != MBB_MESSAGE_TYPE_CLOSE_DONE) || + (CloseDoneMessage->MessageHeader.MessageLength < sizeof(*CloseDoneMessage)) || + (CloseDoneMessage->MessageHeader.MessageTransactionId != CloseMessage.MessageHeader.MessageTransactionId)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + + goto Cleanup; + } + +Cleanup: + + Status = STATUS_SUCCESS; + + MbbBusSelectDataAltSetting(BusObject, ALT_DATA_SETTING_0); + + ACQUIRE_PASSIVE_LOCK(&BusObject->Lock); + + BusObject->State = BUS_STATE_CLOSED; + + RELEASE_PASSIVE_LOCK(&BusObject->Lock); + + return Status; +} + +VOID MbbBusSetNotificationState(__in MBB_BUS_HANDLE BusHandle, __in BOOLEAN Enabled) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + if (!Enabled) + { + WdfIoTargetStop(usbDeviceContext->InterruptPipeIoTarget, WdfIoTargetCancelSentIo); + } + else + { + (void)WdfIoTargetStart(usbDeviceContext->InterruptPipeIoTarget); + } + + return; +} \ No newline at end of file diff --git a/network/wwan/cxwmbclass/cxwmbclass.rc b/network/wwan/cxwmbclass/cxwmbclass.rc new file mode 100644 index 000000000..6df53fd8a --- /dev/null +++ b/network/wwan/cxwmbclass/cxwmbclass.rc @@ -0,0 +1,20 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "windows.h" +#include "ntverp.h" + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +#define VER_FILETYPE VFT_DRV + +#define VER_FILESUBTYPE VFT2_DRV_NETWORK + +#define VER_FILEDESCRIPTION_STR "Windows Mobile Broadband Class Driver" + +#define VER_INTERNALNAME_STR "cxwmbclass.sys" +#define VER_ORIGINALFILENAME_STR "cxwmbclass.sys" + +#include "common.ver" diff --git a/network/wwan/cxwmbclass/cxwmbclass.sln b/network/wwan/cxwmbclass/cxwmbclass.sln new file mode 100644 index 000000000..249990f1e --- /dev/null +++ b/network/wwan/cxwmbclass/cxwmbclass.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32929.385 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cxwmbclass", "cxwmbclass\cxwmbclass.vcxproj", "{11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Debug|ARM64.Build.0 = Debug|ARM64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Debug|x64.ActiveCfg = Debug|x64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Debug|x64.Build.0 = Debug|x64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Debug|x64.Deploy.0 = Debug|x64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Release|ARM64.ActiveCfg = Release|ARM64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Release|ARM64.Build.0 = Release|ARM64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Release|ARM64.Deploy.0 = Release|ARM64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Release|x64.ActiveCfg = Release|x64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Release|x64.Build.0 = Release|x64 + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3DEAC1E8-F245-49DC-AD26-8A3694201775} + EndGlobalSection +EndGlobal diff --git a/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.inf b/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.inf new file mode 100644 index 000000000..69055bfbd --- /dev/null +++ b/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.inf @@ -0,0 +1,119 @@ +;------------------------------------------------------------------------------- +; netwmbclass.inf +; +; Copyright (c) Microsoft Corporation. All rights reserved. + +[version] +Signature = "$Windows NT$" +Class = Net +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %ManufacturerName% +CatalogFile=cxwmbclass.cat +DriverVer = ; will be filled in at build time by StampInf +PnpLockdown = 1 + +[SourceDisksNames] +3426=windows cd + +[SourceDisksFiles] +cxwmbclass.sys = 3426 + +[DestinationDirs] +DefaultDestDir=13 + +[Manufacturer] +%ManufacturerName% = Msft,NT$ARCH$ + +[Msft.NT$ARCH$] + ; DisplayName Section DeviceID + ; ----------- ------- -------- +;%wmbclass.DeviceDesc% = wmbclass.ndi, USB\MS_COMP_MBIM +;%wmbclass.DeviceDesc% = wmbclass.ndi, USB\class_02&subclass_0e&prot_00 +%wmbclass.DeviceDesc% = wmbclass.ndi, USB\VID_1199&PID_9071&MI_0C ;Sierra Wireless EM7430 Qualcomm Snapdragon X7 LTE-A + +;------------------------------------------------------------------------------- +; Adapter DDInstall and Services section +; for NetAdapter drivers +[wmbclass.ndi] +AddReg = wmbclass.Reg +CopyFiles = wmbclassCopyFiles +Characteristics = 0x4 ; NCF_PHYSICAL +BusType = 15 +*IfType = 243; IF_TYPE_WWANPP +*MediaType = 9; NdisMediumWirelessWan +*PhysicalMediaType = 8; NdisPhysicalMediumWirelessWan +EnableDhcp = 0; Disable DHCP + +[wmbclassCopyFiles] +cxwmbclass.sys,,,0x0100 + +[wmbclass.ndi.HW] +Include = pci.inf +Needs = PciD3ColdSupported.HW +AddReg = wmbclass.ndi.AddReg.HW + +[wmbclass.ndi.AddReg.HW] +HKR,,"AllowIdleIrpInD3",0x00010001,0x1 + +[wmbclass.ndi.Services] +AddService = %ServiceName%, 2, wmbclass.Service, wmbclass.EventLog + +; For mobile broadband drivers +[wmbclass.Reg] +HKR, Ndi, Service, 0, %ServiceName% +HKR, Ndi\Interfaces, UpperRange, 0, "flpp4, flpp6" +HKR, Ndi\Interfaces, LowerRange, 0, "ppip" +HKR, , AllowDriverToOverrideDeviceName, 0x00010001, 1 + +; standard INF keywords for NetAdapter drivers +; using AddReg directive so they will work when this INF being Includes/Needs + +HKR, NetworkInterface, *IfConnectorPresent, 0x00010001, 1 +HKR, NetworkInterface, *ConnectionType, 0x00010001, 1 +HKR, NetworkInterface, *DirectionType, 0x00010001, 0 +HKR, NetworkInterface, *AccessType, 0x00010001, 2 +HKR, NetworkInterface, *HardwareLoopback, 0x00010001, 0 +HKR, , NumberOfNetworkInterfaces, 0x00010001, 17 + +; Selective Suspend +HKR,Ndi\params\*SelectiveSuspend,ParamDesc,,%SelectiveSuspend% +HKR,Ndi\params\*SelectiveSuspend,default,,"1" +HKR,Ndi\params\*SelectiveSuspend,type,,"enum" +HKR,Ndi\params\*SelectiveSuspend\enum,0,,%Disabled% +HKR,Ndi\params\*SelectiveSuspend\enum,1,,%Enabled% + +;----------------------------------------------------------------------------- +; Driver and Service Section +; + +; For wmbclass.x drivers +[wmbclass.Service] +DisplayName = %wmbclass.Service.DispName% +ServiceType = 1 ;%SERVICE_KERNEL_DRIVER% +StartType = 3 ;%SERVICE_DEMAND_START% +ErrorControl = 1 ;%SERVICE_ERROR_NORMAL% +ServiceBinary = %13%\cxwmbclass.sys +LoadOrderGroup = NDIS + +[wmbclass.EventLog] +AddReg = wmbclass.AddEventLog.Reg + +[wmbclass.AddEventLog.Reg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll" +HKR, , TypesSupported, 0x00010001, 7 + +;----------------------------------------------------------------------------- +; Non-localizable Strings +; +[Strings] +ServiceName = "cxwmbclass" + +;----------------------------------------------------------------------------- +; Localizable Strings +; +ManufacturerName = "Sample Code" +wmbclass.DeviceDesc = "Generic Mobile Broadband Adapter" +wmbclass.Service.DispName = "USB Mobile Broadband Adapter Driver" +Disabled = "Disabled" +Enabled = "Enabled" +SelectiveSuspend = "Selective Suspend" diff --git a/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.vcxproj b/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.vcxproj new file mode 100644 index 000000000..9d7d5b16b --- /dev/null +++ b/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.vcxproj @@ -0,0 +1,176 @@ + + + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + {11CC63F7-F6D0-4CED-99BA-C5FDAE88D29C} + {1bc93793-694f-48fe-9372-81e2b05556fd} + v4.5 + 12.0 + Debug + x64 + cxwmbclass + + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + + + + + + + + + DbgengKernelDebugger + $(SolutionDir)\inc;$(IncludePath) + $(KIT_SHARED_INC_PATH_WDK)\netcx\shared\1.0;$(KM_IncludePath)\mbbcx\1.0;$(KIT_SHARED_INC_PATH_WDK);$(KM_IncludePath)\netcx\kmdf\adapter\2.3;$(ExternalIncludePath) + + + DbgengKernelDebugger + $(SolutionDir)\inc;$(IncludePath) + $(KIT_SHARED_INC_PATH_WDK)\netcx\shared\1.0;$(KM_IncludePath)\mbbcx\1.0;$(KIT_SHARED_INC_PATH_WDK);$(KM_IncludePath)\netcx\kmdf\adapter\2.3;$(ExternalIncludePath) + + + DbgengKernelDebugger + $(SolutionDir)\inc;$(IncludePath) + $(KIT_SHARED_INC_PATH_WDK)\netcx\shared\1.0;$(KM_IncludePath)\mbbcx\1.0;$(KIT_SHARED_INC_PATH_WDK);$(KM_IncludePath)\netcx\kmdf\adapter\2.3;$(ExternalIncludePath) + + + DbgengKernelDebugger + $(SolutionDir)\inc;$(IncludePath) + $(KIT_SHARED_INC_PATH_WDK)\netcx\shared\1.0;$(KM_IncludePath)\mbbcx\1.0;$(KIT_SHARED_INC_PATH_WDK);$(KM_IncludePath)\netcx\kmdf\adapter\2.3;$(ExternalIncludePath) + + + + sha256 + + + 4748;%(DisableSpecificWarnings);4101;4189;4100;4267 + Level3 + + + $(WindowsDDK_LibraryPath)\x64\ndis.lib;$(WindowsDDK_LibraryPath)\x64\netio.lib;$(WindowsDDK_LibraryPath)\x64\usbd.lib;$(WindowsDDK_LibraryPath)\x64\usbdex.lib;$(WindowsDDK_LibraryPath)\x64\wdmguid.lib;$(WindowsDDK_LibraryPath)\x64\netcx\kmdf\adapter\2.3\netadaptercxstub.lib;$(WindowsDDK_LibraryPath)\x64\mbbcx\1.0\mbbcxstub.lib;%(AdditionalDependencies) + + + + + sha256 + + + Level3 + + + $(WindowsDDK_LibraryPath)\x64\ndis.lib;$(WindowsDDK_LibraryPath)\x64\netio.lib;$(WindowsDDK_LibraryPath)\x64\usbd.lib;$(WindowsDDK_LibraryPath)\x64\usbdex.lib;$(WindowsDDK_LibraryPath)\x64\wdmguid.lib;$(WindowsDDK_LibraryPath)\x64\netcx\kmdf\adapter\2.3\netadaptercxstub.lib;$(WindowsDDK_LibraryPath)\x64\mbbcx\1.0\mbbcxstub.lib;%(AdditionalDependencies) + + + + + sha256 + + + Level3 + + + $(WindowsDDK_LibraryPath)\arm64\ndis.lib;$(WindowsDDK_LibraryPath)\arm64\netio.lib;$(WindowsDDK_LibraryPath)\arm64\usbd.lib;$(WindowsDDK_LibraryPath)\arm64\usbdex.lib;$(WindowsDDK_LibraryPath)\arm64\wdmguid.lib;$(WindowsDDK_LibraryPath)\arm64\netcx\kmdf\adapter\2.3\netadaptercxstub.lib;$(WindowsDDK_LibraryPath)\arm64\mbbcx\1.0\mbbcxstub.lib;%(AdditionalDependencies) + + + + + sha256 + + + Level3 + + + $(WindowsDDK_LibraryPath)\arm64\ndis.lib;$(WindowsDDK_LibraryPath)\arm64\netio.lib;$(WindowsDDK_LibraryPath)\arm64\usbd.lib;$(WindowsDDK_LibraryPath)\arm64\usbdex.lib;$(WindowsDDK_LibraryPath)\arm64\wdmguid.lib;$(WindowsDDK_LibraryPath)\arm64\netcx\kmdf\adapter\2.3\netadaptercxstub.lib;$(WindowsDDK_LibraryPath)\arm64\mbbcx\1.0\mbbcxstub.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.vcxproj.filters b/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.vcxproj.filters new file mode 100644 index 000000000..7136df259 --- /dev/null +++ b/network/wwan/cxwmbclass/cxwmbclass/cxwmbclass.vcxproj.filters @@ -0,0 +1,107 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + Driver Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/network/wwan/cxwmbclass/datapipe.cpp b/network/wwan/cxwmbclass/datapipe.cpp new file mode 100644 index 000000000..4452b7617 --- /dev/null +++ b/network/wwan/cxwmbclass/datapipe.cpp @@ -0,0 +1,998 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +typedef struct _USB_WRITE_REQ_CONTEXT +{ + WDFMEMORY UrbMemory; + PURB Urb; + PMDL Mdl; + WDFMEMORY LookasideBuffer; + PBUS_OBJECT BusObject; + MBB_BUS_SEND_DATA_COMPLETION_CALLBACK Callback; + MBB_REQUEST_HANDLE RequestHandle; + +} USB_WRITE_REQ_CONTEXT, *PUSB_WRITE_REQ_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(USB_WRITE_REQ_CONTEXT, GetWriteRequestContext) + +EVT_WDF_USB_READER_COMPLETION_ROUTINE BulkInReadComplete; + +EVT_WDF_USB_READERS_FAILED BulkInReadError; + +NTSTATUS +GetWriteRequests(WDFUSBDEVICE UsbDevice, WDFREQUEST* ReturnedWriteRequest); + +VOID FreeWriteRequest(WDFUSBDEVICE UsbDevice, WDFREQUEST WriteRequest); + +NTSTATUS +MbbBusSelectDataAltSetting(__in MBB_BUS_HANDLE BusHandle, __in UCHAR AltSetting) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS SettingParams; + WDFUSBINTERFACE UsbInterface = NULL; + WDF_USB_PIPE_INFORMATION pipeInfo; + WDFUSBPIPE pipe; + UCHAR ConfiguredPipes = 0; + UCHAR index = 0; + NTSTATUS Status; + NTSTATUS TempStatus; + WDF_USB_CONTINUOUS_READER_CONFIG ReaderConfig; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + UsbInterface = WdfUsbTargetDeviceGetInterface(BusObject->WdfUsbDevice, usbDeviceContext->WdfDataInterfaceIndex); + + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&SettingParams, AltSetting == 0 ? 0 : usbDeviceContext->UsbDataInterfaceSetting); + + Status = WdfUsbInterfaceSelectSetting(UsbInterface, NULL, &SettingParams); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + ConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(UsbInterface); + + if (((AltSetting == ALT_DATA_SETTING_0) && (ConfiguredPipes != ALT_DATA_SETTING_0_PIPES)) || + ((AltSetting == ALT_DATA_SETTING_1) && (ConfiguredPipes != ALT_DATA_SETTING_1_PIPES))) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + if (AltSetting == ALT_DATA_SETTING_1) + { + for (index = 0; index < ConfiguredPipes; index++) + { + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + UsbInterface, + index, // PipeIndex, + &pipeInfo); + + if (WdfUsbPipeTypeBulk == pipeInfo.PipeType) + { + + if (WdfUsbTargetPipeIsInEndpoint(pipe)) + { + usbDeviceContext->BulkInputPipeConfigured = TRUE; + usbDeviceContext->BulkInputPipe = pipe; + usbDeviceContext->BulkInputPipeMaxPacket = pipeInfo.MaximumPacketSize; + } + else + { + usbDeviceContext->BulkOutputPipeConfigured = TRUE; + usbDeviceContext->BulkOutputPipe = pipe; + usbDeviceContext->BulkOutputPipeMaxPacket = pipeInfo.MaximumPacketSize; + } + } + else + { + + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + } + + if (!(usbDeviceContext->BulkInputPipeConfigured && usbDeviceContext->BulkOutputPipeConfigured)) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + // + // configure the continous reader on the bulk pipe now, since this can only be done once on a given pipe + // unless it is unselected + // + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&ReaderConfig, BulkInReadComplete, BusObject, BusObject->MaxBulkInTransfer); + + if (BusObject->UsbCapDeviceInfo.DeviceInfoHeader.DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM) + { + ReaderConfig.NumPendingReads = PENDING_BULK_IN_READS_FOR_UDE_MBIM; + } + else + { + ReaderConfig.NumPendingReads = PENDING_BULK_IN_READS; + } + ReaderConfig.HeaderLength = BusObject->BulkInHeaderSize; + ReaderConfig.EvtUsbTargetPipeReadersFailed = BulkInReadError; + + Status = WdfUsbTargetPipeConfigContinuousReader(usbDeviceContext->BulkInputPipe, &ReaderConfig); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + // + // call this now that the pipe is configured + // + PreAllocateWriteRequests(BusObject->WdfUsbDevice); + } + else + { + // + // selecting the setting causes the frame work to delete the pipe + // + WDFREQUEST WriteRequest = NULL; + + usbDeviceContext->BulkInputPipeConfigured = FALSE; + usbDeviceContext->BulkInputPipe = NULL; + + usbDeviceContext->BulkOutputPipeConfigured = FALSE; + usbDeviceContext->BulkOutputPipe = NULL; + + WdfSpinLockAcquire(usbDeviceContext->WriteCollectionLock); + + WriteRequest = (WDFREQUEST)WdfCollectionGetLastItem(usbDeviceContext->WriteRequestCollection); + + // + // delete the write request because they are associated with a pipe object + // + while (WriteRequest != NULL) + { + WdfCollectionRemove(usbDeviceContext->WriteRequestCollection, WriteRequest); + + WdfObjectDelete(WriteRequest); + WriteRequest = (WDFREQUEST)WdfCollectionGetLastItem(usbDeviceContext->WriteRequestCollection); + } + + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + } + +Cleanup: + + if (!NT_SUCCESS(Status)) + { + // + // failed to configure the pipes, set back to alt setting 0 + // + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&SettingParams, 0); + + TempStatus = WdfUsbInterfaceSelectSetting(UsbInterface, NULL, &SettingParams); + + usbDeviceContext->BulkInputPipeConfigured = FALSE; + usbDeviceContext->BulkInputPipe = NULL; + + usbDeviceContext->BulkOutputPipeConfigured = FALSE; + usbDeviceContext->BulkOutputPipe = NULL; + } + + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return Status; +} + +NTSTATUS +MbbUsbDeviceStartDataPipes(__in PUSB_DEVICE_CONTEXT usbDeviceContext) +{ + NTSTATUS Status; + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + if (!(usbDeviceContext->BulkInputPipeConfigured && usbDeviceContext->BulkOutputPipeConfigured)) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + Status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkInputPipe)); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + usbDeviceContext->BulkInputPipeStarted = TRUE; + + Status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe)); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + usbDeviceContext->BulkOutputPipeStarted = TRUE; + +Cleanup: + + if (!NT_SUCCESS(Status)) + { + // + // failed to configure the pipes, set back to alt setting 0 + // + if (usbDeviceContext->BulkInputPipeStarted) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkInputPipe), WdfIoTargetCancelSentIo); + } + + if (usbDeviceContext->BulkOutputPipeStarted) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), WdfIoTargetCancelSentIo); + } + + usbDeviceContext->BulkInputPipeStarted = FALSE; + usbDeviceContext->BulkOutputPipeStarted = FALSE; + } + + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return Status; +} + +NTSTATUS +MbbBusStartDataPipes(__in MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + return MbbUsbDeviceStartDataPipes(GetUsbDeviceContext(BusObject->WdfUsbDevice)); +} + +VOID MbbUsbDeviceStopDataPipes(__in PUSB_DEVICE_CONTEXT usbDeviceContext) +{ + WDFUSBINTERFACE UsbInterface = NULL; + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + if (usbDeviceContext->BulkInputPipeConfigured) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkInputPipe), WdfIoTargetCancelSentIo); + } + if (usbDeviceContext->BulkOutputPipeConfigured) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), WdfIoTargetCancelSentIo); + } + + usbDeviceContext->BulkInputPipeStarted = FALSE; + + usbDeviceContext->BulkOutputPipeStarted = FALSE; + + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return; +} + +VOID MbbBusStopDataPipes(__in MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + WdfWorkItemFlush(usbDeviceContext->BulkPipeResetWorkitem); + + MbbUsbDeviceStopDataPipes(GetUsbDeviceContext(BusObject->WdfUsbDevice)); +} + +NTSTATUS +MbbUsbDeviceResetBulkPipe(__in PUSB_DEVICE_CONTEXT usbDeviceContext, __in BOOLEAN Out) + +{ + WDFUSBPIPE Pipe = NULL; + WDF_REQUEST_SEND_OPTIONS SendOptions; + NTSTATUS StatusToReturn = STATUS_SUCCESS; + NTSTATUS Status; + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + if (Out ? usbDeviceContext->BulkOutputPipeConfigured : usbDeviceContext->BulkInputPipeConfigured) + { + + Pipe = Out ? usbDeviceContext->BulkOutputPipe : usbDeviceContext->BulkInputPipe; + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + Status = WdfUsbTargetPipeAbortSynchronously(Pipe, NULL, &SendOptions); + + if (!NT_SUCCESS(Status)) + { + if (StatusToReturn == STATUS_SUCCESS) + { + StatusToReturn = Status; + } + } + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + Status = WdfUsbTargetPipeResetSynchronously(Pipe, NULL, &SendOptions); + + if (!NT_SUCCESS(Status)) + { + if (StatusToReturn == STATUS_SUCCESS) + { + StatusToReturn = Status; + } + } + } + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return StatusToReturn; +} + +NTSTATUS +MbbBusResetBulkPipe(__in MBB_BUS_HANDLE BusHandle, __in BOOLEAN Out) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + return MbbUsbDeviceResetBulkPipe(GetUsbDeviceContext(BusObject->WdfUsbDevice), Out); +} + +EVT_WDF_REQUEST_COMPLETION_ROUTINE WriteCompletionRoutine; + +void WriteCompletionRoutine(__in WDFREQUEST Request, __in WDFIOTARGET Target, __in PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, __in WDFCONTEXT Context) +/*++ + +Routine Description + + Request - Handle to the WDFREQUEST which was used to send data to the USB target. + Target - Handle to the Iotarget to which teh Request was sent. COnceptually this + is the BULK USB __out pipe(on of Data or beacon) + CompletionParams - In case of USB this contains the USB status and amount of bytes transferred + + + Context - This is the COntext we set in WdfRequestSend + + +Arguments: + + + +Return Value: + + + +--*/ + +{ + PUSB_WRITE_REQ_CONTEXT WriteContext; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(Target); + WriteContext = (PUSB_WRITE_REQ_CONTEXT)Context; + + Status = CompletionParams->IoStatus.Status; + + // + // For usb devices, we should look at the Usb.Completion param. + // + + if (WriteContext->Callback != NULL) + { + (*WriteContext->Callback)(WriteContext->BusObject->ProtocolHandle, WriteContext->RequestHandle, Status, WriteContext->Mdl); + } + + if (WriteContext->LookasideBuffer != NULL) + { + + WdfObjectDelete(WriteContext->LookasideBuffer); + } + + if (WriteContext->UrbMemory != NULL) + { + WdfObjectDelete(WriteContext->UrbMemory); + } + + FreeWriteRequest(WriteContext->BusObject->WdfUsbDevice, Request); +} + +NTSTATUS +MbbBusWriteData(__in MBB_BUS_HANDLE BusHandle, __in MBB_REQUEST_HANDLE RequestHandle, __in PMDL Mdl, __in MBB_BUS_SEND_DATA_COMPLETION_CALLBACK Callback) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + PMDL TempMdl = NULL; + ULONGLONG TotalTransferLength = 0; + NTSTATUS Status; + WDFMEMORY urbMemory = NULL; + WDF_OBJECT_ATTRIBUTES objectAttribs; + PURB urbBuffer = NULL; + WDF_REQUEST_SEND_OPTIONS SendOptions; + WDFREQUEST WriteRequest = NULL; + USBD_PIPE_HANDLE usbdPipeHandle = NULL; + PUSB_WRITE_REQ_CONTEXT writeContext = NULL; + BOOLEAN SentToDevice = FALSE; + WDFMEMORY BufferMemoryObject = NULL; + WDFREQUEST WriteRequestZLP = NULL; + PUSB_WRITE_REQ_CONTEXT writeContextZLP = NULL; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + if (!ExAcquireRundownProtection(&usbDeviceContext->BulkPipeResetRundown)) + { + return STATUS_NDIS_ADAPTER_NOT_READY; + } + + // + // make sure the length is not too big + // + TempMdl = Mdl; + + while (TempMdl != NULL) + { + TotalTransferLength += MmGetMdlByteCount(TempMdl); + + TempMdl = TempMdl->Next; + } + + if (TotalTransferLength > BusObject->NtbParam.dwNtbOutMaxSize) + { + // + // too big + // + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + if ((TotalTransferLength < BusObject->NtbParam.dwNtbOutMaxSize) && (TotalTransferLength % usbDeviceContext->BulkOutputPipeMaxPacket == 0)) + { + // + // The transfer length is less than the max out transfer size, and transfer length is a multiple of MaxPacket size. + // Need to send a ZLP to the device stack to terminated the transfer. + + Status = GetWriteRequests(BusObject->WdfUsbDevice, &WriteRequestZLP); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContextZLP = GetWriteRequestContext(WriteRequestZLP); + + writeContextZLP->BusObject = BusObject; + writeContextZLP->Callback = NULL; + } + + Status = GetWriteRequests(BusObject->WdfUsbDevice, &WriteRequest); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext = GetWriteRequestContext(WriteRequest); + + if (usbDeviceContext->LookasideList == NULL) + { + + // + // allocate the URB, request is the parent + // + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); + objectAttribs.ParentObject = WriteRequest; + + Status = WdfUsbTargetDeviceCreateUrb(BusObject->WdfUsbDevice, &objectAttribs, &urbMemory, &urbBuffer); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + // + // get the USBD pipe handle, to build the URB + // + usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(usbDeviceContext->BulkOutputPipe); + + // + // NOTE : call UsbBuildInterruptOrBulkTransferRequest otherwise + // WdfUsbTargetPipeFormatRequestForUrb will assert + // with *** Assertion failed: Urb->UrbHeader.Length >= sizeof(_URB_HEADER) + // + UsbBuildInterruptOrBulkTransferRequest( + urbBuffer, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + usbdPipeHandle, + NULL, + Mdl, + (ULONG)TotalTransferLength, + USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK, + NULL); + + // + // By calling WdfUsbTargetPipeFormatRequestForUrb the frameworks allocate a lot of resources + // like the underlying IRP for the request and hence it is better to do it at initilization + // to prevent an avoidable failure later. + // + Status = WdfUsbTargetPipeFormatRequestForUrb(usbDeviceContext->BulkOutputPipe, WriteRequest, urbMemory, NULL); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext->UrbMemory = urbMemory; + writeContext->Urb = (PURB)urbBuffer; + } + else + { + // + // usb stack does not support chained mdl's, double buffer the transfer + // + PUCHAR DestBuffer = NULL; + PUCHAR SourceAddress = NULL; + size_t BufferSize = 0; + ULONG SourceLength = 0; + WDFMEMORY_OFFSET MemoryOffset; + + Status = WdfMemoryCreateFromLookaside(usbDeviceContext->LookasideList, &BufferMemoryObject); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + DestBuffer = (PUCHAR)WdfMemoryGetBuffer(BufferMemoryObject, &BufferSize); + + TempMdl = Mdl; + TotalTransferLength = 0; + while (TempMdl != NULL) + { + SourceLength = MmGetMdlByteCount(TempMdl); + + SourceAddress = (PUCHAR)MmGetSystemAddressForMdlSafe(TempMdl, NormalPagePriority | MdlMappingNoExecute); + + if (SourceAddress == NULL) + { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + goto Cleanup; + } + + RtlCopyMemory(DestBuffer, SourceAddress, SourceLength); + + DestBuffer += SourceLength; + + TotalTransferLength += SourceLength; + + ASSERT(TotalTransferLength <= BufferSize); + + TempMdl = TempMdl->Next; + } + + MemoryOffset.BufferOffset = 0; + MemoryOffset.BufferLength = (ULONG)TotalTransferLength; + + Status = WdfUsbTargetPipeFormatRequestForWrite(usbDeviceContext->BulkOutputPipe, WriteRequest, BufferMemoryObject, &MemoryOffset); + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext->LookasideBuffer = BufferMemoryObject; + BufferMemoryObject = NULL; + } + + // + // set REQUEST_CONTEXT parameters. + // + + writeContext->Mdl = Mdl; + writeContext->BusObject = BusObject; + writeContext->Callback = Callback; + writeContext->RequestHandle = RequestHandle; + + WdfRequestSetCompletionRoutine(WriteRequest, WriteCompletionRoutine, writeContext); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + SentToDevice = WdfRequestSend(WriteRequest, WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), &SendOptions); + + Status = STATUS_PENDING; + + if (!SentToDevice) + { + Status = WdfRequestGetStatus(WriteRequest); + } + else + { + WriteRequest = NULL; + } + + if (NT_SUCCESS(Status)) + { + + // + // actual data write worked, see if we need to send the zlp + // + + if (WriteRequestZLP != NULL) + { + + NTSTATUS ZlpStatus; + + Status = WdfUsbTargetPipeFormatRequestForWrite(usbDeviceContext->BulkOutputPipe, WriteRequestZLP, NULL, NULL); + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + WdfRequestSetCompletionRoutine(WriteRequestZLP, WriteCompletionRoutine, writeContextZLP); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + SentToDevice = WdfRequestSend(WriteRequestZLP, WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), &SendOptions); + + ZlpStatus = STATUS_PENDING; + + if (!SentToDevice) + { + + ZlpStatus = WdfRequestGetStatus(WriteRequestZLP); + } + else + { + WriteRequestZLP = NULL; + } + } + } + +Cleanup: + + ExReleaseRundownProtection(&usbDeviceContext->BulkPipeResetRundown); + + if (WriteRequest != NULL) + { + if (NULL != writeContext) + { + if (NULL != writeContext->LookasideBuffer) + { + WdfObjectDelete(writeContext->LookasideBuffer); + } + if (NULL != writeContext->UrbMemory) + { + WdfObjectDelete(writeContext->UrbMemory); + } + } + + FreeWriteRequest(BusObject->WdfUsbDevice, WriteRequest); + WriteRequest = NULL; + } + + if (WriteRequestZLP != NULL) + { + FreeWriteRequest(BusObject->WdfUsbDevice, WriteRequestZLP); + WriteRequestZLP = NULL; + } + + return Status; +} + +VOID BulkInReadComplete(__in WDFUSBPIPE Pipe, __in WDFMEMORY Memory, __in size_t NumBytesTransferred, __in WDFCONTEXT Context) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)Context; + PUCHAR Buffer = NULL; + PMDL Mdl = NULL; + PUCHAR DataBuffer = NULL; + + if (NumBytesTransferred > 0) + { + // + // actaully got some data + // + Buffer = (PUCHAR)WdfMemoryGetBuffer(Memory, NULL); + + // + // the header at the front is where we will put the MDL + // + Mdl = (PMDL)Buffer; + + // + // the actual payload starts after the header/mdl + // + DataBuffer = Buffer + BusObject->BulkInHeaderSize; + + ASSERT(((ULONG_PTR)DataBuffer & 0x7) == 0); + + // + // bytes transfered does not include the header + // + MmInitializeMdl(Mdl, DataBuffer, NumBytesTransferred); + + MmBuildMdlForNonPagedPool(Mdl); + + ASSERT(BusObject->BulkInHeaderSize >= MmSizeOfMdl(Mdl, NumBytesTransferred)); + + WdfObjectReference(Memory); + + (*BusObject->ReceiveDataCallback)(BusObject->ProtocolHandle, Memory, Mdl); + } + + return; +} + +BOOLEAN +BulkInReadError(__in WDFUSBPIPE Pipe, __in NTSTATUS Status, __in USBD_STATUS UsbdStatus) + +{ + return TRUE; +} + +VOID MbbBusReturnReceiveBuffer(__in MBB_BUS_HANDLE BusHandle, __in MBB_RECEIVE_CONTEXT ReceiveContext, __in PMDL Mdl) + +{ + WDFMEMORY Memory = (WDFMEMORY)ReceiveContext; + + WdfObjectDereference(Memory); + + return; +} + +NTSTATUS +CreateWriteRequest(WDFUSBDEVICE UsbDevice, WDFREQUEST* ReturnedWriteRequest) + +{ + + WDFREQUEST WriteRequest = NULL; + PUSB_WRITE_REQ_CONTEXT writeContext = NULL; + WDF_OBJECT_ATTRIBUTES objectAttribs; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + NTSTATUS Status = STATUS_INVALID_PARAMETER; + + *ReturnedWriteRequest = NULL; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + if (usbDeviceContext->BulkOutputPipe == NULL) + { + goto Cleanup; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttribs, USB_WRITE_REQ_CONTEXT); + objectAttribs.ParentObject = UsbDevice; + + // + // create the request + // + Status = WdfRequestCreate(&objectAttribs, WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), &WriteRequest); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext = GetWriteRequestContext(WriteRequest); + RtlZeroMemory(writeContext, sizeof(*writeContext)); + + // + // Preallocate the request timer to prevent the request from failing while trying to send it. + // + Status = WdfRequestAllocateTimer(WriteRequest); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + Status = WdfUsbTargetPipeFormatRequestForWrite(usbDeviceContext->BulkOutputPipe, WriteRequest, NULL, NULL); + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + *ReturnedWriteRequest = WriteRequest; + WriteRequest = NULL; + +Cleanup: + + if (WriteRequest != NULL) + { + WdfObjectDelete(WriteRequest); + WriteRequest = NULL; + } + + return Status; +} + +NTSTATUS +PreAllocateWriteRequests(WDFUSBDEVICE UsbDevice) + +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + WDFREQUEST WriteRequest = NULL; + NTSTATUS Status; + ULONG i = 0; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + for (i = 0; i < MAX_PREALLOCATED_WRITE_REQUESTS; i++) + { + Status = CreateWriteRequest(UsbDevice, &WriteRequest); + + if (!NT_SUCCESS(Status)) + { + break; + } + + Status = WdfCollectionAdd(usbDeviceContext->WriteRequestCollection, WriteRequest); + + if (!NT_SUCCESS(Status)) + { + WdfObjectDelete(WriteRequest); + WriteRequest = NULL; + break; + } + } + + return Status; +} + +NTSTATUS +GetWriteRequests(WDFUSBDEVICE UsbDevice, WDFREQUEST* ReturnedWriteRequest) +{ + + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + NTSTATUS Status = STATUS_SUCCESS; + WDF_REQUEST_REUSE_PARAMS ReuseParams; + PUSB_WRITE_REQ_CONTEXT writeContext = NULL; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + *ReturnedWriteRequest = NULL; + + if (usbDeviceContext->BulkOutputPipe == NULL) + { + return STATUS_UNSUCCESSFUL; + } + + WdfSpinLockAcquire(usbDeviceContext->WriteCollectionLock); + + *ReturnedWriteRequest = (WDFREQUEST)WdfCollectionGetLastItem(usbDeviceContext->WriteRequestCollection); + + if (*ReturnedWriteRequest == NULL) + { + // + // the collection is empty, try creating a new one + // + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + + Status = CreateWriteRequest(UsbDevice, ReturnedWriteRequest); + } + else + { + + WdfCollectionRemove(usbDeviceContext->WriteRequestCollection, *ReturnedWriteRequest); + + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, 0, STATUS_SUCCESS); + + WdfRequestReuse(*ReturnedWriteRequest, &ReuseParams); + } + + if (NT_SUCCESS(Status)) + { + writeContext = GetWriteRequestContext(*ReturnedWriteRequest); + RtlZeroMemory(writeContext, sizeof(*writeContext)); + } + + return Status; +} + +VOID FreeWriteRequest(WDFUSBDEVICE UsbDevice, WDFREQUEST WriteRequest) + +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + NTSTATUS Status = STATUS_SUCCESS; + ULONG RequestCount = 0; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + WdfSpinLockAcquire(usbDeviceContext->WriteCollectionLock); + + RequestCount = WdfCollectionGetCount(usbDeviceContext->WriteRequestCollection); + + if (RequestCount < MAX_PREALLOCATED_WRITE_REQUESTS * 2) + { + // + // put it back in the collection + // + Status = WdfCollectionAdd(usbDeviceContext->WriteRequestCollection, WriteRequest); + + if (NT_SUCCESS(Status)) + { + WriteRequest = NULL; + } + } + + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + + if (WriteRequest != NULL) + { + WdfObjectDelete(WriteRequest); + WriteRequest = NULL; + } + + return; +} + +VOID MbbBusResetDataPipes(_In_ MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + if (!InterlockedCompareExchange(&usbDeviceContext->BulkPipeResetFlag, TRUE, FALSE)) + { + WdfWorkItemEnqueue(usbDeviceContext->BulkPipeResetWorkitem); + } + else + { + } +} + +VOID MbbUsbDeviceCyclePort(_In_ PUSB_DEVICE_CONTEXT usbDeviceContext) +{ + NTSTATUS Status = WdfUsbTargetDeviceCyclePortSynchronously(usbDeviceContext->BusObject->WdfUsbDevice); + if (!NT_SUCCESS(Status)) + { + } +} + +void ResetDataPipeWorkItem(_In_ WDFWORKITEM WorkItem) +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = GetUsbDeviceContext(WdfWorkItemGetParentObject(WorkItem)); + + ExWaitForRundownProtectionRelease(&usbDeviceContext->BulkPipeResetRundown); + ExRundownCompleted(&usbDeviceContext->BulkPipeResetRundown); + + MbbUsbDeviceStopDataPipes(usbDeviceContext); + + MbbUsbDeviceResetBulkPipe(usbDeviceContext, TRUE); + + MbbUsbDeviceCyclePort(usbDeviceContext); + + MbbUsbDeviceStartDataPipes(usbDeviceContext); + + ExReInitializeRundownProtection(&usbDeviceContext->BulkPipeResetRundown); + + InterlockedExchange(&usbDeviceContext->BulkPipeResetFlag, FALSE); +} diff --git a/network/wwan/cxwmbclass/device.cpp b/network/wwan/cxwmbclass/device.cpp new file mode 100644 index 000000000..0aadfc355 --- /dev/null +++ b/network/wwan/cxwmbclass/device.cpp @@ -0,0 +1,381 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +#include "device.h" +#include "rxqueue.h" + +const ULONG MBB_DEFAULT_IDLE_TIMEOUT_HINT_MS = 2u * 1000u; // 2 seconds + +_Use_decl_annotations_ VOID EvtMbbDeviceSendMbimFragment(WDFDEVICE Device, MBBREQUEST Fragment) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + + size_t bufferSize = 0; + PVOID buffer = MbbRequestGetBuffer(Fragment, &bufferSize); + + auto completionRoutine = [](MBB_PROTOCOL_HANDLE, MBB_REQUEST_HANDLE RequestHandle, NTSTATUS NtStatus) { + MbbRequestComplete((MBBREQUEST)RequestHandle, NtStatus); + }; + + NTSTATUS sendStatus = MbbBusSendMessageFragment( + deviceContext->BusHandle, Fragment, buffer, (ULONG)bufferSize, (LPGUID)MbbRequestGetCorrelationId(Fragment), completionRoutine); + + // Accoding to the documentation of MbbBusSendMessageFragment the completion routine + // will be called only when ntStatus is STATUS_PENDING, so we need to call it ourselves + // for the other cases + if (sendStatus != STATUS_PENDING) + { + completionRoutine(deviceContext, Fragment, sendStatus); + } +} + +VOID MbbNdisResponseFragmentAvailable(__in MBB_PROTOCOL_HANDLE ProtocolHandle) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = (PWMBCLASS_DEVICE_CONTEXT)ProtocolHandle; + MbbDeviceResponseAvailable(deviceContext->WdfDevice); +} + +_Use_decl_annotations_ VOID EvtMbbDeviceReceiveMbimFragment(WDFDEVICE Device, MBBREQUEST Fragment) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + + size_t bufferSize = 0; + PVOID buffer = MbbRequestGetBuffer(Fragment, &bufferSize); + + auto completionRoutine = [](MBB_PROTOCOL_HANDLE, MBB_REQUEST_HANDLE RequestHandle, NTSTATUS Status, ULONG_PTR ReceivedLength) { + MbbRequestCompleteWithInformation((MBBREQUEST)RequestHandle, Status, ReceivedLength); + }; + + // Accoding to the documentation of MbbBusReceiveMessageFragment the completion routine + // will be called only when ntStatus is STATUS_PENDING, so we need to call it ourselves + // for the other cases + NTSTATUS receiveStatus = MbbBusReceiveMessageFragment( + deviceContext->BusHandle, Fragment, buffer, (ULONG)bufferSize, (LPGUID)MbbRequestGetCorrelationId(Fragment), completionRoutine); + + if (receiveStatus != STATUS_PENDING) + { + completionRoutine(deviceContext, Fragment, receiveStatus, 0); + } +} + +static NTSTATUS SetupAdapterSpecificPowerSettings(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext) +{ + NTSTATUS status = STATUS_SUCCESS; + + if (DeviceContext->BusParams.RemoteWakeCapable) + { + // + // Configure USB selective suspend with default timeout + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); + + idleSettings.IdleTimeout = MBB_DEFAULT_IDLE_TIMEOUT_HINT_MS; + idleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; + + status = WdfDeviceAssignS0IdleSettings(DeviceContext->WdfDevice, &idleSettings); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + } +Exit: + return status; +} + +NTSTATUS +MbbInitializeHardware(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + UNICODE_STRING manufacturer; + UNICODE_STRING model; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceContext->WdfDevice; + status = WdfLookasideListCreate( + &attributes, + sizeof(MBB_NDIS_RECEIVE_CONTEXT), + NonPagedPoolNx, + WDF_NO_OBJECT_ATTRIBUTES, + MbbPoolTagMdlReceive, + &DeviceContext->ReceiveLookasideList); + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + for (int i = 0; i < MBB_MAX_NUMBER_OF_SESSIONS; i++) + { + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = DeviceContext->WdfDevice; + + status = WdfSpinLockCreate(&attributes, &DeviceContext->Sessions[i].WdfRecvSpinLock); + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + } + + status = MbbBusInitializeByWdf( + DeviceContext->WdfDevice, + MbbNdisResponseFragmentAvailable, + MbbNdisReceiveCallback, + nullptr, + nullptr, + DeviceContext, + &DeviceContext->BusHandle, + nullptr); + + if (status != STATUS_SUCCESS) + { + goto Cleanup; + } + + // + // Initialize the OID/CID handlers before the device is OPENED. + // Once the device is opened and the interrupt pipe is connected. + // This driver will start receiving unsolicited interrupt message + // from the device. + // + status = MbbBusQueryBusParameters(DeviceContext->BusHandle, &DeviceContext->BusParams); + + if (status != STATUS_SUCCESS) + { + goto Cleanup; + } + + WDFMEMORY sharedPaddingMemory; + ULONG sharedPaddingLength = max(DeviceContext->BusParams.NdpOutAlignment, DeviceContext->BusParams.NdpOutDivisor); + status = CreateNonPagedWdfMemory( + sharedPaddingLength, &sharedPaddingMemory, (PVOID*)&DeviceContext->sharedPaddingBuffer, DeviceContext->WdfDevice, MbbPoolTagNtbSend); + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + RtlInitUnicodeString(&manufacturer, DeviceContext->BusParams.Manufacturer); + RtlInitUnicodeString(&model, DeviceContext->BusParams.Model); + MBB_DEVICE_MBIM_PARAMETERS mbimParams; + + // 2.0 by default + MBB_MBIM_EXTENDED_VERSION mbimExVer = MbbMbimExtendedVersion2Dot0; + switch(DeviceContext->BusParams.MbimExtendedVersion) + { + case 0x0100: + mbimExVer = MbbMbimExtendedVersion1Dot0; + break; + case 0x0200: + mbimExVer = MbbMbimExtendedVersion2Dot0; + break; + case 0x0300: + mbimExVer = MbbMbimExtendedVersion3Dot0; + break; + case 0x0400: + mbimExVer = MbbMbimExtendedVersion4Dot0; + break; + default: + status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + MBB_DEVICE_MBIM_PARAMETERS_INIT( + &mbimParams, + DeviceContext->BusParams.IsErrataDevice ? MbbMbimVersion1Dot0Errata : MbbMbimVersion1Dot0, + DeviceContext->BusParams.FragmentSize, + mbimExVer); + + MbbDeviceSetMbimParameters(DeviceContext->WdfDevice, &mbimParams); + + MBB_DEVICE_WAKE_CAPABILITIES mbbWakeCapabilities; + MBB_DEVICE_WAKE_CAPABILITIES_INIT(&mbbWakeCapabilities); + + mbbWakeCapabilities.PacketState = TRUE; + mbbWakeCapabilities.RegisterState = TRUE; + mbbWakeCapabilities.SmsReceive = TRUE; + mbbWakeCapabilities.UiccChange = TRUE; + mbbWakeCapabilities.UssdReceive = TRUE; + + MbbDeviceSetWakeCapabilities(DeviceContext->WdfDevice, &mbbWakeCapabilities); + + status = SetupAdapterSpecificPowerSettings(DeviceContext); + if (NT_ERROR(status)) + { + goto Cleanup; + } + +Cleanup: + + if (status != STATUS_SUCCESS) + { + if (DeviceContext != NULL) + { + if (DeviceContext->BusHandle != NULL) + { + MbbBusStop(DeviceContext->BusHandle); + MbbBusCleanup(DeviceContext->BusHandle); + DeviceContext->BusHandle = NULL; + } + } + + } + + return status; +} + +void MbbReleaseHardware(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext) +{ + + if (DeviceContext->BusHandle != NULL) + { + MbbBusCleanup(DeviceContext->BusHandle); + DeviceContext->BusHandle = NULL; + } + + return; +} + +NTSTATUS +EvtDevicePrepareHardware(_In_ WDFDEVICE device, _In_ WDFCMRESLIST resourcesRaw, _In_ WDFCMRESLIST resourcesTranslated) +{ + UNREFERENCED_PARAMETER(resourcesRaw); + UNREFERENCED_PARAMETER(resourcesTranslated); + + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(device); + + NTSTATUS status = MbbInitializeHardware(deviceContext); + + return status; +} + +NTSTATUS +EvtDeviceReleaseHardware(_In_ WDFDEVICE device, _In_ WDFCMRESLIST resourcesTranslated) +{ + UNREFERENCED_PARAMETER(resourcesTranslated); + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(device); + + MbbReleaseHardware(deviceContext); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ void EvtDeviceSurpriseRemoval(WDFDEVICE device) +{ + UNREFERENCED_PARAMETER(device); +} + +NTSTATUS MbbInitAdapterContext(_In_ WDFDEVICE Device, _In_ NETADAPTER NetAdapter) +{ + WDF_OBJECT_ATTRIBUTES adapterAttributes; + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = WmbClassGetNetAdapterContext(NetAdapter); + + ULONG ntbSize; + ntbSize = FIELD_OFFSET(MBB_NTB_BUILD_CONTEXT, NdpDatagramEntries); + ntbSize += (deviceContext->BusParams.MaxOutDatagrams * sizeof(MBB_NDP_HEADER_ENTRY)); + + WDF_OBJECT_ATTRIBUTES_INIT(&adapterAttributes); + adapterAttributes.ParentObject = NetAdapter; + + NTSTATUS ntStatus = WdfLookasideListCreate( + &adapterAttributes, ntbSize, NonPagedPoolNx, WDF_NO_OBJECT_ATTRIBUTES, MbbPoolTagNtbSend, &netAdapterContext->NtbLookasideList); + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&adapterAttributes); + adapterAttributes.ParentObject = NetAdapter; + ntStatus = WdfLookasideListCreate( + &adapterAttributes, + sizeof(MBB_RECEIVE_NDP_CONTEXT), + NonPagedPoolNx, + WDF_NO_OBJECT_ATTRIBUTES, + MbbPoolTagMdlReceive, + &netAdapterContext->ReceiveNdpLookasideList); + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + netAdapterContext->SessionId = MbbAdapterGetSessionId(NetAdapter); + WdfSpinLockAcquire(deviceContext->Sessions[netAdapterContext->SessionId].WdfRecvSpinLock); + deviceContext->Sessions[netAdapterContext->SessionId].NetAdapterContext = netAdapterContext; + // Allow to receive data from this point since connection may happen before RxQueueCreate, if it happens, we allow to cache the recieved NDP + netAdapterContext->AllowRxTraffic = TRUE; + InitializeListHead(&netAdapterContext->ReceiveNdpList); + netAdapterContext->WmbDeviceContext = deviceContext; + netAdapterContext->NetAdapter = NetAdapter; + WdfSpinLockRelease(deviceContext->Sessions[netAdapterContext->SessionId].WdfRecvSpinLock); + return ntStatus; +} + +_Use_decl_annotations_ NTSTATUS EvtMbbDeviceCreateAdapter(WDFDEVICE Device, NETADAPTER_INIT* AdapterInit) +{ + + NET_ADAPTER_DATAPATH_CALLBACKS datapathCallbacks; + NET_ADAPTER_DATAPATH_CALLBACKS_INIT(&datapathCallbacks, EvtAdapterCreateTxQueue, EvtAdapterCreateRxQueue); + + NetAdapterInitSetDatapathCallbacks(AdapterInit, &datapathCallbacks); + + WDF_OBJECT_ATTRIBUTES adapterAttributes; + WDF_OBJECT_ATTRIBUTES_INIT(&adapterAttributes); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&adapterAttributes, WMBCLASS_NETADAPTER_CONTEXT); + adapterAttributes.EvtCleanupCallback = EvtAdapterCleanup; + + NETADAPTER netAdapter; + NTSTATUS ntStatus = NetAdapterCreate(AdapterInit, &adapterAttributes, &netAdapter); + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + ntStatus = MbbAdapterInitialize(netAdapter); + + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + ntStatus = MbbInitAdapterContext(Device, netAdapter); + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + ntStatus = WmbClassAdapterStart(netAdapter); + + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + return ntStatus; +} + +_Use_decl_annotations_ VOID EvtAdapterCleanup(_In_ WDFOBJECT NetAdapter) +{ + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = WmbClassGetNetAdapterContext(NetAdapter); + PWMBCLASS_DEVICE_CONTEXT deviceContext = netAdapterContext->WmbDeviceContext; + if (deviceContext == NULL || deviceContext->Sessions[netAdapterContext->SessionId].NetAdapterContext == NULL) + { + return; + } + + // Cancel these Ndps which are cached before RxQueueCreate but not cleaned in case RxQueueCreate failed. + // NetAdapter should be destoryed immediately if RxQueueCreate failed, or these cached Ndps will stay in memory until release device or delete additional PDP + MbbRecvCancelNdps(deviceContext, netAdapterContext->SessionId); + + WdfSpinLockAcquire(deviceContext->Sessions[netAdapterContext->SessionId].WdfRecvSpinLock); + deviceContext->Sessions[netAdapterContext->SessionId].NetAdapterContext = NULL; + WdfSpinLockRelease(deviceContext->Sessions[netAdapterContext->SessionId].WdfRecvSpinLock); + +} + +_Use_decl_annotations_ VOID EvtMbbDeviceReset(WDFDEVICE WdfDevice) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(WdfDevice); + MbbBusResetDataPipes(deviceContext->BusHandle); +} diff --git a/network/wwan/cxwmbclass/driver.cpp b/network/wwan/cxwmbclass/driver.cpp new file mode 100644 index 000000000..e1c8bc69e --- /dev/null +++ b/network/wwan/cxwmbclass/driver.cpp @@ -0,0 +1,120 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +#include "device.h" +#include "power.h" + +MINIPORT_DRIVER_CONTEXT GlobalControl = {0}; + +EXTERN_C __declspec(code_seg("INIT")) DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD EvtDriverUnload; +EVT_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + +#define MBB_DRIVER_DEFAULT_POOL_TAG 'DBMW' + +__declspec(code_seg("INIT")) NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT driverObject, _In_ PUNICODE_STRING registryPath) +{ + NTSTATUS status = STATUS_SUCCESS; + + WDF_DRIVER_CONFIG driverConfig; + WDF_DRIVER_CONFIG_INIT(&driverConfig, EvtDriverDeviceAdd); + driverConfig.DriverPoolTag = MBB_DRIVER_DEFAULT_POOL_TAG; + + driverConfig.EvtDriverUnload = EvtDriverUnload; + + WDFDRIVER driver; + status = WdfDriverCreate(driverObject, registryPath, WDF_NO_OBJECT_ATTRIBUTES, &driverConfig, &driver); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + return status; +} + +NTSTATUS +EvtDriverDeviceAdd(_In_ WDFDRIVER driver, _Inout_ PWDFDEVICE_INIT deviceInit) +{ + UNREFERENCED_PARAMETER((driver)); + + NTSTATUS status = STATUS_SUCCESS; + + status = NetDeviceInitConfig(deviceInit); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = MbbDeviceInitConfig(deviceInit); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // Register with the NetAdapter framework that we want to do the Device Reset + //NET_DEVICE_RESET_CONFIG resetConfig; + //NET_DEVICE_RESET_CONFIG_INIT(&resetConfig, EvtMbbDeviceReset); + //NetDeviceInitSetResetConfig(deviceInit, &resetConfig); + + NET_DEVICE_POWER_POLICY_EVENT_CALLBACKS netPowerPolicyCallbacks; + NET_DEVICE_POWER_POLICY_EVENT_CALLBACKS_INIT(&netPowerPolicyCallbacks); + netPowerPolicyCallbacks.EvtDevicePreviewBitmapPattern = EvtDevicePreviewBitmapPattern; + + NetDeviceInitSetPowerPolicyEventCallbacks(deviceInit, &netPowerPolicyCallbacks); + + WDF_OBJECT_ATTRIBUTES deviceAttributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, WMBCLASS_DEVICE_CONTEXT); + + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware; + pnpPowerCallbacks.EvtDeviceReleaseHardware = EvtDeviceReleaseHardware; + pnpPowerCallbacks.EvtDeviceSurpriseRemoval = EvtDeviceSurpriseRemoval; + pnpPowerCallbacks.EvtDeviceD0Entry = EvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = EvtDeviceD0Exit; + WdfDeviceInitSetPnpPowerEventCallbacks(deviceInit, &pnpPowerCallbacks); + + WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; + WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks); + powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = EvtDeviceArmWakeFromS0; + powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = EvtDeviceDisarmWakeFromS0; + WdfDeviceInitSetPowerPolicyEventCallbacks(deviceInit, &powerPolicyCallbacks); + + WDFDEVICE wdfDevice; + status = WdfDeviceCreate(&deviceInit, &deviceAttributes, &wdfDevice); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // Set the device to be not ejectable + WDF_DEVICE_PNP_CAPABILITIES pnpCapabilities; + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCapabilities); + pnpCapabilities.SurpriseRemovalOK = WdfTrue; + WdfDeviceSetPnpCapabilities(wdfDevice, &pnpCapabilities); + + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(wdfDevice); + deviceContext->WdfDevice = wdfDevice; + + MBB_DEVICE_CONFIG mbbDeviceConfig; + MBB_DEVICE_CONFIG_INIT( + &mbbDeviceConfig, EvtMbbDeviceSendMbimFragment, EvtMbbDeviceReceiveMbimFragment, EvtMbbDeviceSendDeviceServiceSessionData, EvtMbbDeviceCreateAdapter); + + status = MbbDeviceInitialize(wdfDevice, &mbbDeviceConfig); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + return status; +} + +VOID EvtDriverUnload(_In_ WDFDRIVER driver) +{ + UNREFERENCED_PARAMETER(driver); +} diff --git a/network/wwan/cxwmbclass/inc/BusInterface.h b/network/wwan/cxwmbclass/inc/BusInterface.h new file mode 100644 index 000000000..d72c663a3 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/BusInterface.h @@ -0,0 +1,573 @@ +/*************************************************************************** + +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + BusInterface.h + +Abstract: + + This module defines the interface between the upper NDIS layer and lower + bus layer of the MBB (Mobile BroadBand) Class driver. + +Environment: + + kernel mode only + +Notes: + + The upper ndis layer may only communicate with the lower bus layer through + these interfaces. + +Revision History: + + 2/7/2010 : created + +Authors: + + TriRoy + +****************************************************************************/ + +#ifndef _BusInterface_H_ +#define _BusInterface_H_ + +//////////////////////////////////////////////////////////////////////////////// +// +// INCLUDES +// +//////////////////////////////////////////////////////////////////////////////// +#if 0 +#include "MbbDebug.h" +#endif +//////////////////////////////////////////////////////////////////////////////// +// +// DEFINES +// +//////////////////////////////////////////////////////////////////////////////// + +#define MAX_PARAMETER_STRING (128) + +#define ALT_DATA_SETTING_0 (0) +#define ALT_DATA_SETTING_1 (1) + +#define MAX_PENDING_SENDS (3) + +//////////////////////////////////////////////////////////////////////////////// +// +// TYPEDEFS +// +//////////////////////////////////////////////////////////////////////////////// +typedef PVOID MBB_BUS_HANDLE; +typedef PVOID MBB_PROTOCOL_HANDLE; +typedef PVOID MBB_REQUEST_HANDLE; +typedef PVOID MBB_RECEIVE_CONTEXT; + +typedef struct _MBB_BUS_PARAMETERS +{ + ULONG FragmentSize; + + ULONG MaxSegmentSize; + + BOOLEAN ChainedMdlsSupported; + BOOLEAN Ntb32BitSupported; + BOOLEAN CurrentMode32Bit; + BOOLEAN SelectiveSuspendSupported; + + ULONG MaxOutNtb; + USHORT MaxOutDatagrams; + USHORT NdpOutDivisor; + USHORT NdpOutRemainder; + USHORT NdpOutAlignment; + + BYTE PowerFiltersSupported; + BYTE MaxPowerFilterSize; + + WCHAR Manufacturer[MAX_PARAMETER_STRING]; + WCHAR Model[MAX_PARAMETER_STRING]; + + BYTE MaxOutstandingCommandMessages; + USHORT MTU; + BOOLEAN IsErrataDevice; + USHORT MbimVersion; + BOOLEAN RemoteWakeCapable; + USHORT MbimExtendedVersion; + +} MBB_BUS_PARAMETERS, *PMBB_BUS_PARAMETERS; + +typedef struct _MBB_CONNECTION_STATE +{ + + BOOLEAN ConnectionUp; + ULONGLONG UpStreamBitRate; + ULONGLONG DownStreamBitRate; + +} MBB_CONNECTION_STATE, *PMBB_CONNECTION_STATE; + +typedef __callback VOID (*MBB_BUS_SEND_COMPLETION_CALLBACK)(__in MBB_PROTOCOL_HANDLE ProtocolHandle, __in MBB_REQUEST_HANDLE RequestHandle, __in NTSTATUS Status); + +typedef __callback VOID (*MBB_BUS_RECEIVE_COMPLETION_CALLBACK)( + __in MBB_PROTOCOL_HANDLE ProtocolHandle, __in MBB_REQUEST_HANDLE RequestHandle, __in NTSTATUS Status, __in ULONG_PTR ReceivedLength); + +typedef __callback VOID (*MBB_BUS_RESPONSE_AVAILABLE_CALLBACK)(__in MBB_PROTOCOL_HANDLE ProtocolHandle); + +typedef __callback VOID (*MBB_BUS_SEND_DATA_COMPLETION_CALLBACK)( + __in MBB_PROTOCOL_HANDLE ProtocolHandle, __in MBB_REQUEST_HANDLE RequestHandle, __in NTSTATUS Status, __in PMDL Mdl); + +typedef __callback VOID (*MBB_BUS_DATA_RECEIVE_CALLBACK)(__in MBB_PROTOCOL_HANDLE ProtocolHandle, __in MBB_RECEIVE_CONTEXT ReceiveContext, __in PMDL Mdl); + +typedef __callback VOID (*MBB_BUS_SS_IDLE_CONFIRM_CALLBACK)(__in MBB_PROTOCOL_HANDLE ProtocolHandle, __in DEVICE_POWER_STATE PowerState); + +typedef __callback VOID (*MBB_BUS_SS_IDLE_NOTIFICATION_COMPLETE_CALLBACK)(__in MBB_PROTOCOL_HANDLE ProtocolHandle, __in NTSTATUS Status); + +//////////////////////////////////////////////////////////////////////////////// +// +// INTERFACE +// +//////////////////////////////////////////////////////////////////////////////// +EXTERN_C +NTSTATUS +MbbBusInitialize( + _In_ PDEVICE_OBJECT Pdo, + _In_ PDEVICE_OBJECT Fdo, + _In_ PDEVICE_OBJECT NextDeviceObject, + _In_ MBB_BUS_RESPONSE_AVAILABLE_CALLBACK ResponseAvailableCallback, + _In_ MBB_BUS_DATA_RECEIVE_CALLBACK ReceiveDataCallback, + _In_ MBB_BUS_SS_IDLE_CONFIRM_CALLBACK IdleConfirmCallback, + _In_ MBB_BUS_SS_IDLE_NOTIFICATION_COMPLETE_CALLBACK IdleNotificationComplete, + _In_ MBB_PROTOCOL_HANDLE ProtocolHandle, + _Outptr_ MBB_BUS_HANDLE* BusHandle); +/* + Description + This routine initializes the bus layer i.e. the lower layer in the + MBB Class Driver. All bus layer implementations need to have this + function. The Protocol Layer i.e. the upper layer in the MBB Class + Driver will call this function before calling any other function in + the Bus Layer. + + Parameters + _In_ PDEVICE_OBJECT DeviceObject, + The WDM device representation of the device. + + _In_ MBB_BUS_NOTIFICATION_CALLBACK NotificationCallback, + The routine the bus layer calls when it needs to notify + the upper protocol layer. + + _In_ MBB_PROTOCOL_HANDLE ProtocolHandle, + The handle the bus layer passes back to the protocol layer + when it calls any callback. The protocol layer uses this handle + to identify the instance of the MBB device the callback is meant for. + + _Outptr_ MBB_BUS_HANDLE BusHandle + The handle returned by the bus layer on successful initialization. + The protocol layer passes this handle to the bus layer on subsequent + calls to the bus layer. The bus layer uses this handle to indetify + the instance of the MBB device. + + Return Value + NTSTATUS_SUCCESS + Initialization was successful. + + Other failure code +*/ + +EXTERN_C +NTSTATUS +MbbBusInitializeByWdf( + _In_ WDFDEVICE WdfDevice, + _In_ MBB_BUS_RESPONSE_AVAILABLE_CALLBACK ResponseAvailableCallback, + _In_ MBB_BUS_DATA_RECEIVE_CALLBACK ReceiveDataCallback, + _In_ MBB_BUS_SS_IDLE_CONFIRM_CALLBACK IdleConfirmCallback, + _In_ MBB_BUS_SS_IDLE_NOTIFICATION_COMPLETE_CALLBACK IdleNotificationComplete, + _In_ MBB_PROTOCOL_HANDLE ProtocolHandle, + _Outptr_ MBB_BUS_HANDLE* BusHandle, + _Inout_opt_ MBB_BUS_HANDLE preAllocatedBusObject); + +EXTERN_C +VOID MbbBusCleanup(__in MBB_BUS_HANDLE BusHandle); +/* + Description + This will be last call from Protocol layer in to Bus Layer + to cleanup the bus layer. The bus layer should free all + resources. The BusHandle will not be used for subsequent calls. + If there are pending requests the Bus Layer should not return + from this call unless all operations are complete. + + Parameters + __in MBB_BUS_HANDLE BusHandle + BusHandle identifies the instance of the bus layer. + + Return Value + None +*/ + +EXTERN_C +NTSTATUS +MbbBusQueryBusParameters(__in MBB_BUS_HANDLE BusHandle, __out PMBB_BUS_PARAMETERS BusParameters); +/* + Description + This routine queries the bus specific parameters like transfer size, + DMA support etc... This is called when the bus is initialized to format + requests correctly before sending to the bus. + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + __out PMBB_BUS_PARAMETERS BusParameters + The buffer where the bus layer returns the information to the caller. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ +EXTERN_C +NTSTATUS +MbbBusSendMessageFragment( + __in MBB_BUS_HANDLE BusHandle, + __in MBB_REQUEST_HANDLE RequestHandle, + __in PVOID MessageFragment, + __in ULONG FragmentLength, + __in LPGUID ActivityId, + __in MBB_BUS_SEND_COMPLETION_CALLBACK SendCompletionCallback); +/* + Description + The protocol layer call this routine to request the bus layer to + send a message fragment. Fragmentation / Reassembly is handled by + the protocol layer and it will only handle fragments that are within + the maximum transfer size of the bus. + + This routine is asynchronous and returns immediately after queueing + the transfer. The caller is notified of the completion through the + callback. + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + __in MBB_REQUEST_HANDLE RequestHandle, + Identifies the request. + + __in PVOID MessageFragment, + The data payload that needs to be sent. + + __in ULONG FragmentLength, + Length of the data payload. This will not be greater than the + maximum transfer size supported by the bus. + + __in MBB_BUS_SEND_COMPLETION_CALLBACK SendCompletionCallback + The completion callback routine that will be called by the bus + when the transfer is complete. + + Return Value + + NTSTATUS_SUCCESS + The transfer has completed successfully. SendCompletionCallback will NOT be called. + + NTSTATUS_PENDING + The transfer was queued. SendCompletionCallback will be called on completion. + + Other failure code + The transfer could not be queued. SendCompletionCallback will NOT be called. +*/ + +EXTERN_C +NTSTATUS +MbbBusReceiveMessageFragment( + _In_ MBB_BUS_HANDLE BusHandle, + _In_ MBB_REQUEST_HANDLE RequestHandle, + _In_ __drv_aliasesMem PVOID MessageFragment, + _In_ ULONG FragmentLength, + _In_ LPGUID ActivityId, + _In_ MBB_BUS_RECEIVE_COMPLETION_CALLBACK ReceiveCompletionCallback); +/* + Description + + Parameters + + + Return Value + + NTSTATUS_SUCCESS + Initialization was successful. + + Other failure code +*/ +/* + Description + The protocol layer call this routine to request the bus layer to + receive data from the device. Reassembly is handled by the protocol layer. + + This routine is asynchronous and returns immediately after queueing + the transfer. The caller is notified of the completion through the + callback. + + Parameters + _In_ MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + _In_ MBB_REQUEST_HANDLE RequestHandle, + Identifies the request. + + _InOut_ PVOID MessageFragment, + The data buffer that would be filled with the received data. + + _In_ ULONG FragmentLength, + Length of the data requested from the device. This will not be + greater than the maximum transfer size supported by the bus. + + _In_ MBB_BUS_RECEIVE_COMPLETION_CALLBACK ReceiveCompletionCallback + The completion callback routine that will be called by the bus + when the transfer is complete. + + Return Value + + NTSTATUS_SUCCESS + The transfer has completed successfully. ReceiveCompletionCallback will NOT be called. + + NTSTATUS_PENDING + The transfer was queued. ReceiveCompletionCallback will be called on completion. + + Other failure code + The transfer could not be queued. ReceiveCompletionCallback will NOT be called. +*/ + +EXTERN_C +NTSTATUS +MbbBusSetPacketFilter(__in MBB_BUS_HANDLE BusHandle, __in ULONG PacketFilter); +/* + Description + Sets the packet filter on the device. + For MBB only directed is supported + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + __in ULONG PacketFilter + the filter to apply + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +EXTERN_C +NTSTATUS +MbbBusGetStat(__in MBB_BUS_HANDLE BusHandle, __in USHORT StatIndex, __out ULONGLONG* Value); +/* + Description + Retrieves a status from the device + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + __in ULONG PacketFilter + the filter to apply + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +EXTERN_C +NTSTATUS +MbbBusStart(_In_ MBB_BUS_HANDLE BusHandle); + +EXTERN_C +NTSTATUS +MbbBusStop(__in MBB_BUS_HANDLE BusHandle); + +EXTERN_C +BOOLEAN +MbbBusIsStoped(_In_ MBB_BUS_HANDLE BusHandle); + +EXTERN_C +NTSTATUS +MbbBusOpen(_In_ MBB_BUS_HANDLE BusHandle, _In_ ULONG TransactionId, _In_opt_ PVOID FastIOSendNetBufferListsComplete, _In_opt_ PVOID FastIOIndicateReceiveNetBufferLists); +/* + Description + + Opens the session with the device + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +EXTERN_C +NTSTATUS +MbbBusClose(__in MBB_BUS_HANDLE BusHandle, __in ULONG TransactionId, __in BOOLEAN ForceClose); +/* + Description + + Opens the session with the device + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +EXTERN_C +NTSTATUS +MbbBusStartDataPipes(__in MBB_BUS_HANDLE BusHandle); +/* + Description + + Selects alt data interface 1 and starts the IoTargets + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +EXTERN_C +VOID MbbBusStopDataPipes(__in MBB_BUS_HANDLE BusHandle); +/* + Description + + Resets the IoTargets canceling all and waiting for io to compelte + Selects alt data interface 0 disabling the pipes + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ + +EXTERN_C +void MbbBusResetDataPipes(_In_ MBB_BUS_HANDLE BusHandle); + +EXTERN_C +NTSTATUS +MbbBusWriteData(__in MBB_BUS_HANDLE BusHandle, __in MBB_REQUEST_HANDLE RequestHandle, __in PMDL Mdl, __in MBB_BUS_SEND_DATA_COMPLETION_CALLBACK Callback); +/* + Description + + Writes data to device bulk out pipe + + Parameters + __in MBB_BUS_HANDLE BusHandle, + BusHandle identifies the instance of the bus layer. + + __in MBB_REQUEST_HANDLE RequestHandle, + Identifies the request. + + __in PMDL Mdl + pointer to an MDL identifying the data to send. The bus layer will own this until the completion callback is called. + + __in MBB_BUS_SEND_DATA_COMPLETION_CALLBACK Callback + Callback that will be called when write is complete. + + Return Value + + NTSTATUS_SUCCESS + Information was successfully returned in the BusParameters structure. + + NTSTATUS_INVALID_PARAMETER + One of the required parameters is missing or bad. + + Other failure code +*/ +EXTERN_C +VOID MbbBusReturnReceiveBuffer(__in MBB_BUS_HANDLE BusHandle, __in MBB_RECEIVE_CONTEXT ReceiveContext, __in PMDL Mdl); + +EXTERN_C +NTSTATUS +MbbBusSelectDataAltSetting(__in MBB_BUS_HANDLE BusHandle, __in UCHAR AltSetting); + +EXTERN_C +NTSTATUS +MbbBusIdleNotification(__in MBB_BUS_HANDLE BusHandle, __in BOOLEAN ForceIdle); + +EXTERN_C +VOID MbbBusCancelIdleNotification(__in MBB_BUS_HANDLE BusHandle); + +EXTERN_C +NTSTATUS +MbbBusSetPowerFilterPattern( + __in MBB_BUS_HANDLE BusHandle, + __in ULONG PatternId, + __in_bcount_opt(MaskSize) PCUCHAR Mask, + __in ULONG MaskSize, + __in_bcount_opt(PatternSize) PCUCHAR Pattern, + __in ULONG PatternSize); + +EXTERN_C +NTSTATUS +MbbBusResetBulkPipe(__in MBB_BUS_HANDLE BusHandle, __in BOOLEAN Out); + +EXTERN_C +VOID MbbBusSetNotificationState(__in MBB_BUS_HANDLE BusHandle, __in BOOLEAN Enabled); + +EXTERN_C +BOOLEAN +MbbBusIsUde(_In_ MBB_BUS_HANDLE BusHandle); + +#endif diff --git a/network/wwan/cxwmbclass/inc/MbbLibrary.h b/network/wwan/cxwmbclass/inc/MbbLibrary.h new file mode 100644 index 000000000..03f64d8ae --- /dev/null +++ b/network/wwan/cxwmbclass/inc/MbbLibrary.h @@ -0,0 +1,175 @@ +/*************************************************************************** + +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + MbbLibrary.h + +Abstract: + + This header files contains the interfaces to the pack / unpack and + fragment / reassembly functions provided by the Mbb library. + The class driver Protocol layer calls the libary to convert payloads + to messages as defined in the MBB Class Driver Hardware Interface + document before sending it to the Bus Layer. + +Environment: + + User and kernel mode only + +Notes: + + This library can be used both in user and kernel mode because it does not + to make any memory allocations. + +Revision History: + + 2/7/2010 : created + +Authors: + + TriRoy + +****************************************************************************/ +EXTERN_C +NTSTATUS +MbbLibForamtBufferAsOpenMessage(__out_bcount_opt(*BufferLength) PVOID MessageBuffer, __inout PULONG BufferLength, __in ULONG MaximumControlTransfer); +/* + Description + Formats an input buffer as a MBB Open Message. + + Parameters + __out_opt_bcount(*BufferLength) PVOID MessageBuffer + The input message buffer. This parameter may be NULL + if BufferLength is 0. This parameter should not be NULL + when BufferLength is non-zero. + + __inout PULONG BufferLength + This provides the length of the memory location described by MessageBuffer. + If BufferLength is 0 then the function will return the required buffer length + in this parameter with STATUS_BUFFER_OVERFLOW. On success, the amount of + buffer space used by the routine is returned to the caller in BufferLength. + + __in ULONG MaximumControlTransfer + MaximumControlTransfer field of the Open Message. + + Return Value + STATUS_BUFFER_OVERFLOW + The buffer passed in is not sufficient for formatting the message. + + STATUS_INVALID_PARAMETER + One of the required parameters is missing. + + STATUS_SUCCESS + The input buffer was formatted successfully and the amount of buffer + used is returned in BufferLength. +*/ +EXTERN_C +NTSTATUS +MbbLibForamtBufferAsCloseMessage(__out_bcount_opt(*BufferLength) PVOID MessageBuffer, __inout PULONG BufferLength); +/* + Description + Formats an input buffer as a MBB Close Message. + + Parameters + __out_opt_bcount(*BufferLength) PVOID MessageBuffer + The input message buffer. This parameter may be NULL + if BufferLength is 0. This parameter should not be NULL + when BufferLength is non-zero. + + __inout PULONG BufferLength + This provides the length of the memory location described by MessageBuffer. + If BufferLength is 0 then the function will return the required buffer length + in this parameter with STATUS_BUFFER_OVERFLOW. On success, the amount of + buffer space used by the routine is returned to the caller in BufferLength. + + Return Value + STATUS_BUFFER_OVERFLOW + The buffer passed in is not sufficient for formatting the message. + + STATUS_INVALID_PARAMETER + One of the required parameters is missing. + + STATUS_SUCCESS + The input buffer was formatted successfully and the amount of buffer + used is returned in BufferLength. +*/ +EXTERN_C +NTSTATUS +MbbLibFragmentBufferToCommandMessages( + __in PMBB_COMMAND Command, + __in MBB_COMMAND_TYPE CommandType, + __in_bcount_opt(PayloadLength) PCHAR Payload, + __in ULONG PayloadLength, + __inout_opt PULONG TransactionId, + __in ULONG CurrentFragment, + __inout PULONG FragmentBufferCount, + __inout PULONG FragmentLength, + __out_ecount_opt(*FragmentBufferCount) PCHAR* FragmentBuffers); +/* + Description + Given the Payload the routine fragments the payload + in to the FragmentBuffers. + + Parameters + __in MBB_COMMAND Command + Command contains the GUID and Cid. + The GUID identifying the service for this message. + The command identifier for the given service. + + __in MBB_COMMAND_TYPE CommandType + Identifies whether the command is a Set or Query. + + __in_bcount(PayloadLength) PCHAR Payload + The Payload is a byte array that needs to be fragmented. + If Payload length is not 0 Payload should be provided. + + __in ULONG PayloadLength + Length of the payload. If there is no Payload for this command + Payload is set to 0. + + __inout PULONG TransactionId + If non-zero then this is the transaction id used for the fragments. + If zero then a new transcation id is generated and returned to the caller. + + __in ULONG CurrentFragment + If non-zero then Fragments are constructed starting this Fragment. + If zero then Fragments are constructed from the beginning. + + __inout ULONG FragmentBufferCount + Number of input fragments i.e. numberof buffers described by + FragmentBuffers array. If the caller is querying for the + number of fragments required then this should be set to 0. + The function will return the number of fragment required + with STATUS_BUFFER_OVERFLOW. + + __in ULONG FragmentLength + Length of each output fragment buffers. All fragment + buffers needs to be of the same size. + The length of the last fragment is returned on STATUS_SUCCESS. + All but the last fragment are of FragmentLength size. + The last fragment can be lesser than the FragmentLength size. + + __out_ecount_opt(*FragmentBufferCount) PCHAR* FragmentBuffers + Array of input fragment buffers. If FragmentCount is 0 + FragmentBuffers can be NULL. If FragmentCount is non 0 + FragmentBuffers should be provided. + + Return Value + STATUS_INVALID_PARAMETER + One of the required parameters is missing. + + STATUS_SUCCESS + The Payload was fragmented successfully in to + FragmentBuffers and the number of fragments used is + returned in FragmentCount. + + STATUS_MORE_PROCESSING_REQUIRED + The complete Payload is not fragmented yet. + This is not a failure code but an indication to the caller that + more calls are needed with more fragment buffers. +*/ + +ULONG +MbbLibraryGetNextTransactionId(); diff --git a/network/wwan/cxwmbclass/inc/adapter.h b/network/wwan/cxwmbclass/inc/adapter.h new file mode 100644 index 000000000..236daad42 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/adapter.h @@ -0,0 +1,53 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once + +// packet and header sizes +#define MBB_MAX_PACKET_SIZE (1514) + +// maximum link speed for send and recv in bps +#define MBB_MEDIA_MAX_SPEED 1'000'000'000 + +// supported filters +#define WMBCLASS_MAX_WOL_PATTERN (256) +#define WMBCLASS_MAX_MBIM_WOL_PATTERN (192) + +// +// Context for each NetAdapter instance. +// Each NetAdapter instance corresponds to an IP interface +// +typedef struct _WMBCLASS_NETADAPTER_CONTEXT +{ + PWMBCLASS_DEVICE_CONTEXT WmbDeviceContext; // Wdf device context + NETADAPTER NetAdapter; // NetAdapter object + + ULONG ConnectionId; + ULONG SessionId; + MBB_CONNECTION_STATE ConnectionState; + + // RxQuere-related objects + + WDFLOOKASIDE NtbLookasideList; + WDFLOOKASIDE ReceiveNdpLookasideList; + + LIST_ENTRY ReceiveNdpList; + NETPACKETQUEUE TxQueue; // Tx Queue object + NETPACKETQUEUE RxQueue; // Rx Queue object + BOOLEAN AllowRxTraffic; +} WMBCLASS_NETADAPTER_CONTEXT, *PWMBCLASS_NETADAPTER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WMBCLASS_NETADAPTER_CONTEXT, WmbClassGetNetAdapterContext); + +// +// NetAdapter functions +// + +EVT_NET_ADAPTER_CREATE_TXQUEUE EvtAdapterCreateTxQueue; +EVT_NET_ADAPTER_CREATE_RXQUEUE EvtAdapterCreateRxQueue; + +EVT_WDF_DEVICE_CONTEXT_DESTROY MbbDestroyAdapterContext; + +NTSTATUS +WmbClassAdapterStart(_In_ NETADAPTER netAdapter); diff --git a/network/wwan/cxwmbclass/inc/align.h b/network/wwan/cxwmbclass/inc/align.h new file mode 100644 index 000000000..5c8117d39 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/align.h @@ -0,0 +1,168 @@ +/*++ + +Copyright (c) 1988-1992 Microsoft Corporation + +Module Name: + + Align.h + +Abstract: + + +Author: + + John Rogers (JohnRo) 15-May-1991 + +Environment: + + This code assumes that sizeof(DWORD) >= sizeof(PVOID). + +Revision History: + + 15-May-1991 JohnRo + Created align.h for NT/LAN from OS/2 1.2 HPFS pbmacros.h. + 19-Jun-1991 JohnRo + Make sure pointer-to-wider-then-byte doesn't get messed up. + 10-Jul-1991 JohnRo + Added ALIGN_BYTE and ALIGN_CHAR for completeness. + 21-Aug-1991 CliffV + Fix ROUND_DOWN_* to include ~ + 03-Dec-1991 JohnRo + Worst-case on MIPS is 8-byte alignment. + Added COUNT_IS_ALIGNED() and POINTER_IS_ALIGNED() macros. + 26-Jun-1992 JohnRo + RAID 9933: ALIGN_WORST should be 8 for x86 builds. + +--*/ + +#ifndef _ALIGN_ +#define _ALIGN_ + + +// BOOL +// COUNT_IS_ALIGNED( +// IN DWORD Count, +// IN DWORD Pow2 // undefined if this isn't a power of 2. +// ); +// +#define COUNT_IS_ALIGNED(Count,Pow2) \ + ( ( ( (Count) & (((Pow2)-1)) ) == 0) ? TRUE : FALSE ) + +// BOOL +// POINTER_IS_ALIGNED( +// IN PVOID Ptr, +// IN DWORD Pow2 // undefined if this isn't a power of 2. +// ); +// +#define POINTER_IS_ALIGNED(Ptr,Pow2) \ + ( ( ( ((ULONG_PTR)(Ptr)) & (((Pow2)-1)) ) == 0) ? TRUE : FALSE ) + + +// Note ............. +// There is a subtle issue with all these alignment methods +// The way the alignment is done depends on the lValue assignment of these MACRO +// For example: +// UINT64 fileSizeAlligned = ROUND_UP_COUNT(fileSize, pageSize) +// will do a correct 64 bit aligned rounding up +// UINT32 pagesInFileCount = ROUND_UP_COUNT(fileSize, pageSize) / pageSize; +// this will truncate the pageSize to UINT32 when evaluating ~(Pow2-1) below +// causing the result to truncate the most significant 32 bits in fileSize + + +#define ROUND_DOWN_COUNT(Count,Pow2) \ + ( (Count) & (~(((LONG)(Pow2))-1)) ) + +#define ROUND_DOWN_POINTER(Ptr,Pow2) \ + ( (PVOID) ROUND_DOWN_COUNT( ((ULONG_PTR)(Ptr)), (Pow2) ) ) + + +// If Count is not already aligned, then +// round Count up to an even multiple of "Pow2". "Pow2" must be a power of 2. +// +// DWORD +// ROUND_UP_COUNT( +// IN DWORD Count, +// IN DWORD Pow2 +// ); +#define ROUND_UP_COUNT(Count,Pow2) \ + ( ((Count)+(Pow2)-1) & (~(((LONG)(Pow2))-1)) ) + +// PVOID +// ROUND_UP_POINTER( +// IN PVOID Ptr, +// IN DWORD Pow2 +// ); + +// If Ptr is not already aligned, then round it up until it is. +#define ROUND_UP_POINTER(Ptr,Pow2) \ + ( (PVOID) ( (((ULONG_PTR)(Ptr))+(Pow2)-1) & (~(((LONG)(Pow2))-1)) ) ) + + +// Usage: myPtr = ROUND_UP_POINTER( unalignedPtr, ALIGN_LPVOID ) + +#define ALIGN_BYTE sizeof(UCHAR) +#define ALIGN_CHAR sizeof(CHAR) +#define ALIGN_DESC_CHAR sizeof(DESC_CHAR) +#define ALIGN_DWORD sizeof(DWORD) +#define ALIGN_LONG sizeof(LONG) +#define ALIGN_LPBYTE sizeof(LPBYTE) +#define ALIGN_LPDWORD sizeof(LPDWORD) +#define ALIGN_LPSTR sizeof(LPSTR) +#define ALIGN_LPTSTR sizeof(LPTSTR) +#define ALIGN_LPVOID sizeof(PVOID) +#define ALIGN_LPWORD sizeof(LPWORD) +#define ALIGN_TCHAR sizeof(TCHAR) +#define ALIGN_WCHAR sizeof(WCHAR) +#define ALIGN_WORD sizeof(WORD) + +// +// For now, use a hardcoded constant. however, this should be visited again +// and maybe changed to sizeof(QUAD). +// + +#define ALIGN_QUAD 8 + +#if defined(_X86_) + +#define ALIGN_WORST 8 + +#elif defined(_AMD64_) + +#define ALIGN_WORST 8 + +#elif defined(_ARM_) + +#define ALIGN_WORST 8 + +#elif defined(_ARM64_) + +#define ALIGN_WORST 8 + +#elif defined(_ALPHA_) + +// +// Worst-case alignment on ALPHA is 8 bytes (for double). Specify this here, +// in case our allocator is used for structures containing this. (That is, +// even though NT/LAN doesn't need this for our data structures, let's be +// permissive.) The alignment requirements apply to Alpha. +// + +#define ALIGN_WORST 8 + +#elif defined(_IA64_) + +// +// IA64 note for QUAD: The NT QUAD type definition is NOT the EM 16byte quad type. +// Because of some NT constraints, QUAD type size cannot be changed. +// + +#define ALIGN_WORST 16 + +#else // none of the above + +#error "Unknown alignment requirements for align.h" + +#endif // none of the above + +#endif // _ALIGN_ + diff --git a/network/wwan/cxwmbclass/inc/data.h b/network/wwan/cxwmbclass/inc/data.h new file mode 100644 index 000000000..4ac1a8abc --- /dev/null +++ b/network/wwan/cxwmbclass/inc/data.h @@ -0,0 +1,185 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +//////////////////////////////////////////////////////////////////////////////// +// +// DEFINES +// +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#define MBB_DEFAULT_SESSION_ID 0 + +typedef struct _DSS_PACKET +{ + WDFMEMORY Data; + PMDL Mdl; +} DSS_PACKET, *PDSS_PACKET; + +typedef struct _MBB_PORT MBB_PORT, *PMBB_PORT; + +typedef struct _MINIPORT_DRIVER_CONTEXT +{ + WDFDRIVER hDriver; +} MINIPORT_DRIVER_CONTEXT, *PMINIPORT_DRIVER_CONTEXT; + +typedef struct _MBB_RECEIVE_QUEUE +{ + // + // Queue State + // + BOOLEAN LookasideList; + NDIS_SPIN_LOCK Lock; + KEVENT QueueEmptyEvent; + // + // Track Receives + // + LIST_ENTRY ReceivedQueue; + // + // Resources + // + NDIS_HANDLE NblPool; + NPAGED_LOOKASIDE_LIST ReceiveLookasideList; + +} MBB_RECEIVE_QUEUE, *PMBB_RECEIVE_QUEUE; + +typedef struct _MBB_NDIS_RECEIVE_CONTEXT +{ + // + // Resources + // + + PMDL Mdl; + PUCHAR ReceiveNtbBuffer; + WDFLOOKASIDE ReceiveLookasideList; + PMBB_RECEIVE_QUEUE RecvQueue; + MBB_BUS_HANDLE BusHandle; + MBB_RECEIVE_CONTEXT BusContext; + PWMBCLASS_DEVICE_CONTEXT WmbDeviceContext; + // + // Parse state + // + ULONG NtbSequence; + WDFMEMORY ReceiveLookasideBufferMemory; + + LONG TotalNdpCount; + LONG CompletedNdpCount; +} MBB_NDIS_RECEIVE_CONTEXT, *PMBB_NDIS_RECEIVE_CONTEXT; + +typedef struct _MBB_RECEIVE_NDP_CONTEXT +{ + LIST_ENTRY ReceiveNdpNode; + PMBB_NDIS_RECEIVE_CONTEXT ReceiveContext; + WDFMEMORY ReceiveNdpLookasideBufferMemory; + PVOID Nth; + PVOID Ndp; + ULONG CurrentDatagramIndex; + ULONG IndicatedPackets; + PWMBCLASS_NETADAPTER_CONTEXT NetAdapterContext; +} MBB_RECEIVE_NDP_CONTEXT, *PMBB_RECEIVE_NDP_CONTEXT; + +extern MINIPORT_DRIVER_CONTEXT GlobalControl; + +typedef enum +{ + MbbNdpTypeNoCrc = 0, + MbbNdpTypeCrc, + MbbNdpTypeIps, + MbbNdpTypeVendor_1, // Vendor with session id X (need not be 1) + MbbNdpTypeVendor_2, // Vendor with session id Y (need not be X + 1) + MbbNdpTypeVendor_3, + MbbNdpTypeVendor_Max, // Max 4 vendor sessions in one NTB + MbbNdpTypeMax + +} MBB_NDP_TYPE; + +typedef struct _MBB_PACKET_CONTEXT +{ + PMDL DataStartMdl; + PMDL DataEndMdl; + PMDL PaddingMdl; + PMDL ModifiedMdl; + MDL OriginalMdl; + +} MBB_PACKET_CONTEXT, *PMBB_PACKET_CONTEXT; + +typedef struct _MBB_NDP_HEADER_ENTRY +{ + MBB_NDP_TYPE NdpType; + ULONG SessionId; + ULONG DatagramOffset; + ULONG DatagramLength; + ULONG NextEntryIndex; + PNET_BUFFER NetBuffer; + PNET_BUFFER_LIST NetBufferList; + + union + { + NET_PACKET* NetPacket; + PDSS_PACKET DssPacket; + }; + MBB_PACKET_CONTEXT NetPacketContext; +} MBB_NDP_HEADER_ENTRY, *PMBB_NDP_HEADER_ENTRY; + +typedef struct _MBB_NTB_BUILD_CONTEXT +{ + LIST_ENTRY NtbQLink; + // + // Read-only values + // + BOOLEAN IsNtb32Bit; + ULONG NtbHeaderSize; + ULONG NdpHeaderFixedSize; + ULONG NdpDatagramEntrySize; + ULONG NtbOutMaxSize; + USHORT NtbOutMaxDatagrams; + USHORT NdpOutDivisor; + USHORT NdpOutPayloadRemainder; + USHORT NdpOutAlignment; + PVOID PaddingBuffer; + WDFLOOKASIDE NtbLookasideList; + // + // Network Transfer Header(NTH) + // + union + { + NCM_NTH16 Nth16; + NCM_NTH32 Nth32; + }; + PMDL NthMdl; + // + // NDP Header + // + PMDL NdpMdl; + ULONG NdpSize; + PVOID NdpBuffer; + // + // NDP Datagrams + // + ULONG DatagramCount; + ULONG DatagramLength; + PMDL DatagramLastMdl; + + WDFMEMORY NtbLookasideBufferMemory; + WDFMEMORY NdpBufferMemory; + NETPACKETQUEUE NetTxQueue; + NETADAPTER NetAdapter; + NET_RING_COLLECTION const* NetDatapathDescriptor; + +#if DBG + // + // Testing + // + PCHAR ScratchBuffer; + ULONG ScratchLength; +#endif + + // + // NDP Headers. Varialble length array is limited + // to NdpMaxDatagrams. NdpFirstDatagramEntry of -1 + // is invalid. + // + ULONG NdpFirstDatagramEntry[MbbNdpTypeMax]; + MBB_NDP_HEADER_ENTRY NdpDatagramEntries[ANYSIZE_ARRAY]; + +} MBB_NTB_BUILD_CONTEXT, *PMBB_NTB_BUILD_CONTEXT; diff --git a/network/wwan/cxwmbclass/inc/device.h b/network/wwan/cxwmbclass/inc/device.h new file mode 100644 index 000000000..a00ea7f40 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/device.h @@ -0,0 +1,45 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once + +typedef struct _WMBCLASS_DEVICE_CONTEXT +{ + void* WdfTriageInfoPtr; + + WDFDEVICE WdfDevice; + bool m_armedWake; + ULONG TraceInstance; + + MBB_BUS_HANDLE BusHandle; + MBB_BUS_PARAMETERS BusParams; + + ULONGLONG DSSPacketsReceivedCount; + ULONGLONG DSSPacketsSentCount; + + LONG NtbSequenceNumber; + + WDFLOOKASIDE ReceiveLookasideList; + PUCHAR sharedPaddingBuffer; + + struct + { + WDFSPINLOCK WdfRecvSpinLock; + struct _WMBCLASS_NETADAPTER_CONTEXT* NetAdapterContext; // the context of the netAdapter instance if this session is in use + } Sessions[MBB_MAX_NUMBER_OF_SESSIONS]; + +} WMBCLASS_DEVICE_CONTEXT, *PWMBCLASS_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WMBCLASS_DEVICE_CONTEXT, WmbClassGetDeviceContext); + +EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + +EVT_MBB_DEVICE_SEND_MBIM_FRAGMENT EvtMbbDeviceSendMbimFragment; +EVT_MBB_DEVICE_RECEIVE_MBIM_FRAGMENT EvtMbbDeviceReceiveMbimFragment; +EVT_MBB_DEVICE_CREATE_ADAPTER EvtMbbDeviceCreateAdapter; +//EVT_NET_DEVICE_RESET EvtMbbDeviceReset; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtAdapterCleanup; diff --git a/network/wwan/cxwmbclass/inc/mbbmessages.h b/network/wwan/cxwmbclass/inc/mbbmessages.h new file mode 100644 index 000000000..61957009f --- /dev/null +++ b/network/wwan/cxwmbclass/inc/mbbmessages.h @@ -0,0 +1,3273 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.01.0625 */ +/* at Mon Jan 18 19:14:07 2038 + */ +/* @@MIDL_FILE_HEADING( ) */ + + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#if 0 +#include +#include +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif /* __RPCNDR_H_VERSION__ */ +#endif + +#ifndef __MbbMessages_h__ +#define __MbbMessages_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#ifndef DECLSPEC_XFGVIRT +#if _CONTROL_FLOW_GUARD_XFG +#define DECLSPEC_XFGVIRT(base, func) __declspec(xfg_virtual(base, func)) +#else +#define DECLSPEC_XFGVIRT(base, func) +#endif +#endif + +/* Forward Declarations */ + +/* header files for imported files */ +// #include "wtypes.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_MbbMessages_0000_0000 */ +/* [local] */ + +// +// Copyright (C) Microsoft. All rights reserved. +// +#include +// +// Service Ids +// +// Invald GUID +// 00000000-0000-0000-0000-000000000000 +DEFINE_GUID( MBB_UUID_INVALID, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ); +#define MBB_UUID_INVALID_CONSTANT { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } +// Basic IP Connectivity +// a289cc33-bcbb-8b4f-b6b0-133ec2aae6df +DEFINE_GUID( MBB_UUID_BASIC_CONNECT, 0xa289cc33, 0xbcbb, 0x8b4f, 0xb6, 0xb0, 0x13, 0x3e, 0xc2, 0xaa, 0xe6, 0xdf ); +#define MBB_UUID_BASIC_CONNECT_CONSTANT { 0xa289cc33, 0xbcbb, 0x8b4f, { 0xb6, 0xb0, 0x13, 0x3e, 0xc2, 0xaa, 0xe6, 0xdf } } +// SMS +// 533fbeeb-14fe-4467-9f90-33a223e56c3f +DEFINE_GUID( MBB_UUID_SMS, 0x533fbeeb, 0x14fe, 0x4467, 0x9f, 0x90, 0x33, 0xa2, 0x23, 0xe5, 0x6c, 0x3f ); +#define MBB_UUID_SMS_CONSTANT { 0x533fbeeb, 0x14fe, 0x4467, { 0x9f, 0x90, 0x33, 0xa2, 0x23, 0xe5, 0x6c, 0x3f } } +// USSD +// e550a0c8-5e82-479e-82f7-10abf4c3351f +DEFINE_GUID( MBB_UUID_USSD, 0xe550a0c8, 0x5e82, 0x479e, 0x82, 0xf7, 0x10, 0xab, 0xf4, 0xc3, 0x35, 0x1f ); +#define MBB_UUID_USSD_CONSTANT { 0xe550a0c8, 0x5e82, 0x479e, { 0x82, 0xf7, 0x10, 0xab, 0xf4, 0xc3, 0x35, 0x1f } } +// Phonebook +// 4bf38476-1e6a-41db-b1d8-bed289c25bdb +DEFINE_GUID( MBB_UUID_PHONEBOOK, 0x4bf38476, 0x1e6a, 0x41db, 0xb1, 0xd8, 0xbe, 0xd2, 0x89, 0xc2, 0x5b, 0xdb ); +#define MBB_UUID_PHONEBOOK_CONSTANT { 0x4bf38476, 0x1e6a, 0x41db, { 0xb1, 0xd8, 0xbe, 0xd2, 0x89, 0xc2, 0x5b, 0xdb } } +// SIM Application Toolkit +// d8f20131-fcb5-4e17-8602-d6ed3816164c +DEFINE_GUID( MBB_UUID_SAT, 0xd8f20131, 0xfcb5, 0x4e17, 0x86, 0x02, 0xd6, 0xed, 0x38, 0x16, 0x16, 0x4c ); +#define MBB_UUID_SAT_CONSTANT { 0xd8f20131, 0xfcb5, 0x4e17, { 0x86, 0x02, 0xd6, 0xed, 0x38, 0x16, 0x16, 0x4c } } +// Windows 7 Vendor Extension +// b492e7e2-adba-499d-8401-7794bb913c1c +DEFINE_GUID( MBB_UUID_MS_VENDOR_EXTENSION, 0xb492e7e2, 0xadba, 0x499d, 0x84, 0x01, 0x77, 0x94, 0xbb, 0x91, 0x3c, 0x1c ); +#define MBB_UUID_MS_VENDOR_EXTENSION_CONSTANT { 0xb492e7e2, 0xadba, 0x499d, { 0x84, 0x01, 0x77, 0x94, 0xbb, 0x91, 0x3c, 0x1c } } +// Authentication +// 1d2b5ff7-0aa1-48b2-aa52-50f15767174e +DEFINE_GUID( MBB_UUID_AUTH, 0x1d2b5ff7, 0x0aa1, 0x48b2, 0xaa, 0x52, 0x50, 0xf1, 0x57,0x67, 0x17, 0x4e ); +#define MBB_UUID_AUTH_CONSTANT { 0x1d2b5ff7, 0x0aa1, 0x48b2, { 0xaa, 0x52, 0x50, 0xf1, 0x57,0x67, 0x17, 0x4e } } +// Device Service Stream +// c08a26dd-7718-4382-8482-6e0d583c4d0e +DEFINE_GUID( MBB_UUID_DSS, 0xc08a26dd, 0x7718, 0x4382, 0x84, 0x82, 0x6e, 0x0d, 0x58, 0x3c, 0x4d, 0x0e ); +#define MBB_UUID_DSS_CONSTANT { 0xc08a26dd, 0x7718, 0x4382, { 0x84, 0x82, 0x6e, 0x0d, 0x58, 0x3c, 0x4d, 0x0e } } +// Multi-carrier device service +// 8b569648-628d-4653-9b9f-1025404424e1 +DEFINE_GUID( MBB_UUID_MULTICARRIER, 0x8b569648, 0x628d, 0x4653, 0x9b, 0x9f, 0x10, 0x25, 0x40, 0x44, 0x24, 0xe1 ); +#define MBB_UUID_MULTICARRIER_CONSTANT { 0x8b569648, 0x628d, 0x4653, { 0x9b, 0x9f, 0x10, 0x25, 0x40, 0x44, 0x24, 0xe1 } } +// Host Shutdown device service +// 883b7c26-985f-43fa-9804-27d7fb80959c +DEFINE_GUID( MBB_UUID_HOSTSHUTDOWN, 0x883b7c26, 0x985f, 0x43fa, 0x98, 0x04, 0x27, 0xd7, 0xfb, 0x80, 0x95, 0x9c ); +#define MBB_UUID_HOSTSHUTDOWN_CONSTANT { 0x883b7c26, 0x985f, 0x43fa, { 0x98, 0x04, 0x27, 0xd7, 0xfb, 0x80, 0x95, 0x9c } } +// MBIM 2.0 voice extensions +// 8d8b9eba-37be-449b-8f1e-61cb034a702e +DEFINE_GUID( MBB_UUID_VOICEEXTENSIONS, 0x8d8b9eba, 0x37be, 0x449b, 0x8f, 0x1e, 0x61, 0xcb, 0x03, 0x4a, 0x70, 0x2e ); +#define MBB_UUID_VOICEEXTENSIONS_CONSTANT { 0x8d8b9eba, 0x37be, 0x449b, { 0x8f, 0x1e, 0x61, 0xcb, 0x03, 0x4a, 0x70, 0x2e } } +// Low-Level UICC Access +// c2f6588e-f037-4bc9-8665-f4d44bd09367 +DEFINE_GUID( MBB_UUID_UICC_LOW_LEVEL, 0xc2f6588e, 0xf037, 0x4bc9, 0x86, 0x65, 0xf4, 0xd4, 0x4b, 0xd0, 0x93, 0x67 ); +#define MBB_UUID_UICC_LOW_LEVEL_CONSTANT { 0xc2f6588e, 0xf037, 0x4bc9, { 0x86, 0x65, 0xf4, 0xd4, 0x4b, 0xd0, 0x93, 0x67 } } +// Selective Absorption Rate (SAR) control +// 68223d04-9f6c-4e0f-822d-28441fb72340 +DEFINE_GUID( MBB_UUID_SARCONTROL, 0x68223d04, 0x9f6c, 0x4e0f, 0x82, 0x2d, 0x28, 0x44, 0x1f, 0xb7, 0x23, 0x40 ); +#define MBB_UUID_SARCONTROL_CONSTANT { 0x68223d04, 0x9f6c, 0x4e0f, { 0x82, 0x2d, 0x28, 0x44, 0x1f, 0xb7, 0x23, 0x40 } } +// Basic IP Connectivity Extensions (a private Microsoft service not approved by MBIM USB forum as of 2016/11/09) +// 3d01dcc5-fef5-4d05-0d3a-bef7058e9aaf +DEFINE_GUID( MBB_UUID_BASIC_CONNECT_EXTENSIONS, 0x3d01dcc5, 0xfef5, 0x4d05, 0x0d, 0x3a, 0xbe, 0xf7, 0x05, 0x8e, 0x9a, 0xaf ); +#define MBB_UUID_BASIC_CONNECT_EXT_CONSTANT { 0x3d01dcc5, 0xfef5, 0x4d05, { 0x0d, 0x3a, 0xbe, 0xf7, 0x05, 0x8e, 0x9a, 0xaf } } +// DeviceService GUID for Modem Log Transfer (parameter for DSS connect/disconnect request to open/close DSS data channel) +// 0ebb1ceb-af2d-484d-8df3-53bc51fd162c +DEFINE_GUID( MBB_UUID_MODEM_LOG_TRANSFER, 0x0ebb1ceb, 0xaf2d, 0x484d, 0x8d, 0xf3, 0x53, 0xbc, 0x51, 0xfd, 0x16, 0x2c ); +#define MBB_UUID_MODEM_LOG_TRANSFER_CONSTANT { 0x0ebb1ceb, 0xaf2d, 0x484d, { 0x8d, 0xf3, 0x53, 0xbc, 0x51, 0xfd, 0x16, 0x2c } } +// +// Context Type GUIDs +// +// MBIMContextTypeNone +// B43F758C-A560-4B46-B35E-C5869641FB54 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_NONE, 0xB43F758C, 0xA560, 0x4B46, 0xB3, 0x5E, 0xC5, 0x86, 0x96, 0x41, 0xFB, 0x54 ); +// MBIMContextTypeInternet +// 7E5E2A7E-4E6F-7272-736B-656E7E5E2A7E +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_INTERNET, 0x7E5E2A7E, 0x4E6F, 0x7272, 0x73, 0x6B, 0x65, 0x6E, 0x7E, 0x5E, 0x2A, 0x7E ); +// MBIMContextTypeVpn +// 9B9F7BBE-8952-44B7-83AC-CA41318DF7A0 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_VPN, 0x9B9F7BBE, 0x8952, 0x44B7, 0x83, 0xAC, 0xCA, 0x41, 0x31, 0x8D, 0xF7, 0xA0 ); +// MBIMContextTypeVoice +// 88918294-0EF4-4396-8CCA-A8588FBC02B2 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_VOICE, 0x88918294, 0x0EF4, 0x4396, 0x8C, 0xCA, 0xA8, 0x58, 0x8F, 0xBC, 0x02, 0xB2 ); +// MBIMContextTypeVideoShare +// 05A2A716-7C34-4B4D-9A91-C5EF0C7AAACC +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_VIDEO_SHARE, 0x05A2A716,0x7C34, 0x4B4D, 0x9A, 0x91, 0xC5, 0xEF, 0x0C, 0x7A, 0xAA, 0xCC ); +// MBIMContextTypePurchase +// B3272496-AC6C-422B-A8C0-ACF687A27217 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_PURCHASE, 0xB3272496, 0xAC6C, 0x422B, 0xA8, 0xC0, 0xAC, 0xF6, 0x87, 0xA2, 0x72, 0x17 ); +// MBIMContextTypeIMS +// 21610D01-3074-4BCE-9425-B53A07D697D6 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_IMS, 0x21610D01, 0x3074, 0x4BCE, 0x94, 0x25, 0xB5, 0x3A, 0x07, 0xD6, 0x97, 0xD6 ); +// MBIMContextTypeMMS +// 46726664-7269-6BC6-9624-D1D35389ACA9 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_MMS, 0x46726664, 0x7269, 0x6BC6, 0x96, 0x24, 0xD1, 0xD3, 0x53, 0x89, 0xAC, 0xA9 ); +// MBIMContextTypeLocal +// A57A9AFC-B09F-45D7-BB40-033C39F60DB9 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_LOCAL, 0xA57A9AFC, 0xB09F, 0x45D7, 0xBB, 0x40, 0x03, 0x3C, 0x39, 0xF6, 0x0D, 0xB9 ); +// MBIMMsContextTypeAdmin +// 5f7e4c2e-e80b-40a9-a239-f0abcfd11f4b +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_MS_ADMIN, 0x5f7e4c2e, 0xe80b, 0x40a9, 0xa2, 0x39, 0xf0, 0xab, 0xcf, 0xd1, 0x1f, 0x4b ); +// MBIMMSContextTypeApp +// 74d88a3d-dfbd-4799-9a8c-7310a37bb2ee +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_MS_APP, 0x74d88a3d, 0xdfbd, 0x4799, 0x9a, 0x8c, 0x73, 0x10, 0xa3, 0x7b, 0xb2, 0xee ); +// MBIMMsContextTypeXcap +// 50d378a7-baa5-4a50-b872-3fe5bb463411 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_MS_XCAP, 0x50d378a7, 0xbaa5, 0x4a50, 0xb8, 0x72, 0x3f, 0xe5, 0xbb, 0x46, 0x34, 0x11 ); +// MBIMMsContextTypeTethering +// 5e4e0601-48dc-4e2b-acb8-08b4016bbaac +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_MS_TETHERING, 0x5e4e0601, 0x48dc, 0x4e2b, 0xac, 0xb8, 0x08, 0xb4, 0x01, 0x6b, 0xba, 0xac ); +// MBIMMsContextTypeEmergencyCalling +// 5f41adb8-204e-4d31-9da8-b3c970e360f2 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_MS_EMERGENCYCALL, 0x5f41adb8, 0x204e, 0x4d31, 0x9d, 0xa8, 0xb3, 0xc9, 0x70, 0xe3, 0x60, 0xf2 ); +// 9C494542-A43B-4EA5-B8B7-53310E71DF10 +DEFINE_GUID( MBB_UUID_CONTEXT_TYPE_CUSTOM, 0x9C494542, 0xA43B, 0x4EA5, 0xB8, 0xB7, 0x53, 0x31, 0x0E, 0x71, 0xDF, 0x10); +// 146FED19-EB71-42A7-B3EB-3875DEA61D92 +DEFINE_GUID(GUID_USB_CAPABILITY_DEVICE_TYPE, 0x146FED19, 0xEB71, 0x42A7, 0xB3, 0xEB, 0x38, 0x75, 0xDE, 0xA6, 0x1D, 0x92); +#define MBB_STATUS_SUCCESS( STATUS ) \ + ( \ + ((STATUS) == MBB_STATUS_SUCCESS) || \ + ((STATUS) == MBB_STATUS_SMS_MORE_DATA) \ + ) +#define MBB_STATUS_IS_BASIC(MBBSTATUS) (((MBBSTATUS) >= MBB_STATUS_BASIC_START) && ((MBBSTATUS) < MBB_STATUS_BASIC_END)) +#define MBB_STATUS_BASIC_INDEX(MBBSTATUS) ((MBBSTATUS)-MBB_STATUS_BASIC_START) +#define MBB_STATUS_BASIC_COUNT() (MBB_STATUS_BASIC_END-MBB_STATUS_BASIC_START) +#define MBB_STATUS_IS_SMS(MBBSTATUS) (((MBBSTATUS) >= MBB_STATUS_SMS_START) && ((MBBSTATUS) < MBB_STATUS_SMS_END)) +#define MBB_STATUS_SMS_INDEX(MBBSTATUS) ((MBBSTATUS)-MBB_STATUS_SMS_START) +#define MBB_STATUS_SMS_COUNT() (MBB_STATUS_SMS_END-MBB_STATUS_SMS_START) +#define MBB_STATUS_IS_UICC(MBBSTATUS) (((MBBSTATUS) >= MBB_STATUS_UICC_START) && ((MBBSTATUS) < MBB_STATUS_UICC_END)) +#define MBB_STATUS_UICC_INDEX(MBBSTATUS) ((MBBSTATUS)-MBB_STATUS_UICC_START) +#define MBB_STATUS_UICC_COUNT() (MBB_STATUS_UICC_END-MBB_STATUS_UICC_START) +#define MBB_UUID_TO_NET(_dest, _src) \ +{ \ + (_dest)->Data1 = RtlUlongByteSwap((_src)->Data1); \ + (_dest)->Data2 = RtlUshortByteSwap((_src)->Data2); \ + (_dest)->Data3 = RtlUshortByteSwap((_src)->Data3); \ + RtlCopyMemory((_dest)->Data4, (_src)->Data4, sizeof((_src)->Data4)); \ + \ +} +#define MBB_UUID_TO_HOST(_dest, _src) MBB_UUID_TO_NET(_dest, _src) +#define MBB_IS_DEVICE_REGISTERED( _State_ ) \ +( \ + ( (_State_) == MbbRegisterStateHome ) || \ + ( (_State_) == MbbRegisterStateRoaming ) || \ + ( (_State_) == MbbRegisterStatePartner ) \ +) +#include +#define MBB_MAXIMUM_DATA_CLASS_NAME_LENGTH ( 11 ) + +#define MBB_MAXIMUM_DEVICE_ID_LENGTH ( 17 ) + +#define MBB_MAXIMUM_FIRMWARE_INFO_LENGTH ( 31 ) + +#define MBB_MAXIMUM_SUBSCRIBER_ID_LENGTH ( 15 ) + +#define MBB_MAXIMUM_SIM_ICC_ID_LENGTH ( 20 ) + +#define MBB_MAXIMUM_TELEPHONE_NUMBER_LENGTH ( 15 ) + +#define MBB_MAXIMUM_TELEPHONE_NUMBER_ERRATA_LENGTH ( 22 ) + +#define MBB_MAXIMUM_PIN_LENGTH ( 16 ) + +#define MBB_MAXIMUM_PROVIDER_ID_LENGTH ( 6 ) + +#define MBB_MAXIMUM_PROVIDER_NAME_LENGTH ( 20 ) + +#define MBB_MAXIMUM_ROAMING_TEXT_LENGTH ( 63 ) + +#define MBB_MAXIMUM_ACCESS_STRING_LENGTH ( 100 ) + +#define MBB_MAXIMUM_USERNAME_LENGTH ( 255 ) + +#define MBB_MAXIMUM_PASSWORD_LENGTH ( 255 ) + +#define MBB_MAXIMUM_SMS_ADDRESS_LENGTH ( 20 ) + +#define MBB_MAXIMUM_SMS_CDMA_ADDRESS_LENGTH ( 49 ) + +#define MBB_MAXIMUM_SMS_CDMA_TIMESTAMP_LENGTH ( 21 ) + +#define MBB_MAXIMUM_SMS_CDMA_BUFFER_LENGTH ( 160 ) + +#define MBB_MAXIMUM_SMS_GSM_PDU_BUFFER_LENGTH ( 183 ) + +#define MBB_MAXIMUM_SMS_CDMA_PDU_BUFFER_LENGTH ( 255 ) + +#define MBB_USSD_STRING_LEN_MAX ( 160 ) + +#define MBB_RSSI_DISABLE ( 0xffffffff ) + +#define MBB_RSSI_DEFAULT ( 0 ) + +#define MBB_SET_CONTEXT_STATE_EX3_MIN_TLV_CNT ( 3 ) + +#define MBB_CONTEXT_STATE_EX3_MIN_TLV_CNT ( 1 ) + +#define MBIM_VERSION_1_0 ( 0x100 ) + +#define MBIM_MS_EXTENDED_VER_1_0 ( 0x100 ) + +#define MBIM_MS_EXTENDED_VER_2_0 ( 0x200 ) + +#define MBIM_MS_EXTENDED_VER_3_0 ( 0x300 ) + +#define MBB_MS_DEVICE_CAPS_INFO_V3_MIN_TLV_CNT ( 6 ) + +#define MBB_TLV_TYPE_RESERVED ( 0 ) + +#define MBB_TLV_TYPE_UE_POLICIES ( 1 ) + +#define MBB_TLV_TYPE_SINGLE_NSSAI ( 2 ) + +#define MBB_TLV_TYPE_ALLOWED_NSSAI ( 3 ) + +#define MBB_TLV_TYPE_CFG_NSSAI ( 4 ) + +#define MBB_TLV_TYPE_DFLT_CFG_NSSAI ( 5 ) + +#define MBB_TLV_TYPE_PRECFG_DFLT_CFG_NSSAI ( 6 ) + +#define MBB_TLV_TYPE_REJ_NSSAI ( 7 ) + +#define MBB_TLV_TYPE_LADN ( 8 ) + +#define MBB_TLV_TYPE_TAI ( 9 ) + +#define MBB_TLV_TYPE_WCHAR_STR ( 10 ) + +#define MBB_TLV_TYPE_UINT16_TBL ( 11 ) + +#define MBB_TLV_TYPE_EAP_PACKET ( 12 ) + +#define MBB_TLV_TYPE_PCO ( 13 ) + +#define MBB_TLV_TYPE_ROUTE_SELECTION_DESCRIPTORS ( 14 ) + +#define MBB_TLV_TYPE_TRAFFIC_PARAMETERS ( 15 ) + +#define MBB_TLV_TYPE_WAKE_COMMAND ( 16 ) + +#define MBB_TLV_TYPE_WAKE_PACKET ( 17 ) + +#define MBB_NW_PARAMS_INFO_CONFIG_TLV_CNT ( 6 ) + +#define MBB_NW_PARAMS_INFO_UE_POLICIES_TLV_CNT ( 1 ) + +typedef unsigned short MBB_TLV_TYPE; + +typedef +enum _USB_CAP_DEVICE_TYPE + { + USB_CAP_DEVICE_TYPE_USB = 0, + USB_CAP_DEVICE_TYPE_UDE_MBIM = 1, + USB_CAP_DEVICE_TYPE_UDE_MBIM_FASTIO = 2, + USB_CAP_DEVICE_TYPE_MAXIMUM = ( USB_CAP_DEVICE_TYPE_UDE_MBIM_FASTIO + 1 ) + } USB_CAP_DEVICE_TYPE; + +typedef struct _USB_CAP_DEVICE_INFO_HEADER + { + USB_CAP_DEVICE_TYPE DeviceType; + UCHAR DeviceMinorVersion; + UCHAR DeviceMajorVersion; + ULONG Reserved; + } USB_CAP_DEVICE_INFO_HEADER; + +typedef struct _USB_CAP_DEVICE_INFO_HEADER *PUSB_CAP_DEVICE_INFO_HEADER; + +typedef struct _USB_CAP_DEVICE_INFO + { + USB_CAP_DEVICE_INFO_HEADER DeviceInfoHeader; + } USB_CAP_DEVICE_INFO; + +typedef struct _USB_CAP_DEVICE_INFO *PUSB_CAP_DEVICE_INFO; + +typedef +enum _MBB_NBL_TYPE + { + MBB_NBL_TYPE_IP = 0, + MBB_NBL_TYPE_DSS = 1, + MBB_NBL_TYPE_MAXIMUM = ( MBB_NBL_TYPE_DSS + 1 ) + } MBB_NBL_TYPE; + +typedef +enum _MBB_STATUS + { + MBB_STATUS_SUCCESS = 0, + MBB_STATUS_BASIC_START = 0, + MBB_STATUS_BUSY = 1, + MBB_STATUS_FAILURE = 2, + MBB_STATUS_SIM_NOT_INSERTED = 3, + MBB_STATUS_BAD_SIM = 4, + MBB_STATUS_PIN_REQUIRED = 5, + MBB_STATUS_PIN_DISABLED = 6, + MBB_STATUS_NOT_REGISTERED = 7, + MBB_STATUS_PROVIDERS_NOT_FOUND = 8, + MBB_STATUS_NO_DEVICE_SUPPORT = 9, + MBB_STATUS_PROVIDER_NOT_VISIBLE = 10, + MBB_STATUS_DATA_CLASS_NOT_AVAILABLE = 11, + MBB_STATUS_PACKET_SVC_DETACHED = 12, + MBB_STATUS_MAX_ACTIVATED_CONTEXTS = 13, + MBB_STATUS_NOT_INITIALIZED = 14, + MBB_STATUS_VOICE_CALL_IN_PROGRESS = 15, + MBB_STATUS_CONTEXT_NOT_ACTIVATED = 16, + MBB_STATUS_SERVICE_NOT_ACTIVATED = 17, + MBB_STATUS_INVALID_ACCESS_STRING = 18, + MBB_STATUS_INVALID_USER_NAME_PWD = 19, + MBB_STATUS_RADIO_POWER_OFF = 20, + MBB_STATUS_INVALID_PARAMETERS = 21, + MBB_STATUS_READ_FAILURE = 22, + MBB_STATUS_WRITE_FAILURE = 23, + MBB_STATUS_DENIED_POLICY = 24, + MBB_STATUS_NO_PHONEBOOK = 25, + MBB_STATUS_PARAMETER_TOO_LONG = 26, + MBB_STATUS_STK_BUSY = 27, + MBB_STATUS_OPERATION_NOT_ALLOWED = 28, + MBB_STATUS_MEMORY_FAILURE = 29, + MBB_STATUS_INVALID_MEMORY_INDEX = 30, + MBB_STATUS_MEMORY_FULL = 31, + MBB_STATUS_FILTER_NOT_SUPPORTED = 32, + MBB_STATUS_DSS_INSTANCE_LIMIT = 33, + MBB_STATUS_INVALID_DEVICE_SERVICE_OPERATION = 34, + MBB_STATUS_AUTH_INCORRECT_AUTN = 35, + MBB_STATUS_AUTH_SYNC_FAILURE = 36, + MBB_STATUS_AUTH_AMF_NOT_SET = 37, + MBB_STATUS_CONTEXT_NOT_SUPPORTED = 38, + MBB_STATUS_SHAREABILITY_CONDITION_ERROR = 39, + MBB_STATUS_PIN_FAILURE = 40, + MBB_STATUS_NO_LTE_ATTACH_CONFIG = 41, + MBB_STATUS_SESSION_ALREADY_EXISTS = 42, + MBB_STATUS_BASIC_END = ( MBB_STATUS_SESSION_ALREADY_EXISTS + 1 ) , + MBB_STATUS_SMS_UNKNOWN_SMSC_ADDRESS = 100, + MBB_STATUS_SMS_START = 100, + MBB_STATUS_SMS_NETWORK_TIMEOUT = 101, + MBB_STATUS_SMS_LANG_NOT_SUPPORTED = 102, + MBB_STATUS_SMS_ENCODING_NOT_SUPPORTED = 103, + MBB_STATUS_SMS_FORMAT_NOT_SUPPORTED = 104, + MBB_STATUS_SMS_MORE_DATA = 105, + MBB_STATUS_SMS_END = ( MBB_STATUS_SMS_MORE_DATA + 1 ) , + MBB_STATUS_UICC_NO_LOGICAL_CHANNELS = 0x87430001, + MBB_STATUS_UICC_START = 0x87430001, + MBB_STATUS_UICC_SELECT_FAILED = 0x87430002, + MBB_STATUS_UICC_INVALID_LOGICAL_CHANNEL = 0x87430003, + MBB_STATUS_UICC_END = ( MBB_STATUS_UICC_INVALID_LOGICAL_CHANNEL + 1 ) + } MBB_STATUS; + +typedef +enum _MBB_ERROR + { + MBB_ERROR_NONE = 0, + MBB_ERROR_TIMEOUT_FRAGMENT = 1, + MBB_ERROR_FRAGMENT_OUT_OF_SEQUENCE = 2, + MBB_ERROR_LENGTH_MISMATCH = 3, + MBB_ERROR_DUPLICATE_TID = 4, + MBB_ERROR_NOT_OPENED = 5, + MBB_ERROR_UNKNOWN = 6, + MBB_ERROR_CANCEL = 7, + MBB_ERROR_MAX_TRANSFER = 8 + } MBB_ERROR; + +typedef +enum _MBB_MESSAGE_TYPE + { + MBB_MESSAGE_TYPE_NONE = 0, + MBB_MESSAGE_TYPE_OPEN = 0x1, + MBB_MESSAGE_TYPE_CLOSE = 0x2, + MBB_MESSAGE_TYPE_COMMAND = 0x3, + MBB_MESSAGE_TYPE_HOST_ERROR = 0x4, + MBB_MESSAGE_TYPE_OPEN_DONE = 0x80000001, + MBB_MESSAGE_TYPE_CLOSE_DONE = 0x80000002, + MBB_MESSAGE_TYPE_COMMAND_DONE = 0x80000003, + MBB_MESSAGE_TYPE_FUNCTION_ERROR = 0x80000004, + MBB_MESSAGE_TYPE_INDICATE_STATUS = 0x80000007 + } MBB_MESSAGE_TYPE; + +typedef +enum _MBB_COMMAND_TYPE + { + MBB_COMMAND_TYPE_QUERY = 0, + MBB_COMMAND_TYPE_SET = 1 + } MBB_COMMAND_TYPE; + +typedef struct _MBB_MESSAGE_HEADER + { + MBB_MESSAGE_TYPE MessageType; + ULONG MessageLength; + ULONG MessageTransactionId; + } MBB_MESSAGE_HEADER; + +typedef struct _MBB_MESSAGE_HEADER *PMBB_MESSAGE_HEADER; + +typedef struct _MBB_FRAGMENT_HEADER + { + ULONG TotalFragments; + ULONG CurrentFragment; + } MBB_FRAGMENT_HEADER; + +typedef struct _MBB_FRAGMENT_HEADER *PMBB_FRAGMENT_HEADER; + +typedef struct _MBB_COMMAND + { + GUID ServiceId; + ULONG CommandId; + } MBB_COMMAND; + +typedef struct _MBB_COMMAND *PMBB_COMMAND; + +typedef struct _MBB_COMMAND_HEADER + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_FRAGMENT_HEADER FragmentHeader; + MBB_COMMAND Command; + MBB_COMMAND_TYPE CommandType; + ULONG InformationBufferLength; + } MBB_COMMAND_HEADER; + +typedef struct _MBB_COMMAND_HEADER *PMBB_COMMAND_HEADER; + +typedef struct _MBB_COMMAND_FRAGMENT_HEADER + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_FRAGMENT_HEADER FragmentHeader; + } MBB_COMMAND_FRAGMENT_HEADER; + +typedef struct _MBB_COMMAND_FRAGMENT_HEADER *PMBB_COMMAND_FRAGMENT_HEADER; + +typedef struct _MBB_COMMAND_DONE_HEADER + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_FRAGMENT_HEADER FragmentHeader; + MBB_COMMAND Command; + MBB_STATUS MbbStatus; + ULONG InformationBufferLength; + } MBB_COMMAND_DONE_HEADER; + +typedef struct _MBB_COMMAND_DONE_HEADER *PMBB_COMMAND_DONE_HEADER; + +typedef struct _MBB_INDICATE_STATUS_HEADER + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_FRAGMENT_HEADER FragmentHeader; + MBB_COMMAND Command; + ULONG InformationBufferLength; + } MBB_INDICATE_STATUS_HEADER; + +typedef struct _MBB_INDICATE_STATUS_HEADER *PMBB_INDICATE_STATUS_HEADER; + +typedef struct _MBB_OPEN_MESSAGE + { + MBB_MESSAGE_HEADER MessageHeader; + ULONG MaximumControlTransfer; + } MBB_OPEN_MESSAGE; + +typedef struct _MBB_OPEN_MESSAGE *PMBB_OPEN_MESSAGE; + +typedef struct _MBB_OPEN_MESSAGE_FASTIO + { + MBB_MESSAGE_HEADER MessageHeader; + ULONG MaximumControlTransfer; + PVOID AdapterContext; + PVOID SendNetBufferListsCompleteHandler; + PVOID ReceiveNetBufferListsHandler; + } MBB_OPEN_MESSAGE_FASTIO; + +typedef struct _MBB_OPEN_MESSAGE_FASTIO *PMBB_OPEN_MESSAGE_FASTIO; + +typedef struct _MBB_CLOSE_MESSAGE + { + MBB_MESSAGE_HEADER MessageHeader; + } MBB_CLOSE_MESSAGE; + +typedef struct _MBB_CLOSE_MESSAGE *PMBB_CLOSE_MESSAGE; + +typedef struct _MBB_OPEN_DONE + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_STATUS MbbStatus; + } MBB_OPEN_DONE; + +typedef struct _MBB_OPEN_DONE *PMBB_OPEN_DONE; + +typedef struct _MBB_OPEN_DONE_FASTIO + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_STATUS MbbStatus; + PVOID ModemContext; + PVOID SendNetBufferListsHandler; + PVOID ReturnNetBufferListsHandler; + PVOID CancelSendHandler; + PVOID HaltHandler; + PVOID PauseHandler; + PVOID ShutdownHandler; + PVOID ResetHandler; + PVOID RestartHandler; + } MBB_OPEN_DONE_FASTIO; + +typedef struct _MBB_OPEN_DONE_FASTIO *PMBB_OPEN_DONE_FASTIO; + +typedef struct _MBB_CLOSE_DONE + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_STATUS MbbStatus; + } MBB_CLOSE_DONE; + +typedef struct _MBB_CLOSE_DONE *PMBB_CLOSE_DONE; + +typedef struct _MBB_ERROR_MESSAGE + { + MBB_MESSAGE_HEADER MessageHeader; + MBB_ERROR ErrorCode; + } MBB_ERROR_MESSAGE; + +typedef struct _MBB_ERROR_MESSAGE *PMBB_ERROR_MESSAGE; + +typedef +enum _MBB_BASIC_CID + { + MBB_BASIC_CID_DEVICE_CAPS = 1, + MBB_BASIC_CID_SUBSCRIBER_READY_INFO = 2, + MBB_BASIC_CID_RADIO_STATE = 3, + MBB_BASIC_CID_PIN_INFO = 4, + MBB_BASIC_CID_PIN_LIST = 5, + MBB_BASIC_CID_HOME_PROVIDER = 6, + MBB_BASIC_CID_PREFERRED_PROVIDERS = 7, + MBB_BASIC_CID_VISIBLE_PROVIDERS = 8, + MBB_BASIC_CID_REGISTER_STATE = 9, + MBB_BASIC_CID_PACKET_SERVICE = 10, + MBB_BASIC_CID_SIGNAL_STATE = 11, + MBB_BASIC_CID_CONNECT = 12, + MBB_BASIC_CID_PROVISIONED_CONTEXTS = 13, + MBB_BASIC_CID_SERVICE_ACTIVATION = 14, + MBB_BASIC_CID_IP_ADDRESS_INFO = 15, + MBB_BASIC_CID_DEVICE_SERVICES = 16, + MBB_BASIC_CID_NOTIFY_DEVICE_SERVICE_UPDATES = 19, + MBB_BASIC_CID_PACKET_STATISTICS = 20, + MBB_BASIC_CID_NETWORK_IDLE_HINT = 21, + MBB_BASIC_CID_EMERGENCY_MODE = 22, + MBB_BASIC_CID_PACKET_FILTERS = 23, + MBB_BASIC_CID_MULTICARRIER_PROVIDERS = 24, + MBB_BASIC_CID_MAXIMUM = ( MBB_BASIC_CID_MULTICARRIER_PROVIDERS + 1 ) + } MBB_BASIC_CID; + +typedef +enum _MBB_SMS_CID + { + MBB_SMS_CID_CONFIGURATION = 1, + MBB_SMS_CID_READ = 2, + MBB_SMS_CID_SEND = 3, + MBB_SMS_CID_DELETE = 4, + MBB_SMS_CID_STATUS = 5, + MBB_SMS_CID_MAXIMUM = ( MBB_SMS_CID_STATUS + 1 ) + } MBB_SMS_CID; + +typedef +enum _MBB_VENDOR_CID + { + MBB_VENDOR_CID_MS_VENDOR_SPECIFIC = 1, + MBB_VENDOR_CID_MAXIMUM = ( MBB_VENDOR_CID_MS_VENDOR_SPECIFIC + 1 ) + } MBB_VENDOR_CID; + +typedef +enum _MBB_USSD_CID + { + MBB_USSD_CID_USSD = 1, + MBB_USSD_CID_MAXIMUM = ( MBB_USSD_CID_USSD + 1 ) + } MBB_USSD_CID; + +typedef +enum _MBB_PHONEBOOK_CID + { + MBB_PHONEBOOK_CID_CONFIGURATION = 1, + MBB_PHONEBOOK_CID_READ = 2, + MBB_PHONEBOOK_CID_DELETE = 3, + MBB_PHONEBOOK_CID_SAVE = 4, + MBB_PHONEBOOK_CID_MAXIMUM = ( MBB_PHONEBOOK_CID_SAVE + 1 ) + } MBB_PHONEBOOK_CID; + +typedef +enum _MBB_SAT_CID + { + MBB_SAT_CID_PAC = 1, + MBB_SAT_CID_TERMINAL_RESPONSE = 2, + MBB_SAT_CID_ENVELOPE = 3, + MBB_SAT_CID_MAXIMUM = ( MBB_SAT_CID_ENVELOPE + 1 ) + } MBB_SAT_CID; + +typedef +enum _MBB_AUTH_CID + { + MBB_AUTH_CID_AKA = 1, + MBB_AUTH_CID_AKAP = 2, + MBB_AUTH_CID_SIM = 3, + MBB_AUTH_CID_MAXIUM = ( MBB_AUTH_CID_SIM + 1 ) + } MBB_AUTH_CID; + +typedef +enum _MBB_DSS_CID + { + MBB_DSS_CID_CONNECT = 1, + MBB_DSS_CID_MAXIUM = ( MBB_DSS_CID_CONNECT + 1 ) + } MBB_DSS_CID; + +typedef +enum _MBB_MULTICARRIER_CID + { + MBB_MULTICARRIER_CID_CAPABILITIES = 1, + MBB_MULTICARRIER_CID_LOCATION_INFO = 2, + MBB_MULTICARRIER_CID_CURRENT_CID_LIST = 3, + MBB_MULTICARRIER_CID_MAXIMUM = ( MBB_MULTICARRIER_CID_CURRENT_CID_LIST + 1 ) + } MBB_MULTICARRIER_CID; + +typedef +enum _MBB_HOSTSHUTDOWN_CID + { + MBB_HOSTSHUTDOWN_CID_ONE = 1, + MBB_HOSTSHUTDOWN_CID_PRESHUTDOWN = 2, + MBB_HOSTSHUTDOWN_CID_MAX = ( MBB_HOSTSHUTDOWN_CID_PRESHUTDOWN + 1 ) + } MBB_HOSTSHUTDOWN_CID; + +typedef +enum _MBB_VOICEEXTENSIONS_CID + { + MBB_VOICEEXTENSIONS_CID_SYS_CAPS = 1, + MBB_VOICEEXTENSIONS_CID_DEVICE_CAPS_V2 = 2, + MBB_VOICEEXTENSIONS_CID_SYS_SLOTMAPPINGS = 3, + MBB_VOICEEXTENSIONS_CID_SLOT_INFO_STATUS = 4, + MBB_VOICEEXTENSIONS_CID_DEVICE_BINDINGS = 5, + MBB_VOICEEXTENSIONS_CID_REGISTER_STATE_V2 = 6, + MBB_VOICEEXTENSIONS_CID_IMS_VOICE_STATE = 7, + MBB_VOICEEXTENSIONS_CID_SIGNAL_STATE_V2 = 8, + MBB_VOICEEXTENSIONS_CID_LOCATION_STATE = 9, + MBB_VOICEEXTENSIONS_CID_NITZ = 10, + MBB_VOICEEXTENSIONS_CID_MAX = ( MBB_VOICEEXTENSIONS_CID_NITZ + 1 ) + } MBB_VOICEEXTENSIONS_CID; + +typedef +enum _MBB_UICC_CID + { + MBB_UICC_CID_ATR = 1, + MBB_UICC_CID_OPEN_CHANNEL = 2, + MBB_UICC_CID_CLOSE_CHANNEL = 3, + MBB_UICC_CID_APDU = 4, + MBB_UICC_CID_TERMINAL_CAPABILITY = 5, + MBB_UICC_CID_RESET = 6, + MBB_UICC_CID_APP_LIST = 7, + MBB_UICC_CID_FILE_STATUS = 8, + MBB_UICC_CID_ACCESS_BINARY = 9, + MBB_UICC_CID_ACCESS_RECORD = 10, + MBB_UICC_CID_MAXIMUM = ( MBB_UICC_CID_ACCESS_RECORD + 1 ) + } MBB_UICC_CID; + +typedef +enum _MBB_SAR_CID + { + MBB_SAR_CID_CONFIG = 1, + MBB_SAR_CID_TRANSMISSION_STATUS = 2, + MBB_SAR_CID_MAXIMUM = ( MBB_SAR_CID_TRANSMISSION_STATUS + 1 ) + } MBB_SAR_CID; + +typedef +enum _MBB_BASICCONNECTEXT_CID + { + MBB_BASICCONNECTEXT_CID_PROVISIONED_CONTEXT_V2 = 1, + MBB_BASICCONNECTEXT_CID_NETWORK_BLACKLIST = 2, + MBB_BASICCONNECTEXT_CID_LTE_ATTACH_CONFIG = 3, + MBB_BASICCONNECTEXT_CID_LTE_ATTACH_STATUS = 4, + MBB_BASICCONNECTEXT_CID_SYS_CAPS = 5, + MBB_BASICCONNECTEXT_CID_DEVICE_CAPS_V2 = 6, + MBB_BASICCONNECTEXT_CID_DEVICE_SLOT_MAPPINGS = 7, + MBB_BASICCONNECTEXT_CID_SLOT_INFO_STATUS = 8, + MBB_BASICCONNECTEXT_CID_PCO = 9, + MBB_BASICCONNECTEXT_CID_DEVICE_RESET = 10, + MBB_BASICCONNECTEXT_CID_BASE_STATIONS_INFO = 11, + MBB_BASICCONNECTEXT_CID_LOCATION_INFO_STATUS = 12, + MBB_BASICCONNECTEXT_CID_MODEM_LOGGING_CONFIG = 13, + MBB_BASICCONNECTEXT_CID_PIN_INFO_EX2 = 14, + MBB_BASICCONNECTEXT_CID_VERSION = 15, + MBB_BASICCONNECTEXT_CID_MODEM_CONFIG = 16, + MBB_BASICCONNECTEXT_CID_REGISTRATION_PARAMS = 17, + MBB_BASICCONNECTEXT_CID_NETWORK_PARAMS = 18, + MBB_BASICCONNECTEXT_CID_WAKE_REASON = 19, + MBB_BASICCONNECTEXT_CID_MAXIMUM = ( MBB_BASICCONNECTEXT_CID_WAKE_REASON + 1 ) + } MBB_BASICCONNECTEXT_CID; + +typedef +enum _MBB_DEVICE_TYPE + { + MbbDeviceTypeUnknown = 0, + MbbDeviceTypeEmbedded = 1, + MbbDeviceTypeRemovable = 2, + MbbDeviceTypeRemote = 3, + MbbDeviceTypeMaximum = ( MbbDeviceTypeRemote + 1 ) + } MBB_DEVICE_TYPE; + +typedef +enum _MBB_CELLULAR_CLASS + { + MbbCellularClassInvalid = 0, + MbbCellularClassGsm = 1, + MbbCellularClassCdma = 2, + MbbCellularClassMaximum = ( MbbCellularClassCdma + 1 ) + } MBB_CELLULAR_CLASS; + +typedef +enum _MBB_VOICE_CLASS + { + MbbVoiceClassInvalid = 0, + MbbVoiceClassNoVoice = 1, + MbbVoiceClassSeparateVoiceData = 2, + MbbVoiceClassSimultaneousVoiceData = 3, + MbbVoiceClassMaximum = ( MbbVoiceClassSimultaneousVoiceData + 1 ) + } MBB_VOICE_CLASS; + +typedef +enum _MBB_SIM_CLASS + { + MbbSimClassInvalid = 0, + MbbSimClassSimLogical = 1, + MbbSimClassSimRemovable = 2, + MbbSimClassMaximum = ( MbbSimClassSimRemovable + 1 ) + } MBB_SIM_CLASS; + +typedef +enum _MBB_DATA_CLASS_VALUE + { + MbbDataClassNone = 0, + MbbDataClassGprs = 0x1, + MbbDataClassEdge = 0x2, + MbbDataClassUmts = 0x4, + MbbDataClassHsdpa = 0x8, + MbbDataClassHsupa = 0x10, + MbbDataClassLte = 0x20, + MbbDataClass5G = 0x40, + MbbDataClass_UNUSED = 0x80, + MbbDataClassTdScdma = 0x1000, + MbbDataClass1xRtt = 0x10000, + MbbDataClass1xEvdo = 0x20000, + MbbDataClass1xEvdoReva = 0x40000, + MbbDataClass1xEvdv = 0x80000, + MbbDataClass3xRtt = 0x100000, + MbbDataClass1xEvdoRevb = 0x200000, + MbbDataClassUmb = 0x400000, + MbbDataClassCustom = 0x80000000 + } MBB_DATA_CLASS_VALUE; + +typedef +enum _MBB_DATA_SUBCLASS_VALUE + { + MbbDataSubClassNone = 0, + MbbDataSubClass5GENDC = 0x1, + MbbDataSubClass5GNR = 0x2, + MbbDataSubClass5GNEDC = 0x4, + MbbDataSubClass5GELTE = 0x8, + MbbDataSubClassNGENDC = 0x10 + } MBB_DATA_SUBCLASS_VALUE; + +typedef +enum _MBB_FREQUENCY_RANGE + { + MbbFrequencyRangeUnknown = 0, + MbbFrequencyRange1 = 1, + MbbFrequencyRange2 = 2, + MbbFrequencyRange1AndRange2 = 3, + MbbFrequencyRangeMaximum = ( MbbFrequencyRange1AndRange2 + 1 ) + } MBB_FREQUENCY_RANGE; + +typedef +enum _MBB_BAND_CLASS_VALUE + { + MbbBandClassUnknown = 0, + MbbBandClass0 = 0x1, + MbbBandClassI = 0x2, + MbbBandClassII = 0x4, + MbbBandClassIII = 0x8, + MbbBandClassIV = 0x10, + MbbBandClassV = 0x20, + MbbBandClassVI = 0x40, + MbbBandClassVII = 0x80, + MbbBandClassVIII = 0x100, + MbbBandClassIX = 0x200, + MbbBandClassX = 0x400, + MbbBandClassXI = 0x800, + MbbBandClassXII = 0x1000, + MbbBandClassXIII = 0x2000, + MbbBandClassXIV = 0x4000, + MbbBandClassXV = 0x8000, + MbbBandClassXVI = 0x10000, + MbbBandClassXVII = 0x20000, + MbbBandClassCustom = 0x80000000 + } MBB_BAND_CLASS_VALUE; + +typedef +enum _MBB_SMS_CAPS_VALUE + { + MbbSmsCapsNone = 0, + MbbSmsCapsPduReceive = 0x1, + MbbSmsCapsPduSend = 0x2, + MbbSmsCapsTextReceive = 0x4, + MbbSmsCapsTextSend = 0x8 + } MBB_SMS_CAPS_VALUE; + +typedef +enum _MBB_CONTROL_CAPS_VALUE + { + MbbControlCapsNone = 0, + MbbControlCapsRegManual = 0x1, + MbbControlCapsHwRadioSwitch = 0x2, + MbbControlCapsCdmaMobileIp = 0x4, + MbbControlCapsCdmaSimpleIp = 0x8, + MbbControlCapsMultiCarrier = 0x10, + MbbControlCapsESIM = 0x20, + MbbControlCapsUEPolicyRouteSelection = 0x40, + MbbControlCapsSIMHotSwapCapable = 0x80 + } MBB_CONTROL_CAPS_VALUE; + +typedef +enum _MBB_READY_STATE + { + MbbReadyStateOff = 0, + MbbReadyStateInitialized = 1, + MbbReadyStateSimNotInserted = 2, + MbbReadyStateBadSim = 3, + MbbReadyStateFailure = 4, + MbbReadyStateNotActivated = 5, + MbbReadyStateDeviceLocked = 6, + MbbReadyStateNoEsimProfile = 7, + MbbReadyStateMaximum = ( MbbReadyStateNoEsimProfile + 1 ) + } MBB_READY_STATE; + +typedef +enum _MBB_READY_INFO_FLAGS + { + MbbReadyInfoFlagsNone = 0, + MbbReadyInfoFlagsUniqueId = 1 + } MBB_READY_INFO_FLAGS; + +typedef +enum _MBB_EMERGENCY_MODE + { + MbbEmergencyModeOff = 0, + MbbEmergencyModeOn = 1, + MbbEmergencyModeMaximum = ( MbbEmergencyModeOn + 1 ) + } MBB_EMERGENCY_MODE; + +typedef +enum _MBB_RADIO_STATE + { + MbbRadioStateOff = 0, + MbbRadioStateOn = 1, + MbbRadioStateMaximum = ( MbbRadioStateOn + 1 ) + } MBB_RADIO_STATE; + +typedef +enum _MBB_PIN_TYPE + { + MbbPinTypeNone = 0, + MbbPinTypeCustom = 1, + MbbPinTypePin1 = 2, + MbbPinTypePin2 = 3, + MbbPinTypeDeviceSimPin = 4, + MbbPinTypeDeviceFirstSimPin = 5, + MbbPinTypeNetworkPin = 6, + MbbPinTypeNetworkSubsetPin = 7, + MbbPinTypeSvcProviderPin = 8, + MbbPinTypeCorporatePin = 9, + MbbPinTypeSubsidyLock = 10, + MbbPinTypePuk1 = 11, + MbbPinTypePuk2 = 12, + MbbPinTypeDeviceFirstSimPuk = 13, + MbbPinTypeNetworkPuk = 14, + MbbPinTypeNetworkSubsetPuk = 15, + MbbPinTypeSvcProviderPuk = 16, + MbbPinTypeCorporatePuk = 17, + MbbPinTypeNev = 18, + MbbPinTypeAdm = 19, + MbbPinTypeMaximum = ( MbbPinTypeAdm + 1 ) + } MBB_PIN_TYPE; + +typedef +enum _MBB_PIN_STATE + { + MbbPinStateUnlocked = 0, + MbbPinStateLocked = 1, + MbbPinStateMaximum = ( MbbPinStateLocked + 1 ) + } MBB_PIN_STATE; + +typedef +enum _MBB_PIN_OPERATION + { + MbbPinOperationEnter = 0, + MbbPinOperationEnable = 1, + MbbPinOperationDisable = 2, + MbbPinOperationChange = 3, + MbbPinOperationMaximum = ( MbbPinOperationChange + 1 ) + } MBB_PIN_OPERATION; + +typedef +enum _MBB_PIN_MODE + { + MbbPinModeNotSupported = 0, + MbbPinModeEnabled = 1, + MbbPinModeDisabled = 2, + MbbPinModeMaximum = ( MbbPinModeDisabled + 1 ) + } MBB_PIN_MODE; + +typedef +enum _MBB_PIN_FORMAT + { + MbbPinFormatUnknown = 0, + MbbPinFormatNumeric = 1, + MbbPinFormatAlphaNumeric = 2, + MbbPinFormatMaximum = ( MbbPinFormatAlphaNumeric + 1 ) + } MBB_PIN_FORMAT; + +typedef +enum _MBB_PROVIDER_STATE_VALUE + { + MbbProviderStateHome = 0x1, + MbbProviderStateForbidden = 0x2, + MbbProviderStatePreferred = 0x4, + MbbProviderStateVisible = 0x8, + MbbProviderStateRegistered = 0x10, + MbbProviderStatePreferredMulticarrier = 0x20 + } MBB_PROVIDER_STATE_VALUE; + +typedef +enum _MBB_REGISTER_ACTION + { + MbbRegisterActionAutomatic = 0, + MbbRegisterActionManual = 1, + MbbRegisterActionMaximum = ( MbbRegisterActionManual + 1 ) + } MBB_REGISTER_ACTION; + +typedef +enum _MBB_REGISTER_STATE + { + MbbRegisterStateUnknown = 0, + MbbRegisterStateDeregistered = 1, + MbbRegisterStateSearching = 2, + MbbRegisterStateHome = 3, + MbbRegisterStateRoaming = 4, + MbbRegisterStatePartner = 5, + MbbRegisterStateDenied = 6, + MbbRegisterStateMaximum = ( MbbRegisterStateDenied + 1 ) + } MBB_REGISTER_STATE; + +typedef +enum _MBB_REGISTER_MODE + { + MbbRegisterModeUnknown = 0, + MbbRegisterModeAutomatic = 1, + MbbRegisterModeManual = 2, + MbbRegisterModeMaximum = ( MbbRegisterModeManual + 1 ) + } MBB_REGISTER_MODE; + +typedef +enum _MBB_PACKET_SERVICE_ACTION + { + MbbPacketServiceActionAttach = 0, + MbbPacketServiceActionDetach = 1, + MbbPacketServiceActionMaximum = ( MbbPacketServiceActionDetach + 1 ) + } MBB_PACKET_SERVICE_ACTION; + +typedef +enum _MBB_PACKET_SERVICE_STATE + { + MbbPacketServiceStateUnknown = 0, + MbbPacketServiceStateAttaching = 1, + MbbPacketServiceStateAttached = 2, + MbbPacketServiceStateDetaching = 3, + MbbPacketServiceStateDetached = 4, + MbbPacketServiceStateMaximum = ( MbbPacketServiceStateDetached + 1 ) + } MBB_PACKET_SERVICE_STATE; + +typedef +enum _MBB_CONTEXT_IP_TYPE + { + MbbContextIPTypeDefault = 0, + MbbContextIPTypeIPv4 = 1, + MbbContextIPTypeIPv6 = 2, + MbbContextIPTypeIPv4v6 = 3, + MbbContextIPTypeIPv4AndIPv6 = 4, + MbbContextIPTypeMaximum = ( MbbContextIPTypeIPv4AndIPv6 + 1 ) + } MBB_CONTEXT_IP_TYPE; + +typedef +enum _MBB_ACTIVATION_COMMAND + { + MbbActivationCommandDeactivate = 0, + MbbActivationCommandActivate = 1, + MbbActivationCommandCancel = 2, + MbbActivationCommandMaximum = ( MbbActivationCommandCancel + 1 ) + } MBB_ACTIVATION_COMMAND; + +typedef +enum _MBB_COMPRESSION + { + MbbCompressionNone = 0, + MbbCompressionEnable = 1, + MbbCompressionMaximum = ( MbbCompressionEnable + 1 ) + } MBB_COMPRESSION; + +typedef +enum _MBB_AUTH_PROTOCOL + { + MbbAuthProtocolNone = 0, + MbbAuthProtocolPap = 1, + MbbAuthProtocolChap = 2, + MbbAuthProtocolMsChapV2 = 3, + MbbAuthProtocolMaximum = ( MbbAuthProtocolMsChapV2 + 1 ) + } MBB_AUTH_PROTOCOL; + +typedef +enum _MBB_ACTIVATION_STATE + { + MbbActivationStateUnknown = 0, + MbbActivationStateActivated = 1, + MbbActivationStateActivating = 2, + MbbActivationStateDeactivated = 3, + MbbActivationStateDeactivating = 4, + MbbActivationStateMaximum = ( MbbActivationStateDeactivating + 1 ) + } MBB_ACTIVATION_STATE; + +typedef +enum _MBB_VOICE_CALL_STATE + { + MbbVoiceCallStateNone = 0, + MbbVoiceCallStateInProgress = 1, + MbbVoiceCallStateHangUp = 2, + MbbVoiceCallStateMaximum = ( MbbVoiceCallStateHangUp + 1 ) + } MBB_VOICE_CALL_STATE; + +typedef +enum _MBB_SMS_FORMAT + { + MbbSmsFormatPdu = 0, + MbbSmsFormatCdma = 1, + MbbSmsFormatMaximum = ( MbbSmsFormatCdma + 1 ) + } MBB_SMS_FORMAT; + +typedef +enum _MBB_SMS_FLAG + { + MbbSmsFlagAll = 0, + MbbSmsFlagIndex = 1, + MbbSmsFlagNew = 2, + MbbSmsFlagOld = 3, + MbbSmsFlagSent = 4, + MbbSmsFlagDraft = 5, + MbbSmsFlagMaximum = ( MbbSmsFlagDraft + 1 ) + } MBB_SMS_FLAG; + +typedef +enum _MBB_SMS_CDMA_LANGUAGE + { + MbbSmsCdmaLanguageUnknown = 0, + MbbSmsCdmaLanguageEnglish = 1, + MbbSmsCdmaLanguageFrench = 2, + MbbSmsCdmaLanguageSpanish = 3, + MbbSmsCdmaLanguageJapanese = 4, + MbbSmsCdmaLanguageKorean = 5, + MbbSmsCdmaLanguageChinese = 6, + MbbSmsCdmaLanguageHebrew = 7, + MbbSmsCdmaLanguageMaximum = ( MbbSmsCdmaLanguageHebrew + 1 ) + } MBB_SMS_CDMA_LANGUAGE; + +typedef +enum _MBB_SMS_CDMA_ENCODING + { + MbbSmsCdmaEncodingOctet = 0, + MbbSmsCdmaEncodingEpm = 1, + MbbSmsCdmaEncoding7BitAscii = 2, + MbbSmsCdmaEncodingIa5 = 3, + MbbSmsCdmaEncodingUnicode = 4, + MbbSmsCdmaEncodingShiftJis = 5, + MbbSmsCdmaEncodingKorean = 6, + MbbSmsCdmaEncodingLatinHebrew = 7, + MbbSmsCdmaEncodingLatin = 8, + MbbSmsCdmaEncodingGsm7Bit = 9, + MbbSmsCdmaEncodingMaximum = ( MbbSmsCdmaEncodingGsm7Bit + 1 ) + } MBB_SMS_CDMA_ENCODING; + +typedef +enum _MBB_SMS_MESSAGE_STATUS + { + MbbSmsMessageStatusNew = 0, + MbbSmsMessageStatusOld = 1, + MbbSmsMessageStatusDraft = 2, + MbbSmsMessageStatusSent = 3, + MbbSmsMessageStatusMaximum = ( MbbSmsMessageStatusSent + 1 ) + } MBB_SMS_MESSAGE_STATUS; + +typedef +enum _MBB_REG_FLAGS_VALUE + { + MbbRegFlagsNone = 0, + MbbRegFlagsNoManualReg = 0x1, + MbbRegFlagsPSAutoAttach = 0x2 + } MBB_REG_FLAGS_VALUE; + +typedef +enum _MBB_SMS_STATUS_FLAGS_VALUE + { + MbbSmsFlagNone = 0, + MbbSmsFlagMessageStoreFull = 1, + MbbSmsFlagNewMessage = 2 + } MBB_SMS_STATUS_FLAGS_VALUE; + +typedef struct _MBB_STRING + { + ULONG Offset; + ULONG Size; + } MBB_STRING; + +typedef struct _MBB_STRING *PMBB_STRING; + +typedef struct _MBB_ARRAY_ELEMENT + { + ULONG Offset; + ULONG Size; + } MBB_ARRAY_ELEMENT; + +typedef struct _MBB_ARRAY_ELEMENT *PMBB_ARRAY_ELEMENT; + +typedef struct _MBB_ARRAY_ELEMENT2 + { + ULONG Size; + ULONG Offset; + } MBB_ARRAY_ELEMENT2; + +typedef struct _MBB_ARRAY_ELEMENT2 *PMBB_ARRAY_ELEMENT2; + +typedef +enum _MBB_DSS_PAYLOAD_SUPPORT + { + MbbDssPayloadNone = 0, + MbbDssPayloadHostToDevice = 0x1, + MbbDssPayloadDeviceToHost = 0x2 + } MBB_DSS_PAYLOAD_SUPPORT; + +typedef +enum _MBB_DSS_LINK_STATE + { + MbbDssLinkDeactivate = 0, + MbbDssLinkActivate = 0x1 + } MBB_DSS_LINK_STATE; + +typedef +enum _MBB_IP_CONFIGURATION_FLAGS_VALUE + { + MbbIpFlagsNone = 0, + MbbIpFlagsAddressAvailable = 0x1, + MbbIpFlagsGatewayAvailable = 0x2, + MbbIpFlagsDnsServerAvailable = 0x4, + MbbIpFlagsMTUAvailable = 0x8 + } MBB_IP_CONFIGURATION_FLAGS_VALUE; + +typedef +enum _MBB_NETWORK_IDLE_HINT_STATE + { + MbbNetworkIdleHintDisabled = 0, + MbbNetworkIdleHintEnabled = 1 + } MBB_NETWORK_IDLE_HINT_STATE; + +typedef +enum _MBB_SAR_BACKOFF_STATE + { + MbbSarBackoffStatusDisabled = 0, + MbbSarBackoffStatusEnabled = 1, + MbbSarBackoffStatusMaximum = ( MbbSarBackoffStatusEnabled + 1 ) + } MBB_SAR_BACKOFF_STATE; + +typedef +enum _MBB_SAR_CONTROL_MODE + { + MbbSarControlModeDevice = 0, + MbbSarControlModeOS = 1, + MbbSarControlModeMaximum = ( MbbSarControlModeOS + 1 ) + } MBB_SAR_CONTROL_MODE; + +typedef +enum _MBB_SAR_WIFI_HARDWARE_INTEGRATION + { + MbbSarWifiHardwareNotIntegrated = 0, + MbbSarWifiHardwareIntegrated = 1, + MbbSarWifiHardwareIntegrationMaximum = ( MbbSarWifiHardwareIntegrated + 1 ) + } MBB_SAR_WIFI_HARDWARE_INTEGRATION; + +typedef +enum _MBB_SAR_TRANSMISSION_STATUS_NOTIFICATION_STATE + { + MbbTransmissionNotificationDisabled = 0, + MbbTransmissionNotificationEnabled = 1, + MbbTransmissionNotificationMaximum = ( MbbTransmissionNotificationEnabled + 1 ) + } MBB_SAR_TRANSMISSION_STATUS_NOTIFICATION_STATE; + +typedef +enum _MBB_SAR_TRANSMISSION_STATUS + { + MbbTransmissionStateInactive = 0, + MbbTransmissionStateActive = 1, + MbbTransmissionStateMaximum = ( MbbTransmissionStateActive + 1 ) + } MBB_SAR_TRANSMISSION_STATUS; + +typedef +enum _MBB_BASICCONNECTEXT_CONTEXT_ROAMING_CONTROL + { + MbbMsContextRoamingControlHomeOnly = 0, + MbbMsContextRoamingControlPartnerOnly = 1, + MbbMsContextRoamingControlNonPartnerOnly = 2, + MbbMsContextRoamingControlHomeAndPartner = 3, + MbbMsContextRoamingControlHomeAndNonPartner = 4, + MbbMsContextRoamingControlPartnerAndNonPartner = 5, + MbbMsContextRoamingControlAllowAll = 6, + MbbMsContextRoamingControlMaximum = ( MbbMsContextRoamingControlAllowAll + 1 ) + } MBB_BASICCONNECTEXT_CONTEXT_ROAMING_CONTROL; + +typedef +enum _MBB_BASICCONNECTEXT_CONTEXT_MEDIA_TYPE + { + MbbMsContextMediaTypeCellularOnly = 0, + MbbMsContextMediaTypeWifiOnly = 1, + MbbMsContextMediaTypeAll = 2, + MbbMsContextMediaTypeMaximum = ( MbbMsContextMediaTypeAll + 1 ) + } MBB_BASICCONNECTEXT_CONTEXT_MEDIA_TYPE; + +typedef +enum _MBB_BASICCONNECTEXT_CONTEXT_ENABLE + { + MbbMsContextDisabled = 0, + MbbMsContextEnabled = 1, + MbbMsContextEnableMaximum = ( MbbMsContextEnabled + 1 ) + } MBB_BASICCONNECTEXT_CONTEXT_ENABLE; + +typedef +enum _MBB_BASICCONNECTEXT_CONTEXT_SOURCE + { + MbbMsContextSourceAdmin = 0, + MbbMsContextSourceUser = 1, + MbbMsContextSourceOperator = 2, + MbbMsContextSourceModem = 3, + MbbMsContextSourceDevice = 4, + MbbMsContextSourceMaximum = ( MbbMsContextSourceDevice + 1 ) + } MBB_BASICCONNECTEXT_CONTEXT_SOURCE; + +typedef +enum _MBB_BASICCONNECTEXT_CONTEXT_OPERATIONS + { + MbbMsContextOperationDefault = 0, + MbbMsContextOperationDelete = 1, + MbbMsContextOperationRestoreFactory = 2, + MbbMsContextOperationMaximum = ( MbbMsContextOperationRestoreFactory + 1 ) + } MBB_BASICCONNECTEXT_CONTEXT_OPERATIONS; + +typedef +enum _MBB_BASICCONNECTEXT_NETWORK_BLACKLIST_STATE + { + MbbMsNetworkBlacklistStateNotActuated = 0, + MbbMsNetworkBlacklistSIMProviderActuated = 1, + MbbMsNetworkBlacklistNetworkProviderActuated = 2, + MbbMsNetworkBlacklistStateMaximum = ( MbbMsNetworkBlacklistNetworkProviderActuated + 1 ) + } MBB_BASICCONNECTEXT_NETWORK_BLACKLIST_STATE; + +typedef +enum _MBB_BASICCONNECTEXT_NETWORK_BLACKLIST_TYPE + { + MbbMsNetworkBlacklistTypeSIM = 0, + MbbMsNetworkBlacklistTypeNetwork = 1, + MbbMsNetworkBlacklistTypeMaximum = ( MbbMsNetworkBlacklistTypeNetwork + 1 ) + } MBB_BASICCONNECTEXT_NETWORK_BLACKLIST_TYPE; + +typedef +enum _MBB_BASICCONNECTEXT_LTEATTACH_ROAMING_CONTROL + { + MbbMsLteAttachContextRoamingControlHome = 0, + MbbMsLteAttachContextRoamingControlPartner = 1, + MbbMsLteAttachContextRoamingControlNonPartner = 2, + MbbMsLteAttachContextRoamingControlMaximum = ( MbbMsLteAttachContextRoamingControlNonPartner + 1 ) + } MBB_BASICCONNECTEXT_LTEATTACH_ROAMING_CONTROL; + +typedef +enum _MBB_BASICCONNECTEXT_LTEATTACH_CONTEXT_OPERATIONS + { + MbbMsLteAttachContextOperationDefault = 0, + MbbMsLteAttachContextOperationRestoreFactory = 1, + MbbMsLteAttachContextOperationMaximum = ( MbbMsLteAttachContextOperationRestoreFactory + 1 ) + } MBB_BASICCONNECTEXT_LTEATTACH_CONTEXT_OPERATIONS; + +typedef +enum _MBB_BASICCONNECTEXT_LTEATTACH_STATE + { + MbbMsLteAttachStateDetached = 0, + MbbMsLteAttachStateAttached = 1, + MbbMsLteAttachStateMaximum = ( MbbMsLteAttachStateAttached + 1 ) + } MBB_BASICCONNECTEXT_LTEATTACH_STATE; + +typedef +enum _MBB_BASICCONNECTEXT_UICCSLOT_STATE + { + MbbMsUiccSlotStateUnknown = 0, + MbbMsUiccSlotStateOffEmpty = 1, + MbbMsUiccSlotStateOff = 2, + MbbMsUiccSlotStateEmpty = 3, + MbbMsUiccSlotStateNotReady = 4, + MbbMsUiccSlotStateActive = 5, + MbbMsUiccSlotStateError = 6, + MbbMsUiccSlotStateActiveEsim = 7, + MbbMsUiccSlotStateActiveEsimNoProfiles = 8 + } MBB_BASICCONNECTEXT_UICCSLOT_STATE; + +typedef +enum _MBB_BASICCONNECTEXT_MODEM_LOGGING_LEVEL_CONFIG + { + MbbMsModemLoggingLevelProd = 0, + MbbMsModemLoggingLevelLabVerbose = 1, + MbbMsModemLoggingLevelLabMedium = 2, + MbbMsModemLoggingLevelLabLow = 3, + MbbMsModemLoggingLevelOem = 4, + MbbMsModemLoggingLevelMaximum = ( MbbMsModemLoggingLevelOem + 1 ) + } MBB_BASICCONNECTEXT_MODEM_LOGGING_LEVEL_CONFIG; + +typedef +enum _MBB_PCO_TYPE + { + MbbPcoTypeComplete = 0, + MbbPcoTypePartial = 1, + MbbPcoTypeMaximum = ( MbbPcoTypePartial + 1 ) + } MBB_PCO_TYPE; + +typedef struct _MBB_DEVICE_CAPS + { + MBB_DEVICE_TYPE DeviceType; + MBB_CELLULAR_CLASS CellularClass; + MBB_VOICE_CLASS VoiceClass; + MBB_SIM_CLASS SimClass; + ULONG DataClass; + ULONG SmsCaps; + ULONG ControlCaps; + ULONG dwMaxSessions; + MBB_STRING CustomDataClass; + MBB_STRING DeviceIdString; + MBB_STRING FirmwareInfo; + MBB_STRING HardwareInfo; + UCHAR DataBuffer[ 1 ]; + } MBB_DEVICE_CAPS; + +typedef struct _MBB_DEVICE_CAPS *PMBB_DEVICE_CAPS; + +typedef struct _MBB_SUBSCRIBER_READY_INFO + { + MBB_READY_STATE ReadyState; + MBB_STRING SubscriberId; + MBB_STRING SimIccId; + MBB_READY_INFO_FLAGS ReadyInfoFlags; + ULONG TelephoneNumberCount; + MBB_STRING TelephoneNumbers[ 1 ]; + } MBB_SUBSCRIBER_READY_INFO; + +typedef struct _MBB_SUBSCRIBER_READY_INFO *PMBB_SUBSCRIBER_READY_INFO; + +typedef +enum _MBB_SUBSCRIBER_READY_STATUS_FLAGS + { + MbbSubscriberReadyStatusFlagNone = 0, + MbbSubscriberReadyStatusFlagESim = 0x1, + MbbSubscriberReadyStatusFlagSIMRemovabilityKnown = 0x2, + MbbSubscriberReadyStatusFlagSIMRemovable = 0x4 + } MBB_SUBSCRIBER_READY_STATUS_FLAGS; + +typedef struct _MBB_SUBSCRIBER_READY_INFO_EX3 + { + MBB_READY_STATE ReadyState; + MBB_SUBSCRIBER_READY_STATUS_FLAGS StatusFlags; + MBB_STRING SubscriberId; + MBB_STRING SimIccId; + MBB_READY_INFO_FLAGS ReadyInfoFlags; + ULONG TelephoneNumberCount; + MBB_STRING TelephoneNumbers[ 1 ]; + } MBB_SUBSCRIBER_READY_INFO_EX3; + +typedef struct _MBB_SUBSCRIBER_READY_INFO_EX3 *PMBB_SUBSCRIBER_READY_INFO_EX3; + +typedef struct _MBB_QUERY_RADIO_STATE + { + MBB_RADIO_STATE HwRadioState; + MBB_RADIO_STATE SwRadioState; + } MBB_QUERY_RADIO_STATE; + +typedef struct _MBB_QUERY_RADIO_STATE *PMBB_QUERY_RADIO_STATE; + +typedef struct _MBB_PIN_INFO + { + MBB_PIN_TYPE PinType; + MBB_PIN_STATE PinState; + ULONG AttemptsRemaining; + } MBB_PIN_INFO; + +typedef struct _MBB_PIN_INFO *PMBB_PIN_INFO; + +typedef struct _MBB_PIN_ACTION + { + MBB_PIN_TYPE PinType; + MBB_PIN_OPERATION PinOperation; + MBB_STRING Pin; + MBB_STRING NewPin; + UCHAR DataBuffer[ 1 ]; + } MBB_PIN_ACTION; + +typedef struct _MBB_PIN_ACTION *PMBB_PIN_ACTION; + +typedef struct _MBB_PIN_DESCRIPTION + { + MBB_PIN_MODE PinMode; + MBB_PIN_FORMAT PinFormat; + ULONG PinLengthMin; + ULONG PinLengthMax; + } MBB_PIN_DESCRIPTION; + +typedef struct _MBB_PIN_DESCRIPTION *PMBB_PIN_DESCRIPTION; + +typedef struct _MBB_PIN_LIST + { + MBB_PIN_DESCRIPTION PinDescPin1; + MBB_PIN_DESCRIPTION PinDescPin2; + MBB_PIN_DESCRIPTION PinDescDeviceSimPin; + MBB_PIN_DESCRIPTION PinDescDeviceFirstSimPin; + MBB_PIN_DESCRIPTION PinDescNetworkPin; + MBB_PIN_DESCRIPTION PinDescNetworkSubsetPin; + MBB_PIN_DESCRIPTION PinDescSvcProviderPin; + MBB_PIN_DESCRIPTION PinDescCorporatePin; + MBB_PIN_DESCRIPTION PinDescSubsidyLock; + MBB_PIN_DESCRIPTION PinDescCustom; + } MBB_PIN_LIST; + +typedef struct _MBB_PIN_LIST *PMBB_PIN_LIST; + +typedef struct _MBB_PROVIDER + { + MBB_STRING ProviderId; + ULONG ProviderState; + MBB_STRING ProviderName; + MBB_CELLULAR_CLASS CellularClass; + ULONG Rssi; + ULONG ErrorRate; + } MBB_PROVIDER; + +typedef struct _MBB_PROVIDER *PMBB_PROVIDER; + +typedef struct _MBB_PROVIDER_LIST + { + ULONG ProviderCount; + MBB_ARRAY_ELEMENT Providers[ 1 ]; + } MBB_PROVIDER_LIST; + +typedef struct _MBB_PROVIDER_LIST *PMBB_PROVIDER_LIST; + +typedef struct _MBB_REGISTRATION_STATE + { + ULONG NetworkError; + MBB_REGISTER_STATE RegisterState; + MBB_REGISTER_MODE RegisterMode; + ULONG AvailableDataClasses; + MBB_CELLULAR_CLASS CurrentCellularClass; + MBB_STRING ProviderId; + MBB_STRING ProviderName; + MBB_STRING RoamingText; + ULONG RegFlags; + UCHAR DataBuffer[ 1 ]; + } MBB_REGISTRATION_STATE; + +typedef struct _MBB_REGISTRATION_STATE *PMBB_REGISTRATION_STATE; + +typedef struct _MBB_SET_REGISTER_STATE + { + MBB_STRING ProviderId; + MBB_REGISTER_ACTION RegisterAction; + ULONG DataClass; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_REGISTER_STATE; + +typedef struct _MBB_SET_REGISTER_STATE *PMBB_SET_REGISTER_STATE; + +typedef struct _MBB_SET_PACKET_SERVICE + { + MBB_PACKET_SERVICE_ACTION PacketServiceAction; + } MBB_SET_PACKET_SERVICE; + +typedef struct _MBB_SET_PACKET_SERVICE *PMBB_SET_PACKET_SERVICE; + +typedef struct _MBB_PACKET_SERVICE + { + ULONG NetworkError; + MBB_PACKET_SERVICE_STATE PacketServiceState; + ULONG HighestAvailableDataClass; + ULONGLONG UplinkSpeed; + ULONGLONG DownlinkSpeed; + } MBB_PACKET_SERVICE; + +typedef struct _MBB_PACKET_SERVICE *PMBB_PACKET_SERVICE; + +typedef struct _MBB_PACKET_SERVICE_INFO_V2 + { + ULONG NetworkError; + MBB_PACKET_SERVICE_STATE PacketServiceState; + MBB_DATA_CLASS_VALUE CurrentDataClass; + ULONGLONG UplinkSpeed; + ULONGLONG DownlinkSpeed; + MBB_FREQUENCY_RANGE FrequencyRange; + } MBB_PACKET_SERVICE_INFO_V2; + +typedef struct _MBB_PACKET_SERVICE_INFO_V2 *PMBB_PACKET_SERVICE_INFO_V2; + +typedef struct _MBB_PLMN + { + USHORT Mcc; + USHORT Mnc; + } MBB_PLMN; + +typedef struct _MBB_PLMN *PMBB_PLMN; + +typedef struct _MBB_TAI + { + MBB_PLMN Plmn; + ULONG Tac; + } MBB_TAI; + +typedef struct _MBB_TAI *PMBB_TAI; + +typedef struct _MBB_PACKET_SERVICE_INFO_V3 + { + ULONG NetworkError; + MBB_PACKET_SERVICE_STATE PacketServiceState; + MBB_DATA_CLASS_VALUE CurrentDataClass; + ULONGLONG UplinkSpeed; + ULONGLONG DownlinkSpeed; + MBB_FREQUENCY_RANGE FrequencyRange; + MBB_DATA_SUBCLASS_VALUE CurrentDataSubClass; + MBB_TAI TrackingAreaId; + } MBB_PACKET_SERVICE_INFO_V3; + +typedef struct _MBB_PACKET_SERVICE_INFO_V3 *PMBB_PACKET_SERVICE_INFO_V3; + +typedef struct _MBB_SET_SIGNAL_INDICATION + { + ULONG RssiInterval; + ULONG RssiThreshold; + ULONG ErrorRateThreshold; + } MBB_SET_SIGNAL_INDICATION; + +typedef struct _MBB_SET_SIGNAL_INDICATION *PMBB_SET_SIGNAL_INDICATION; + +typedef struct _MBB_SIGNAL_STATE + { + ULONG Rssi; + ULONG ErrorRate; + ULONG RssiInterval; + ULONG RssiThreshold; + ULONG ErrorRateThreshold; + } MBB_SIGNAL_STATE; + +typedef struct _MBB_SIGNAL_STATE *PMBB_SIGNAL_STATE; + +typedef struct _MBB_SET_CONTEXT_STATE + { + ULONG SessionId; + MBB_ACTIVATION_COMMAND ActivationCommand; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + MBB_CONTEXT_IP_TYPE IPType; + GUID ContextType; + CHAR DataBuffer[ 1 ]; + } MBB_SET_CONTEXT_STATE; + +typedef struct _MBB_SET_CONTEXT_STATE *PMBB_SET_CONTEXT_STATE; + +typedef +enum _MBB_ACCESS_MEDIA_PREF + { + MbbAccessMediaPrefNone = 0, + MbbAccessMediaPref3GPP = 1, + MbbAccessMediaPref3GPPPreferred = 2, + MbbAccessMediaPrefMaximum = ( MbbAccessMediaPref3GPPPreferred + 1 ) + } MBB_ACCESS_MEDIA_PREF; + +typedef struct _MBB_SET_CONTEXT_STATE_EX3 + { + ULONG SessionId; + MBB_ACTIVATION_COMMAND ActivationCommand; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + MBB_CONTEXT_IP_TYPE IPType; + GUID ContextType; + MBB_ACCESS_MEDIA_PREF MediaPreference; + } MBB_SET_CONTEXT_STATE_EX3; + +typedef struct _MBB_SET_CONTEXT_STATE_EX3 *PMBB_SET_CONTEXT_STATE_EX3; + +typedef struct _MBB_QUERY_CONTEXT_EX3 + { + ULONG SessionId; + } MBB_QUERY_CONTEXT_EX3; + +typedef struct _MBB_QUERY_CONTEXT_EX3 *PMBB_QUERY_CONTEXT_EX3; + +typedef struct _MBB_CONTEXT_STATE + { + ULONG SessionId; + MBB_ACTIVATION_STATE ActivationState; + MBB_VOICE_CALL_STATE VoiceCallState; + MBB_CONTEXT_IP_TYPE IPType; + GUID ContextType; + ULONG NetworkError; + } MBB_CONTEXT_STATE; + +typedef struct _MBB_CONTEXT_STATE *PMBB_CONTEXT_STATE; + +typedef struct _MBB_CONTEXT_STATE_EX3 + { + ULONG SessionId; + MBB_ACTIVATION_STATE ActivationState; + MBB_VOICE_CALL_STATE VoiceCallState; + MBB_CONTEXT_IP_TYPE IPType; + GUID ContextType; + ULONG NetworkError; + MBB_ACCESS_MEDIA_PREF MediaPreference; + } MBB_CONTEXT_STATE_EX3; + +typedef struct _MBB_CONTEXT_STATE_EX3 *PMBB_CONTEXT_STATE_EX3; + +typedef struct _MBB_SET_CONTEXT + { + ULONG ContextId; + GUID ContextType; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + MBB_STRING ProviderId; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_CONTEXT; + +typedef struct _MBB_SET_CONTEXT *PMBB_SET_CONTEXT; + +typedef struct _MBB_CONTEXT + { + ULONG ContextId; + GUID ContextType; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + UCHAR DataBuffer[ 1 ]; + } MBB_CONTEXT; + +typedef struct _MBB_CONTEXT *PMBB_CONTEXT; + +typedef struct _MBB_CONTEXT_LIST + { + ULONG ContextCount; + MBB_ARRAY_ELEMENT Contexts[ 1 ]; + } MBB_CONTEXT_LIST; + +typedef struct _MBB_CONTEXT_LIST *PMBB_CONTEXT_LIST; + +typedef struct _MBB_SERVICE_ACTIVATION + { + CHAR VendorSpecificBuffer[ 1 ]; + } MBB_SERVICE_ACTIVATION; + +typedef struct _MBB_SERVICE_ACTIVATION *PMBB_SERVICE_ACTIVATION; + +typedef struct _MBB_SERVICE_ACTIVATION_STATUS + { + ULONG NetworkError; + CHAR VendorSpecificBuffer[ 1 ]; + } MBB_SERVICE_ACTIVATION_STATUS; + +typedef struct _MBB_SERVICE_ACTIVATION_STATUS *PMBB_SERVICE_ACTIVATION_STATUS; + +typedef struct _MBB_IPV4_ADDRESS + { + ULONG OnLinkPrefixLength; + UCHAR IPV4Address[ 4 ]; + } MBB_IPV4_ADDRESS; + +typedef struct _MBB_IPV4_ADDRESS *PMBB_IPV4_ADDRESS; + +typedef struct _MBB_IPV6_ADDRESS + { + ULONG OnLinkPrefixLength; + UCHAR IPV6Address[ 16 ]; + } MBB_IPV6_ADDRESS; + +typedef struct _MBB_IPV6_ADDRESS *PMBB_IPV6_ADDRESS; + +typedef struct _MBB_IP_ADDRESS_INFO + { + ULONG SessionId; + ULONG IPv4Flags; + ULONG IPv6Flags; + ULONG IPv4AddressCount; + ULONG IPv4AddressOffset; + ULONG IPv6AddressCount; + ULONG IPv6AddressOffset; + ULONG IPv4GatewayOffset; + ULONG IPv6GatewayOffset; + ULONG IPv4DnsServerCount; + ULONG IPv4DnsServerOffset; + ULONG IPv6DnsServerCount; + ULONG IPv6DnsServerOffset; + ULONG IPv4MTU; + ULONG IPv6MTU; + } MBB_IP_ADDRESS_INFO; + +typedef struct _MBB_IP_ADDRESS_INFO *PMBB_IP_ADDRESS_INFO; + +typedef struct _MBB_PACKET_STATISTICS + { + ULONG InDiscards; + ULONG InErrors; + ULONGLONG InOctets; + ULONGLONG InPackets; + ULONGLONG OutOctets; + ULONGLONG OutPackets; + ULONG OutErrors; + ULONG OutDiscards; + } MBB_PACKET_STATISTICS; + +typedef struct _MBB_PACKET_STATISTICS *PMBB_PACKET_STATISTICS; + +typedef +enum _MBB_VISIBLE_PROVIDERS_ACTION_VALUE + { + MbbVisibleProvidersActionFull = 0, + MbbVisibleProvidersActionMulticarrier = 0x1, + MbbVisibleProvidersActionMax = ( MbbVisibleProvidersActionMulticarrier + 1 ) + } MBB_VISIBLE_PROVIDERS_ACTION_VALUE; + +typedef struct _MBB_GET_VISIBLE_PROVIDERS + { + ULONG Action; + } MBB_GET_VISIBLE_PROVIDERS; + +typedef struct _MBB_GET_VISIBLE_PROVIDERS *PMBB_GET_VISIBLE_PROVIDERS; + +typedef +enum _MBB_SMS_STORAGE_STATE + { + MbbSmsStorageNotInitialized = 0, + MbbSmsStorageInitialized = 1 + } MBB_SMS_STORAGE_STATE; + +typedef struct _MBB_SET_SMS_CONFIGURATION + { + MBB_SMS_FORMAT SmsFormat; + MBB_STRING ScAddress; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_SMS_CONFIGURATION; + +typedef struct _MBB_SET_SMS_CONFIGURATION *PMBB_SET_SMS_CONFIGURATION; + +typedef struct _MBB_SMS_CONFIGURATION + { + MBB_SMS_STORAGE_STATE SmsStorageState; + MBB_SMS_FORMAT SmsFormat; + ULONG MaxMessages; + ULONG CdmaShortMessageSize; + MBB_STRING ScAddress; + UCHAR DataBuffer[ 1 ]; + } MBB_SMS_CONFIGURATION; + +typedef struct _MBB_SMS_CONFIGURATION *PMBB_SMS_CONFIGURATION; + +typedef struct _MBB_SMS_READ + { + MBB_SMS_FORMAT SmsFormat; + MBB_SMS_FLAG SmsFlag; + ULONG MessageIndex; + } MBB_SMS_READ; + +typedef struct _MBB_SMS_READ *PMBB_SMS_READ; + +typedef struct _MBB_SMS_CDMA_RECORD + { + ULONG MessageIndex; + MBB_SMS_MESSAGE_STATUS MessageStatus; + MBB_STRING Address; + MBB_STRING TimeStamp; + MBB_SMS_CDMA_ENCODING EncodingId; + MBB_SMS_CDMA_LANGUAGE LanguageId; + MBB_ARRAY_ELEMENT EncodedMessage; + ULONG SizeInCharacters; + UCHAR DataBuffer[ 1 ]; + } MBB_SMS_CDMA_RECORD; + +typedef struct _MBB_SMS_CDMA_RECORD *PMBB_SMS_CDMA_RECORD; + +typedef struct _MBB_SMS_PDU_RECORD + { + ULONG MessageIndex; + MBB_SMS_MESSAGE_STATUS MessageStatus; + MBB_ARRAY_ELEMENT PduData; + UCHAR DataBuffer[ 1 ]; + } MBB_SMS_PDU_RECORD; + +typedef struct _MBB_SMS_PDU_RECORD *PMBB_SMS_PDU_RECORD; + +typedef struct _MBB_SMS_RECEIVE + { + MBB_SMS_FORMAT SmsFormat; + ULONG MessageCount; + MBB_ARRAY_ELEMENT MessageElement[ 1 ]; + } MBB_SMS_RECEIVE; + +typedef struct _MBB_SMS_RECEIVE *PMBB_SMS_RECEIVE; + +typedef struct _MBB_SMS_SEND_PDU + { + MBB_ARRAY_ELEMENT PduData; + UCHAR DataBuffer[ 1 ]; + } MBB_SMS_SEND_PDU; + +typedef struct _MBB_SMS_SEND_PDU *PMBB_SMS_SEND_PDU; + +typedef struct _MBB_SMS_SEND_CDMA + { + MBB_SMS_CDMA_ENCODING EncodingId; + MBB_SMS_CDMA_LANGUAGE LanguageId; + MBB_STRING Address; + MBB_ARRAY_ELEMENT EncodedMessage; + ULONG SizeInCharacters; + UCHAR DataBuffer[ 1 ]; + } MBB_SMS_SEND_CDMA; + +typedef struct _MBB_SMS_SEND_CDMA *PMBB_SMS_SEND_CDMA; + +typedef struct _MBB_SMS_SEND + { + MBB_SMS_FORMAT SmsFormat; + /* [switch_is] */ /* [switch_type] */ union __MIDL___MIDL_itf_MbbMessages_0000_0000_0001 + { + /* [case()] */ MBB_SMS_SEND_PDU Pdu; + /* [case()] */ MBB_SMS_SEND_CDMA Cdma; + } u; + } MBB_SMS_SEND; + +typedef struct _MBB_SMS_SEND *PMBB_SMS_SEND; + +typedef struct _MBB_SMS_SEND_STATUS + { + ULONG MessageReference; + } MBB_SMS_SEND_STATUS; + +typedef struct _MBB_SMS_SEND_STATUS *PMBB_SMS_SEND_STATUS; + +typedef struct _MBB_SMS_DELETE + { + MBB_SMS_FLAG SmsFlags; + ULONG MessageIndex; + } MBB_SMS_DELETE; + +typedef struct _MBB_SMS_DELETE *PMBB_SMS_DELETE; + +typedef struct _MBB_SMS_STATUS + { + ULONG StatusFlags; + ULONG MessageIndex; + } MBB_SMS_STATUS; + +typedef struct _MBB_SMS_STATUS *PMBB_SMS_STATUS; + +typedef +enum _MBB_USSD_ACTION + { + MbbUSSDInitiate = 0, + MbbUSSDContinue = 1, + MbbUSSDCancel = 2 + } MBB_USSD_ACTION; + +typedef +enum _MBB_USSD_RESPONSE + { + MbbUSSDNoActionRequired = 0, + MbbUSSDActionRequired = 1, + MbbUSSDTerminated = 2, + MbbUSSDOtherLocalClient = 3, + MbbUSSDOperationNotSupported = 4, + MbbUSSDNetworkTimeOut = 5 + } MBB_USSD_RESPONSE; + +typedef +enum _MBB_USSD_SESSION_STATE + { + MbbUSSDNewSession = 0, + MbbUSSDExistingSession = 1 + } MBB_USSD_SESSION_STATE; + +typedef struct _MBB_SET_USSD + { + MBB_USSD_ACTION USSDAction; + ULONG USSDDataCodingScheme; + MBB_ARRAY_ELEMENT USSDPayload; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_USSD; + +typedef struct _MBB_SET_USSD *PMBB_SET_USSD; + +typedef struct _MBB_USSD + { + MBB_USSD_RESPONSE USSDResponse; + MBB_USSD_SESSION_STATE USSDSessionState; + ULONG USSDDataCodingScheme; + MBB_ARRAY_ELEMENT USSDPayload; + UCHAR DataBuffer[ 1 ]; + } MBB_USSD; + +typedef struct _MBB_USSD *PMBB_USSD; + +typedef struct _MBB_AKA_AUTH_CHALLENGE + { + UCHAR Rand[ 16 ]; + UCHAR Autn[ 16 ]; + } MBB_AKA_AUTH_CHALLENGE; + +typedef struct _MBB_AKA_AUTH_CHALLENGE *PMBB_AKA_AUTH_CHALLENGE; + +typedef struct _MBB_AKA_AUTH_RESPONSE + { + UCHAR Res[ 16 ]; + ULONG ResLength; + UCHAR IK[ 16 ]; + UCHAR CK[ 16 ]; + UCHAR Auts[ 14 ]; + } MBB_AKA_AUTH_RESPONSE; + +typedef struct _MBB_AKA_AUTH_RESPONSE *PMBB_AKA_AUTH_RESPONSE; + +typedef struct _MBB_AKAP_AUTH_CHALLENGE + { + UCHAR Rand[ 16 ]; + UCHAR Autn[ 16 ]; + MBB_STRING NetworkName; + UCHAR DataBuffer[ 1 ]; + } MBB_AKAP_AUTH_CHALLENGE; + +typedef struct _MBB_AKAP_AUTH_CHALLENGE *PMBB_AKAP_AUTH_CHALLENGE; + +typedef struct _MBB_AKAP_AUTH_RESPONSE + { + UCHAR Res[ 16 ]; + ULONG ResLength; + UCHAR IK[ 16 ]; + UCHAR CK[ 16 ]; + UCHAR Auts[ 14 ]; + } MBB_AKAP_AUTH_RESPONSE; + +typedef struct _MBB_AKAP_AUTH_RESPONSE *PMBB_AKAP_AUTH_RESPONSE; + +typedef struct _MBB_SIM_AUTH_CHALLENGE + { + UCHAR Rand1[ 16 ]; + UCHAR Rand2[ 16 ]; + UCHAR Rand3[ 16 ]; + ULONG n; + } MBB_SIM_AUTH_CHALLENGE; + +typedef struct _MBB_SIM_AUTH_CHALLENGE *PMBB_SIM_AUTH_CHALLENGE; + +typedef struct _MBB_SIM_AUTH_RESPONSE + { + UCHAR Sres1[ 4 ]; + UCHAR Kc1[ 8 ]; + UCHAR Sres2[ 4 ]; + UCHAR Kc2[ 8 ]; + UCHAR Sres3[ 4 ]; + UCHAR Kc3[ 8 ]; + ULONG n; + } MBB_SIM_AUTH_RESPONSE; + +typedef struct _MBB_SIM_AUTH_RESPONSE *PMBB_SIM_AUTH_RESPONSE; + +typedef struct _MBB_PACKET_FILTERS + { + ULONG SessionId; + ULONG PacketFiltersCount; + MBB_ARRAY_ELEMENT ArrayElement[ 1 ]; + } MBB_PACKET_FILTERS; + +typedef struct _MBB_PACKET_FILTERS *PMBB_PACKET_FILTERS; + +typedef struct _MBB_SINGLE_PACKET_FILTER + { + ULONG FilterSize; + ULONG PacketFilterOffset; + ULONG PacketMaskOffset; + UCHAR DataBuffer[ 1 ]; + } MBB_SINGLE_PACKET_FILTER; + +typedef struct _MBB_SINGLE_PACKET_FILTER *PMBB_SINGLE_PACKET_FILTER; + +typedef struct _MBB_SINGLE_PACKET_FILTER_V2 + { + ULONG FilterSize; + ULONG PacketFilterOffset; + ULONG PacketMaskOffset; + ULONG FilterId; + UCHAR DataBuffer[ 1 ]; + } MBB_SINGLE_PACKET_FILTER_V2; + +typedef struct _MBB_SINGLE_PACKET_FILTER_V2 *PMBB_SINGLE_PACKET_FILTER_V2; + +typedef struct _MBB_NETWORK_IDLE_HINT + { + MBB_NETWORK_IDLE_HINT_STATE NetworkIdleHintState; + } MBB_NETWORK_IDLE_HINT; + +typedef struct _MBB_NETWORK_IDLE_HINT *PMBB_NETWORK_IDLE_HINT; + +typedef struct _MBB_DEVICE_SERVICE_ELEMENT + { + GUID DeviceServiceId; + MBB_DSS_PAYLOAD_SUPPORT DSSPayload; + ULONG MaxDSSInstances; + ULONG CIDCount; + ULONG CIDList[ 1 ]; + } MBB_DEVICE_SERVICE_ELEMENT; + +typedef struct _MBB_DEVICE_SERVICE_ELEMENT *PMBB_DEVICE_SERVICE_ELEMENT; + +typedef struct _MBB_DEVICE_SERVICES_HEADER + { + ULONG DeviceServicesCount; + ULONG MaxDSSSessions; + MBB_ARRAY_ELEMENT ArrayElement[ 1 ]; + } MBB_DEVICE_SERVICES_HEADER; + +typedef struct _MBB_DEVICE_SERVICES_HEADER *PMBB_DEVICE_SERVICES_HEADER; + +typedef struct _MBB_SUBSCRIBE_EVENT_ENTRY + { + GUID DeviceServiceId; + ULONG CIDCount; + ULONG CIDList[ 1 ]; + } MBB_SUBSCRIBE_EVENT_ENTRY; + +typedef struct _MBB_SUBSCRIBE_EVENT_ENTRY *PMBB_SUBSCRIBE_EVENT_ENTRY; + +typedef struct _MBB_SUBSCRIBE_EVENT_LIST + { + ULONG Count; + MBB_ARRAY_ELEMENT ArrayElement[ 1 ]; + } MBB_SUBSCRIBE_EVENT_LIST; + +typedef struct _MBB_SUBSCRIBE_EVENT_LIST *PMBB_SUBSCRIBE_EVENT_LIST; + +typedef struct _MBB_SET_DSS_CONNECT + { + GUID DeviceServiceId; + ULONG DssSessionId; + MBB_DSS_LINK_STATE DssLinkState; + } MBB_SET_DSS_CONNECT; + +typedef struct _MBB_SET_DSS_CONNECT *PMBB_SET_DSS_CONNECT; + +typedef struct _MBB_SET_DSS_CLOSE + { + ULONG DssSessionId; + } MBB_SET_DSS_CLOSE; + +typedef struct _MBB_SET_DSS_CLOSE *PMBB_SET_DSS_CLOSE; + +typedef struct _MBB_MULTICARRIER_CURRENT_CID_LIST + { + ULONG CIDCount; + ULONG CIDList[ 1 ]; + } MBB_MULTICARRIER_CURRENT_CID_LIST; + +typedef struct _MBB_MULTICARRIER_CURRENT_CID_LIST *PMBB_MULTICARRIER_CURRENT_CID_LIST; + +typedef +enum _MBB_UICC_APP_TYPE + { + MbbUiccAppTypeUnknown = 0, + MbbUiccAppTypeMf = 1, + MbbUiccAppTypeMfSIM = 2, + MbbUiccAppTypeMfRUIM = 3, + MbbUiccAppTypeUSIM = 4, + MbbUiccAppTypeCSIM = 5, + MbbUiccAppTypeISIM = 6, + MbbUiccAppTypeMax = ( MbbUiccAppTypeISIM + 1 ) + } MBB_UICC_APP_TYPE; + +typedef struct _MBB_UICC_APP_INFO + { + MBB_UICC_APP_TYPE AppType; + MBB_ARRAY_ELEMENT AppId; + MBB_ARRAY_ELEMENT AppName; + ULONG NumPins; + MBB_ARRAY_ELEMENT PinRef; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_APP_INFO; + +typedef struct _MBB_UICC_APP_INFO *PMBB_UICC_APP_INFO; + +typedef struct _MBB_UICC_APP_LIST + { + ULONG Version; + ULONG AppCount; + ULONG ActiveAppIndex; + ULONG AppListSize; + MBB_ARRAY_ELEMENT DataBuffer[ 1 ]; + } MBB_UICC_APP_LIST; + +typedef struct _MBB_UICC_APP_LIST *PMBB_UICC_APP_LIST; + +typedef +enum _MBB_UICC_FILE_ACCESSIBILITY + { + MbbUiccFileAccessibilityUnknown = 0, + MbbUiccFileAccessibilityNotShareable = 1, + MbbUiccFileAccessibilityShareable = 2, + MbbUiccFileAccessibilityMax = ( MbbUiccFileAccessibilityShareable + 1 ) + } MBB_UICC_FILE_ACCESSIBILITY; + +typedef +enum _MBB_UICC_FILE_TYPE + { + MbbUiccFileTypeUnknown = 0, + MbbUiccFileTypeWorkingEf = 1, + MbbUiccFileTypeInternalEf = 2, + MbbUiccFileTypeDfOrAdf = 3, + MbbUiccFileTypeMax = ( MbbUiccFileTypeDfOrAdf + 1 ) + } MBB_UICC_FILE_TYPE; + +typedef +enum _MBB_UICC_FILE_STRUCTURE + { + MbbUiccFileStructureUnknown = 0, + MbbUiccFileStructureTransparent = 1, + MbbUiccFileStructureCyclic = 2, + MbbUiccFileStructureLinear = 3, + MbbUiccFileStructureBertlv = 4, + MbbUiccFileStructureMax = ( MbbUiccFileStructureBertlv + 1 ) + } MBB_UICC_FILE_STRUCTURE; + +typedef struct _MBB_UICC_FILE_PATH + { + ULONG Version; + MBB_ARRAY_ELEMENT AppId; + MBB_ARRAY_ELEMENT FilePath; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_FILE_PATH; + +typedef struct _MBB_UICC_FILE_PATH *PMBB_UICC_FILE_PATH; + +typedef struct _MBB_UICC_FILE_STATUS + { + ULONG Version; + ULONG StatusWord1; + ULONG StatusWord2; + MBB_UICC_FILE_ACCESSIBILITY FileAccessibility; + MBB_UICC_FILE_TYPE FileType; + MBB_UICC_FILE_STRUCTURE FileStructure; + ULONG ItemCount; + ULONG ItemSize; + MBB_PIN_TYPE FileLockStatus[ 4 ]; + } MBB_UICC_FILE_STATUS; + +typedef struct _MBB_UICC_FILE_STATUS *PMBB_UICC_FILE_STATUS; + +typedef struct _MBB_UICC_ACCESS_BINARY + { + ULONG Version; + MBB_ARRAY_ELEMENT AppId; + MBB_ARRAY_ELEMENT UiccFilePath; + ULONG FileOffset; + ULONG NumberOfBytes; + MBB_ARRAY_ELEMENT LocalPin; + MBB_ARRAY_ELEMENT BinaryData; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_ACCESS_BINARY; + +typedef struct _MBB_UICC_ACCESS_BINARY *PMBB_UICC_ACCESS_BINARY; + +typedef struct _MBB_UICC_ACCESS_RECORD + { + ULONG Version; + MBB_ARRAY_ELEMENT AppId; + MBB_ARRAY_ELEMENT UiccFilePath; + ULONG RecordNumber; + MBB_ARRAY_ELEMENT LocalPin; + MBB_ARRAY_ELEMENT RecordData; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_ACCESS_RECORD; + +typedef struct _MBB_UICC_ACCESS_RECORD *PMBB_UICC_ACCESS_RECORD; + +typedef struct _MBB_UICC_RESPONSE + { + ULONG Version; + ULONG StatusWord1; + ULONG StatusWord2; + MBB_ARRAY_ELEMENT ResponseData; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_RESPONSE; + +typedef struct _MBB_UICC_RESPONSE *PMBB_UICC_RESPONSE; + +typedef struct _MBB_PIN_APP + { + ULONG Version; + MBB_ARRAY_ELEMENT AppId; + UCHAR DataBuffer[ 1 ]; + } MBB_PIN_APP; + +typedef struct _MBB_PIN_APP *PMBB_PIN_APP; + +typedef struct _MBB_PIN_ACTION_EX2 + { + MBB_PIN_TYPE PinType; + MBB_PIN_OPERATION PinOperation; + MBB_STRING Pin; + MBB_STRING NewPin; + MBB_ARRAY_ELEMENT AppId; + UCHAR DataBuffer[ 1 ]; + } MBB_PIN_ACTION_EX2; + +typedef struct _MBB_PIN_ACTION_EX2 *PMBB_PIN_ACTION_EX2; + +typedef struct _MBB_SYS_CAPS_INFO + { + ULONG NumberOfExecutors; + ULONG NumberOfSlots; + ULONG Concurrency; + } MBB_SYS_CAPS_INFO; + +typedef struct _MBB_SYS_CAPS_INFO *PMBB_SYS_CAPS_INFO; + +typedef struct _MBB_DEVICE_CAPS_V2 + { + MBB_DEVICE_TYPE DeviceType; + MBB_CELLULAR_CLASS CellularClass; + MBB_VOICE_CLASS VoiceClass; + MBB_SIM_CLASS SimClass; + ULONG DataClass; + ULONG SmsCaps; + ULONG ControlCaps; + ULONG dwMaxSessions; + MBB_STRING CustomDataClass; + MBB_STRING DeviceIdString; + MBB_STRING FirmwareInfo; + MBB_STRING HardwareInfo; + ULONG DeviceIndex; + UCHAR DataBuffer[ 1 ]; + } MBB_DEVICE_CAPS_V2; + +typedef struct _MBB_DEVICE_CAPS_V2 *PMBB_DEVICE_CAPS_V2; + +typedef struct _MBB_DEVICE_SLOT_MAPPING_INFO + { + ULONG MapCount; + MBB_ARRAY_ELEMENT SlotMapList[ 1 ]; + } MBB_DEVICE_SLOT_MAPPING_INFO; + +typedef struct _MBB_DEVICE_SLOT_MAPPING_INFO *PMBB_DEVICE_SLOT_MAPPING_INFO; + +typedef +enum _MBB_UICCSLOT_STATE + { + MbbUiccSlotStateOffEmpty = 0, + MbbUiccSlotStateOff = 1, + MbbUiccSlotStateEmpty = 2, + MbbUiccSlotStateNotReady = 3, + MbbUiccSlotStateActive = 4, + MbbUiccSlotStateError = 5 + } MBB_UICCSLOT_STATE; + +typedef struct _MBB_SLOT_INFO_REQ + { + ULONG SlotIndex; + } MBB_SLOT_INFO_REQ; + +typedef struct _MBB_SLOT_INFO_REQ *PMBB_SLOT_INFO_REQ; + +typedef struct _MBB_SLOT_INFO + { + ULONG SlotIndex; + MBB_UICCSLOT_STATE State; + } MBB_SLOT_INFO; + +typedef struct _MBB_SLOT_INFO *PMBB_SLOT_INFO; + +typedef struct _MBB_DEVICE_BINDINGS_INFO + { + ULONG ApplicationCount; + MBB_ARRAY_ELEMENT ApplicationList[ 1 ]; + } MBB_DEVICE_BINDINGS_INFO; + +typedef struct _MBB_DEVICE_BINDINGS_INFO *PMBB_DEVICE_BINDINGS_INFO; + +typedef +enum _MBB_REGISTRATION_VOICE_CLASS + { + MbbRegistrationVoiceClassVoiceCentric = 0, + MbbRegistrationVoiceClassDataCentric = 1 + } MBB_REGISTRATION_VOICE_CLASS; + +typedef +enum _MBB_REGISTRATION_VOICE_DOMAIN_PREFERENCE + { + MbbRegistrationVoiceDomainPreferenceCsOnly = 0, + MbbRegistrationVoiceDomainPreferenceCsPreferred = 1, + MbbRegistrationVoiceDomainPreferenceImsPreferred = 2, + MbbRegistrationVoiceDomainPreferenceImsOnly = 3 + } MBB_REGISTRATION_VOICE_DOMAIN_PREFERENCE; + +typedef +enum _MBB_REGISTRATION_VOICE_SUPPORT + { + MbbRegistrationVoiceSupportNone = 0, + MbbRegistrationVoiceSupportIms = 0x1, + MbbRegistrationVoiceSupportEmergencyAttach = 0x2, + MbbRegistrationVoiceSupportCs = 0x4, + MbbRegistrationVoiceSupportCsfb = 0x8, + MbbRegistrationVoiceSupport1xCsfb = 0x10, + MbbRegistrationVoiceSupportCsEmergency = 0x20 + } MBB_REGISTRATION_VOICE_SUPPORT; + +typedef +enum _MBB_REGISTRATION_CDMA_ROAM_MODE + { + MbbRegistrationCdmaRoamModeAutomatic = 0, + MbbRegistrationCdmaRoamModeHomeOnly = 1 + } MBB_REGISTRATION_CDMA_ROAM_MODE; + +typedef struct _MBB_SET_REGISTER_STATE_V2 + { + MBB_STRING ProviderId; + MBB_REGISTER_ACTION RegisterAction; + ULONG DataClass; + MBB_REGISTRATION_VOICE_CLASS VoiceClass; + MBB_REGISTRATION_VOICE_DOMAIN_PREFERENCE VoiceDomain; + MBB_REGISTRATION_CDMA_ROAM_MODE CdmaRoamMode; + MBB_ARRAY_ELEMENT AcquisitionOrder[ 1 ]; + } MBB_SET_REGISTER_STATE_V2; + +typedef struct _MBB_SET_REGISTER_STATE_V2 *PMBB_SET_REGISTER_STATE_V2; + +typedef struct _MBB_REGISTRATION_STATE_V2 + { + ULONG NetworkError; + MBB_REGISTER_STATE RegisterState; + MBB_REGISTER_MODE RegisterMode; + ULONG AvailableDataClasses; + MBB_CELLULAR_CLASS CurrentCellularClass; + MBB_STRING ProviderId; + MBB_STRING ProviderName; + MBB_STRING RoamingText; + ULONG RegFlags; + MBB_REGISTRATION_VOICE_SUPPORT VoiceSupport; + ULONG CurrentRATClass; + UCHAR DataBuffer[ 1 ]; + } MBB_REGISTRATION_STATE_V2; + +typedef struct _MBB_REGISTRATION_STATE_V2 *PMBB_REGISTRATION_STATE_V2; + +typedef struct _MBB_REGISTRATION_STATE_INFOS_V2 + { + ULONG ElementCount; + MBB_ARRAY_ELEMENT RegistrationStateList[ 1 ]; + } MBB_REGISTRATION_STATE_INFOS_V2; + +typedef struct _MBB_REGISTRATION_STATE_INFOS_V2 *PMBB_REGISTRATION_STATE_INFOS_V2; + +typedef struct _MBB_REGISTRATION_STATE_INFO_V2 + { + ULONG NetworkError; + MBB_REGISTER_STATE RegisterState; + MBB_REGISTER_MODE RegisterMode; + ULONG AvailableDataClasses; + MBB_CELLULAR_CLASS CurrentCellularClass; + MBB_STRING ProviderId; + MBB_STRING ProviderName; + MBB_STRING RoamingText; + ULONG RegistrationFlag; + ULONG PreferredDataClasses; + UCHAR DataBuffer[ 1 ]; + } MBB_REGISTRATION_STATE_INFO_V2; + +typedef struct _MBB_REGISTRATION_STATE_INFO_V2 *PMBB_REGISTRATION_STATE_INFO_V2; + +typedef +enum _MBB_IMS_VOICE_STATUS + { + MbbImsVoiceStatusUnknown = 0, + MbbImsVoiceStatusUnregistered = 1, + MbbImsVoiceStatusRegistered = 2 + } MBB_IMS_VOICE_STATUS; + +typedef struct _MBB_SET_IMS_VOICE_STATE + { + MBB_IMS_VOICE_STATUS ImsVoiceStatus; + } MBB_SET_IMS_VOICE_STATE; + +typedef struct _MBB_SET_IMS_VOICE_STATE *PMBB_SET_IMS_VOICE_STATE; + +typedef struct _MBB_IMS_VOICE_STATE + { + MBB_IMS_VOICE_STATUS ImsVoiceStatus; + } MBB_IMS_VOICE_STATE; + +typedef struct _MBB_IMS_VOICE_STATE *PMBB_IMS_VOICE_STATE; + +typedef struct _MBB_SET_SIGNAL_INDICATION_V2 + { + ULONG RssiInterval; + ULONG RssiThreshold; + ULONG ErrorRateThreshold; + ULONG SnrThreshold; + } MBB_SET_SIGNAL_INDICATION_V2; + +typedef struct _MBB_SET_SIGNAL_INDICATION_V2 *PMBB_SET_SIGNAL_INDICATION_V2; + +typedef struct _MBB_SIGNAL_STATE_V2 + { + ULONG Rssi; + ULONG ErrorRate; + ULONG RssiInterval; + ULONG RssiThreshold; + ULONG ErrorRateThreshold; + ULONG Snr; + ULONG SnrThreshold; + ULONG DataClass; + } MBB_SIGNAL_STATE_V2; + +typedef struct _MBB_SIGNAL_STATE_V2 *PMBB_SIGNAL_STATE_V2; + +typedef struct _MBB_RSRP_SNR_INFO + { + ULONG RSRP; + ULONG SNR; + ULONG RSRPThreshold; + ULONG SNRThreshold; + MBB_DATA_CLASS_VALUE SystemType; + } MBB_RSRP_SNR_INFO; + +typedef struct _MBB_RSRP_SNR_INFO *PMBB_RSRP_SNR_INFO; + +typedef struct _MBB_RSRP_SNR + { + ULONG ElementCount; + MBB_RSRP_SNR_INFO DataBuffer[ 1 ]; + } MBB_RSRP_SNR; + +typedef struct _MBB_RSRP_SNR *PMBB_RSRP_SNR; + +typedef struct _MBB_SIGNAL_STATE_INFO_V2 + { + ULONG Rssi; + ULONG ErrorRate; + ULONG SignalStrengthInterval; + ULONG RssiThreshold; + ULONG ErrorRateThreshold; + ULONG RsrpSnrOffset; + ULONG RsrpSnrSize; + MBB_RSRP_SNR DataBuffer; + } MBB_SIGNAL_STATE_INFO_V2; + +typedef struct _MBB_SIGNAL_STATE_INFO_V2 *PMBB_SIGNAL_STATE_INFO_V2; + +typedef struct _MBB_SIGNAL_STATE_INFOS_V2 + { + ULONG ElementCount; + MBB_ARRAY_ELEMENT SignalStateList[ 1 ]; + } MBB_SIGNAL_STATE_INFOS_V2; + +typedef struct _MBB_SIGNAL_STATE_INFOS_V2 *PMBB_SIGNAL_STATE_INFOS_V2; + +typedef +enum _MBB_LOCATION_TRIGGER_MODE + { + MbbLocationTriggerNone = 0, + MbbLocationTriggerAreaCode = 1, + MbbLocationTriggerAreaCellId = 2 + } MBB_LOCATION_TRIGGER_MODE; + +typedef struct _MBB_SET_LOCATION_STATE + { + MBB_LOCATION_TRIGGER_MODE Trigger; + } MBB_SET_LOCATION_STATE; + +typedef struct _MBB_SET_LOCATION_STATE *PMBB_SET_LOCATION_STATE; + +typedef struct _MBB_LOCATION_STATE_INFO + { + MBB_LOCATION_TRIGGER_MODE Trigger; + ULONG DataClass; + ULONG AreaCode; + ULONG CellId; + } MBB_LOCATION_STATE_INFO; + +typedef struct _MBB_LOCATION_STATE_INFO *PMBB_LOCATION_STATE_INFO; + +typedef struct _MBB_NITZ_INFO + { + ULONG Year; + ULONG Month; + ULONG Day; + ULONG Hour; + ULONG Minute; + ULONG Second; + ULONG TimeZoneOffsetMinutes; + ULONG DaylightSavingTimeOffsetMinutes; + ULONG DataClasses; + } MBB_NITZ_INFO; + +typedef struct _MBB_NITZ_INFO *PMBB_NITZ_INFO; + +typedef struct _MBB_ATR_INFO + { + MBB_ARRAY_ELEMENT2 Atr; + UCHAR DataBuffer[ 1 ]; + } MBB_ATR_INFO; + +typedef struct _MBB_ATR_INFO *PMBB_ATR_INFO; + +typedef struct _MBB_SET_UICC_OPEN_CHANNEL + { + MBB_ARRAY_ELEMENT2 AppId; + ULONG SelectP2Arg; + ULONG ChannelGroup; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_UICC_OPEN_CHANNEL; + +typedef struct _MBB_SET_UICC_OPEN_CHANNEL *PMBB_SET_UICC_OPEN_CHANNEL; + +typedef struct _MBB_UICC_OPEN_CHANNEL_INFO + { + UCHAR Status[ 4 ]; + ULONG Channel; + MBB_ARRAY_ELEMENT2 Response; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_OPEN_CHANNEL_INFO; + +typedef struct _MBB_UICC_OPEN_CHANNEL_INFO *PMBB_UICC_OPEN_CHANNEL_INFO; + +typedef struct _MBB_SET_UICC_CLOSE_CHANNEL + { + ULONG Channel; + ULONG ChannelGroup; + ULONG SelectP2Arg; + } MBB_SET_UICC_CLOSE_CHANNEL; + +typedef struct _MBB_SET_UICC_CLOSE_CHANNEL *PMBB_SET_UICC_CLOSE_CHANNEL; + +typedef struct _MBB_UICC_CLOSE_CHANNEL_INFO + { + UCHAR Status[ 4 ]; + } MBB_UICC_CLOSE_CHANNEL_INFO; + +typedef struct _MBB_UICC_CLOSE_CHANNEL_INFO *PMBB_UICC_CLOSE_CHANNEL_INFO; + +typedef +enum _MBB_UICC_SECURE_MESSAGING + { + MbbUiccSecureMessagingNone = 0, + MbbUiccSecureMessagingNoHdrAuth = 1 + } MBB_UICC_SECURE_MESSAGING; + +typedef +enum _MBB_UICC_CLASS_BYTE_TYPE + { + MbbUiccClassByteTypeInterindustry = 0, + MbbUiccClassByteTypeExtended = 1 + } MBB_UICC_CLASS_BYTE_TYPE; + +typedef struct _MBB_SET_UICC_APDU + { + ULONG Channel; + MBB_UICC_SECURE_MESSAGING SecureMessaging; + MBB_UICC_CLASS_BYTE_TYPE Type; + MBB_ARRAY_ELEMENT2 Command; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_UICC_APDU; + +typedef struct _MBB_SET_UICC_APDU *PMBB_SET_UICC_APDU; + +typedef struct _MBB_UICC_APDU_INFO + { + UCHAR Status[ 4 ]; + MBB_ARRAY_ELEMENT2 Response; + UCHAR DataBuffer[ 1 ]; + } MBB_UICC_APDU_INFO; + +typedef struct _MBB_UICC_APDU_INFO *PMBB_UICC_APDU_INFO; + +typedef struct _MBB_UICC_TERMINAL_CAPABILITY_TLV + { + UCHAR Data[ 3 ]; + } MBB_UICC_TERMINAL_CAPABILITY_TLV; + +typedef struct _MBB_UICC_TERMINAL_CAPABILITY_TLV *PMBB_UICC_TERMINAL_CAPABILITY_TLV; + +typedef struct _MBB_SET_UICC_TERMINAL_CAPABILITY + { + ULONG ElementCount; + MBB_ARRAY_ELEMENT CapabilityList[ 1 ]; + } MBB_SET_UICC_TERMINAL_CAPABILITY; + +typedef struct _MBB_SET_UICC_TERMINAL_CAPABILITY *PMBB_SET_UICC_TERMINAL_CAPABILITY; + +typedef struct _MBB_UICC_TERMINAL_CAPABILITY_INFO + { + ULONG ElementCount; + MBB_ARRAY_ELEMENT CapabilityList[ 1 ]; + } MBB_UICC_TERMINAL_CAPABILITY_INFO; + +typedef struct _MBB_UICC_TERMINAL_CAPABILITY_INFO *PMBB_UICC_TERMINAL_CAPABILITY_INFO; + +typedef +enum _MBB_UICC_PASSTHROUGH_ACTION + { + MbbUiccPassThroughDisable = 0, + MbbUiccPassThroughEnable = 1 + } MBB_UICC_PASSTHROUGH_ACTION; + +typedef +enum _MBB_UICC_PASSTHROUGH_STATUS + { + MbbUiccPassThroughDisabled = 0, + MbbUiccPassThroughEnabled = 1 + } MBB_UICC_PASSTHROUGH_STATUS; + +typedef struct _MBB_SET_UICC_RESET + { + MBB_UICC_PASSTHROUGH_ACTION PassThroughAction; + } MBB_SET_UICC_RESET; + +typedef struct _MBB_SET_UICC_RESET *PMBB_SET_UICC_RESET; + +typedef struct _MBB_UICC_RESET_INFO + { + MBB_UICC_PASSTHROUGH_STATUS PassThroughStatus; + } MBB_UICC_RESET_INFO; + +typedef struct _MBB_UICC_RESET_INFO *PMBB_UICC_RESET_INFO; + +typedef struct _MBB_SAR_CONFIG_INDICES + { + ULONG SarAntennaIndex; + ULONG SarBackoffIndex; + } MBB_SAR_CONFIG_INDICES; + +typedef struct _MBB_SAR_CONFIG_INDICES *PMBB_SAR_CONFIG_INDICES; + +typedef struct _MBB_SAR_CONFIG_INFO + { + MBB_SAR_CONTROL_MODE SarMode; + MBB_SAR_BACKOFF_STATE SarBackoffStatus; + MBB_SAR_WIFI_HARDWARE_INTEGRATION SarWifiIntegration; + ULONG ElementCount; + MBB_ARRAY_ELEMENT Configurations[ 1 ]; + } MBB_SAR_CONFIG_INFO; + +typedef struct _MBB_SAR_CONFIG_INFO *PMBB_SAR_CONFIG_INFO; + +typedef struct _MBB_SET_SAR_CONFIG + { + MBB_SAR_CONTROL_MODE SarMode; + MBB_SAR_BACKOFF_STATE SarBackoffStatus; + ULONG ElementCount; + MBB_ARRAY_ELEMENT Configurations[ 1 ]; + } MBB_SET_SAR_CONFIG; + +typedef struct _MBB_SET_SAR_CONFIG *PMBB_SET_SAR_CONFIG; + +typedef struct _MBB_SAR_TRANSMISSION_STATUS_INFO + { + MBB_SAR_TRANSMISSION_STATUS_NOTIFICATION_STATE ChannelNotification; + MBB_SAR_TRANSMISSION_STATUS TransmissionStatus; + ULONG HysteresisTimer; + } MBB_SAR_TRANSMISSION_STATUS_INFO; + +typedef struct _MBB_SAR_TRANSMISSION_STATUS_INFO *PMBB_SAR_TRANSMISSION_STATUS_INFO; + +typedef struct _MBB_SET_SAR_TRANSMISSION_STATUS + { + MBB_SAR_TRANSMISSION_STATUS_NOTIFICATION_STATE ChannelNotification; + ULONG HysteresisTimer; + } MBB_SET_SAR_TRANSMISSION_STATUS; + +typedef struct _MBB_SET_SAR_TRANSMISSION_STATUS *PMBB_SET_SAR_TRANSMISSION_STATUS; + +typedef struct _MBB_SET_MS_CONTEXT_PROVISIONED_CONTEXT_V2 + { + MBB_BASICCONNECTEXT_CONTEXT_OPERATIONS Operation; + GUID ContextType; + MBB_CONTEXT_IP_TYPE IPType; + MBB_BASICCONNECTEXT_CONTEXT_ENABLE Enable; + MBB_BASICCONNECTEXT_CONTEXT_ROAMING_CONTROL Roaming; + MBB_BASICCONNECTEXT_CONTEXT_MEDIA_TYPE MediaType; + MBB_BASICCONNECTEXT_CONTEXT_SOURCE Source; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + UCHAR DataBuffer[ 1 ]; + } MBB_SET_MS_CONTEXT_PROVISIONED_CONTEXT_V2; + +typedef struct _MBB_SET_MS_CONTEXT_PROVISIONED_CONTEXT_V2 *PMBB_SET_MS_CONTEXT_PROVISIONED_CONTEXT_V2; + +typedef struct _MBB_MS_CONTEXT_V2 + { + ULONG ContextId; + GUID ContextType; + MBB_CONTEXT_IP_TYPE IPType; + MBB_BASICCONNECTEXT_CONTEXT_ENABLE Enable; + MBB_BASICCONNECTEXT_CONTEXT_ROAMING_CONTROL Roaming; + MBB_BASICCONNECTEXT_CONTEXT_MEDIA_TYPE MediaType; + MBB_BASICCONNECTEXT_CONTEXT_SOURCE Source; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_CONTEXT_V2; + +typedef struct _MBB_MS_CONTEXT_V2 *PMBB_MS_CONTEXT_V2; + +typedef struct _MBB_MS_NETWORK_BLACKLIST_PROVIDER + { + ULONG MCC; + ULONG MNC; + MBB_BASICCONNECTEXT_NETWORK_BLACKLIST_TYPE NetworkBlacklistType; + } MBB_MS_NETWORK_BLACKLIST_PROVIDER; + +typedef struct _MBB_MS_NETWORK_BLACKLIST_PROVIDER *PMBB_MS_NETWORK_BLACKLIST_PROVIDER; + +typedef struct _MBB_MS_NETWORK_BLACKLIST_INFO + { + MBB_BASICCONNECTEXT_NETWORK_BLACKLIST_STATE BlacklistState; + ULONG ElementCount; + MBB_ARRAY_ELEMENT Contexts[ 1 ]; + } MBB_MS_NETWORK_BLACKLIST_INFO; + +typedef struct _MBB_MS_NETWORK_BLACKLIST_INFO *PMBB_MS_NETWORK_BLACKLIST_INFO; + +typedef struct _MBB_MS_VERSION_INFO + { + USHORT bcdMBIMVersion; + USHORT bcdMBIMExtendedVersion; + } MBB_MS_VERSION_INFO; + +typedef struct _MBB_MS_VERSION_INFO *PMBB_MS_VERSION_INFO; + +typedef struct _MBB_MS_LTE_ATTACH_CONTEXT + { + MBB_CONTEXT_IP_TYPE IPType; + MBB_BASICCONNECTEXT_LTEATTACH_ROAMING_CONTROL Roaming; + MBB_BASICCONNECTEXT_CONTEXT_SOURCE Source; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_LTE_ATTACH_CONTEXT; + +typedef struct _MBB_MS_LTE_ATTACH_CONTEXT *PMBB_MS_LTE_ATTACH_CONTEXT; + +typedef struct _MBB_SET_MS_CONTEXT_LTE_ATTACH_CONFIG + { + MBB_BASICCONNECTEXT_LTEATTACH_CONTEXT_OPERATIONS Operation; + ULONG ElementCount; + MBB_ARRAY_ELEMENT Contexts[ 1 ]; + } MBB_SET_MS_CONTEXT_LTE_ATTACH_CONFIG; + +typedef struct _MBB_SET_MS_CONTEXT_LTE_ATTACH_CONFIG *PMBB_SET_MS_CONTEXT_LTE_ATTACH_CONFIG; + +typedef struct _MBB_MS_LTE_ATTACH_CONFIG_INFO + { + ULONG ElementCount; + MBB_ARRAY_ELEMENT Contexts[ 1 ]; + } MBB_MS_LTE_ATTACH_CONFIG_INFO; + +typedef struct _MBB_MS_LTE_ATTACH_CONFIG_INFO *PMBB_MS_LTE_ATTACH_CONFIG_INFO; + +typedef struct _MBB_MS_LTE_ATTACH_STATUS + { + MBB_BASICCONNECTEXT_LTEATTACH_STATE LteAttachState; + MBB_CONTEXT_IP_TYPE IPType; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_LTE_ATTACH_STATUS; + +typedef struct _MBB_MS_LTE_ATTACH_STATUS *PMBB_MS_LTE_ATTACH_STATUS; + +typedef struct _MBB_MS_LTE_ATTACH_STATUS_V2 + { + MBB_BASICCONNECTEXT_LTEATTACH_STATE LteAttachState; + ULONG NetworkError; + MBB_CONTEXT_IP_TYPE IPType; + MBB_STRING AccessString; + MBB_STRING UserName; + MBB_STRING Password; + MBB_COMPRESSION Compression; + MBB_AUTH_PROTOCOL AuthProtocol; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_LTE_ATTACH_STATUS_V2; + +typedef struct _MBB_MS_LTE_ATTACH_STATUS_V2 *PMBB_MS_LTE_ATTACH_STATUS_V2; + +typedef struct _MBB_MS_SYS_CAPS_INFO + { + ULONG NumberOfExecutors; + ULONG NumberOfSlots; + ULONG Concurrency; + ULONG64 ModemId; + } MBB_MS_SYS_CAPS_INFO; + +typedef struct _MBB_MS_SYS_CAPS_INFO *PMBB_MS_SYS_CAPS_INFO; + +typedef struct _MBB_MS_DEVICE_CAPS_INFO_V2 + { + MBB_DEVICE_TYPE DeviceType; + MBB_CELLULAR_CLASS CellularClass; + MBB_VOICE_CLASS VoiceClass; + MBB_SIM_CLASS SimClass; + ULONG DataClass; + ULONG SmsCaps; + ULONG ControlCaps; + ULONG dwMaxSessions; + MBB_STRING CustomDataClass; + MBB_STRING DeviceIdString; + MBB_STRING FirmwareInfo; + MBB_STRING HardwareInfo; + ULONG ExecutorIndex; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_DEVICE_CAPS_INFO_V2; + +typedef struct _MBB_MS_DEVICE_CAPS_INFO_V2 *PMBB_MS_DEVICE_CAPS_INFO_V2; + +typedef struct _MBB_MS_DEVICE_CAPS_INFO_V3_OBS + { + MBB_DEVICE_TYPE DeviceType; + MBB_CELLULAR_CLASS CellularClass; + MBB_VOICE_CLASS VoiceClass; + ULONG SimClassBitMasks; + ULONG DataClass; + ULONG SmsCaps; + ULONG ControlCaps; + ULONGLONG MiscCaps; + ULONG dwMaxSessions; + ULONG ExecutorIndex; + ULONG WcdmaBandClass; + } MBB_MS_DEVICE_CAPS_INFO_V3_OBS; + +typedef struct _MBB_MS_DEVICE_CAPS_INFO_V3_OBS *PMBB_MS_DEVICE_CAPS_INFO_V3_OBS; + +typedef struct _MBB_MS_DEVICE_CAPS_INFO_V3 + { + MBB_DEVICE_TYPE DeviceType; + MBB_CELLULAR_CLASS CellularClass; + MBB_VOICE_CLASS VoiceClass; + ULONG SimClassBitMasks; + ULONG DataClass; + ULONG SmsCaps; + ULONG ControlCaps; + ULONGLONG DataSubClass; + ULONG dwMaxSessions; + ULONG ExecutorIndex; + ULONG WcdmaBandClass; + } MBB_MS_DEVICE_CAPS_INFO_V3; + +typedef struct _MBB_MS_DEVICE_CAPS_INFO_V3 *PMBB_MS_DEVICE_CAPS_INFO_V3; + +typedef struct _MBB_MS_DEVICE_SLOT_MAPPING_INFO + { + ULONG MapCount; + MBB_ARRAY_ELEMENT SlotMapList[ 1 ]; + } MBB_MS_DEVICE_SLOT_MAPPING_INFO; + +typedef struct _MBB_MS_DEVICE_SLOT_MAPPING_INFO *PMBB_MS_DEVICE_SLOT_MAPPING_INFO; + +typedef struct _MBB_MS_SLOT_INFO_REQ + { + ULONG SlotIndex; + } MBB_MS_SLOT_INFO_REQ; + +typedef struct _MBB_MS_SLOT_INFO_REQ *PMBB_MS_SLOT_INFO_REQ; + +typedef struct _MBB_MS_SLOT_INFO + { + ULONG SlotIndex; + MBB_BASICCONNECTEXT_UICCSLOT_STATE State; + } MBB_MS_SLOT_INFO; + +typedef struct _MBB_MS_SLOT_INFO *PMBB_MS_SLOT_INFO; + +typedef struct _MBB_MS_PCO_VALUE + { + ULONG SessionId; + ULONG PcoDataSize; + MBB_PCO_TYPE PcoDataType; + UCHAR PcoDataBuffer[ 1 ]; + } MBB_MS_PCO_VALUE; + +typedef struct _MBB_MS_PCO_VALUE *PMBB_MS_PCO_VALUE; + +typedef struct _MBB_MS_BASE_STATIONS_INFO_REQ + { + ULONG MaxGSMCount; + ULONG MaxUMTSCount; + ULONG MaxTDSCDMACount; + ULONG MaxLTECount; + ULONG MaxCDMACount; + } MBB_MS_BASE_STATIONS_INFO_REQ; + +typedef struct _MBB_MS_BASE_STATIONS_INFO_REQ *PMBB_MS_BASE_STATIONS_INFO_REQ; + +typedef struct _MBB_MS_BASE_STATIONS_INFO_REQ_V2 + { + ULONG MaxGSMCount; + ULONG MaxUMTSCount; + ULONG MaxTDSCDMACount; + ULONG MaxLTECount; + ULONG MaxCDMACount; + ULONG MaxNRCount; + } MBB_MS_BASE_STATIONS_INFO_REQ_V2; + +typedef struct _MBB_MS_BASE_STATIONS_INFO_REQ_V2 *PMBB_MS_BASE_STATIONS_INFO_REQ_V2; + +typedef struct _MBB_MS_BASE_STATIONS_INFO + { + MBB_DATA_CLASS_VALUE SystemType; + MBB_ARRAY_ELEMENT GSMServingCell; + MBB_ARRAY_ELEMENT UMTSServingCell; + MBB_ARRAY_ELEMENT TDSCDMAServingCell; + MBB_ARRAY_ELEMENT LTEServingCell; + MBB_ARRAY_ELEMENT GSMNmr; + MBB_ARRAY_ELEMENT UMTSMrl; + MBB_ARRAY_ELEMENT TDSCDMAMrl; + MBB_ARRAY_ELEMENT LTEMrl; + MBB_ARRAY_ELEMENT CDMAMrl; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_BASE_STATIONS_INFO; + +typedef struct _MBB_MS_BASE_STATIONS_INFO *PMBB_MS_BASE_STATIONS_INFO; + +typedef struct _MBB_MS_BASE_STATIONS_INFO_V2 + { + MBB_DATA_CLASS_VALUE SystemType; + MBB_DATA_SUBCLASS_VALUE SystemSubType; + MBB_ARRAY_ELEMENT GSMServingCell; + MBB_ARRAY_ELEMENT UMTSServingCell; + MBB_ARRAY_ELEMENT TDSCDMAServingCell; + MBB_ARRAY_ELEMENT LTEServingCell; + MBB_ARRAY_ELEMENT GSMNmr; + MBB_ARRAY_ELEMENT UMTSMrl; + MBB_ARRAY_ELEMENT TDSCDMAMrl; + MBB_ARRAY_ELEMENT LTEMrl; + MBB_ARRAY_ELEMENT CDMAMrl; + MBB_ARRAY_ELEMENT NRServingCells; + MBB_ARRAY_ELEMENT NRNeighborCells; + UCHAR DataBuffer[ 1 ]; + } MBB_MS_BASE_STATIONS_INFO_V2; + +typedef struct _MBB_MS_BASE_STATIONS_INFO_V2 *PMBB_MS_BASE_STATIONS_INFO_V2; + +typedef struct _MBB_MODEM_LOGGING_CONFIG + { + ULONG Version; + ULONG MaxSegmentSize; + ULONG MaxFlushTime; + MBB_BASICCONNECTEXT_MODEM_LOGGING_LEVEL_CONFIG LevelConfig; + } MBB_MODEM_LOGGING_CONFIG; + +typedef struct _MBB_MODEM_LOGGING_CONFIG *PMBB_MODEM_LOGGING_CONFIG; + +typedef struct _MBB_TLV_IE + { + MBB_TLV_TYPE Type; + UCHAR Reserved; + UCHAR PaddingLength; + ULONG DataLength; + } MBB_TLV_IE; + +typedef struct _MBB_TLV_IE *PMBB_TLV_IE; + +typedef +enum _MBB_ACCESS_TYPE + { + MbbAccessUnknown = 0, + MbbAccess3GPP = 1, + MbbAccessNon3GPP = 2, + MbbAccessMaximum = ( MbbAccessNon3GPP + 1 ) + } MBB_ACCESS_TYPE; + +typedef struct _MBB_PRE_DFLT_NSSAI_INFO + { + MBB_ACCESS_TYPE AccessType; + MBB_TLV_IE PreferredNSSAI; + } MBB_PRE_DFLT_NSSAI_INFO; + +typedef struct _MBB_PRE_DFLT_NSSAI_INFO *PMBB_PRE_DFLT_NSSAI_INFO; + +typedef struct _MBB_SNSSAI_INFO + { + UCHAR SnssaiLength; + UCHAR Sst; + } MBB_SNSSAI_INFO; + +typedef struct _MBB_SNSSAI_INFO *PMBB_SNSSAI_INFO; + +typedef struct _MBB_TAI_LIST_SINGLE_PLMN + { + MBB_PLMN Plmn; + UCHAR ElementCount; + ULONG TacList[ 1 ]; + } MBB_TAI_LIST_SINGLE_PLMN; + +typedef struct _MBB_TAI_LIST_SINGLE_PLMN *PMBB_TAI_LIST_SINGLE_PLMN; + +typedef struct _MBB_TAI_LIST_MULTI_PLMNS + { + UCHAR ElementCount; + MBB_TAI TaiList[ 1 ]; + } MBB_TAI_LIST_MULTI_PLMNS; + +typedef struct _MBB_TAI_LIST_MULTI_PLMNS *PMBB_TAI_LIST_MULTI_PLMNS; + +typedef struct _MBB_TAI_LIST_INFO + { + UCHAR ListType; + /* [switch_is] */ /* [switch_type] */ union __MIDL___MIDL_itf_MbbMessages_0000_0000_0002 + { + /* [case()] */ MBB_TAI_LIST_SINGLE_PLMN SinglePlmnTaiList; + /* [case()] */ MBB_TAI_LIST_MULTI_PLMNS MultiPlmnsTaiList; + } u; + } MBB_TAI_LIST_INFO; + +typedef struct _MBB_TAI_LIST_INFO *PMBB_TAI_LIST_INFO; + +typedef struct _MBB_DNN + { + UCHAR DnnLength; + } MBB_DNN; + +typedef struct _MBB_DNN *PMBB_DNN; + +typedef struct _MBB_LADN + { + MBB_DNN Dnn; + } MBB_LADN; + +typedef struct _MBB_LADN *PMBB_LADN; + +typedef +enum _MBB_MODEM_CONFIG_STATUS + { + ModemConfigStatusUnknown = 0, + ModemConfigStatusStarted = 1, + ModemConfigStatusCompleted = 2, + ModemConfigStatusMaximum = ( ModemConfigStatusCompleted + 1 ) + } MBB_MODEM_CONFIG_STATUS; + +typedef struct _MBB_MODEM_CONFIG_INFO + { + MBB_MODEM_CONFIG_STATUS ConfigStatus; + MBB_TLV_IE ConfigName; + } MBB_MODEM_CONFIG_INFO; + +typedef struct _MBB_MODEM_CONFIG_INFO *PMBB_MODEM_CONFIG_INFO; + +typedef +enum _MBB_MICO_MODE + { + MicoModeDisabled = 0, + MicoModeEnabled = 1, + MicoModeUnsupported = 2, + MBIMMicoModeDefault = 3, + MicoModeMaximum = ( MBIMMicoModeDefault + 1 ) + } MBB_MICO_MODE; + +typedef +enum _MBB_DRX_PARAMS + { + DRXNotSpecified = 0, + MBIMDRXNotSupported = 1, + DRXCycle32 = 2, + DRXCycle64 = 3, + DRXCycle128 = 4, + DRXCycle256 = 5, + DRXCycleMaximum = ( DRXCycle256 + 1 ) + } MBB_DRX_PARAMS; + +typedef +enum _MBB_DEFAULT_PDU_HINT + { + MBIMDefaultPDUSessionActivationUnlikely = 0, + MBIMDefaultPDUSessionActivationLikely = 1, + DefaultPDUMaximum = ( MBIMDefaultPDUSessionActivationLikely + 1 ) + } MBB_DEFAULT_PDU_HINT; + +typedef +enum _MBB_MS_LADN_IND + { + LADNInfoNotNeeded = 0, + LADNInfoRequested = 1, + LADNInfoMaximum = ( LADNInfoRequested + 1 ) + } MBB_MS_LADN_IND; + +typedef struct _MBB_REGISTRATION_PARAMS_INFO + { + MBB_MICO_MODE MicoMode; + MBB_DRX_PARAMS DRXParams; + MBB_MS_LADN_IND LADNInfo; + MBB_DEFAULT_PDU_HINT DefaultPDUHint; + ULONG ReRegisterIfNeeded; + } MBB_REGISTRATION_PARAMS_INFO; + +typedef struct _MBB_REGISTRATION_PARAMS_INFO *PMBB_REGISTRATION_PARAMS_INFO; + +typedef +enum _MBB_MICO_IND + { + RaaiTypeRaNotAllocated = 0, + RaaiTypeRaAllocated = 1, + RaaiTypeNotAvailable = 0xffffffff + } MBB_MICO_IND; + +typedef struct _MBB_NW_PARAMS_QUERY_INFO + { + USHORT AreConfigurationsNeeded; + USHORT AreUEPoliciesNeeded; + } MBB_NW_PARAMS_QUERY_INFO; + +typedef struct _MBB_NW_PARAMS_QUERY_INFO *PMBB_NW_PARAMS_QUERY_INFO; + +typedef struct _MBB_NW_PARAMS_INFO + { + MBB_MICO_IND MicoInd; + MBB_DRX_PARAMS DRXParams; + } MBB_NW_PARAMS_INFO; + +typedef struct _MBB_NW_PARAMS_INFO *PMBB_NW_PARAMS_INFO; + +typedef +enum _MBB_WAKE_TYPE + { + WakeTypeCIDResponse = 0, + WakeTypeCIDIndication = 1, + WakeTypePacket = 2 + } MBB_WAKE_TYPE; + +typedef struct _MBB_WAKE_REASON + { + MBB_WAKE_TYPE WakeType; + ULONG SessionId; + } MBB_WAKE_REASON; + +typedef struct _MBB_WAKE_REASON *PMBB_WAKE_REASON; + +typedef struct _MBB_WAKE_COMMAND + { + MBB_COMMAND Command; + ULONG PayloadOffset; + ULONG PayloadSize; + UCHAR DataBuffer[ 1 ]; + } MBB_WAKE_COMMAND; + +typedef struct _MBB_WAKE_COMMAND *PMBB_WAKE_COMMAND; + +typedef struct _MBB_WAKE_PACKET + { + ULONG FilterId; + ULONG OriginalPacketSize; + ULONG SavedPacketOffset; + ULONG SavedPacketSize; + UCHAR DataBuffer[ 1 ]; + } MBB_WAKE_PACKET; + +typedef struct _MBB_WAKE_PACKET *PMBB_WAKE_PACKET; + +#include + + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/network/wwan/cxwmbclass/inc/mbbncm.h b/network/wwan/cxwmbclass/inc/mbbncm.h new file mode 100644 index 000000000..9731dedf2 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/mbbncm.h @@ -0,0 +1,431 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once + +#define NCM10_CC_INTERFACE_CLASS (0x02) +#define NCM10_CC_INTERFACE_SUBCLASS (0x0d) +#define NCM10_CC_INTERFACE_PROTOCOL (0x00) + +#define MBIM_CC_INTERFACE_CLASS (0x02) +#define MBIM_CC_INTERFACE_SUBCLASS (0x0e) +#define MBIM_CC_INTERFACE_PROTOCOL (0x00) +#define MBIM_CC_INTERFACE_NBL_PROTOCOL (0x01) +#define MBIM_CC_INTERFACE_NETPACKET_PROTOCOL (0x02) + + +#define MBIM_DC_INTERFACE_CLASS (0x0A) +#define MBIM_DC_INTERFACE_SUBCLASS (0x00) +#define MBIM_DC_INTERFACE_PROTOCOL (0x02) + +#define MBIM_MBB_FUNCDESC_MIN_VERSION (0x0100) +#define MBIM_MBB_FUNCDESC_EXTENDED_MIN_VERSION (0x0100) + +#define SEND_ENCAPSULATE_COMMAND (0x00) +#define GET_ENCAPSULATE_RESPONSE (0x01) +#define RESET_FUNCTION (0x05) +#define SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER (0x41) +#define GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER (0x42) +#define SET_PACKET_FILTER (0x43) +#define GET_STATISTIC (0x44) + +#define GET_NTB_PARAMETERS (0x80) +#define GET_NBT_FORMAT (0x83) +#define SET_NBT_FORMAT (0x84) +#define GET_NTB_INPUT_SIZE (0x85) +#define SET_NTB_INPUT_SIZE (0x86) +#define GET_MAX_DATAGRAM_SIZE (0x87) + + +#define MBIM_MIN_SEGMENT_SIZE (1280) +#define MBIM_MAX_PACKET_FILTER_SIZE (192) +#define MBIM_MIN_NUMBER_OF_PACKET_FILTERS (16) +#define MBIM_MIN_MTU_SIZE (1280) +#define MBIM_MAX_MTU_SIZE (1500) + +#define USB_CDC_CS_DESCRIPTOR_TYPE (0x24) + +#define USB_CDC_CS_DESCRIPTOR_SUBTYPE (0x0) +#define USB_CDC_UNION_DESCRIPTOR_SUBTYPE (0x6) +#define USB_CDC_CS_ECM_DESCRIPTOR_SUBTYPE (0xf) +#define USB_CDC_CS_NCM_DESCRIPTOR_SUBTYPE (0x1a) +#define USB_CDC_CS_MBB_DESCRIPTOR_SUBTYPE (0x1b) +#define USB_CDC_CS_MBB_DESCRIPTOR_EXTENDED_SUBTYPE (0x1c) + + +#define USB_CDC_NOTIFICATION_NETWORK_CONNECTION (0x00) +#define USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE (0x01) +#define USB_CDC_NOTIFICATION_CONNECTION_SPEED_CHANGE (0x2a) + +#define NCM_NETWORK_CAPS_SET_FILTER_SUPPORTED (1 << 0) +#define NCM_NETWORK_CAPS_GET_SET_ADDRESS_SUPPORTED (1 << 1) +#define NCM_NETWORK_CAPS_ENCAPSULATED_COMMAND_SUPPORTED (1 << 2) +#define NCM_NETWORK_CAPS_MAX_DATAGRAM_SUPPORTED (1 << 3) +#define NCM_NETWORK_CAPS_GET_SET_CRC_SUPPORTED (1 << 4) +#define NCM_NETWORK_CAPS_GET_8_BYTE_INPUT_SIZE_SUPPORTED (1 << 5) + +#define NCM_NTB_FORMAT_16_BIT (1 << 0) +#define NCM_NTB_FORMAT_32_BIT (1 << 1) + +#define NCM_PACKET_FILTER_DIRECTED (1 << 2) + +#define NCM_SET_NTB_FORMAT_16_BIT (0x0) +#define NCM_SET_NTB_FORMAT_32_BIT (0x1) + + + +#define NCM_STAT_RESERVED 0x00 +#define NCM_XMIT_OK 0x01 +#define NCM_RCV_OK 0x02 +#define NCM_XMIT_ERROR 0x03 +#define NCM_RCV_ERROR 0x04 +#define NCM_RCV_NO_BUFFER 0x05 +#define NCM_DIRECTED_BYTES_XMIT 0x06 +#define NCM_DIRECTED_FRAMES_XMIT 0x07 +#define NCM_MULTICAST_BYTES_XMIT 0x08 +#define NCM_MULTICAST_FRAMES_XMIT 0x09 +#define NCM_BROADCAST_BYTES_XMIT 0x0A +#define NCM_BROADCAST_FRAMES_XMIT 0x0B +#define NCM_DIRECTED_BYTES_RCV 0x0C +#define NCM_DIRECTED_FRAMES_RCV 0x0D +#define NCM_MULTICAST_BYTES_RCV 0x0E +#define NCM_MULTICAST_FRAMES_RCV 0x0F +#define NCM_BROADCAST_BYTES_RCV 0x10 +#define NCM_BROADCAST_FRAMES_RCV 0x11 +#define NCM_RCV_CRC_ERROR 0x12 +#define NCM_TRANSMIT_QUEUE_LENGTH 0x13 +#define NCM_RCV_ERROR_ALIGNMENT 0x14 +#define NCM_XMIT_ONE_COLLISION 0x15 +#define NCM_XMIT_MORE_COLLISIONS 0x16 +#define NCM_XMIT_DEFERRED 0x17 +#define NCM_XMIT_MAX_COLLISIONS 0x18 +#define NCM_RCV_OVERRUN 0x19 +#define NCM_XMIT_UNDERRUN 0x1A +#define NCM_XMIT_HEARTBEAT_FAILURE 0x1B +#define NCM_XMIT_TIMES_CRS_LOST 0x1C +#define NCM_XMIT_LATE_COLLISIONS 0x1D + +#define NCM_NDP_SESSION_SHIFT 24 +#define NCM_NDP_SIGNATURE_MASK 0x00FFFFFF + +#define NCM_NTH16_SIG 'HMCN' +#define NCM_NTH32_SIG 'hmcn' + +#define NCM_NDP16_IPS 'SPI' +#define NCM_NDP16_VENDOR 'SSD' + +#define NCM_NDP32_IPS 'spi' +#define NCM_NDP32_VENDOR 'ssd' + +#define NCM_CID_SIG 'dcbm' + +#pragma pack( push,1) + +typedef struct _NCM_NTB_PARAMETER { + + USHORT wLength; + USHORT bmNtbFormatSupported; + ULONG dwNtbInMaxSize; + USHORT wNdpInDivisor; + USHORT wNdpInPayloadRemainder; + USHORT wNdpInAlignment; + USHORT wReserved1; + ULONG dwNtbOutMaxSize; + USHORT wNdpOutDivisor; + USHORT wNdpOutPayloadRemainder; + USHORT wNdpOutAlignment; + USHORT wNtbOutMaxDatagrams; + +} NCM_NTB_PARAMETER, *PNCM_NTB_PARAMETER; + +typedef struct _USB_CS_DESCRIPTOR { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + +} USB_CS_DESCRIPTOR, *PUSB_CS_DESCRIPTOR; + +typedef struct _USB_CS_UNION_DESCRIPTOR { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + BYTE bControlInterface; + BYTE bSubordinateInterface[1]; + +} USB_CS_UNION_DESCRIPTOR, *PUSB_CS_UNION_DESCRIPTOR; + + +typedef struct _USB_CS_CDC_DESCRIPTOR { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + USHORT wCDCVersion; + +} USB_CS_CDC_DESCRIPTOR, *PUSB_CS_CDC_DESCRIPTOR; + +typedef struct _USB_CS_ECM_DESCRIPTOR { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + BYTE iMacAddress; + ULONG bmEthernetStatistics; + USHORT wMaxSegmentSize; + USHORT wNumberMCFilters; + BYTE bNumberPowerFilters; + +} USB_CS_ECM_DESCRIPTOR, *PUSB_CS_ECM_DESCRIPTOR; + +typedef struct _USB_CS_NCM_DESCRIPTOR { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + USHORT wNcmVersion; + BYTE bmNetworkCapabilities; + +} USB_CS_NCM_DESCRIPTOR, *PUSB_CS_NCM_DESCRIPTOR; + + +typedef struct _USB_CS_MBB_DESCRIPTOR { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + USHORT wMbbVersion; + USHORT wMaxControlMessage; + BYTE bNumberPowerFilters; + BYTE bMaxFilterSize; + USHORT wMaxSegmentSize; + BYTE bmNetworkCapabilities; + +} USB_CS_MBB_DESCRIPTOR, *PUSB_CS_MBB_DESCRIPTOR; + +typedef struct _USB_CS_MBB_DESCRIPTOR_EXTENDED { + + BYTE bLength; + BYTE bDescriptorType; + BYTE bSubType; + USHORT wMbbVersion; + BYTE bMaxOutstandingCommandMessages; + USHORT wMTU; + +} USB_CS_MBB_DESCRIPTOR_EXTENDED, *PUSB_CS_MBB_DESCRIPTOR_EXTENDED; + +typedef struct _USB_CDC_NOTIFICATION { + + BYTE bmRequestType; + BYTE bNotificationCode; + USHORT wValue; + USHORT wIndex; + USHORT wLength; + +} USB_CDC_NOTIFICATION, *PUSB_CDC_NOTIFICATION; + +typedef struct _USB_CDC_NOTIFICATION_SPEED_CHANGE { + + USB_CDC_NOTIFICATION NotificationHeader; + ULONG DownLinkBitRate; + ULONG UpLinkBitRate; + +} USB_CDC_NOTIFICATION_SPEED_CHANGE, *PUSB_CDC_NOTIFICATION_SPEED_CHANGE; + + +typedef struct _NCM_NTH16 { + + ULONG dwSignature; + USHORT wHeaderLength; + USHORT wSequence; + USHORT wBlockLength; + USHORT wFpIndex; + +} NCM_NTH16, *PNCM_NTH16; + +typedef struct _NCM_NTH32 { + + ULONG dwSignature; + USHORT wHeaderLength; + USHORT wSequence; + ULONG dwBlockLength; + ULONG dwFpIndex; + +} NCM_NTH32, *PNCM_NTH32; + +typedef struct _NCM_NDP16_DATAGRAM { + + USHORT wDatagramIndex; + USHORT wDatagramLength; + +} NCM_NDP16_DATAGRAM, *PNCM_NDP16_DATAGRAM; + + +typedef struct _NCM_NDP16 { + + ULONG dwSignature; + USHORT wLength; + USHORT wNextFpIndex; + + NCM_NDP16_DATAGRAM Datagram[1]; + +} NCM_NDP16, *PNCM_NDP16; + + +typedef struct _NCM_NDP32_DATAGRAM { + + ULONG dwDatagramIndex; + ULONG dwDatagramLength; + +} NCM_NDP32_DATAGRAM, *PNCM_NDP32_DATAGRAM; + + +typedef struct _NCM_NDP32 { + + ULONG dwSignature; + USHORT wLength; + USHORT wReserved6; + ULONG dwNextFpIndex; + ULONG dwReserved12; + + NCM_NDP32_DATAGRAM Datagram[1]; + +} NCM_NDP32, *PNCM_NDP32; + + +#pragma pack( pop) + +// +// NTB +// + +#define MBB_NTB_GET_OFFSET(NTH,_X_) ((ULONG)(((SIZE_T)(_X_))-((SIZE_T)(NTH)))) +#define MBB_NTB_GET_SEQUENCE(NTH) (((PNCM_NTH32)(NTH))->wSequence) +#define MBB_NTB_GET_SIGNATURE(NTH) (((PNCM_NTH32)(NTH))->dwSignature) +#define MBB_NTB_GET_HEADER_LENGTH(NTH) (((PNCM_NTH32)(NTH))->wHeaderLength) +#define MBB_NTB_IS_32BIT(NTH) (MBB_NTB_GET_SIGNATURE(NTH) == NCM_NTH32_SIG) +#define MBB_NTB_IS_16BIT(NTH) (MBB_NTB_GET_SIGNATURE(NTH) == NCM_NTH16_SIG) + +// +// NTB32 + +#define MBB_NTH32_GET_SEQUENCE(NTH) MBB_NTB_GET_SEQUENCE(NTH) +#define MBB_NTH32_GET_SIGNATURE(NTH) MBB_NTB_GET_SIGNATURE(NTH) +#define MBB_NTH32_GET_HEADER_LENGTH(NTH) MBB_NTB_GET_HEADER_LENGTH(NTH) +#define MBB_NTH32_GET_BLOCK_LENGTH(NTH) ((NTH)->dwBlockLength) +#define MBB_NTH32_GET_FIRST_NDP_OFFSET(NTH) ((NTH)->dwFpIndex) +#define MBB_NTH32_GET_FIRST_NDP(NTH) ((MBB_NTH32_GET_FIRST_NDP_OFFSET(NTH) != 0)? ((PNCM_NDP32)(((PCHAR)(NTH)) + MBB_NTH32_GET_FIRST_NDP_OFFSET(NTH))): NULL) +#define MBB_NTH32_IS_VALID_BLOCK_LENGTH(NTH,MAXLEN) (MBB_NTH32_GET_BLOCK_LENGTH(NTH) <= (MAXLEN)) +#define MBB_NTH32_IS_VALID_HEADER_LENGTH(NTH) (MBB_NTB_GET_HEADER_LENGTH(NTH) == sizeof(NCM_NTH32)) +#define MBB_NTH32_IS_VALID_SIGNATURE(NTH) (MBB_NTB_GET_SIGNATURE(NTH) == NCM_NTH32_SIG) +#define MBB_NTH32_IS_VALID_FIRST_NDP(NTH) \ + ( \ + MBB_NTH32_GET_FIRST_NDP_OFFSET(NTH)<= (ULONG_MAX - sizeof(NCM_NDP32)) && \ + (MBB_NTH32_GET_FIRST_NDP_OFFSET(NTH) + sizeof(NCM_NDP32)) <= MBB_NTH32_GET_BLOCK_LENGTH(NTH) \ + ) + +#define MBB_NDP32_GET_SIGNATURE(NDP) ((NDP)->dwSignature) +#define MBB_NDP32_GET_SESSIONID(NDP) (MBB_NDP32_GET_SIGNATURE(NDP) >> NCM_NDP_SESSION_SHIFT) +#define MBB_NDP32_GET_SIGNATURE_TYPE(NDP) (MBB_NDP32_GET_SIGNATURE(NDP) & NCM_NDP_SIGNATURE_MASK) +#define MBB_NDP32_GET_LENGTH(NDP) ((NDP)->wLength) +#define MBB_NDP32_GET_NEXT_NDP_OFFSET(NDP) ((NDP)->dwNextFpIndex) +#define MBB_NDP32_GET_NEXT_NDP(NTH,NDP) ((MBB_NDP32_GET_NEXT_NDP_OFFSET(NDP) != 0)? ((PNCM_NDP32)(((PCHAR)(NTH)) + MBB_NDP32_GET_NEXT_NDP_OFFSET(NDP))): NULL) +#define MBB_NDP32_GET_DATAGRAM_COUNT(NDP) ((MBB_NDP32_GET_LENGTH(NDP)-FIELD_OFFSET(NCM_NDP32,Datagram)) / sizeof(NCM_NDP32_DATAGRAM)) +#define MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) ((NDP)->Datagram[(IDX)].dwDatagramIndex) +#define MBB_NDP32_GET_DATAGRAM_LENGTH(NDP,IDX) ((NDP)->Datagram[(IDX)].dwDatagramLength) +#define MBB_NDP32_GET_DATAGRAM(NTH,NDP,IDX) ((MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) != 0)? (((PCHAR)(NTH)) + MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX)): NULL) +#define MBB_NDP32_IS_DATAGRAM_PRESENT(NDP,IDX) ((FIELD_OFFSET(NCM_NDP32,Datagram)+((IDX)*sizeof(NCM_NDP32_DATAGRAM))) <= MBB_NDP32_GET_LENGTH(NDP)) + +#define MBB_NTB32_IS_END_DATAGRAM(NTH,NDP,IDX) \ + ( \ + MBB_NDP32_IS_DATAGRAM_PRESENT(NDP,IDX) && \ + ( \ + MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) == 0 || \ + MBB_NDP32_GET_DATAGRAM_LENGTH(NDP,IDX) == 0 \ + ) \ + ) +#define MBB_NTB32_IS_VALID_DATAGRAM(NTH,NDP,IDX) \ + ( \ + MBB_NDP32_IS_DATAGRAM_PRESENT(NDP,IDX) && \ + MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) != 0 && \ + MBB_NDP32_GET_DATAGRAM_LENGTH(NDP,IDX) != 0 && \ + MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) < MBB_NTH32_GET_BLOCK_LENGTH(NTH) && \ + MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) <= (ULONG_MAX - MBB_NDP32_GET_DATAGRAM_LENGTH(NDP,IDX)) && \ + (MBB_NDP32_GET_DATAGRAM_OFFSET(NDP,IDX) + MBB_NDP32_GET_DATAGRAM_LENGTH(NDP,IDX)) <= MBB_NTH32_GET_BLOCK_LENGTH(NTH) \ + ) +#define MBB_NTB32_IS_VALID_NDP_LENGTH(NTH,NDP) \ + ( \ + (MBB_NTB_GET_OFFSET(NTH,NDP) < MBB_NTH32_GET_BLOCK_LENGTH(NTH)) && \ + (MBB_NDP32_GET_LENGTH(NDP) >= FIELD_OFFSET(NCM_NDP32,Datagram)) && \ + (MBB_NTB_GET_OFFSET(NTH,NDP) <= ULONG_MAX - MBB_NDP32_GET_LENGTH(NDP)) && \ + ((MBB_NTB_GET_OFFSET(NTH,NDP)+MBB_NDP32_GET_LENGTH(NDP)) <= MBB_NTH32_GET_BLOCK_LENGTH(NTH)) \ + ) +#define MBB_NTB32_IS_VALID_NDP_SIGNATURE(NDP) \ + ( \ + ((MBB_NDP32_GET_SIGNATURE(NDP) & NCM_NDP_SIGNATURE_MASK) == NCM_NDP32_IPS) || \ + ((MBB_NDP32_GET_SIGNATURE(NDP) & NCM_NDP_SIGNATURE_MASK) == NCM_NDP32_VENDOR) \ + ) + +// +// NTB16 +// + +#define MBB_NTH16_GET_SEQUENCE(NTH) MBB_NTB_GET_SEQUENCE(NTH) +#define MBB_NTH16_GET_SIGNATURE(NTH) MBB_NTB_GET_SIGNATURE(NTH) +#define MBB_NTH16_GET_HEADER_LENGTH(NTH) MBB_NTB_GET_HEADER_LENGTH(NTH) +#define MBB_NTH16_GET_BLOCK_LENGTH(NTH) ((NTH)->wBlockLength) +#define MBB_NTH16_GET_FIRST_NDP_OFFSET(NTH) ((NTH)->wFpIndex) +#define MBB_NTH16_GET_FIRST_NDP(NTH) ((MBB_NTH16_GET_FIRST_NDP_OFFSET(NTH) != 0)? ((PNCM_NDP16)(((PCHAR)(NTH)) + MBB_NTH16_GET_FIRST_NDP_OFFSET(NTH))): NULL) +#define MBB_NTH16_IS_VALID_BLOCK_LENGTH(NTH,MAXLEN) (MBB_NTH16_GET_BLOCK_LENGTH(NTH) <= (MAXLEN)) +#define MBB_NTH16_IS_VALID_HEADER_LENGTH(NTH) (MBB_NTB_GET_HEADER_LENGTH(NTH) == sizeof(NCM_NTH16)) +#define MBB_NTH16_IS_VALID_SIGNATURE(NTH) (MBB_NTB_GET_SIGNATURE(NTH) == NCM_NTH16_SIG) +#define MBB_NTH16_IS_VALID_FIRST_NDP(NTH) \ + ( \ + MBB_NTH16_GET_FIRST_NDP_OFFSET(NTH) <= (USHRT_MAX - sizeof(NCM_NDP16)) &&\ + (MBB_NTH16_GET_FIRST_NDP_OFFSET(NTH) + sizeof(NCM_NDP16)) <= MBB_NTH16_GET_BLOCK_LENGTH(NTH) \ + ) + +#define MBB_NDP16_GET_SIGNATURE(NDP) ((NDP)->dwSignature) +#define MBB_NDP16_GET_SESSIONID(NDP) (MBB_NDP16_GET_SIGNATURE(NDP) >> NCM_NDP_SESSION_SHIFT) +#define MBB_NDP16_GET_SIGNATURE_TYPE(NDP) (MBB_NDP16_GET_SIGNATURE(NDP) & NCM_NDP_SIGNATURE_MASK) +#define MBB_NDP16_GET_LENGTH(NDP) ((NDP)->wLength) +#define MBB_NDP16_GET_NEXT_NDP_OFFSET(NDP) ((NDP)->wNextFpIndex) +#define MBB_NDP16_GET_NEXT_NDP(NTH,NDP) ((MBB_NDP16_GET_NEXT_NDP_OFFSET(NDP) != 0)? ((PNCM_NDP16)(((PCHAR)(NTH)) + MBB_NDP16_GET_NEXT_NDP_OFFSET(NDP))): NULL) +#define MBB_NDP16_GET_DATAGRAM_COUNT(NDP) ((MBB_NDP16_GET_LENGTH(NDP)-FIELD_OFFSET(NCM_NDP16,Datagram)) / sizeof(NCM_NDP16_DATAGRAM)) +#define MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) ((NDP)->Datagram[(IDX)].wDatagramIndex) +#define MBB_NDP16_GET_DATAGRAM_LENGTH(NDP,IDX) ((NDP)->Datagram[(IDX)].wDatagramLength) +#define MBB_NDP16_GET_DATAGRAM(NTH,NDP,IDX) ((MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) != 0)? (((PCHAR)(NTH)) + MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX)): NULL) +#define MBB_NDP16_IS_DATAGRAM_PRESENT(NDP,IDX) ((FIELD_OFFSET(NCM_NDP16,Datagram)+((IDX)*sizeof(NCM_NDP16_DATAGRAM))) <= MBB_NDP16_GET_LENGTH(NDP)) + +#define MBB_NTB16_IS_END_DATAGRAM(NTH,NDP,IDX) \ + ( \ + MBB_NDP16_IS_DATAGRAM_PRESENT(NDP,IDX) && \ + ( \ + MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) == 0 || \ + MBB_NDP16_GET_DATAGRAM_LENGTH(NDP,IDX) == 0 \ + ) \ + ) +#define MBB_NTB16_IS_VALID_DATAGRAM(NTH,NDP,IDX) \ + ( \ + MBB_NDP16_IS_DATAGRAM_PRESENT(NDP,IDX) && \ + MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) != 0 && \ + MBB_NDP16_GET_DATAGRAM_LENGTH(NDP,IDX) != 0 && \ + MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) < MBB_NTH16_GET_BLOCK_LENGTH(NTH) && \ + MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) <= (USHRT_MAX - MBB_NDP16_GET_DATAGRAM_LENGTH(NDP,IDX)) &&\ + (MBB_NDP16_GET_DATAGRAM_OFFSET(NDP,IDX) + MBB_NDP16_GET_DATAGRAM_LENGTH(NDP,IDX)) <= MBB_NTH16_GET_BLOCK_LENGTH(NTH) \ + ) +#define MBB_NTB16_IS_VALID_NDP_LENGTH(NTH,NDP) \ + ( \ + (MBB_NTB_GET_OFFSET(NTH,NDP) < MBB_NTH16_GET_BLOCK_LENGTH(NTH)) && \ + (MBB_NDP16_GET_LENGTH(NDP) >= FIELD_OFFSET(NCM_NDP16,Datagram)) && \ + (MBB_NTB_GET_OFFSET(NTH,NDP) <= (ULONG)(USHRT_MAX - MBB_NDP16_GET_LENGTH(NDP))) &&\ + ((MBB_NTB_GET_OFFSET(NTH,NDP)+MBB_NDP16_GET_LENGTH(NDP)) <= MBB_NTH16_GET_BLOCK_LENGTH(NTH)) \ + ) +#define MBB_NTB16_IS_VALID_NDP_SIGNATURE(NDP) \ + ( \ + ((MBB_NDP16_GET_SIGNATURE(NDP) & NCM_NDP_SIGNATURE_MASK) == NCM_NDP16_IPS) || \ + ((MBB_NDP16_GET_SIGNATURE(NDP) & NCM_NDP_SIGNATURE_MASK) == NCM_NDP16_VENDOR) \ + ) + diff --git a/network/wwan/cxwmbclass/inc/power.h b/network/wwan/cxwmbclass/inc/power.h new file mode 100644 index 000000000..0205fb8ee --- /dev/null +++ b/network/wwan/cxwmbclass/inc/power.h @@ -0,0 +1,11 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once + +EVT_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; +EVT_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; +EVT_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; +EVT_NET_DEVICE_PREVIEW_WAKE_SOURCE EvtDevicePreviewBitmapPattern; diff --git a/network/wwan/cxwmbclass/inc/precomp.h b/network/wwan/cxwmbclass/inc/precomp.h new file mode 100644 index 000000000..706407ba0 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/precomp.h @@ -0,0 +1,53 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define INITGUID +#include + +#include + +#include "mbbncm.h" + +#include "mbbmessages.h" +#define MBB_MAX_NUMBER_OF_SESSIONS 17 // including the default session for the physical/primary interface +#define MBB_DEFAULT_SESSION_ID 0 // for physical/primay interface. Must be 0. Do NOT change it. +#define MBB_INVALID_SESSION_ID MBB_MAX_NUMBER_OF_SESSIONS + +#define WMBCLASS_RADIO_STATE_OFF 0 +#define WMBCLASS_RADIO_STATE_ON 1 + +#include "BusInterface.h" + +#include "align.h" +#include "device.h" +#include "adapter.h" +#include "data.h" +#include "txqueue.h" +#include "util.h" +#include "usbbus.h" +#include "utils.h" diff --git a/network/wwan/cxwmbclass/inc/rxqueue.h b/network/wwan/cxwmbclass/inc/rxqueue.h new file mode 100644 index 000000000..fa57e6e05 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/rxqueue.h @@ -0,0 +1,26 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once + +typedef struct _MBB_RXQUEUE_CONTEXT +{ + PWMBCLASS_NETADAPTER_CONTEXT NetAdapterContext; + LONG NotificationEnabled; + NET_RING_COLLECTION const* DatapathDescriptor; + NET_EXTENSION ReturnContextExtension; + NET_EXTENSION VirtualAddressExtension; +} MBB_RXQUEUE_CONTEXT, *PMBB_RXQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MBB_RXQUEUE_CONTEXT, MbbGetRxQueueContext); + +EVT_WDF_OBJECT_CONTEXT_DESTROY EvtRxQueueDestroy; + +EVT_PACKET_QUEUE_SET_NOTIFICATION_ENABLED EvtRxQueueSetNotificationEnabled; +EVT_PACKET_QUEUE_ADVANCE EvtRxQueueAdvance; +EVT_PACKET_QUEUE_CANCEL EvtRxQueueCancel; + +VOID MbbNdisReceiveCallback(_In_ MBB_PROTOCOL_HANDLE ProtocolHandle, _In_ MBB_RECEIVE_CONTEXT ReceiveContext, _In_ PMDL Mdl); + +VOID EvtAdapterReturnRxBuffer(_In_ NETADAPTER Adapter, _In_ NET_FRAGMENT_RETURN_CONTEXT_HANDLE RxBufferReturnContext); diff --git a/network/wwan/cxwmbclass/inc/txqueue.h b/network/wwan/cxwmbclass/inc/txqueue.h new file mode 100644 index 000000000..7bab9c076 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/txqueue.h @@ -0,0 +1,22 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once + +typedef struct _MBB_TXQUEUE_CONTEXT +{ + PWMBCLASS_NETADAPTER_CONTEXT NetAdapterContext; + LONG NotificationEnabled; + UINT32 CompletionBatchSize; + NET_RING_COLLECTION const* DatapathDescriptor; + NET_EXTENSION MdlExtension; +} MBB_TXQUEUE_CONTEXT, *PMBB_TXQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MBB_TXQUEUE_CONTEXT, MbbGetTxQueueContext); + +EVT_WDF_OBJECT_CONTEXT_DESTROY EvtTxQueueDestroy; +EVT_PACKET_QUEUE_SET_NOTIFICATION_ENABLED EvtTxQueueSetNotificationEnabled; +EVT_PACKET_QUEUE_CANCEL EvtTxQueueCancel; +EVT_PACKET_QUEUE_ADVANCE EvtTxQueueAdvance; + +EVT_MBB_DEVICE_SEND_DEVICE_SERVICE_SESSION_DATA EvtMbbDeviceSendDeviceServiceSessionData; diff --git a/network/wwan/cxwmbclass/inc/usbbus.h b/network/wwan/cxwmbclass/inc/usbbus.h new file mode 100644 index 000000000..cca02f60a --- /dev/null +++ b/network/wwan/cxwmbclass/inc/usbbus.h @@ -0,0 +1,235 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once + +#define INITIALIZE_PASSIVE_LOCK(__lock) KeInitializeGuardedMutex(__lock) + +#define ACQUIRE_PASSIVE_LOCK(__lock) KeAcquireGuardedMutex(__lock) + +#define RELEASE_PASSIVE_LOCK(__lock) KeReleaseGuardedMutex(__lock) + +#define WMB_PUSH_LOCK EX_PUSH_LOCK + +#define INIT_PUSHLOCK(PushLock) ExInitializePushLock(PushLock) + +#define ACQUIRE_PUSHLOCK_EXCLUSIVE(PushLock) \ + do \ + { \ + KeEnterCriticalRegion(); \ + ExAcquirePushLockExclusive((PushLock)); \ + } while (0) + +#define RELEASE_PUSHLOCK_EXCLUSIVE(PushLock) \ + do \ + { \ + ExReleasePushLockExclusive((PushLock)); \ + KeLeaveCriticalRegion(); \ + } while (0) + +#define ACQUIRE_PUSHLOCK_SHARED(PushLock) \ + do \ + { \ + KeEnterCriticalRegion(); \ + ExAcquirePushLockShared((PushLock)); \ + } while (0) + +#define RELEASE_PUSHLOCK_SHARED(PushLock) \ + do \ + { \ + ExReleasePushLockShared((PushLock)); \ + KeLeaveCriticalRegion(); \ + } while (0) + +#define MAX_PREALLOCATED_WRITE_REQUESTS (20) + +//#define DEFAULT_INTERRUPT_PIPE_READ_SIZE (8) +#define DEFAULT_IO_TIMEOUT (10) + +#define MAX_HOST_NTB_SIZE (0x10000) +#define MAX_HOST_NTB_SIZE_FOR_UDE_MBIM (0x20000) +#define MAX_OUT_DATAGRAMS (64) + +#define INTERRUPT_REASSEMBLY_BUFFER_SIZE (64) + +#define MIN_CONTROL_MESSAGE_SIZE (64) +#define MAX_CONTROL_MESSAGE_SIZE (4096) + +#define ALT_DATA_SETTING_0_PIPES (0) +#define ALT_DATA_SETTING_1_PIPES (2) + +#define INITIAL_OPEN_TIMEOUT (5) +#define MAX_OPEN_RETRY_ATTEMPTS (4) + +#define PENDING_BULK_IN_READS (3) +#define PENDING_BULK_IN_READS_FOR_UDE_MBIM (10) + +typedef enum _BUS_STATE +{ + + BUS_STATE_CLOSED = 0, + BUS_STATE_CLOSING, + + BUS_STATE_OPENING, + BUS_STATE_OPENED + +} BUS_STATE, + *PBUS_STATE; + +typedef struct _POWER_FILTER_LOOKUP +{ + + ULONG PatternId; + BOOLEAN InUse; + +} POWER_FILTER_LOOKUP, *PPOWER_FILTER_LOOKUP; + +typedef struct _BUS_OBJECT +{ + + KGUARDED_MUTEX Lock; + BUS_STATE State; + + PDEVICE_OBJECT Pdo; + PDEVICE_OBJECT Fdo; + PDEVICE_OBJECT NextDeviceObject; + + MBB_PROTOCOL_HANDLE ProtocolHandle; + MBB_BUS_RESPONSE_AVAILABLE_CALLBACK ResponseAvailableCallback; + + MBB_BUS_DATA_RECEIVE_CALLBACK ReceiveDataCallback; + + MBB_BUS_SS_IDLE_CONFIRM_CALLBACK IdleConfirmCallback; + MBB_BUS_SS_IDLE_NOTIFICATION_COMPLETE_CALLBACK IdleNotificationComplete; + + WDFDEVICE WdfDevice; + WDFUSBDEVICE WdfUsbDevice; + + USHORT MaxControlChannelSize; + + USHORT MaxSegmentSize; + BYTE NcmParams; + BOOLEAN NtbFormat32Bit; + BYTE PowerFiltersSupported; + BYTE MaxPowerFilterSize; + + BYTE MaxOutstandingCommandMessages; + USHORT MTU; + + NCM_NTB_PARAMETER NtbParam; + + PWSTR Manufacturer; + PWSTR Model; + + ULONG MaxBulkInTransfer; + ULONG BulkInHeaderSize; + + BOOLEAN ChainedMdlsSupported; + + PIRP UsbSsIrp; + USB_IDLE_CALLBACK_INFO UsbSsCallback; + + KEVENT UsbSsIrpComplete; + + PPOWER_FILTER_LOOKUP PowerFilterTable; + + PUCHAR SyncInterruptReadBuffer; + + UCHAR InterruptReassemnblyBuffer[INTERRUPT_REASSEMBLY_BUFFER_SIZE]; + ULONG CurrentOffset; + ULONG ExpectLength; + + USHORT MbimVersion; + USHORT MbimExtendedVersion; + BOOLEAN RemoteWakeCapable; + + USB_CAP_DEVICE_INFO UsbCapDeviceInfo; + PVOID ModemContext; + +} BUS_OBJECT, *PBUS_OBJECT; + +typedef struct _WDF_DEVICE_INFO +{ + + PBUS_OBJECT BusObject; + +} WDF_DEVICE_INFO, *PWDF_DEVICE_INFO; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WDF_DEVICE_INFO, GetWdfDeviceInfo) + +// +// put this in the NIC data structure +// +typedef struct _USB_DEVICE_CONTEXT +{ + size_t NumberOfPipes; + + WDFWAITLOCK PipeStateLock; + + UCHAR UsbCommunicationInterfaceIndex; + UCHAR UsbDataInterfaceIndex; + + UCHAR UsbCommunicationInterfaceSetting; + UCHAR UsbDataInterfaceSetting; + + UCHAR WdfCommunicationInterfaceIndex; + UCHAR WdfDataInterfaceIndex; + + BOOLEAN BulkInputPipeConfigured; + BOOLEAN BulkInputPipeStarted; + ULONG BulkInputPipeMaxPacket; + WDFUSBPIPE BulkInputPipe; + + BOOLEAN BulkOutputPipeConfigured; + BOOLEAN BulkOutputPipeStarted; + ULONG BulkOutputPipeMaxPacket; + WDFUSBPIPE BulkOutputPipe; + + WDFUSBPIPE InterruptPipe; + + WDFIOTARGET InterruptPipeIoTarget; + ULONG InterruptPipeMaxPacket; + + WDFLOOKASIDE LookasideList; + + WDFSPINLOCK WriteCollectionLock; + WDFCOLLECTION WriteRequestCollection; + + WDFWORKITEM BulkPipeResetWorkitem; + LONG BulkPipeResetFlag; + EX_RUNDOWN_REF BulkPipeResetRundown; + PBUS_OBJECT BusObject; +} USB_DEVICE_CONTEXT, *PUSB_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(USB_DEVICE_CONTEXT, GetUsbDeviceContext) + +typedef struct _REQUEST_CONTEXT +{ + + PVOID CallbackContext; + union + { + + MBB_BUS_SEND_COMPLETION_CALLBACK Send; + MBB_BUS_RECEIVE_COMPLETION_CALLBACK Receive; + + } Callback; + + MBB_PROTOCOL_HANDLE ProtocolHandle; + + PUSB_DEVICE_CONTEXT UsbDeviceContext; + + PVOID Buffer; + ULONG BufferLength; + +} REQUEST_CONTEXT, *PREQUEST_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext) + +VOID MbbBusMiniportUsbIdle(PVOID Context); + +NTSTATUS +PreAllocateWriteRequests(WDFUSBDEVICE UsbDevice); + +#define IS_USB_DEVICE_REMOTE_WAKE_CAPABLE(deviceInformation) \ + ((deviceInformation.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE) > 0 ? TRUE : FALSE); diff --git a/network/wwan/cxwmbclass/inc/util.h b/network/wwan/cxwmbclass/inc/util.h new file mode 100644 index 000000000..12d166b47 --- /dev/null +++ b/network/wwan/cxwmbclass/inc/util.h @@ -0,0 +1,42 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once +typedef enum +{ + MbbPoolTagDefault = '0CBM', + MbbPoolTagNtbSend = '1CBM', + MbbPoolTagNblSend = '2CBM', + MbbPoolTagNbSend = '3CBM', + MbbPoolTagMdlReceive = '6CBM' +} MBB_POOL_TAG; + +#define ALLOCATE_PAGED_POOL(_y) ExAllocatePool2(POOL_FLAG_PAGED, _y, MbbPoolTagDefault) +#define ALLOCATE_NONPAGED_POOL(_y) ExAllocatePool2(POOL_FLAG_NON_PAGED, _y, MbbPoolTagDefault) +#define ALLOCATE_NONPAGED_POOL_WITH_TAG(_x, _y) ExAllocatePool2(POOL_FLAG_NON_PAGED, _x, _y) + +#define FREE_POOL(_x) \ + { \ + ExFreePool(_x); \ + _x = NULL; \ + }; + +#define MIN(_X_, _Y_) (((_X_) < (_Y_)) ? (_X_) : (_Y_)) +#define MAX(_X_, _Y_) (((_X_) > (_Y_)) ? (_X_) : (_Y_)) + +#define ALIGN_FLOOR(_VALUE_, _ALIGN_) ALIGN_DOWN_BY(_VALUE_, _ALIGN_) +#define ALIGN_CIELING(_VALUE_, _ALIGN_) ALIGN_UP_BY(_VALUE_, _ALIGN_) +#define ALIGN(_VALUE_, _ALIGN_) ALIGN_CIELING(_VALUE_, _ALIGN_) +#define ALIGN_AT_OFFSET(_VALUE_, _ALIGN_, _OFFSET_) \ + (((SIZE_T)(_VALUE_) <= (ALIGN_FLOOR(_VALUE_, _ALIGN_) + (_OFFSET_))) ? (ALIGN_FLOOR(_VALUE_, _ALIGN_) + (_OFFSET_)) \ + : (ALIGN(_VALUE_, _ALIGN_) + (_OFFSET_))) + +NTSTATUS +MbbNtbValidate(_In_ PVOID Nth, _In_ ULONG BufferLength, _In_ BOOLEAN Is32Bit, _Out_opt_ ULONG* NdpCount); + +NTSTATUS +CreateNonPagedWdfMemory(_In_ ULONG ObjectSize, _Out_ WDFMEMORY* WdfMemory, _Out_opt_ PVOID* ObjectMemory, _In_ WDFOBJECT Parent, _In_ ULONG PoolTag); + +PMDL AllocateNonPagedMdl(_In_reads_bytes_(Length) PVOID VirtualAddress, _In_ ULONG Length); + +VOID MbbRecvCancelNdps(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext, _In_ ULONG SessionId); diff --git a/network/wwan/cxwmbclass/inc/utils.h b/network/wwan/cxwmbclass/inc/utils.h new file mode 100644 index 000000000..e7d06637f --- /dev/null +++ b/network/wwan/cxwmbclass/inc/utils.h @@ -0,0 +1,61 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once +NTSTATUS +SendSyncControlCommand( + __in WDFUSBDEVICE WdfUsbDevice, + __in WDF_USB_BMREQUEST_DIRECTION Direction, + __in WDF_USB_BMREQUEST_RECIPIENT Recipient, + __in BYTE Request, + __in USHORT Value, + __inout_bcount_opt(BufferLength) PUCHAR Buffer, + __in ULONG BufferLength, + __out_opt PULONG BytesTransfered); + +NTSTATUS +TransactControlChannel( + __in PBUS_OBJECT BusObject, + __in ULONG TimeOut, + __in_bcount_opt(InBufferLength) PUCHAR InBuffer, + __in ULONG InBufferLength, + __out_bcount_opt(OutBufferLength) PUCHAR OutBuffer, + __in ULONG OutBufferLength, + __out PULONG BytesRead); + +NTSTATUS +ReadInterrupt(_In_ PBUS_OBJECT BusObject, _Inout_updates_bytes_(BufferLength) PUCHAR Buffer, _In_ ULONG BufferLength, _In_ ULONG Timeout, _Out_ PULONG BytesRead); + +NTSTATUS +GetDeviceString(__in WDFUSBDEVICE UsbDevice, __in UCHAR Index, __out PWSTR* String); + +NTSTATUS +MbbBusSetPacketFilter(__in MBB_BUS_HANDLE BusHandle, __in ULONG PacketFilter); + +NTSTATUS +MbbBusSetNtbInSize(__in MBB_BUS_HANDLE BusHandle, __in ULONG InSize); + +NTSTATUS +MbbBusGetStat(__in MBB_BUS_HANDLE BusHandle, __in USHORT StatIndex, __out ULONGLONG* Value); + +NTSTATUS +MbbBusSetNtbFormat(__in MBB_BUS_HANDLE BusHandle, __in USHORT Format); + +NTSTATUS +MbbBusResetFunction(__in MBB_BUS_HANDLE BusHandle); + +ULONG +ProcessInterruptPipeRead( + PBUS_OBJECT BusObject, + __in_ecount(NewFragmentLength) PCUCHAR NewFragment, + ULONG NewFragmentLength, + __out_ecount(MessageBufferSize) PUCHAR CompleteMessageBuffer, + ULONG MessageBufferSize); + +NTSTATUS +WaitForResponseAvailible(PBUS_OBJECT BusObject, ULONG TimeOut); + +NTSTATUS +MbbBusResetDeviceAndSetParms(__in PBUS_OBJECT BusObject); + +BOOLEAN IsUsbCapDeviceInfoValid(_In_ USB_CAP_DEVICE_INFO UsbCapDeviceInfo, _In_ ULONG CapResultLength); diff --git a/network/wwan/cxwmbclass/power.cpp b/network/wwan/cxwmbclass/power.cpp new file mode 100644 index 000000000..e0726975c --- /dev/null +++ b/network/wwan/cxwmbclass/power.cpp @@ -0,0 +1,116 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +#include "power.h" +#include "device.h" +#include "adapter.h" + +_Use_decl_annotations_ NTSTATUS EvtDeviceD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE previousPowerState) +{ + NTSTATUS status = STATUS_SUCCESS; + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + UNREFERENCED_PARAMETER(previousPowerState); + do + { + if (MbbBusIsStoped(deviceContext->BusHandle)) + { + // + // device was in d3, open it again + // + status = MbbBusStart(deviceContext->BusHandle); + + if (!NT_SUCCESS(status)) + { + WdfDeviceSetFailed(deviceContext->WdfDevice, WdfDeviceFailedAttemptRestart); + break; + } + } + else + { + MbbBusSetNotificationState(deviceContext->BusHandle, TRUE); + } + // Allow sessions to receive data from this point since RxQueueCreate happens later after D0Entry. We need cache NDPs receive before RxQueueCreate + for (int i = 0; i < MBB_MAX_NUMBER_OF_SESSIONS; i++) + { + if (deviceContext->Sessions[i].NetAdapterContext == NULL) + { + continue; + } + deviceContext->Sessions[i].NetAdapterContext->AllowRxTraffic = TRUE; + } + MbbBusStartDataPipes(deviceContext->BusHandle); + } while (FALSE); + + return status; +} + +_Use_decl_annotations_ NTSTATUS EvtDeviceD0Exit(WDFDEVICE Device, WDF_POWER_DEVICE_STATE TargetPowerState) +{ + UNREFERENCED_PARAMETER(TargetPowerState); + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + + MbbBusStopDataPipes(deviceContext->BusHandle); + // + // If the device is not armed for wake, close has been sent by MbbCx. All response available notifications from close in MbbCx to EvtDeviceD0Exit will be ignored. + // + // If the device is armed for wake, No response available notification after EvtDeviceArmWakeFromS0 where we stop the notification. + if (!deviceContext->m_armedWake) + { + MbbBusStop(deviceContext->BusHandle); + } + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ NTSTATUS EvtDevicePreviewBitmapPattern(WDFDEVICE Device, NETWAKESOURCE BitmapPattern) +{ + // We don't need to look at the pattern itself, only how many we currently have + UNREFERENCED_PARAMETER(BitmapPattern); + + NET_WAKE_SOURCE_LIST wakeSourceList; + NET_WAKE_SOURCE_LIST_INIT(&wakeSourceList); + NetDeviceGetWakeSourceList(Device, &wakeSourceList); + + auto const wakeSourceCount = NetWakeSourceListGetCount(&wakeSourceList); + size_t numberOfPowerFilters = 0; + + // Count how many power filters are currently stored for this device + for (size_t i = 0; i < wakeSourceCount; i++) + { + auto wakeSource = NetWakeSourceListGetElement(&wakeSourceList, i); + auto const wakeSourceType = NetWakeSourceGetType(wakeSource); + + if (wakeSourceType == NetWakeSourceTypeBitmapPattern) + { + numberOfPowerFilters++; + } + } + + auto const deviceContext = WmbClassGetDeviceContext(Device); + auto const maxPowerFilters = deviceContext->BusParams.PowerFiltersSupported; + + NT_ASSERT(numberOfPowerFilters <= maxPowerFilters); + + if (numberOfPowerFilters == maxPowerFilters) + { + return STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL; + } + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ NTSTATUS EvtDeviceArmWakeFromS0(WDFDEVICE Device) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + deviceContext->m_armedWake = true; + MbbBusSetNotificationState(deviceContext->BusHandle, FALSE); + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ VOID EvtDeviceDisarmWakeFromS0(WDFDEVICE Device) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + deviceContext->m_armedWake = false; +} diff --git a/network/wwan/cxwmbclass/rxqueue.cpp b/network/wwan/cxwmbclass/rxqueue.cpp new file mode 100644 index 000000000..836201a56 --- /dev/null +++ b/network/wwan/cxwmbclass/rxqueue.cpp @@ -0,0 +1,602 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +#include "device.h" +#include "rxqueue.h" + +#define MBB_NTH_GET_FIRST_NDP_OFFSET(IS32BIT, NTH) \ + ((IS32BIT) ? MBB_NTH32_GET_FIRST_NDP_OFFSET((PNCM_NTH32)NTH) : MBB_NTH16_GET_FIRST_NDP_OFFSET((PNCM_NTH16)NTH)) + +void MbbNotifyRxReady(_In_ NETPACKETQUEUE RxQueue) +{ + PMBB_RXQUEUE_CONTEXT rxQueueContext = MbbGetRxQueueContext(RxQueue); + if (InterlockedExchange(&rxQueueContext->NotificationEnabled, FALSE) == TRUE) + { + NetRxQueueNotifyMoreReceivedPacketsAvailable(RxQueue); + } +} + +VOID MbbRecvCleanup(_In_ PMBB_NDIS_RECEIVE_CONTEXT Receive) +{ + MbbBusReturnReceiveBuffer(Receive->BusHandle, Receive->BusContext, Receive->Mdl); + + WdfObjectDelete(Receive->ReceiveLookasideBufferMemory); +} + +VOID MbbRecvReturnNdp(_In_ PMBB_NDIS_RECEIVE_CONTEXT ReceiveContext, _In_opt_ PMBB_RECEIVE_NDP_CONTEXT ReceiveNdpContext) +{ + LONG newCompletedCount = InterlockedIncrement(&ReceiveContext->CompletedNdpCount); + if (newCompletedCount == ReceiveContext->TotalNdpCount) + { + MbbRecvCleanup(ReceiveContext); + } + if (ReceiveNdpContext != NULL) + { + WdfObjectDelete(ReceiveNdpContext->ReceiveNdpLookasideBufferMemory); + } +} + +_Use_decl_annotations_ VOID MbbRecvCancelNdps(PWMBCLASS_DEVICE_CONTEXT DeviceContext, ULONG SessionId) +{ + LIST_ENTRY tempList; + PLIST_ENTRY listEntry; + PLIST_ENTRY nextEntry; + PMBB_RECEIVE_NDP_CONTEXT receiveNdpContext = NULL; + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = DeviceContext->Sessions[SessionId].NetAdapterContext; + + InitializeListHead(&tempList); + + WdfSpinLockAcquire(DeviceContext->Sessions[SessionId].WdfRecvSpinLock); + InsertHeadList(&netAdapterContext->ReceiveNdpList, &tempList); + RemoveEntryList(&netAdapterContext->ReceiveNdpList); + InitializeListHead(&netAdapterContext->ReceiveNdpList); + // Cannot cache the received Ndps anymore + netAdapterContext->AllowRxTraffic = FALSE; + WdfSpinLockRelease(DeviceContext->Sessions[SessionId].WdfRecvSpinLock); + + for (listEntry = tempList.Flink; listEntry != &tempList; listEntry = nextEntry) + { + nextEntry = listEntry->Flink; + receiveNdpContext = CONTAINING_RECORD(listEntry, MBB_RECEIVE_NDP_CONTEXT, ReceiveNdpNode); + MbbRecvReturnNdp(receiveNdpContext->ReceiveContext, receiveNdpContext); + } +} + +void MbbReceiveDssData(__in PWMBCLASS_DEVICE_CONTEXT DeviceContext, __in ULONG SessionId, __in_bcount_opt(InBufferSize) PUCHAR InBuffer, __in ULONG InBufferSize) +{ + NTSTATUS status; + WDFMEMORY data; + + status = WdfMemoryCreatePreallocated(WDF_NO_OBJECT_ATTRIBUTES, InBuffer, InBufferSize, &data); + + if (NT_SUCCESS(status)) + { + DeviceContext->DSSPacketsReceivedCount++; + + MbbDeviceReceiveDeviceServiceSessionData(DeviceContext->WdfDevice, SessionId, data); + WdfObjectDelete(data); + } +} + +NTSTATUS +MbbRecvNdpUnpackDss32(_In_ PMBB_NDIS_RECEIVE_CONTEXT ReceiveContext, _In_ PNCM_NTH32 Nth, _In_ PNCM_NDP32 Ndp) +{ + UNREFERENCED_PARAMETER(Nth); + NTSTATUS status = STATUS_SUCCESS; + ULONG datagramCount = MBB_NDP32_GET_DATAGRAM_COUNT(Ndp); + ULONG sessionId = MBB_NDP32_GET_SESSIONID(Ndp); + for (ULONG index = 0; index < datagramCount; index++) + { + if (MBB_NTB32_IS_END_DATAGRAM(Nth, Ndp, index)) + break; + + // Forward to the dss receive handler + MbbReceiveDssData( + ReceiveContext->WmbDeviceContext, sessionId, (PUCHAR)MBB_NDP32_GET_DATAGRAM(Nth, Ndp, index), MBB_NDP32_GET_DATAGRAM_LENGTH(Ndp, index)); + } + + MbbRecvReturnNdp(ReceiveContext, NULL); + return status; +} + +NTSTATUS +MbbRecvNdpUnpackDss16(_In_ PMBB_NDIS_RECEIVE_CONTEXT ReceiveContext, _In_ PNCM_NTH16 Nth, _In_ PNCM_NDP16 Ndp) +{ + UNREFERENCED_PARAMETER(Nth); + NTSTATUS status = STATUS_SUCCESS; + ULONG datagramCount = MBB_NDP16_GET_DATAGRAM_COUNT(Ndp); + ULONG sessionId = MBB_NDP16_GET_SESSIONID(Ndp); + for (ULONG index = 0; index < datagramCount; index++) + { + if (MBB_NTB16_IS_END_DATAGRAM(Nth, Ndp, index)) + break; + + // Forward to the dss receive handler + MbbReceiveDssData( + ReceiveContext->WmbDeviceContext, sessionId, (PUCHAR)MBB_NDP16_GET_DATAGRAM(Nth, Ndp, index), MBB_NDP16_GET_DATAGRAM_LENGTH(Ndp, index)); + } + MbbRecvReturnNdp(ReceiveContext, NULL); + return status; +} + +NTSTATUS +MbbRecvAddNdp(_In_ PMBB_NDIS_RECEIVE_CONTEXT ReceiveContext, _In_ PVOID Nth, _In_ PVOID Ndp, _In_ ULONG SessionId) +{ + NTSTATUS status = STATUS_SUCCESS; + PWMBCLASS_DEVICE_CONTEXT deviceContext = ReceiveContext->WmbDeviceContext; + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = NULL; + WDFMEMORY ndpContextMemory; + PMBB_RECEIVE_NDP_CONTEXT ndpContext = NULL; + size_t ndpContextSize; + BOOLEAN returnNdp = FALSE; + + WdfSpinLockAcquire(deviceContext->Sessions[SessionId].WdfRecvSpinLock); + do + { + netAdapterContext = deviceContext->Sessions[SessionId].NetAdapterContext; + if (netAdapterContext == NULL) + { + returnNdp = TRUE; + break; + } + + if (!NT_SUCCESS(status = WdfMemoryCreateFromLookaside(netAdapterContext->ReceiveNdpLookasideList, &ndpContextMemory))) + { + returnNdp = TRUE; + break; + } + + ndpContext = (PMBB_RECEIVE_NDP_CONTEXT)WdfMemoryGetBuffer(ndpContextMemory, &ndpContextSize); + RtlZeroMemory(ndpContext, ndpContextSize); + ndpContext->Nth = Nth; + ndpContext->Ndp = Ndp; + ndpContext->ReceiveContext = ReceiveContext; + ndpContext->ReceiveNdpLookasideBufferMemory = ndpContextMemory; + ndpContext->NetAdapterContext = netAdapterContext; + if (netAdapterContext->AllowRxTraffic) + { + InsertTailList(&netAdapterContext->ReceiveNdpList, &ndpContext->ReceiveNdpNode); + } + else + { + returnNdp = TRUE; + break; + } + + // If RxQueueCreate hasn't completed yet, we only queue the received Ndp and don't need notify RxReady + if (netAdapterContext->RxQueue) + { + MbbNotifyRxReady(netAdapterContext->RxQueue); + } + } while (FALSE); + WdfSpinLockRelease(deviceContext->Sessions[SessionId].WdfRecvSpinLock); + + if (returnNdp) + { + MbbRecvReturnNdp(ReceiveContext, ndpContext); + } + return status; +} + +VOID MbbRecvNtbParse(_In_ PMBB_NDIS_RECEIVE_CONTEXT ReceiveContext) +{ + NTSTATUS status = STATUS_SUCCESS; + PNCM_NTH32 nth32; + PNCM_NTH16 nth16; + PNCM_NDP32 ndp32; + PNCM_NDP16 ndp16; + PVOID nth = ReceiveContext->ReceiveNtbBuffer; + + if (MBB_NTB_IS_32BIT(nth)) + { + nth32 = (PNCM_NTH32)nth; + for (ndp32 = MBB_NTH32_GET_FIRST_NDP(nth32); ndp32 != NULL; ndp32 = MBB_NDP32_GET_NEXT_NDP(nth32, ndp32)) + { + if (MBB_NDP32_GET_SIGNATURE_TYPE(ndp32) == NCM_NDP32_VENDOR) + { + status = MbbRecvNdpUnpackDss32(ReceiveContext, nth32, ndp32); + if (!NT_SUCCESS(status)) + { + } + } + else if (MBB_NDP32_GET_SIGNATURE_TYPE(ndp32) == NCM_NDP32_IPS) + { + status = MbbRecvAddNdp(ReceiveContext, nth32, ndp32, MBB_NDP32_GET_SESSIONID(ndp32)); + if (!NT_SUCCESS(status)) + { + } + } + else + { + MbbRecvReturnNdp(ReceiveContext, NULL); + } + } + } + else if (MBB_NTB_IS_16BIT(nth)) + { + nth16 = (PNCM_NTH16)nth; + for (ndp16 = MBB_NTH16_GET_FIRST_NDP(nth16); ndp16 != NULL; ndp16 = MBB_NDP16_GET_NEXT_NDP(nth16, ndp16)) + { + if (MBB_NDP16_GET_SIGNATURE_TYPE(ndp16) == NCM_NDP16_VENDOR) + { + status = MbbRecvNdpUnpackDss16(ReceiveContext, nth16, ndp16); + if (!NT_SUCCESS(status)) + { + } + } + else if (MBB_NDP16_GET_SIGNATURE_TYPE(ndp16) == NCM_NDP16_IPS) + { + status = MbbRecvAddNdp(ReceiveContext, nth16, ndp16, MBB_NDP32_GET_SESSIONID(ndp16)); + if (!NT_SUCCESS(status)) + { + } + } + else + { + MbbRecvReturnNdp(ReceiveContext, NULL); + } + } + } +} + +NTSTATUS +MbbRecvNtbUnpackIpNdp32(_In_ PMBB_RECEIVE_NDP_CONTEXT ReceiveNdpContext, _In_ PNCM_NTH32 Nth32, _In_ PNCM_NDP32 Ndp32, _Inout_ ULONG* IncompletedDatagramIndex, _In_ PMBB_RXQUEUE_CONTEXT RxQueueContext) +{ + PCHAR incompletedDatagram; + ULONG incompletedDatagramLength; + NET_PACKET* packet; + NET_FRAGMENT* fragment; + NET_FRAGMENT_RETURN_CONTEXT* returnContext; + NET_FRAGMENT_VIRTUAL_ADDRESS* virtualAddress; + NTSTATUS status = STATUS_SUCCESS; + ULONG datagramCount = MBB_NDP32_GET_DATAGRAM_COUNT(Ndp32); + + NET_RING * pr = NetRingCollectionGetPacketRing(RxQueueContext->DatapathDescriptor); + NET_RING * fr = NetRingCollectionGetFragmentRing(RxQueueContext->DatapathDescriptor); + + while ((incompletedDatagram = MBB_NDP32_GET_DATAGRAM(Nth32, Ndp32, *IncompletedDatagramIndex)) != NULL) + { + if (*IncompletedDatagramIndex >= datagramCount) + { + break; + } + + if (fr->BeginIndex == fr->EndIndex) + { + status = STATUS_BUFFER_OVERFLOW; + break; + } + + incompletedDatagramLength = MBB_NDP32_GET_DATAGRAM_LENGTH(Ndp32, *IncompletedDatagramIndex); + + UINT32 const fragmentIndex = fr->BeginIndex; + fragment = NetRingGetFragmentAtIndex(fr, fragmentIndex); + fragment->Capacity = incompletedDatagramLength; + fragment->ValidLength = incompletedDatagramLength; + fragment->Offset = 0; + + returnContext = NetExtensionGetFragmentReturnContext(&RxQueueContext->ReturnContextExtension, fragmentIndex); + virtualAddress = + NetExtensionGetFragmentVirtualAddress(&RxQueueContext->VirtualAddressExtension, fragmentIndex); + + + returnContext->Handle = (NET_FRAGMENT_RETURN_CONTEXT_HANDLE)ReceiveNdpContext; + virtualAddress->VirtualAddress = incompletedDatagram; + + (ReceiveNdpContext->IndicatedPackets)++; + (*IncompletedDatagramIndex)++; + + UINT32 const packetIndex = pr->BeginIndex; + packet = NetRingGetPacketAtIndex(pr, packetIndex); + packet->FragmentIndex = fragmentIndex; + packet->FragmentCount = 1; + packet->Layout = {}; + + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + fr->BeginIndex = NetRingIncrementIndex(fr, fr->BeginIndex); + } + return status; +} + +NTSTATUS +MbbRecvNtbUnpackIpNdp16(_In_ PMBB_RECEIVE_NDP_CONTEXT ReceiveNdpContext, _In_ PNCM_NTH16 Nth16, _In_ PNCM_NDP16 Ndp16, _Inout_ ULONG* IncompletedDatagramIndex, _In_ PMBB_RXQUEUE_CONTEXT RxQueueContext) +{ + PCHAR incompletedDatagram; + ULONG incompletedDatagramLength; + NET_PACKET* packet; + NET_FRAGMENT* fragment; + NET_FRAGMENT_RETURN_CONTEXT* returnContext; + NET_FRAGMENT_VIRTUAL_ADDRESS* virtualAddress; + NTSTATUS status = STATUS_SUCCESS; + ULONG datagramCount = MBB_NDP16_GET_DATAGRAM_COUNT(Ndp16); + + NET_RING * pr = NetRingCollectionGetPacketRing(RxQueueContext->DatapathDescriptor); + NET_RING * fr = NetRingCollectionGetFragmentRing(RxQueueContext->DatapathDescriptor); + + while ((incompletedDatagram = MBB_NDP16_GET_DATAGRAM(Nth16, Ndp16, *IncompletedDatagramIndex)) != NULL) + { + if (*IncompletedDatagramIndex >= datagramCount) + { + break; + } + + if (fr->BeginIndex == fr->EndIndex) + { + status = STATUS_BUFFER_OVERFLOW; + break; + } + + incompletedDatagramLength = MBB_NDP16_GET_DATAGRAM_LENGTH(Ndp16, *IncompletedDatagramIndex); + + UINT32 const fragmentIndex = fr->BeginIndex; + fragment = NetRingGetFragmentAtIndex(fr, fragmentIndex); + fragment->Capacity = incompletedDatagramLength; + fragment->ValidLength = incompletedDatagramLength; + fragment->Offset = 0; + + returnContext = NetExtensionGetFragmentReturnContext(&RxQueueContext->ReturnContextExtension, fragmentIndex); + virtualAddress = + NetExtensionGetFragmentVirtualAddress(&RxQueueContext->VirtualAddressExtension, fragmentIndex); + + returnContext->Handle = (NET_FRAGMENT_RETURN_CONTEXT_HANDLE)ReceiveNdpContext; + virtualAddress->VirtualAddress = incompletedDatagram; + + (ReceiveNdpContext->IndicatedPackets)++; + (*IncompletedDatagramIndex)++; + + UINT32 const packetIndex = pr->BeginIndex; + packet = NetRingGetPacketAtIndex(pr, packetIndex); + packet->FragmentIndex = fragmentIndex; + packet->FragmentCount = 1; + packet->Layout = {}; + + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + fr->BeginIndex = NetRingIncrementIndex(fr, fr->BeginIndex); + } + + return status; +} + +NTSTATUS +MbbRecvNdpUnpackIps(_In_ PMBB_RECEIVE_NDP_CONTEXT ReceiveNdpContext, _In_ PMBB_RXQUEUE_CONTEXT RxQueueContext) +{ + NTSTATUS status = STATUS_SUCCESS; + PNCM_NTH32 nth32; + PNCM_NTH16 nth16; + PNCM_NDP32 ndp32; + PNCM_NDP16 ndp16; + PMBB_NDIS_RECEIVE_CONTEXT receiveContext = ReceiveNdpContext->ReceiveContext; + PVOID nth = receiveContext->ReceiveNtbBuffer; + + if (MBB_NTB_IS_32BIT(nth)) + { + nth32 = (PNCM_NTH32)nth; + ndp32 = (PNCM_NDP32)ReceiveNdpContext->Ndp; + status = MbbRecvNtbUnpackIpNdp32(ReceiveNdpContext, nth32, ndp32, &ReceiveNdpContext->CurrentDatagramIndex, RxQueueContext); + } + else if (MBB_NTB_IS_16BIT(nth)) + { + nth16 = (PNCM_NTH16)nth; + ndp16 = (PNCM_NDP16)ReceiveNdpContext->Ndp; + status = MbbRecvNtbUnpackIpNdp16(ReceiveNdpContext, nth16, ndp16, &ReceiveNdpContext->CurrentDatagramIndex, RxQueueContext); + } + + return status; +} + +PMBB_NDIS_RECEIVE_CONTEXT +MbbRecvQQueueReceive(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext, _In_ MBB_RECEIVE_CONTEXT BusContext, _In_ PMDL Mdl, _In_reads_(sizeof(NCM_NTH32)) PUCHAR ReceiveNtbBuffer) +{ + PMBB_NDIS_RECEIVE_CONTEXT receiveContext = NULL; + WDFMEMORY receiveContextMemory; + size_t receiveContextSize; + NTSTATUS status = STATUS_SUCCESS; + + do + { + if (!NT_SUCCESS(status = WdfMemoryCreateFromLookaside(DeviceContext->ReceiveLookasideList, &receiveContextMemory))) + { + break; + } + + receiveContext = (PMBB_NDIS_RECEIVE_CONTEXT)WdfMemoryGetBuffer(receiveContextMemory, &receiveContextSize); + RtlZeroMemory(receiveContext, receiveContextSize); + + receiveContext->Mdl = Mdl; + receiveContext->WmbDeviceContext = DeviceContext; + receiveContext->BusHandle = DeviceContext->BusHandle; + receiveContext->BusContext = BusContext; + receiveContext->ReceiveLookasideList = DeviceContext->ReceiveLookasideList; + receiveContext->ReceiveLookasideBufferMemory = receiveContextMemory; + receiveContext->ReceiveNtbBuffer = ReceiveNtbBuffer; + receiveContext->NtbSequence = MBB_NTB_GET_SEQUENCE(ReceiveNtbBuffer); + } while (FALSE); + + return receiveContext; +} + +VOID MbbNdisReceiveCallback(_In_ MBB_PROTOCOL_HANDLE ProtocolHandle, _In_ MBB_RECEIVE_CONTEXT ReceiveContext, _In_ PMDL Mdl) +{ + PUCHAR dataBuffer; + ULONG dataLength; + PVOID nth; + BOOLEAN returnBuffer = TRUE; + PWMBCLASS_DEVICE_CONTEXT deviceContext = (PWMBCLASS_DEVICE_CONTEXT)ProtocolHandle; + PMBB_NDIS_RECEIVE_CONTEXT receive = NULL; + ULONG ndpCount = 1; + NTSTATUS status = STATUS_SUCCESS; + do + { + if ((dataBuffer = (PUCHAR)MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority | MdlMappingNoExecute)) == NULL) + { + status = STATUS_RESOURCE_DATA_NOT_FOUND; + break; + } + dataLength = MmGetMdlByteCount(Mdl); + + nth = dataBuffer; + + if (!NT_SUCCESS(status = MbbNtbValidate(nth, dataLength, deviceContext->BusParams.CurrentMode32Bit, &ndpCount))) + { + { + ULONG i; + ULONG j; + + PUCHAR buffer = (PUCHAR)nth; + + for (i = 0; i < dataLength; i += 16) + { + UCHAR numString[16 * 3 + 1]; + UCHAR asciiBuffer[40]; + UCHAR value = 0; + const char translateTable[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + RtlZeroMemory(numString, sizeof(numString)); + RtlZeroMemory(asciiBuffer, sizeof(asciiBuffer)); + + for (j = 0; j < 16; j++) + { + if (i + j >= dataLength) + { + // + // past the end, just put spaces + // + numString[j * 3] = ' '; + numString[j * 3 + 1] = ' '; + numString[j * 3 + 2] = ' '; + } + else + { + value = buffer[i + j]; + + numString[j * 3] = translateTable[value >> 4]; + numString[j * 3 + 1] = translateTable[value & 0xf]; + numString[j * 3 + 2] = ' '; + + if ((buffer[i + j] >= 32) && (buffer[i + j] < 128)) + { + asciiBuffer[j] = value; + } + else + { + asciiBuffer[j] = '.'; + } + } + } + } + } + break; + } + + if ((receive = MbbRecvQQueueReceive(deviceContext, ReceiveContext, Mdl, (PUCHAR)nth)) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + returnBuffer = FALSE; + receive->TotalNdpCount = ndpCount; + + // Receive DSS, IPs will be received in EvtRxQueueAdvance + MbbRecvNtbParse(receive); + } while (FALSE); + + if (returnBuffer) + { + if (receive != NULL) + { + MbbRecvCleanup(receive); + } + else + { + MbbBusReturnReceiveBuffer(deviceContext->BusHandle, ReceiveContext, Mdl); + } + } +} + +void EvtRxQueueDestroy(_In_ WDFOBJECT RxQueue) +{ + PMBB_RXQUEUE_CONTEXT rxQueueContext = MbbGetRxQueueContext(RxQueue); + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = rxQueueContext->NetAdapterContext; + netAdapterContext->RxQueue = NULL; +} + +VOID EvtRxQueueSetNotificationEnabled(_In_ NETPACKETQUEUE RxQueue, _In_ BOOLEAN NotificationEnabled) +{ + PMBB_RXQUEUE_CONTEXT txQueueContext = MbbGetRxQueueContext(RxQueue); + InterlockedExchange(&txQueueContext->NotificationEnabled, NotificationEnabled); +} + +void EvtRxQueueAdvance(_In_ NETPACKETQUEUE RxQueue) +{ + PMBB_RXQUEUE_CONTEXT rxQueueContext = MbbGetRxQueueContext(RxQueue); + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = rxQueueContext->NetAdapterContext; + WDFSPINLOCK wdfRecvSpinLock = netAdapterContext->WmbDeviceContext->Sessions[netAdapterContext->SessionId].WdfRecvSpinLock; + PMBB_RECEIVE_NDP_CONTEXT receiveNdpContext; + NTSTATUS status = STATUS_SUCCESS; + + WdfSpinLockAcquire(wdfRecvSpinLock); + while (!IsListEmpty(&netAdapterContext->ReceiveNdpList)) + { + receiveNdpContext = CONTAINING_RECORD(RemoveHeadList(&netAdapterContext->ReceiveNdpList), MBB_RECEIVE_NDP_CONTEXT, ReceiveNdpNode); + receiveNdpContext->ReceiveNdpNode.Flink = receiveNdpContext->ReceiveNdpNode.Blink = NULL; + WdfSpinLockRelease(wdfRecvSpinLock); + + status = MbbRecvNdpUnpackIps(receiveNdpContext, rxQueueContext); + if (status == STATUS_BUFFER_OVERFLOW) + { + WdfSpinLockAcquire(wdfRecvSpinLock); + InsertHeadList(&netAdapterContext->ReceiveNdpList, &receiveNdpContext->ReceiveNdpNode); + break; + } + else + { + if (!NT_SUCCESS(status)) + { + } + } + + WdfSpinLockAcquire(wdfRecvSpinLock); + } + WdfSpinLockRelease(wdfRecvSpinLock); +} + +void EvtRxQueueCancel(_In_ NETPACKETQUEUE RxQueue) +{ + PMBB_RXQUEUE_CONTEXT rxQueueContext = MbbGetRxQueueContext(RxQueue); + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = rxQueueContext->NetAdapterContext; + PWMBCLASS_DEVICE_CONTEXT deviceContext = netAdapterContext->WmbDeviceContext; + NET_RING_COLLECTION const* rings = rxQueueContext->DatapathDescriptor; + + NET_RING * pr = NetRingCollectionGetPacketRing(rings); + + while (pr->BeginIndex != pr->EndIndex) + { + NET_PACKET * packet = NetRingGetPacketAtIndex(pr, pr->BeginIndex); + packet->Ignore = 1; + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + } + + NET_RING * fr = NetRingCollectionGetFragmentRing(rings); + fr->BeginIndex = fr->EndIndex; + + // Cancel received Ndps which may be received after EvtRxQueueCancel started, these Ndps may never be processed by EvtRxQueueAdvance + MbbRecvCancelNdps(deviceContext, netAdapterContext->SessionId); +} + +VOID EvtAdapterReturnRxBuffer(_In_ NETADAPTER Adapter, _In_ NET_FRAGMENT_RETURN_CONTEXT_HANDLE RxBufferReturnContext) +{ + PMBB_RECEIVE_NDP_CONTEXT receiveNdpContext = (PMBB_RECEIVE_NDP_CONTEXT)RxBufferReturnContext; + UNREFERENCED_PARAMETER(Adapter); + NT_ASSERT(receiveNdpContext->IndicatedPackets); + + receiveNdpContext->IndicatedPackets--; + if ((receiveNdpContext->IndicatedPackets == 0) && (receiveNdpContext->ReceiveNdpNode.Blink == NULL) && + (receiveNdpContext->ReceiveNdpNode.Flink == NULL)) + { + MbbRecvReturnNdp(receiveNdpContext->ReceiveContext, receiveNdpContext); + } +} diff --git a/network/wwan/cxwmbclass/sources.inc b/network/wwan/cxwmbclass/sources.inc new file mode 100644 index 000000000..7b1e526c9 --- /dev/null +++ b/network/wwan/cxwmbclass/sources.inc @@ -0,0 +1,12 @@ +MBBCX_MAJOR_VERSION=1 +MBBCX_MINOR_VERSION=0 + +MBBCX_VERSION=$(MBBCX_MAJOR_VERSION).$(MBBCX_MINOR_VERSION) + +MBBCX_DDK_INC_PATH=$(ONECORE_EXTERNAL_DDK_INC_PATH)\mbbcx\$(MBBCX_VERSION) +MBBCX_DDK_LIB_PATH=$(ONECORE_EXTERNAL_DDK_LIB_PATH)\mbbcx\$(MBBCX_VERSION) + +KMDF_VERSION_MAJOR=1 +KMDF_VERSION_MINOR=31 +KMDF_VERSION=$(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) +KMDF_DDK_INC_PATH=$(ONECORE_INTERNAL_DDK_INC_PATH)\wdf\kmdf\$(KMDF_VERSION); diff --git a/network/wwan/cxwmbclass/txqueue.cpp b/network/wwan/cxwmbclass/txqueue.cpp new file mode 100644 index 000000000..9708b8b2a --- /dev/null +++ b/network/wwan/cxwmbclass/txqueue.cpp @@ -0,0 +1,988 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +#include "device.h" +#include "txqueue.h" + +void MbbNotifyTxReady(_In_ NETPACKETQUEUE TxQueue) +{ + PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue); + + if (InterlockedExchange(&txQueueContext->NotificationEnabled, FALSE) == TRUE) + { + NetTxQueueNotifyMoreCompletedPacketsAvailable(TxQueue); + } +} + +ULONG +MbbGetNetPacketDataLength(_In_ NET_PACKET* NetPacket, _In_ NET_RING_COLLECTION const* Rings) +{ + ULONG length = 0; + auto fr = NetRingCollectionGetFragmentRing(Rings); + for (UINT32 i = 0; i < NetPacket->FragmentCount; i++) + { + auto fragment = NetRingGetFragmentAtIndex(fr, (NetPacket->FragmentIndex + i) & fr->ElementIndexMask); + length += static_cast(fragment->ValidLength); + } + + return length; +} + +VOID MbbPacketRestoreMdl(_In_ PMBB_PACKET_CONTEXT PacketContext) +{ + if (PacketContext->ModifiedMdl != NULL) + { + *PacketContext->ModifiedMdl = PacketContext->OriginalMdl; + PacketContext->ModifiedMdl = NULL; + } +} + +VOID MbbPacketCleanupContext(_In_ PMBB_PACKET_CONTEXT PacketContext) +{ + MbbPacketRestoreMdl(PacketContext); + if (PacketContext->PaddingMdl != NULL) + { + IoFreeMdl(PacketContext->PaddingMdl); + PacketContext->PaddingMdl = NULL; + } + if (PacketContext->DataEndMdl != NULL) + { + IoFreeMdl(PacketContext->DataEndMdl); + PacketContext->DataEndMdl = NULL; + } + if (PacketContext->DataStartMdl != NULL) + { + IoFreeMdl(PacketContext->DataStartMdl); + PacketContext->DataStartMdl = NULL; + } +} + +FORCEINLINE +PMDL MbbPacketGetFirstMdl(_In_ PMBB_PACKET_CONTEXT PacketContext) +{ + if (PacketContext->PaddingMdl != NULL) + return PacketContext->PaddingMdl; + else + return PacketContext->DataStartMdl; +} + +FORCEINLINE +PMDL MbbPacketGetLastMdl(_In_ PMBB_PACKET_CONTEXT PacketContext) +{ + if (PacketContext->DataEndMdl != NULL) + return PacketContext->DataEndMdl; + else + return PacketContext->DataStartMdl; +} + +VOID MbbPacketSaveAndSetMdl(_In_ PMBB_PACKET_CONTEXT PacketContext, _In_ PMDL MdlToSave, _In_ PMDL MdlToSet) +{ + if (PacketContext->ModifiedMdl == NULL) + { + PacketContext->ModifiedMdl = MdlToSave; + PacketContext->OriginalMdl = *MdlToSave; + } + *MdlToSave = *MdlToSet; +} + +VOID MbbCleanupDssPacket(_In_ PDSS_PACKET Packet) +{ + if (Packet->Mdl != NULL) + { + IoFreeMdl(Packet->Mdl); + } + if (Packet != NULL) + { + FREE_POOL(Packet); + } +} + +VOID MbbNtbCleanupContext(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext, _In_ NTSTATUS NtStatus) +{ + ULONG DatagramIndex; + BOOLEAN NeedReturnCompletedPackets = FALSE; + + for (DatagramIndex = 0; DatagramIndex < NtbContext->DatagramCount; DatagramIndex++) + { + MbbPacketCleanupContext(&NtbContext->NdpDatagramEntries[DatagramIndex].NetPacketContext); + if (NtbContext->NdpDatagramEntries[DatagramIndex].NdpType == MbbNdpTypeIps) + { + NtbContext->NdpDatagramEntries[DatagramIndex].NetPacket->Scratch = 1; + NeedReturnCompletedPackets = TRUE; + } + else if (NtbContext->NdpDatagramEntries[DatagramIndex].NdpType == MbbNdpTypeVendor_1) + { + MbbDeviceSendDeviceServiceSessionDataComplete(NtbContext->NdpDatagramEntries[DatagramIndex].DssPacket->Data, NtStatus); + + MbbCleanupDssPacket(NtbContext->NdpDatagramEntries[DatagramIndex].DssPacket); + } + } + if (NtbContext->NdpMdl != NULL) + { + IoFreeMdl(NtbContext->NdpMdl); + } + if (NtbContext->NthMdl != NULL) + { + IoFreeMdl(NtbContext->NthMdl); + } + if (NtbContext->NdpBufferMemory != NULL) + { + WdfObjectDelete(NtbContext->NdpBufferMemory); + } +#if DBG + if (NtbContext->ScratchBuffer != NULL) + { + FREE_POOL(NtbContext->ScratchBuffer); + } +#endif + if (NeedReturnCompletedPackets) + { + MbbNotifyTxReady(NtbContext->NetTxQueue); + } + WdfObjectDelete(NtbContext->NtbLookasideBufferMemory); +} + +FORCEINLINE +ULONG +MbbSendQGetNtbSequence(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext) +{ + return InterlockedIncrement(&DeviceContext->NtbSequenceNumber); +} + +PMBB_NTB_BUILD_CONTEXT +MbbNtbAllocateContext(_In_ WDFLOOKASIDE NtbLookasideList, _In_ PMBB_BUS_PARAMETERS BusParams, _In_ PVOID PaddingBuffer, _In_ ULONG NtbSequence) +{ + NTSTATUS status = NDIS_STATUS_SUCCESS; + size_t ntbSize; + PMBB_NTB_BUILD_CONTEXT ntbContext = NULL; + WDFMEMORY ntbContextMemory; + + do + { +#pragma prefast(suppress \ + : __WARNING_MEMORY_LEAK, "By Design: Allocate ntb context from lookaside pool, released when send completes.") + if (!NT_SUCCESS(status = WdfMemoryCreateFromLookaside(NtbLookasideList, &ntbContextMemory))) + { + break; + } + + ntbContext = (PMBB_NTB_BUILD_CONTEXT)WdfMemoryGetBuffer(ntbContextMemory, &ntbSize); + RtlZeroMemory(ntbContext, ntbSize); + ntbContext->PaddingBuffer = PaddingBuffer; + ntbContext->NtbLookasideList = NtbLookasideList; + ntbContext->NtbLookasideBufferMemory = ntbContextMemory; + +#if DBG + ntbContext->ScratchLength = BusParams->MaxOutNtb; + if ((ntbContext->ScratchBuffer = (PCHAR)ALLOCATE_NONPAGED_POOL(ntbContext->ScratchLength)) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } +#endif + // + // Initialize the NTH and the NTH MDL. + // + if ((ntbContext->IsNtb32Bit = BusParams->CurrentMode32Bit) == TRUE) + { + if ((ntbContext->NthMdl = AllocateNonPagedMdl(&ntbContext->Nth32, sizeof(ntbContext->Nth32))) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + ntbContext->Nth32.dwSignature = NCM_NTH32_SIG; + ntbContext->Nth32.wHeaderLength = sizeof(NCM_NTH32); + ntbContext->Nth32.wSequence = (USHORT)NtbSequence; + + ntbContext->NtbHeaderSize = sizeof(NCM_NTH32); + ntbContext->NdpHeaderFixedSize = sizeof(NCM_NDP32); + ntbContext->NdpDatagramEntrySize = sizeof(NCM_NDP32_DATAGRAM); + } + else + { + if ((ntbContext->NthMdl = AllocateNonPagedMdl(&ntbContext->Nth16, sizeof(ntbContext->Nth16))) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + ntbContext->Nth16.dwSignature = NCM_NTH16_SIG; + ntbContext->Nth16.wHeaderLength = sizeof(NCM_NTH16); + ntbContext->Nth16.wSequence = (USHORT)NtbSequence; + + ntbContext->NtbHeaderSize = sizeof(NCM_NTH16); + ntbContext->NdpHeaderFixedSize = sizeof(NCM_NDP16); + ntbContext->NdpDatagramEntrySize = sizeof(NCM_NDP16_DATAGRAM); + } + + ntbContext->NtbOutMaxSize = BusParams->MaxOutNtb; + ntbContext->NtbOutMaxDatagrams = BusParams->MaxOutDatagrams; + ntbContext->NdpOutDivisor = BusParams->NdpOutDivisor; + ntbContext->NdpOutPayloadRemainder = BusParams->NdpOutRemainder; + ntbContext->NdpOutAlignment = BusParams->NdpOutAlignment; + } while (FALSE); + + if (!NT_SUCCESS(status)) + { + if (ntbContext != NULL) + { + MbbNtbCleanupContext(ntbContext, status); + } + ntbContext = NULL; + } + return ntbContext; +} + +NTSTATUS +MbbFillPacketContext( + _In_ PMBB_PACKET_CONTEXT PacketContext, + _In_ PMDL PacketDataStartMdl, + _In_ ULONG PacketDataStartMdlDataOffset, + _In_ ULONG DatagramLength, + _In_ PVOID PaddingBuffer, + _In_ ULONG PaddingLength) +{ + ULONG packetDataStartMdlDataLength; + PCHAR packetDataStartBuffer; + PMDL packetDataEndMdl; + ULONG packetDataEndMdlDataLength; + PCHAR packetDataEndBuffer; + PMDL packetMdl; + ULONG packetMdlOffset; + ULONG packetMdlLength; + PMDL packetPenultimateMdl; + NTSTATUS status = STATUS_SUCCESS; + + do + { + if ((packetDataStartBuffer = (PCHAR)MmGetSystemAddressForMdlSafe(PacketDataStartMdl, NormalPagePriority | MdlMappingNoExecute)) == NULL) + { + status = STATUS_RESOURCE_DATA_NOT_FOUND; + break; + } + packetDataStartBuffer += PacketDataStartMdlDataOffset; + // + // Create new DataStart and DataEnd Mdls + // to remove the unused data space. + // + packetDataStartMdlDataLength = MmGetMdlByteCount(PacketDataStartMdl); + packetDataStartMdlDataLength -= PacketDataStartMdlDataOffset; + + if ((PacketContext->DataStartMdl = + AllocateNonPagedMdl(packetDataStartBuffer, (ULONG)(MIN(DatagramLength, packetDataStartMdlDataLength)))) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + PacketContext->DataStartMdl->Next = PacketDataStartMdl->Next; + // + // Find the end MDL and the amount of data in the end MDL + // + packetMdl = PacketDataStartMdl; + packetMdlOffset = PacketDataStartMdlDataOffset; + packetPenultimateMdl = NULL; + + for (packetDataEndMdlDataLength = (ULONG)DatagramLength; packetDataEndMdlDataLength > (MmGetMdlByteCount(packetMdl) - packetMdlOffset); + packetDataEndMdlDataLength -= packetMdlLength) + { + packetPenultimateMdl = packetMdl; + packetMdlLength = MmGetMdlByteCount(packetMdl) - packetMdlOffset; + packetMdlOffset = 0; + packetMdl = packetMdl->Next; + } + packetDataEndMdl = packetMdl; + // + // If the starting and ending MDLs are not the same + // then build another partial MDL removing any unused + // data space. + // + if (packetDataEndMdl != PacketDataStartMdl) + { + if ((packetDataEndBuffer = (PCHAR)MmGetSystemAddressForMdlSafe(packetDataEndMdl, NormalPagePriority | MdlMappingNoExecute)) == NULL) + { + status = STATUS_RESOURCE_DATA_NOT_FOUND; + break; + } + + if ((PacketContext->DataEndMdl = AllocateNonPagedMdl(packetDataEndBuffer, packetDataEndMdlDataLength)) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + PacketContext->DataEndMdl->Next = NULL; + + if (packetPenultimateMdl != PacketDataStartMdl) + { + MDL TempMdl = *packetPenultimateMdl; + TempMdl.Next = PacketContext->DataEndMdl; + + MbbPacketSaveAndSetMdl(PacketContext, packetPenultimateMdl, &TempMdl); + } + + if (PacketContext->DataStartMdl->Next == packetDataEndMdl) + { + PacketContext->DataStartMdl->Next = PacketContext->DataEndMdl; + } + } + // + // Allocate padding, if needed. The padding buffer is a share buffer. + // Every padding MDL points to this same buffer. The buffer contains + // all 0s. + // + if (PaddingLength != 0) + { + if ((PacketContext->PaddingMdl = AllocateNonPagedMdl(PaddingBuffer, PaddingLength)) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + PacketContext->PaddingMdl->Next = PacketContext->DataStartMdl; + } + } while (FALSE); + + return status; +} + +VOID MbbNtbChainNb(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext, _In_ PMBB_PACKET_CONTEXT PacketContext) +{ + if (NtbContext->DatagramLastMdl != NULL) + { + NtbContext->DatagramLastMdl->Next = MbbPacketGetFirstMdl(PacketContext); + } + else + { + NtbContext->NthMdl->Next = MbbPacketGetFirstMdl(PacketContext); + } + + NtbContext->DatagramLastMdl = MbbPacketGetLastMdl(PacketContext); +} + +NTSTATUS +MbbNtbAddPacket( + _In_ PMBB_NTB_BUILD_CONTEXT NtbContext, + _In_ PVOID PacketContext, + _In_ ULONG DatagramLength, + _In_ PMDL PacketDataStartMdl, + _In_ ULONG PacketDataStartMdlDataOffset, + _In_ MBB_NDP_TYPE CurrentNdpType, + _In_ ULONG SessionId) +{ + ULONG datagramOffset; + ULONG paddingLength; + ULONG ndpSize; + NTSTATUS status = STATUS_SUCCESS; + ULONG totalLength; + PMBB_PACKET_CONTEXT packetContext = NULL; + + do + { + if ((NtbContext->DatagramCount + 1) > NtbContext->NtbOutMaxDatagrams) + { + status = STATUS_BUFFER_OVERFLOW; + break; + } + + // + // Size of passed in NET_BUFFER, to be updated later in the NDP Context. + // + totalLength = NtbContext->NtbHeaderSize + NtbContext->DatagramLength; + paddingLength = ALIGN_AT_OFFSET(totalLength, NtbContext->NdpOutDivisor, NtbContext->NdpOutPayloadRemainder) - totalLength; + // + // Calculate the new NTB size based on the passed in MBB_PACKET + // + + // + // Fixed size NTH & DatagramSize along with Padding for all NDPs + // + datagramOffset = totalLength + paddingLength; + totalLength += DatagramLength + paddingLength; + + // + // Calculate NDP HeaderSize for all NDPs + // + ndpSize = totalLength; + totalLength = ALIGN(totalLength, NtbContext->NdpOutAlignment); + totalLength += NtbContext->NdpHeaderFixedSize; + totalLength += ((NtbContext->DatagramCount + 1) * NtbContext->NdpDatagramEntrySize); + ndpSize = totalLength - ndpSize; + // + // Can everything fit? + // + if (totalLength > NtbContext->NtbOutMaxSize) + { + status = STATUS_BUFFER_OVERFLOW; + break; + } + packetContext = &NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].NetPacketContext; + if (!NT_SUCCESS( + status = MbbFillPacketContext( + packetContext, PacketDataStartMdl, PacketDataStartMdlDataOffset, DatagramLength, NtbContext->PaddingBuffer, paddingLength))) + { + break; + } + // + // Update the NTB Context for the new NET_BUFFER. + // + NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].DatagramOffset = datagramOffset; + NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].DatagramLength = DatagramLength; + NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].NdpType = CurrentNdpType; + NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].SessionId = SessionId; + if (CurrentNdpType == MbbNdpTypeIps) + { + NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].NetPacket = (NET_PACKET*)PacketContext; + } + else if (CurrentNdpType == MbbNdpTypeVendor_1) + { + NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].DssPacket = (PDSS_PACKET)PacketContext; + } + + NtbContext->NdpSize = ndpSize; + NtbContext->DatagramCount += 1; + NtbContext->DatagramLength += (DatagramLength + paddingLength); + + MbbNtbChainNb(NtbContext, packetContext); + } while (FALSE); + + if (!NT_SUCCESS(status)) + { + if (packetContext != NULL) + { + MbbPacketCleanupContext(packetContext); + } + } + return status; +} + +FORCEINLINE +PMDL MbbNtbGetMdlChainHead(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext) +{ + return NtbContext->NthMdl; +} + +VOID MbbSendQCompleteNtb(_In_ MBB_PROTOCOL_HANDLE ProtocolHandle, _In_ MBB_REQUEST_HANDLE RequestHandle, _In_ NTSTATUS NtStatus, _In_ PMDL Mdl) +{ + UNREFERENCED_PARAMETER(ProtocolHandle); + PMBB_NTB_BUILD_CONTEXT ntbContext = (PMBB_NTB_BUILD_CONTEXT)RequestHandle; + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetNetAdapterContext(ntbContext->NetAdapter)->WmbDeviceContext; + UNREFERENCED_PARAMETER(Mdl); + + if (!NT_SUCCESS(NtStatus)) + { + if (NtStatus == STATUS_NDIS_ADAPTER_NOT_READY) + { + } + else if (NtStatus == STATUS_CANCELLED) + { + } + else if (NtStatus == STATUS_NO_SUCH_DEVICE) + { + } + else + { + MbbBusResetDataPipes(deviceContext->BusHandle); + } + } + + MbbNtbCleanupContext(ntbContext, NtStatus); +} + +ULONG +MbbNtbMapNdpTypeToSignature(_In_ MBB_NDP_TYPE MbbNdpType, _In_ BOOLEAN Is32Bit, _In_ ULONG SessionId) +{ + ULONG SessionMask = (SessionId << NCM_NDP_SESSION_SHIFT); + + switch (MbbNdpType) + { + case MbbNdpTypeIps: return ((Is32Bit == TRUE) ? NCM_NDP32_IPS | SessionMask : NCM_NDP16_IPS | SessionMask); + default: + if ((MbbNdpType >= MbbNdpTypeVendor_1) && (MbbNdpType <= MbbNdpTypeVendor_Max)) + { + return ((Is32Bit == TRUE) ? NCM_NDP32_VENDOR | SessionMask : NCM_NDP16_VENDOR | SessionMask); + } + } + return 0; +} + +VOID MbbNtbFillNdp32Header(_In_ PNCM_NDP32 Ndp, _In_ MBB_NDP_TYPE NdpType, _In_ PMBB_NTB_BUILD_CONTEXT NtbContext) +{ + ULONG datagramIndex = 0; + ULONG ndpDatagramIndex = 0; + PNCM_NDP32_DATAGRAM ndpDatagramEntries; + + Ndp->dwSignature = MbbNtbMapNdpTypeToSignature(NdpType, TRUE, NtbContext->NdpDatagramEntries[datagramIndex].SessionId); + Ndp->dwNextFpIndex = 0; + ndpDatagramEntries = Ndp->Datagram; + // + // Add datagram entries to the NDP Table + // + + for (datagramIndex = 0; datagramIndex < NtbContext->DatagramCount; datagramIndex++) + { + ndpDatagramEntries[ndpDatagramIndex].dwDatagramIndex = NtbContext->NdpDatagramEntries[datagramIndex].DatagramOffset; + ndpDatagramEntries[ndpDatagramIndex].dwDatagramLength = NtbContext->NdpDatagramEntries[datagramIndex].DatagramLength; + ndpDatagramIndex++; + } + // + // Terminating entry is taken in to account + // in the fixed size NDP Header. + // + ndpDatagramEntries[ndpDatagramIndex].dwDatagramIndex = 0; + ndpDatagramEntries[ndpDatagramIndex].dwDatagramLength = 0; + + Ndp->wLength = (USHORT)(NtbContext->NdpHeaderFixedSize + (ndpDatagramIndex * NtbContext->NdpDatagramEntrySize)); +} + +VOID MbbNtbFillNdp16Header(__in PNCM_NDP16 Ndp, __in MBB_NDP_TYPE NdpType, __in PMBB_NTB_BUILD_CONTEXT NtbContext) +{ + ULONG datagramIndex = 0; + ULONG ndpDatagramIndex = 0; + PNCM_NDP16_DATAGRAM ndpDatagramEntries; + + Ndp->dwSignature = MbbNtbMapNdpTypeToSignature(NdpType, FALSE, NtbContext->NdpDatagramEntries[datagramIndex].SessionId); + + Ndp->wNextFpIndex = 0; + ndpDatagramEntries = Ndp->Datagram; + // + // Add datagram entries to the NDP Table + // + for (datagramIndex = 0; datagramIndex < NtbContext->DatagramCount; datagramIndex++) + { + ndpDatagramEntries[ndpDatagramIndex].wDatagramIndex = (USHORT)NtbContext->NdpDatagramEntries[datagramIndex].DatagramOffset; + ndpDatagramEntries[ndpDatagramIndex].wDatagramLength = (USHORT)NtbContext->NdpDatagramEntries[datagramIndex].DatagramLength; + ndpDatagramIndex++; + } + // + // Terminating entry is taken in to account + // in the fixed size NDP Header. + // + ndpDatagramEntries[ndpDatagramIndex].wDatagramIndex = 0; + ndpDatagramEntries[ndpDatagramIndex].wDatagramLength = 0; + + Ndp->wLength = (USHORT)(NtbContext->NdpHeaderFixedSize + (ndpDatagramIndex * NtbContext->NdpDatagramEntrySize)); +} + +NTSTATUS +MbbNtbAddNdpHeaders(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext) +{ + // Offset from the start of the NTB buffer to the start of NDP headers + ULONG ndpStartOffset; + // Offset from the start of the NTB Buffer to the current position. + ULONG ntbOffset; + PCHAR ndpBuffer; + MBB_NDP_TYPE ndpType; + PNCM_NDP16 ndp16; + PNCM_NDP32 ndp32; + NTSTATUS status = STATUS_SUCCESS; + + do + { + // + // Allocate buffer for all NDP headers. + // This includes padding for NDP Header alignment. + // + status = CreateNonPagedWdfMemory( + NtbContext->NdpSize, + &NtbContext->NdpBufferMemory, + &NtbContext->NdpBuffer, + NtbContext->NetTxQueue == NULL ? (WDFOBJECT)NtbContext->NetAdapter : NtbContext->NetTxQueue, + MbbPoolTagNtbSend); + if (!NT_SUCCESS(status)) + { + break; + } + RtlZeroMemory(NtbContext->NdpBuffer, NtbContext->NdpSize); + ndpBuffer = (PCHAR)(NtbContext->NdpBuffer); + // + // Chain the NDP Header through its MDL to datagram MDL + // + if ((NtbContext->NdpMdl = AllocateNonPagedMdl(NtbContext->NdpBuffer, NtbContext->NdpSize)) == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + NtbContext->DatagramLastMdl->Next = NtbContext->NdpMdl; + ndpStartOffset = NtbContext->NtbHeaderSize + NtbContext->DatagramLength; + + if (NtbContext->IsNtb32Bit) + NtbContext->Nth32.dwFpIndex = ALIGN(ndpStartOffset, NtbContext->NdpOutAlignment); + else + NtbContext->Nth16.wFpIndex = (USHORT)ALIGN(ndpStartOffset, NtbContext->NdpOutAlignment); + + ntbOffset = ALIGN(ndpStartOffset, NtbContext->NdpOutAlignment); + ndpType = NtbContext->NdpDatagramEntries[0].NdpType; + + if (NtbContext->IsNtb32Bit == TRUE) + { + ndp32 = (PNCM_NDP32)(ndpBuffer + (ntbOffset - ndpStartOffset)); + + MbbNtbFillNdp32Header(ndp32, ndpType, NtbContext); + } + else + { + ndp16 = (PNCM_NDP16)(ndpBuffer + (ntbOffset - ndpStartOffset)); + + MbbNtbFillNdp16Header(ndp16, ndpType, NtbContext); + } + + if (NtbContext->IsNtb32Bit == TRUE) + { + NtbContext->Nth32.dwBlockLength = NtbContext->NtbHeaderSize; + NtbContext->Nth32.dwBlockLength += NtbContext->DatagramLength; + NtbContext->Nth32.dwBlockLength += NtbContext->NdpSize; + } + else + { + NtbContext->Nth16.wBlockLength = (USHORT)(NtbContext->NtbHeaderSize); + NtbContext->Nth16.wBlockLength += (USHORT)(NtbContext->DatagramLength); + NtbContext->Nth16.wBlockLength += (USHORT)(NtbContext->NdpSize); + } + } while (FALSE); + // + // No cleanup. Cleanup done by caller. + // + return status; +} + +NTSTATUS +MbbTestValidateNtb(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext, _In_reads_bytes_(ScratchLength) PCHAR ScratchBuffer, _In_ ULONG ScratchLength) +{ + PMDL currentMdl; + ULONGLONG ntbLength; + ULONG mdlLength; + PVOID mdlVa; + PVOID nth; + + nth = ScratchBuffer; + ntbLength = 0; + + for (currentMdl = MbbNtbGetMdlChainHead(NtbContext); currentMdl != NULL; currentMdl = currentMdl->Next) + { + mdlLength = MmGetMdlByteCount(currentMdl); + + if ((mdlVa = MmGetSystemAddressForMdlSafe(currentMdl, NormalPagePriority | MdlMappingNoExecute)) == NULL) + { + return STATUS_RESOURCE_DATA_NOT_FOUND; + } + + if ((ntbLength + mdlLength) > ScratchLength) + { + return STATUS_BUFFER_OVERFLOW; + } + + RtlCopyMemory(ScratchBuffer, mdlVa, mdlLength); + + ScratchBuffer += mdlLength; + ntbLength += mdlLength; + } + + return MbbNtbValidate(nth, (ULONG)ntbLength, NtbContext->IsNtb32Bit, NULL); +} + +void EvtTxQueueDestroy(_In_ WDFOBJECT TxQueue) +{ + PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue); + + txQueueContext->NetAdapterContext->TxQueue = NULL; +} + +VOID EvtTxQueueSetNotificationEnabled(_In_ NETPACKETQUEUE TxQueue, _In_ BOOLEAN NotificationEnabled) +{ + PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue); + + InterlockedExchange(&txQueueContext->NotificationEnabled, NotificationEnabled); +} + +void EvtTxQueueCancel(_In_ NETPACKETQUEUE TxQueue) +{ + NET_RING_COLLECTION const* rings = MbbGetTxQueueContext(TxQueue)->DatapathDescriptor; + + NET_RING * pr = NetRingCollectionGetPacketRing(rings); + while (pr->BeginIndex != pr->EndIndex) + { + UINT32 const packetIndex = pr->BeginIndex; + NetRingGetPacketAtIndex(pr, packetIndex)->Scratch = 1; + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + } +} + +bool MbbEnableTxBatching(_In_ NET_RING_COLLECTION const* Rings) +{ + NET_RING * ring = Rings->Rings[NetRingTypeFragment]; + return ((ring->EndIndex - ring->BeginIndex) & ring->ElementIndexMask) > (NetRingCollectionGetPacketRing(Rings)->NumberOfElements / 2); +} + +inline +VOID +CompleteTxPacketsBatch( + _In_ NET_RING_COLLECTION const * Rings, + _In_ UINT32 BatchSize +) +{ + UINT32 packetCount = 0; + + NET_RING * pr = NetRingCollectionGetPacketRing(Rings); + + while (pr->BeginIndex != pr->EndIndex) + { + UINT32 const packetIndex = pr->BeginIndex; + auto packet = NetRingGetPacketAtIndex(pr, packetIndex); + + // this function uses Scratch field as the bit for testing completion + if (!packet->Scratch) + { + break; + } + + packetCount++; + + NET_RING * fr = NetRingCollectionGetFragmentRing(Rings); + fr->BeginIndex = fr->EndIndex; + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + + if (packetCount >= BatchSize) + { + Rings->Rings[NetRingTypeFragment]->BeginIndex = fr->BeginIndex; + } + } +} + +void EvtTxQueueAdvance(_In_ NETPACKETQUEUE TxQueue) +{ + NTSTATUS status = STATUS_SUCCESS; + PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue); + NET_RING_COLLECTION const* rings = txQueueContext->DatapathDescriptor; + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = txQueueContext->NetAdapterContext; + PWMBCLASS_DEVICE_CONTEXT deviceContext = netAdapterContext->WmbDeviceContext; + PMBB_NTB_BUILD_CONTEXT ntbContext = NULL; + ULONG sessionId = netAdapterContext->SessionId; + ULONG batchSize = MbbEnableTxBatching(rings) ? txQueueContext->CompletionBatchSize : 1; + + NET_RING * pr = NetRingCollectionGetPacketRing(rings); + while (pr->BeginIndex != pr->EndIndex) + { + UINT32 packetIndex = pr->BeginIndex; + auto packet = NetRingGetPacketAtIndex(pr, packetIndex); + if (packet->Ignore) + { + packet->Scratch = 1; + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + continue; + } + + ntbContext = MbbNtbAllocateContext( + netAdapterContext->NtbLookasideList, &deviceContext->BusParams, deviceContext->sharedPaddingBuffer, MbbSendQGetNtbSequence(deviceContext)); + + if (ntbContext == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + ntbContext->NetTxQueue = TxQueue; + ntbContext->NetAdapter = netAdapterContext->NetAdapter; + ntbContext->NetDatapathDescriptor = rings; + + auto fr = NetRingCollectionGetFragmentRing(rings); + while (NT_SUCCESS( + status = MbbNtbAddPacket( + ntbContext, + packet, + MbbGetNetPacketDataLength(packet, rings), + NetExtensionGetFragmentMdl(&txQueueContext->MdlExtension, packet->FragmentIndex)->Mdl, + NetRingGetFragmentAtIndex(fr, packet->FragmentIndex)->Offset, + MbbNdpTypeIps, + sessionId))) + { + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + + // the ring buffer has no more net packets to send, + // so packing is done. break now to make USB request + if (pr->BeginIndex == pr->EndIndex) + { + break; + } + + packetIndex = pr->BeginIndex; + packet = NetRingGetPacketAtIndex(pr, packetIndex); + } + + if (status == STATUS_BUFFER_OVERFLOW) + { + // + // If the NTB was empty and this packet couldnt be added + // then ignore this packet to prevent retrying forever. + // Or send this NTB to bus then start a new NTB + // + if (ntbContext->DatagramCount == 0) + { + packet->Scratch = 1; + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + } + } + else if (status != STATUS_SUCCESS) + { + // + // MbbNtbAddPacket failed, we should ignore this packet, or the loop may never complete + // + packet->Scratch = 1; + pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex); + } + + if (ntbContext->DatagramCount > 0) + { + status = MbbNtbAddNdpHeaders(ntbContext); + if (!NT_SUCCESS(status)) + { + } + else + { +#if DBG + if (!NT_SUCCESS(MbbTestValidateNtb(ntbContext, ntbContext->ScratchBuffer, ntbContext->ScratchLength))) + { + ASSERT(FALSE); + } +#endif + // + // Send the data. On failure, cleanup. + // + status = MbbBusWriteData(deviceContext->BusHandle, ntbContext, MbbNtbGetMdlChainHead(ntbContext), MbbSendQCompleteNtb); + if (!NT_SUCCESS(status)) + { + } + } + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + if (!NT_SUCCESS(status)) + { + MbbSendQCompleteNtb(netAdapterContext, ntbContext, status, MbbNtbGetMdlChainHead(ntbContext)); + } + } + + CompleteTxPacketsBatch(rings, batchSize); +} + +PDSS_PACKET MbbAllocateDssPacket(_In_ WDFMEMORY Data, _In_ PVOID DataBuffer, _In_ size_t DataSize) +{ + NTSTATUS status = STATUS_SUCCESS; + PDSS_PACKET packet = NULL; + do + { +// By Design: Allocate packet from NtbSend Pool, released in function MbbNtbCleanupContext called from MbbSendQCompleteNtb. +#pragma prefast(suppress : __WARNING_MEMORY_LEAK, "Released in function MbbNtbCleanupContext") + packet = (PDSS_PACKET)ALLOCATE_NONPAGED_POOL_WITH_TAG(sizeof(DSS_PACKET), MbbPoolTagNtbSend); + if (packet == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + RtlZeroMemory(packet, sizeof(DSS_PACKET)); + + packet->Data = Data; + packet->Mdl = AllocateNonPagedMdl(DataBuffer, (ULONG)DataSize); + + if (packet->Mdl == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + } while (FALSE); + + if (!NT_SUCCESS(status)) + { + if (packet != NULL) + { + MbbCleanupDssPacket(packet); + packet = NULL; + } + } + + return packet; +} + +_Use_decl_annotations_ VOID EvtMbbDeviceSendDeviceServiceSessionData(WDFDEVICE Device, DSS_SESSION_ID SessionId, WDFMEMORY Data) +{ + PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device); + NTSTATUS status = STATUS_SUCCESS; + + PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = deviceContext->Sessions[MBB_DEFAULT_SESSION_ID].NetAdapterContext; + + PMBB_NTB_BUILD_CONTEXT ntbContext = NULL; + PDSS_PACKET packet = NULL; + BOOLEAN completeNow = TRUE; + + do + { + ntbContext = MbbNtbAllocateContext( + netAdapterContext->NtbLookasideList, &deviceContext->BusParams, deviceContext->sharedPaddingBuffer, MbbSendQGetNtbSequence(deviceContext)); + + if (ntbContext == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + ntbContext->NetTxQueue = NULL; + ntbContext->NetAdapter = netAdapterContext->NetAdapter; + size_t bufferSize = 0; + PVOID buffer = WdfMemoryGetBuffer(Data, &bufferSize); + + packet = MbbAllocateDssPacket(Data, buffer, bufferSize); + if (packet == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + status = MbbNtbAddPacket(ntbContext, packet, (ULONG)bufferSize, packet->Mdl, 0, MbbNdpTypeVendor_1, SessionId); + if (!NT_SUCCESS(status)) + { + MbbCleanupDssPacket(packet); + break; + } + + completeNow = FALSE; + + status = MbbNtbAddNdpHeaders(ntbContext); + if (!NT_SUCCESS(status)) + { + break; + } + +#if DBG + if (!NT_SUCCESS(MbbTestValidateNtb(ntbContext, ntbContext->ScratchBuffer, ntbContext->ScratchLength))) + { + ASSERT(FALSE); + } +#endif + + // + // Send the data. On failure, cleanup. It will return STATUS_PENDING when success + // + status = MbbBusWriteData(deviceContext->BusHandle, ntbContext, MbbNtbGetMdlChainHead(ntbContext), MbbSendQCompleteNtb); + if (!NT_SUCCESS(status)) + { + break; + } + + deviceContext->DSSPacketsSentCount++; + } while (FALSE); + + if (!NT_SUCCESS(status)) + { + if (ntbContext != NULL) + { + MbbSendQCompleteNtb(deviceContext, ntbContext, status, MbbNtbGetMdlChainHead(ntbContext)); + } + if (completeNow) + { + MbbDeviceSendDeviceServiceSessionDataComplete(Data, status); + } + } +} diff --git a/network/wwan/cxwmbclass/util.cpp b/network/wwan/cxwmbclass/util.cpp new file mode 100644 index 000000000..2e2e5f340 --- /dev/null +++ b/network/wwan/cxwmbclass/util.cpp @@ -0,0 +1,326 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +//////////////////////////////////////////////////////////////////////////////// +// +// INCLUDES +// +//////////////////////////////////////////////////////////////////////////////// +#include "precomp.h" + +NTSTATUS +MbbNtbDetectNdp32Loop(_In_ PNCM_NTH32 Nth) +{ + PNCM_NDP32 FirstNdp; + PNCM_NDP32 Ndp; + PNCM_NDP32 LoopNdp; + + if ((FirstNdp = MBB_NTH32_GET_FIRST_NDP(Nth)) == NULL) + return STATUS_SUCCESS; + + if (!MBB_NTB32_IS_VALID_NDP_LENGTH(Nth, FirstNdp)) + { + return STATUS_UNSUCCESSFUL; + } + LoopNdp = MBB_NDP32_GET_NEXT_NDP(Nth, FirstNdp); + + for (Ndp = FirstNdp; Ndp != NULL && LoopNdp != NULL; Ndp = MBB_NDP32_GET_NEXT_NDP(Nth, Ndp)) + { + if (!MBB_NTB32_IS_VALID_NDP_LENGTH(Nth, LoopNdp)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTB32_IS_VALID_NDP_LENGTH(Nth, Ndp)) + { + return STATUS_UNSUCCESSFUL; + } + + if (LoopNdp == Ndp) + { + return STATUS_UNSUCCESSFUL; + } + + if ((LoopNdp = MBB_NDP32_GET_NEXT_NDP(Nth, LoopNdp)) != NULL) + { + if (!MBB_NTB32_IS_VALID_NDP_LENGTH(Nth, LoopNdp)) + { + return STATUS_UNSUCCESSFUL; + } + LoopNdp = MBB_NDP32_GET_NEXT_NDP(Nth, LoopNdp); + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbbNtbValidateNdp32(_In_ PNCM_NTH32 Nth, _In_ PNCM_NDP32 Ndp) +{ + ULONG Index; + ULONG DatagramCount = MBB_NDP32_GET_DATAGRAM_COUNT(Ndp); + + if (!MBB_NTB32_IS_VALID_NDP_SIGNATURE(Ndp)) + { + return STATUS_UNSUCCESSFUL; + } + + if (MBB_NDP32_GET_SIGNATURE_TYPE(Ndp) == NCM_NDP32_IPS) + { + // + // Check if the session id is valid, else discard + // + + // Check if session Id is greater than maximum supported. Here + // we can also check against MaxActivatedContexts, but this would + // mean we need to take a lock for getting the value of maxactivatedcontexts + // The lock can be avoided by checking against the maximum number of ports + // supported by the class driver. SESSION_PORT_TABLE.InUse can be used + // to check whether the session id is in use. + + if (MBB_NDP32_GET_SESSIONID(Ndp) >= MBB_MAX_NUMBER_OF_SESSIONS) + { + return STATUS_UNSUCCESSFUL; + } + } + + if (!MBB_NTB32_IS_VALID_NDP_LENGTH(Nth, Ndp)) + { + return STATUS_UNSUCCESSFUL; + } + + for (Index = 0; Index < DatagramCount; Index++) + { + if (MBB_NTB32_IS_END_DATAGRAM(Nth, Ndp, Index)) + return STATUS_SUCCESS; + + if (!MBB_NTB32_IS_VALID_DATAGRAM(Nth, Ndp, Index)) + { + return STATUS_UNSUCCESSFUL; + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbbNtbValidateNth32(_In_ PNCM_NTH32 Nth, _In_ ULONG BufferLength, _Out_opt_ ULONG* NdpCount) +{ + PNCM_NDP32 Ndp; + ULONG ndpCount = 0; + if (BufferLength < sizeof(NCM_NTH32)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH32_IS_VALID_SIGNATURE(Nth)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH32_IS_VALID_HEADER_LENGTH(Nth)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH32_IS_VALID_BLOCK_LENGTH(Nth, BufferLength)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH32_IS_VALID_FIRST_NDP(Nth)) + { + return STATUS_UNSUCCESSFUL; + } + + if (MbbNtbDetectNdp32Loop(Nth) != STATUS_SUCCESS) + return STATUS_UNSUCCESSFUL; + + for (Ndp = MBB_NTH32_GET_FIRST_NDP(Nth); Ndp != NULL; Ndp = MBB_NDP32_GET_NEXT_NDP(Nth, Ndp)) + { + if (MbbNtbValidateNdp32(Nth, Ndp) != STATUS_SUCCESS) + return STATUS_UNSUCCESSFUL; + ndpCount++; + } + if (NdpCount != NULL) + { + *NdpCount = ndpCount; + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbbNtbDetectNdp16Loop(_In_ PNCM_NTH16 Nth) +{ + PNCM_NDP16 FirstNdp; + PNCM_NDP16 Ndp; + PNCM_NDP16 LoopNdp; + + if ((FirstNdp = MBB_NTH16_GET_FIRST_NDP(Nth)) == NULL) + return STATUS_SUCCESS; + + if (!MBB_NTB16_IS_VALID_NDP_LENGTH(Nth, FirstNdp)) + { + return STATUS_UNSUCCESSFUL; + } + LoopNdp = MBB_NDP16_GET_NEXT_NDP(Nth, FirstNdp); + + for (Ndp = FirstNdp; Ndp != NULL && LoopNdp != NULL; Ndp = MBB_NDP16_GET_NEXT_NDP(Nth, Ndp)) + { + if (!MBB_NTB16_IS_VALID_NDP_LENGTH(Nth, LoopNdp)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTB16_IS_VALID_NDP_LENGTH(Nth, Ndp)) + { + return STATUS_UNSUCCESSFUL; + } + + if (LoopNdp == Ndp) + { + return STATUS_UNSUCCESSFUL; + } + + if ((LoopNdp = MBB_NDP16_GET_NEXT_NDP(Nth, LoopNdp)) != NULL) + { + if (!MBB_NTB16_IS_VALID_NDP_LENGTH(Nth, LoopNdp)) + { + return STATUS_UNSUCCESSFUL; + } + LoopNdp = MBB_NDP16_GET_NEXT_NDP(Nth, LoopNdp); + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbbNtbValidateNdp16(_In_ PNCM_NTH16 Nth, _In_ PNCM_NDP16 Ndp) +{ + ULONG Index; + ULONG DatagramCount = MBB_NDP16_GET_DATAGRAM_COUNT(Ndp); + + if (!MBB_NTB16_IS_VALID_NDP_SIGNATURE(Ndp)) + { + return STATUS_UNSUCCESSFUL; + } + + if (MBB_NDP16_GET_SIGNATURE_TYPE(Ndp) == NCM_NDP16_IPS) + { + // + // Check if the session id is valid, else discard + // + + // Check if session Id is greater than maximum supported. Here + // we can also check against MaxActivatedContexts, but this would + // mean we need to take a lock for getting the value of maxactivatedcontexts + // The lock can be avoided by checking against the maximum number of ports + // supported by the class driver. SESSION_PORT_TABLE.InUse can be used + // to check whether the session id is in use. + + if (MBB_NDP16_GET_SESSIONID(Ndp) >= MBB_MAX_NUMBER_OF_SESSIONS) + { + return STATUS_UNSUCCESSFUL; + } + } + + if (!MBB_NTB16_IS_VALID_NDP_LENGTH(Nth, Ndp)) + { + return STATUS_UNSUCCESSFUL; + } + + for (Index = 0; Index < DatagramCount; Index++) + { + if (MBB_NTB16_IS_END_DATAGRAM(Nth, Ndp, Index)) + return STATUS_SUCCESS; + + if (!MBB_NTB16_IS_VALID_DATAGRAM(Nth, Ndp, Index)) + { + return STATUS_UNSUCCESSFUL; + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbbNtbValidateNth16(_In_ PNCM_NTH16 Nth, _In_ ULONG BufferLength, _Out_opt_ ULONG* NdpCount) +{ + PNCM_NDP16 Ndp; + ULONG ndpCount = 0; + if (BufferLength < sizeof(NCM_NTH16)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH16_IS_VALID_SIGNATURE(Nth)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH16_IS_VALID_HEADER_LENGTH(Nth)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH16_IS_VALID_BLOCK_LENGTH(Nth, BufferLength)) + { + return STATUS_UNSUCCESSFUL; + } + + if (!MBB_NTH16_IS_VALID_FIRST_NDP(Nth)) + { + return STATUS_UNSUCCESSFUL; + } + + if (MbbNtbDetectNdp16Loop(Nth) != STATUS_SUCCESS) + return STATUS_UNSUCCESSFUL; + + for (Ndp = MBB_NTH16_GET_FIRST_NDP(Nth); Ndp != NULL; Ndp = MBB_NDP16_GET_NEXT_NDP(Nth, Ndp)) + { + if (MbbNtbValidateNdp16(Nth, Ndp) != STATUS_SUCCESS) + return STATUS_UNSUCCESSFUL; + ndpCount++; + } + + if (NdpCount != NULL) + { + *NdpCount = ndpCount; + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbbNtbValidate(_In_ PVOID Nth, _In_ ULONG BufferLength, _In_ BOOLEAN Is32Bit, _Out_opt_ ULONG* NdpCount) +{ + if (Is32Bit == TRUE) + return MbbNtbValidateNth32((PNCM_NTH32)Nth, BufferLength, NdpCount); + else + return MbbNtbValidateNth16((PNCM_NTH16)Nth, BufferLength, NdpCount); +} + +NTSTATUS +CreateNonPagedWdfMemory(_In_ ULONG ObjectSize, _Out_ WDFMEMORY* WdfMemory, _Out_opt_ PVOID* ObjectMemory, _In_ WDFOBJECT Parent, _In_ ULONG PoolTag = 0) +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES objectAttribs; + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); + objectAttribs.ParentObject = Parent; + + status = WdfMemoryCreate(&objectAttribs, NonPagedPoolNx, PoolTag, ObjectSize, WdfMemory, ObjectMemory); + + return status; +} + +PMDL AllocateNonPagedMdl(_In_reads_bytes_(Length) PVOID VirtualAddress, _In_ ULONG Length) +{ + PMDL Mdl; + + Mdl = IoAllocateMdl(VirtualAddress, Length, FALSE, FALSE, NULL); + + if (Mdl) + { + MmBuildMdlForNonPagedPool(Mdl); + Mdl->Next = NULL; + } + + return Mdl; +} diff --git a/network/wwan/cxwmbclass/utils.cpp b/network/wwan/cxwmbclass/utils.cpp new file mode 100644 index 000000000..ec791ab44 --- /dev/null +++ b/network/wwan/cxwmbclass/utils.cpp @@ -0,0 +1,588 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include +#include "util.h" +NTSTATUS +SendSyncControlCommand( + __in WDFUSBDEVICE WdfUsbDevice, + __in WDF_USB_BMREQUEST_DIRECTION Direction, + __in WDF_USB_BMREQUEST_RECIPIENT Recipient, + __in BYTE Request, + __in USHORT Value, + __inout_bcount_opt(BufferLength) PUCHAR Buffer, + __in ULONG BufferLength, + __out_opt PULONG BytesTransfered) + +{ + + NTSTATUS Status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_MEMORY_DESCRIPTOR memoryDescriptor; + WDF_REQUEST_SEND_OPTIONS SendOptions; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + + usbDeviceContext = GetUsbDeviceContext(WdfUsbDevice); + + if (Buffer != NULL) + { + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID)Buffer, BufferLength); + } + + WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS(&controlSetupPacket, Direction, Recipient, Request, Value, usbDeviceContext->UsbCommunicationInterfaceIndex); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(10)); + + Status = WdfUsbTargetDeviceSendControlTransferSynchronously( + WdfUsbDevice, WDF_NO_HANDLE, &SendOptions, &controlSetupPacket, (Buffer != NULL) ? &memoryDescriptor : NULL, BytesTransfered); + + if (!NT_SUCCESS(Status)) + { + BOOLEAN ToHost = Direction == BmRequestDeviceToHost; + } + + return Status; +} + +NTSTATUS +TransactControlChannel( + __in PBUS_OBJECT BusObject, + __in ULONG TimeOut, + __in_bcount_opt(InBufferLength) PUCHAR InBuffer, + __in ULONG InBufferLength, + __out_bcount_opt(OutBufferLength) PUCHAR OutBuffer, + __in ULONG OutBufferLength, + __out PULONG BytesRead) + +{ + ULONG BytesTransfered = 0; + NTSTATUS Status; + + *BytesRead = 0; + + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SEND_ENCAPSULATE_COMMAND, 0, InBuffer, InBufferLength, &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + if (BytesTransfered < InBufferLength) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = WaitForResponseAvailible(BusObject, TimeOut); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestDeviceToHost, BmRequestToInterface, GET_ENCAPSULATE_RESPONSE, 0, OutBuffer, OutBufferLength, &BytesTransfered); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + *BytesRead = BytesTransfered; + +Cleanup: + + return Status; +} + +NTSTATUS +ReadInterrupt(_In_ PBUS_OBJECT BusObject, _Inout_updates_bytes_(BufferLength) PUCHAR Buffer, _In_ ULONG BufferLength, _In_ ULONG Timeout, _Out_ PULONG BytesRead) + +{ + + NTSTATUS status; + WDFMEMORY memHandle = NULL; + + WDFREQUEST request = NULL; + BOOLEAN SentToDevice = FALSE; + WDF_REQUEST_SEND_OPTIONS SendOptions; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + WDF_MEMORY_DESCRIPTOR MemoryDescriptor; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&MemoryDescriptor, (PVOID)Buffer, BufferLength); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(Timeout)); + + status = WdfUsbTargetPipeReadSynchronously(usbDeviceContext->InterruptPipe, NULL, &SendOptions, &MemoryDescriptor, BytesRead); + + return status; +} + +NTSTATUS +GetDeviceString(__in WDFUSBDEVICE UsbDevice, __in UCHAR Index, __out PWSTR* String) + +{ + NTSTATUS Status; + WDF_REQUEST_SEND_OPTIONS SendOptions; + USHORT CharacterCount = 0; + ULONG AllocationSize = 0; + PWSTR AllocatedString = NULL; + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(DEFAULT_IO_TIMEOUT)); + + *String = NULL; + + Status = WdfUsbTargetDeviceQueryString(UsbDevice, NULL, &SendOptions, NULL, &CharacterCount, Index, 0); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + // + // allocate one more char to make sure sting is null terminated + // + AllocationSize = (CharacterCount + 1) * sizeof(WCHAR); + + AllocatedString = (PWSTR)ALLOCATE_PAGED_POOL(AllocationSize); + + if (AllocatedString == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + RtlZeroMemory(AllocatedString, AllocationSize); + + Status = WdfUsbTargetDeviceQueryString(UsbDevice, NULL, &SendOptions, AllocatedString, &CharacterCount, Index, 0); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + *String = AllocatedString; + AllocatedString = NULL; + +Cleanup: + + if (AllocatedString != NULL) + { + FREE_POOL(AllocatedString); + AllocatedString = NULL; + } + + return Status; +} + +NTSTATUS +MbbBusSetPacketFilter(__in MBB_BUS_HANDLE BusHandle, __in ULONG PacketFilter) + +{ + + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + ULONG BytesTransfered = 0; + UCHAR ReadBuffer[256]; + + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SET_PACKET_FILTER, 0, (PUCHAR)&PacketFilter, sizeof(PacketFilter), &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + if (BytesTransfered < sizeof(PacketFilter)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + return Status; +} + +NTSTATUS +MbbBusSetNtbInSize(__in MBB_BUS_HANDLE BusHandle, __in ULONG InSize) + +{ + + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + ULONG BytesTransfered = 0; + + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SET_NTB_INPUT_SIZE, 0, (PUCHAR)&InSize, sizeof(InSize), &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + if (BytesTransfered < sizeof(InSize)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + return Status; +} + +NTSTATUS +MbbBusGetStat(__in MBB_BUS_HANDLE BusHandle, __in USHORT StatIndex, __out ULONGLONG* Value) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + ULONG BytesTransfered = 0; + +#pragma warning(suppress : 6001) + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestDeviceToHost, BmRequestToInterface, GET_STATISTIC, StatIndex, (PUCHAR)Value, sizeof(*Value), &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + if (BytesTransfered < sizeof(Value)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + return Status; +} + +NTSTATUS +MbbBusSetNtbFormat(__in MBB_BUS_HANDLE BusHandle, __in USHORT Format) + +{ + + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + ULONG BytesTransfered = 0; + + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SET_NBT_FORMAT, Format, (PUCHAR)NULL, 0, &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + } + + return Status; +} + +NTSTATUS +MbbBusResetFunction(__in MBB_BUS_HANDLE BusHandle) + +{ + + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + NTSTATUS Status; + ULONG BytesTransfered = 0; + + Status = SendSyncControlCommand( + BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, RESET_FUNCTION, 0, (PUCHAR)NULL, 0, &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + } + + return Status; +} + +NTSTATUS +MbbBusResetDeviceAndSetParms(__in PBUS_OBJECT BusObject) + +{ + NTSTATUS Status; + USHORT NtbFormat = NCM_SET_NTB_FORMAT_16_BIT; + + // + // put the device back into a known state + // + Status = MbbBusResetFunction(BusObject); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + Status = MbbBusSetNtbInSize(BusObject, BusObject->MaxBulkInTransfer); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + if ((BusObject->NtbParam.bmNtbFormatSupported & NCM_NTB_FORMAT_32_BIT) == NCM_NTB_FORMAT_32_BIT) + { + // + // device supports 32 bit mode + // + if (BusObject->NtbFormat32Bit) + { + // + // the device can actually handle a transfer larger than 16bit, change to 32 bit + // + NtbFormat = NCM_SET_NTB_FORMAT_32_BIT; + } + + // + // set the format + // + Status = MbbBusSetNtbFormat(BusObject, NtbFormat); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + } + +Cleanup: + + return Status; +} + +ULONG +ProcessInterruptPipeRead( + PBUS_OBJECT BusObject, + __in_ecount(NewFragmentLength) PCUCHAR NewFragment, + ULONG NewFragmentLength, + __out_ecount(MessageBufferSize) PUCHAR CompleteMessageBuffer, + ULONG MessageBufferSize) + +{ + + ULONG CompleteMessageLength = 0; + PUSB_CDC_NOTIFICATION CdcNotification = NULL; + + ASSERT(MessageBufferSize == sizeof(BusObject->InterruptReassemnblyBuffer)); + + if (BusObject->CurrentOffset == 0) + { + // + // beggining of interrupt transfer + // + if ((NewFragmentLength >= sizeof(*CdcNotification)) && (NewFragmentLength <= sizeof(BusObject->InterruptReassemnblyBuffer))) + { + // + // big enough for a notification + // + CdcNotification = (PUSB_CDC_NOTIFICATION)NewFragment; + + if ((CdcNotification->bmRequestType == 0xa1)) + { + BusObject->ExpectLength = sizeof(*CdcNotification) + CdcNotification->wLength; + + RtlCopyMemory(&BusObject->InterruptReassemnblyBuffer[BusObject->CurrentOffset], NewFragment, NewFragmentLength); + + BusObject->CurrentOffset += NewFragmentLength; + } + else + { + // + // wrong request type, drop + // + } + } + else + { + // + // not big enough to be a cdc notification, drop + // + } + } + else + { + // + // we already have some of the data + // + if ((NewFragmentLength + BusObject->CurrentOffset) <= sizeof(BusObject->InterruptReassemnblyBuffer)) + { + // + // still room in the NewFragment + // + RtlCopyMemory(&BusObject->InterruptReassemnblyBuffer[BusObject->CurrentOffset], NewFragment, NewFragmentLength); + } + else + { + // + // over flow, Keep procssing until we get the whole thing so we don't get out of sync + // + } + BusObject->CurrentOffset += NewFragmentLength; + } + + if (BusObject->CurrentOffset < BusObject->ExpectLength) + { + // + // we don't have the whole thing yet, keep going + // + if (NewFragmentLength == 0) + { + // + // got a zero length transfer, reset the re-assembly state + BusObject->ExpectLength = 0; + BusObject->CurrentOffset = 0; + } + } + else + { + if (BusObject->CurrentOffset == BusObject->ExpectLength) + { + // + // got it all + // + if ((BusObject->CurrentOffset <= sizeof(BusObject->InterruptReassemnblyBuffer)) && (BusObject->CurrentOffset <= MessageBufferSize)) + { + // + // the whole thing fit in the NewFragment + // + RtlCopyMemory(CompleteMessageBuffer, BusObject->InterruptReassemnblyBuffer, BusObject->CurrentOffset); + + CompleteMessageLength = BusObject->CurrentOffset; + BusObject->CurrentOffset = 0; + } + else + { + // + // it is bigger than the re-assembly NewFragment, + // drop it + // + } + + // + // done with the current re-assembled NewFragment + // + BusObject->ExpectLength = 0; + BusObject->CurrentOffset = 0; + } + else + { + // + // current offset is beyond the what we expected + // + ASSERT(0); + } + } + + return CompleteMessageLength; +} + +NTSTATUS +WaitForResponseAvailible(PBUS_OBJECT BusObject, ULONG TimeOut) + +{ + NTSTATUS Status; + UCHAR IndicateBuffer[INTERRUPT_REASSEMBLY_BUFFER_SIZE]; + ULONG BufferLength = 0; + ULONG BytesTransfered = 0; + BOOLEAN ExitLoop = FALSE; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + PUSB_CDC_NOTIFICATION Notification = NULL; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + BusObject->ExpectLength = 0; + BusObject->CurrentOffset = 0; + + while (!ExitLoop) + { + + Status = ReadInterrupt(BusObject, BusObject->SyncInterruptReadBuffer, usbDeviceContext->InterruptPipeMaxPacket, TimeOut, &BytesTransfered); + + if (NT_SUCCESS(Status)) + { + + BufferLength = ProcessInterruptPipeRead( + BusObject, BusObject->SyncInterruptReadBuffer, BytesTransfered, IndicateBuffer, sizeof(IndicateBuffer)); + + if (BufferLength == 0) + { + // + // + // don't have a complete message yet + // + continue; + } + else + { + if (BufferLength < sizeof(*Notification)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Cleanup; + } + + Notification = (PUSB_CDC_NOTIFICATION)IndicateBuffer; + + if (Notification->bNotificationCode != USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE) + { + continue; + } + } + } + else + { + goto Cleanup; + } + + ExitLoop = TRUE; + } + + Status = STATUS_SUCCESS; + +Cleanup: + + return Status; +} + +BOOLEAN IsUsbCapDeviceInfoValid(_In_ USB_CAP_DEVICE_INFO UsbCapDeviceInfo, _In_ ULONG CapResultLength) +{ + if (CapResultLength < sizeof(USB_CAP_DEVICE_INFO_HEADER)) + { + return FALSE; + } + switch (UsbCapDeviceInfo.DeviceInfoHeader.DeviceType) + { + case USB_CAP_DEVICE_TYPE_UDE_MBIM: __fallthrough; + case USB_CAP_DEVICE_TYPE_UDE_MBIM_FASTIO: + // Only support version 1.0 now + if (UsbCapDeviceInfo.DeviceInfoHeader.DeviceMajorVersion == 0x1 && UsbCapDeviceInfo.DeviceInfoHeader.DeviceMinorVersion == 0x0) + { + return TRUE; + } + else + { + return FALSE; + } + default: return FALSE; + } +} + +/*++ + +Routine Description: + + Check if the bus type is Ude + +Arguments: + + BusHandle - identifies the instance of the bus layer. + +Return Value: + + TRUE - The bus type is Ude + FALSE - The bus type isn't Ude + +--*/ +BOOLEAN +MbbBusIsUde(_In_ MBB_BUS_HANDLE BusHandle) +{ + USB_CAP_DEVICE_TYPE DeviceType = ((PBUS_OBJECT)BusHandle)->UsbCapDeviceInfo.DeviceInfoHeader.DeviceType; + return (DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM || DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM_FASTIO); +}