编写 MBBCx 客户端驱动程序

警告

本主题中的序列图仅用于说明目的。 它们不是公共合同,将来可能会改变。

MBBCx 客户端驱动程序的 INF 文件

MBBCx 客户端驱动程序的 INF 文件与其他 NetAdapterCx 客户端驱动程序相同。 有关详细信息,请参阅 NetAdapterCx 客户端驱动程序的 INF 文件

按照 通用指南 确保 INF 文件满足通用要求。

初始化设备

除了 NetAdapterCx 为 NetAdapter 设备初始化所需的任务外,MBB 客户端驱动程序还必须在其 EvtDriverDeviceAdd 回调函数中执行以下任务:

  1. 在调用 NetDeviceInitConfig 之后调用MBB_DEVICE_CONFIG_INIT,但在调用 WdfDeviceCreate 之前,引用框架传入的同一WDFDEVICE_INIT对象。

  2. 调用 MbbDeviceInitialize 以使用初始化 的MBB_DEVICE_CONFIG 结构和从 WdfDeviceCreate 获取的 WDFDEVICE 对象注册 MBB 设备特定的回调函数。

以下示例演示如何初始化 MBB 设备。 为了清楚起见,错误处理已被排除。

    status = NetDeviceInitConfig(deviceInit);
    status = MbbDeviceInitConfig(deviceInit);

    // Set up other callbacks such as Pnp and Power policy

    status = WdfDeviceCreate(&deviceInit, &deviceAttributes, &wdfDevice);

    MBB_DEVICE_CONFIG mbbDeviceConfig;
    MBB_DEVICE_CONFIG_INIT(&mbbDeviceConfig,
                           EvtMbbDeviceSendMbimFragment,
                           EvtMbbDeviceReceiveMbimFragment,
                           EvtMbbDeviceSendServiceSessionData,
                           EvtMbbDeviceCreateAdapter);

    status = MbbDeviceInitialize(wdfDevice, &mbbDeviceConfig);

与其他类型的 NetAdapterCx 驱动程序不同,MBB 客户端驱动程序不得从 EvtDriverDeviceAdd 回调函数中创建 NETADAPTER 对象。 相反,MBBCx 会指示它稍后再这样做。

接下来,客户端驱动程序必须调用 MbbDeviceSetMbimParameters,通常位于后面的 EvtDevicePrepareHardware 回调函数中。

此消息流图说明了初始化过程。

显示 MBBCx 客户端驱动程序初始化过程的流程图。

此消息流图说明了初始化过程。

展示 MBBCx 客户端驱动程序初始化过程的图表。

处理 MBIM 控制消息

MBBCx 使用 MBIM 规范 Rev 1.0、第 8 节、9 和 10 中为控制平面定义的标准 MBIM 控件命令。 命令和响应通过 MBBCx 提供的客户端驱动程序和 API 提供的一组回调函数交换。 MBBCx 通过使用以下函数调用来模拟 MBIM 设备的操作模型,如 MBIM 规范版本 1.0 第 5.3 节中所定义:

  • MBBCx 通过调用其 EvtMbbDeviceSendMbimFragment 回调函数将 MBIM 命令消息发送到客户端驱动程序。 客户端驱动程序通过调用 MbbRequestComplete 异步完成此发送请求。
  • 客户端驱动程序通过调用 MbbDeviceResponseAvailable 来指示结果的可用性。
  • MBBCx 通过调用其 EvtMbbDeviceReceiveMbimFragment 回调函数从客户端驱动程序提取 MBIM 响应消息。 客户端驱动程序通过调用 MbbRequestCompleteWithInformation 异步完成此 get-response 请求。
  • MBB 客户端驱动程序可以调用 MbbDeviceResponseAvailable 来通知 MBBCx 有未请求的设备事件。 然后,MBBCx 从客户端驱动程序检索信息,这与它提取 MBIM 响应消息的方式类似。

下图演示了 MBBCx 客户端驱动程序消息交换流。

显示 MBBCx 与客户端驱动程序之间的 MBIM 消息交换的关系图。

MBIM 控制消息的同步

MBBCx 框架始终将调用序列化到客户端驱动程序的 EvtMbbDeviceSendMbimFragmentEvtMbbDeviceReceiveMbimFragment 回调函数中。 在客户端驱动程序调用 MbbRequestComplete 或 MbbRequestCompleteWithInformation 之前,框架不会发出任何新调用。

虽然保证客户端驱动程序不会接收重叠的 EvtMbbDeviceSendMbimFragmentEvtMbbDeviceReceiveMbimFragment 回调,但在设备提供上一个命令的响应之前,它可能会连续接收对它们的多次调用。

如果设备未处于 D0 状态,MBBCx 框架将首先将设备引入 D0(换句话说,在调用 EvtMbbDeviceSendMbimFragmentEvtMbbDeviceReceiveMbimFragment 之前调用 EvtDeviceDeviceD0Entry)。 MBBCx 框架还保证它将设备保持为 D0 状态,这意味着在客户端调用 MbbRequestCompleteMbbRequestCompleteWithInformation 之前,它不会调用 EvtDeviceD0Exit

为 PDP 上下文/EPS 载体创建 NetAdapter 接口

在建立数据会话之前,MBBCx 将指示客户端驱动程序创建 NETADAPTER 对象,MBBCx 将使用它来表示激活的数据会话的网络接口。 这是通过 MBBCx 调用客户端驱动程序的 EvtMbbDeviceCreateAdapter 回调函数来实现的。

