NDIS Driver Compile Flags

    技术2022-05-11  22

    March 15, 2004 Stephan Wolf

    Copyright © 2004 by Stephan Wolf. All rights reserved

    The Windows DDK offers several compile-time flags for NDIS drivers. Most of these flags are described in the DDK documentation in sections "Compile Flags Used by NDIS Drivers" and "Specifying the NDIS Version Number". But there are still some undocumented pitfalls, which you should be aware of.

    Note that all the NDIS compile flags discussed in this article are available only in the NT-based DDKs. These compile flags do not apply to the Windows 9x/Me DDKs.

    Compile Flag Definition vs. Actual Value

    Compile flags are not used in a consistent manner in the DDK's "ndis.h" header file. Some compile flags just need to exist, regardless if they are assigned a value or not. These compile flags are tested with the #ifdef preprocessor directive in "ndis.h".

    Other compile flags actually need to be assigned a value. That is, "ndis.h" evaluates the actual value of these compile flags with the #if preprocessor directive.

    For the sake of simplicity, I recommend you always assign a value of "1" to the NDIS compile flags that are relevant to your NDIS driver. The only exception to this rule is the BINARY_COMPATIBLE compile flag, which can also be assigned a "0".

    Definition of Compile Flags

    You can define compile flags in your SOURCES file, in your source code, or in both. Use the "-D" option to define a compile flag in your SOURCES file as in the following example:

    C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER=1

    Or you can use the #define preprocessor directive to define a compile flag in your source code. Note that the definition needs to be placed above the line where "ndis.h" gets included as the following example shows:

    #define NDIS_MINIPORT_DRIVER 1 #include <ndis.h>

    Available Compile Flags for NDIS Drivers

    Here is a list of the NDIS compile flags that are available in the DDK (Windows 2003 and earlier DDKs):

    Compile FlagRequired forNDIS MiniportsRequired forNDIS ProtocolsTarget Windows VersionsNDIS_MINIPORT_DRIVERYesNoAllNDIS51_MINIPORTNDIS50_MINIPORTNDIS40_MINIPORT YesNoAllNDIS51NDIS50NDIS40 NoYesAllBINARY_COMPATIBLENo (implicitly set)OptionalWindows 9x/MeUSE_KLOCKSYes, if "deserialized"YesWindows 9x/MeNDIS_WDMYes, if NDIS-WDMN/AAll_WIN2K_COMPAT_SLIST_USAGEYesYesWindows 2000 and earlierWIN9X_COMPAT_SPINLOCKYesYesWindows 9x/Me

    Note: NDIS intermediate drivers implement both a miniport and a protocol. Thus, all of the compile flags listed here apply to intermediate drivers.

    Detailed description of the individual compile flags.

    NDIS_MINIPORT_DRIVER

    This compile flag is a requirement for every NDIS miniport driver and, by implication, for every intermediate (IM) driver. The NDIS_MINIPORT_DRIVER flag enables the NDIS driver to make use of NdisMXxx() functions (the 'M' after "Ndis" stands for "Miniport").

    Note: You should pay attention to the fact that NDIS_MINIPORT_DRIVER implicitly sets "BINARY_COMPATIBLE=1" unless you explicitly define a different value to BINARY_COMPATIBLE before your source code includes "ndis.h".

    NDIS51_MINIPORTNDIS50_MINIPORTNDIS40_MINIPORT

    NDIS miniport (and intermediate) drivers need to tell "ndis.h" the NDIS version to which they apply. The actual outline of the NDIS_MINIPORT_CHARACTERISTICS structure will depend on the NDIS version that you define.

    Specify one of the following NDIS versions for your miniport:

    Compile FlagMaximum NDIS Versionof Your MiniportNDIS51_MINIPORTNDIS 5.1NDIS50_MINIPORTNDIS 5.0NDIS40_MINIPORTNDIS 4.x(none)NDIS 3.x

    Note: NDIS_MINIPORT_CHARACTERISTICS defaults to NDIS version 3.0 if you do not specify the NDIS version used by your miniport.

    Each version of the Windows operating system supports a specific NDIS version. Each Windows variant supports NDIS drivers written to this and earlier NDIS versions. Windows will not accept your NDIS driver if either of the following is true:

    Your driver uses NDIS functions that are not supported by the NDIS Wrapper library on the target Windows system. In this case, your driver will not even load because the external references to the missing NDIS functions cannot be resolved.

     

    Your driver sets an NDIS version in the NDIS_MINIPORT_CHARACTERISTICS structure that is higher than the NDIS version supported by the NDIS Wrapper library. In this case, NdisMRegisterMiniport() will return an error status of NDIS_STATUS_BAD_VERSION. See section "NDIS Versions" in the DDK docs for details on the NDIS versions supported by the various Windows variants.

    NDIS Major and Minor Version Defined

    If you have have specified an NDIS version of 5.0 or higher for your miniport, "ndis.h" makes the following definitions for you, which you can use to set the 'MajorNdisVersion' and 'MinorNdisVersion' fields in the NDIS_MINIPORT_CHARACTERISTICS structure when you call NdisMRegisterMiniport():

    NDIS_MINIPORT_MAJOR_VERSIONNDIS_MINIPORT_MINOR_VERSION

    NDIS51NDIS50NDIS40

    Analogous to the NDIS version of miniports, NDIS protocol (and intermediate) drivers need to tell "ndis.h" the NDIS version to which they apply. The actual outline of the NDIS_PROTOCOL_CHARACTERISTICS structure will depend on the NDIS version that you define. Specify one of the following NDIS versions for your protocol:

    Compile FlagMaximum NDIS Versionof Your ProtocolNDIS51NDIS 5.1NDIS50NDIS 5.0NDIS40NDIS 4.x(none)NDIS 3.x

    Note: NDIS_PROTOCOL_CHARACTERISTICS defaults to NDIS version 3.0 if you do not specify the NDIS version used by your protocol.

    If you have have specified an NDIS version of 5.0 or higher for your protocol, "ndis.h" makes the following definitions for you, which you can use to set the 'MajorNdisVersion' and 'MinorNdisVersion' fields in the NDIS_PROTOCOL_CHARACTERISTICS structure when you call NdisRegisterProtocol():

    NDIS_PROTOCOL_MAJOR_VERSIONNDIS_PROTOCOL_MINOR_VERSION

    BINARY_COMPATIBLE

    One important feature that the developers of NDIS had in mind was platform independency. The same NDIS driver source code shall compile for any hardware and software platform that supports NDIS. NDIS achieves this compatibility by providing a complete set of interface functions, which NDIS drivers use instead of directly calling system functions provided by the operating system. In other words, NDIS drivers should only call NdisXxx() functions.

    A special case is the "Windows on x86" platform. You can define the BINARY_COMPATIBLE compile flag in order to generate an NDIS driver that will run on both the Windows 9x/Me and the Windows NT/2000/XP/2003 platforms.

    Note: You do not need to explicitly define BINARY_COMPATIBLE if your driver is an NDIS miniport, because NDIS_MINIPORT_DRIVER already implies BINARY_COMPATIBLE.

    However, for an NDIS protocol driver, you can explicitly set BINARY_COMPATIBLE=1 so the driver can run on all Windows platforms.

    How Does BINARY_COMPATIBLE Work?

    What BINARY_COMPATIBLE does is that it tells "ndis.h" to declare prototypes for some particular NdisXxx() functions so your NDIS driver will actually call NDIS library functions. Otherwise, if BINARY_COMPATIBLE is not defined or is defined a zero value, "ndis.h" will define macros for these NdisXxx() function names. The macros heavily depend on the NT-based platforms and thus make your driver incompatible with Windows 9x/Me.

    Is My NDIS Driver Actually Binary-Compatible?

    Unfortunately, there are some pitfalls, which can prevent binary-compatibility of your NDIS driver. If your driver is a "serialized" NDIS miniport and you have defined the NDIS_MINIPORT_DRIVER compile flag, your driver will run fine on all Windows platforms.

    However, your driver is likely to fail (crash) on the Windows 9x/Me platform, if the following conditions are met:

    your driver is a "deserialized" miniport, a protocol driver, or an intermediate driver

    and

    your driver makes use of NDIS spin locks: NDIS_SPIN_LOCKoryour driver makes use of NDIS interlocked functions: NdisInterlockedXxx()

    The reason is that NDIS spin lock functions are implemented as no-ops in Windows 9x/Me and NDIS interlocked functions are not synchronized. Thus, follow these guidelines in order to make your NDIS driver ready for the Windows 9x/Me platform:

    Define the USE_KLOCKS compile flag. If your driver is a miniport, do not specify the NDIS_ATTRIBUTE_DESERIALIZE flag in the call to NdisMSetAttributesEx(). If the design of your driver requires it to be "deserialized", do not use any NDIS interlocked functions like NdisInterlockedInsertTailList(), NdisInterlockedAddUlong(), etc. Note that protocol and intermediate drivers are deserialized by definition.

    USE_KLOCKS

    This compile flag can be used as a workaround for the fact that NDIS spin locks are implemented as dummies (i.e. no-ops) in Windows 9x/Me. So it is a good idea to define this compile flag in order to get spin locks to work as expected on Windows 9x/Me.

    See BINARY_COMPATIBLE for more details on NDIS quirks related to the Windows 9x/Me platform.

    Historical Background

    NDIS miniports were originally "serialized", which means that the NDIS Wrapper library takes care of not calling more than one function concurrently in a serialized miniport at any time. Thus, there is absolutely no need for serialized miniports to use spin locks. As a result, all NDIS spin lock functions are implemented as empty no-op functions in Windows 9x/Me.

    When the "full-duplex" attribute NDIS_MAC_OPTION_FULL_DUPLEX was introduced in NDIS 4.0, the miniport's send and receive paths could be called concurrently by the NDIS Wrapper.

    Note: You should not use the NDIS_MAC_OPTION_FULL_DUPLEX attribute but use the NDIS_ATTRIBUTE_DESERIALIZE attribute instead.

    The "deserialized" attribute NDIS_ATTRIBUTE_DESERIALIZE introduced in NDIS 4.1 as well as the deprecated NDIS_MAC_OPTION_FULL_DUPLEX attribute both require a deserialized miniport to protect its shared resources because the NDIS Wrapper does not serialize calls to deserialized miniports (some exceptions apply, e.g. the Wrapper serializes calls to MiniportQueryInformation()).

    The miniport thus now needs to be able to protect any resources that it shares between its MiniportXxx() functions. As a workaround for the no-op spin locks in Windows 9x/Me, you can define the USE_KLOCKS compile flag. The flag tells "ndis.h" to directly map NDIS spin lock functions to kernel spin lock functions, which work as expected on all Windows platforms including Windows 9x/Me.

    NDIS_WDM

    Define this compile flag if your NDIS miniport talks to a WDM (Windows Driver Model) device driver at its lower edge. The NDIS_WDM flag tells "ndis.h" to include the appropriate WDM header file for you. See section "Miniport Driver with a WDM Lower Interface" in the DDK docs for details on NDIS-WDM miniport drivers.

    The BINARY_COMPATIBLE compile flag also affects the NDIS_WDM compile flag. The header file that "ndis.h" will include for your miniport to be able to access a WDM lower-edge driver actually depends on the combination of the two flags as follows:

    BINARY_COMPATIBLEDefined AsNDIS_WDMDefined AsHeader File IncludedBy "ndis.h"11"wdm.h"10(none)01"ntddk.h"00"ntddk.h"

    _WIN2K_COMPAT_SLIST_USAGE

    Note the leading underscore in the compile flag's name.

    The XP and later DDKs (i.e. DDK build number 2600+) use an optimized implementation of functions related to the singly linked list (SLIST) data structure. These optimizations are incompatible with Windows 2000 and earlier operating system versions.

    Thus, if you use SLISTs in your driver and the same driver file must be used on all Windows platforms, you need to define the _WIN2K_COMPAT_SLIST_USAGE compile flag. The flag tells the XP and later DDKs to use an implementation of SLIST related functions that is compatible with Windows 2000 and earlier versions.

    As an alternative to _WIN2K_COMPAT_SLIST_USAGE, you can build your driver with the Windows 2000 DDK. For details, see section "New Slist Implementation" in the DDK release notes (i.e. file "relnote.htm" in the DDK root directory).

    WIN9X_COMPAT_SPINLOCK

    You can define this compile flag in order to disable another "optimization", which was first introduced in the Windows 2003 DDK (i.e. DDK build number 3790+).

    If you define the WIN9X_COMPAT_SPINLOCK compile flag, which I recommend, the function KeInitializeSpinLock() is an actual library function. Otherwise, i.e. if you do not define WIN9X_COMPAT_SPINLOCK, KeInitializeSpinLock() is implemented as an inline function that is incompatible with Windows 9x/Me.

    Thus, if your driver binary file must be used on all Windows platforms including Windows 9x/Me, you should define the WIN9X_COMPAT_SPINLOCK compile flag.

    Summary of Compile Flags for Miniports and Protocols

    Depending on whether your driver is an NDIS miniport, a protocol, or an intermediate driver, you need to add the following directives to your SOURCES file:

    Note: NDIS version 5.1 is assumed here. Make sure to replace the "51" with the NDIS version number that your driver supports. See section "NDIS Versions" in the DDK docs for details on the NDIS versions supported by the various Windows variants.

    for an NDIS miniport driver add:

    C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER=1 -DNDIS51_MINIPORT=1

    for an NDIS protocol driver add:

    C_DEFINES=$(C_DEFINES) -DNDIS51=1

    for an NDIS intermediate (IM) driver add:

    C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER=1 -DNDIS51_MINIPORT=1 -DNDIS51=1

    Summary of Compile Flags for Binary-Compatible Drivers

    You might ask yourself "Which compile flags do I need for my NDIS driver to run correctly on Windows XYZ?". First of all, you should specify the type of your NDIS driver and the NDIS version that your driver supports.

    Then also add one or more of the following directives to your SOURCES file, if your driver must  run on one or more of the respective Windows variants:

    for Windows 9x/Me add:

    C_DEFINES=$(C_DEFINES) -DBINARY_COMPATIBLE=1 -DUSE_KLOCKS=1 -DWIN9X_COMPAT_SPINLOCK=1

    for Windows 2000 and earlier add:

    C_DEFINES=$(C_DEFINES) -D_WIN2K_COMPAT_SLIST_USAGE=1

    for Windows XP and later:

    (nothing to add for XP at the time of this writing)

    About the author:

    Stephan Wolf has worked as an independent system software developer since 1988. He lives and works mainly in Germany, but sometimes abroad. His focus is on network driver development (not only) for all Windows variants (including CE). You can contact him at stewo68@hotmail.com (hotmail sometimes "recognizes" serious email as spam, so try again if you get no answer).

     


    最新回复(0)