EvtMbbDeviceCreateAdapter 回调函数的实现中,MBBCx 客户端驱动程序必须首先执行与任何 NetAdapterCx 客户端驱动程序创建 NETADAPTER 对象所需的相同任务。 此外,它还必须执行以下附加任务:

  1. NetAdapterCreate 创建的 NETADAPTER 对象上调用 MbbAdapterInitialize

  2. 调用 MbbAdapterinitialize 后,调用 MbbAdapterGetSessionId 以检索 MBBCx 打算使用此 NETADAPTER 对象的数据会话 ID。 例如,如果返回的值为 0,则表示 MBBCx 会将此 NETADAPTER 接口用于由主 PDP 上下文/默认 EPS 持有者建立的数据会话。

  3. 建议 MBBCx 客户端驱动程序在创建的 NETADAPTER 对象和返回的 SessionId 之间保留内部映射。 这有助于跟踪数据会话到 NETADAPTER 对象的关系,当激活多个 PDP 上下文/EPS 载体时尤其有用。

  4. 在从 EvtMbbDeviceCreateAdapter返回之前,客户端驱动程序必须通过调用 NetAdapterStart来启动适配器。 (可选)还可以通过在 调用 NetAdapterStart之前调用其中一个或多个函数来设置适配器的功能

MBBCx 至少调用此回调函数一次,因此主 PDP 上下文/默认 EPS 载体始终有一个 NETADPATER 对象。 如果激活了多个 PDP 上下文/EPS 载体,MBBCx 可能会多次调用此回调函数,每次建立数据会话时调用一次。 NETADAPTER 对象和数据会话表示的网络接口之间必须存在一对一关系,如下图所示。

显示了不同数据会话的多个 NETADAPTER 对象的示意图。

以下示例演示如何为数据会话创建 NETADAPTER 对象。 请注意,为简洁和清晰起见,设置适配器功能所需的错误处理和代码已省略。

    NTSTATUS
    EvtMbbDeviceCreateAdapter(
        WDFDEVICE  Device,
        PNETADAPTER_INIT AdapterInit
    )
    {
        // Get the client driver defined per-device context
        PMY_DEVICE_CONTEXT deviceContext = MyGetDeviceContext(Device);

        // Set up the client driver defined per-adapter context
        WDF_OBJECT_ATTRIBUTES adapterAttributes;
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&adapterAttributes,
                                                MY_NETADAPTER_CONTEXT);


        // Create the NETADAPTER object
        NETADAPTER netAdapter;
        NTSTATUS status = NetAdapterCreate(AdapterInit,
                                           &adapterAttributes,
                                           &netAdapter);

        // Initialize the adapter for MBB
        status = MbbAdapterInitialize(netAdapter);

        // Retrieve the Session ID and use an array to store
        // the session <-> NETADAPTER object mapping
        ULONG sessionId;
        PMY_NETADAPTER_CONTEXT netAdapterContext = MyGetNetAdapterContext(netAdapter);

        netAdapterContext->NetAdapter = netAdapter;

        sessionId = MbbAdapterGetSessionId(netAdapter);

        netAdapterContext->SessionId = sessionId;

        deviceContext->Sessions[sessionId].NetAdapterContext = netAdapterContext;

        //
        // Optional: set adapter capabilities
        //
        ...
        NetAdapterSetDatapathCapabilities(netAdapter,
                                          &txCapabilities,
                                          &rxCapabilities);

        ...
        NetAdapterSetLinkLayerCapabilities(netAdapter,
                                           &linkLayerCapabilities);

        ...
        NetAdapterSetLinkLayerMtuSize(netAdapter,
                                      MY_MAX_PACKET_SIZE - ETHERNET_HEADER_LENGTH);

        //
        // Required: start the adapter
        //
        status = NetAdapterStart(netAdapter);

        return status;
    }

有关设置数据路径功能的代码示例,请参阅 网络数据缓冲区管理

MBBCx 保证在使用相同会话 ID 请求 MBIM_CID_CONNECT 之前调用 EvtMbbDeviceCreateAdapter。 下列流程图显示了客户端驱动程序与类扩展在创建 NETADAPTER 对象时的交互。

显示了 MBB 客户端驱动程序的 NETADAPTER 创建和激活的示意图。

EvtDevicePrepareHardware 成功完成时,MBBCx 将启动创建用于主 PDP 上下文/默认 EPS 承载的 NETADAPTER 对象的流程。

每当应用程序请求按需连接时, WwanSvc 就会触发用于为辅助 PDP 上下文/专用 EPS 持有者创建 NETADAPTER 对象的流。

NETADAPTER 对象的生存期

客户端驱动程序创建的 NETADAPTER 对象将在不再使用时由 MBBCx 自动销毁。 例如,在额外的 PDP 上下文/EPS 载体被停用后就会发生这种情况。 MBBCx 客户端驱动程序不得在创建的 NETADAPTER 对象上调用 WdfObjectDelete

如果客户端驱动程序需要清理绑定到 NETADAPTER 对象的上下文数据,则应在调用 NetAdapterCreate 时在对象属性结构中提供 EvtDestroyCallback 函数。

MBB 设备的电源管理

对于电源管理,客户端驱动程序应像 其他类型的 NetAdapterCx 客户端驱动程序一样使用 NETPOWERSETTINGS 对象。

处理设备服务会话

当应用程序将 DSS 数据向下发送到调制解调器设备时,MBBCx 将调用客户端驱动程序的 EvtMbbDeviceSendServiceSessionData 回调函数。 然后,客户端驱动程序应以异步方式将数据发送到设备,并在发送完成后调用 MbbDeviceSendDeviceServiceSessionDataComplete ,因此 MBBCx 随后可以释放为数据分配的内存。

相反,客户端驱动程序调用 MbbDeviceReceiveDeviceServiceSessionData ,以通过 MBBCx 将任何数据传递到应用程序。

Windows 驱动程序符合要求