Sample NDIS-WDM Miniport Driver (WDF Version)

SUMMARY

The purpose of this sample is to illustrate functionality of an NDIS-WDF miniport driver. An NDIS-WDF driver exposes NDIS miniport interface at its upper edge and uses Windows Driver Framework interfaces to interact with other WDM drivers such as USB, IEEE 1394, and serial at its lower edge.

This sample can either use NDISPROT sample driver from the DDK to read/write packets to any network device installed on the system or it can use PCIDRV sample to talk to Intel 10/100 network device.

1) The diagram below shows how this sample uses NDISPROT (NDIS protocol sample available in the Windows Server 2003 DDK) as its lower WDM edge driver to read and write packets to the physical network interface card (NIC). In order to test this sample, you should at least have one physical NIC on the test machine.

                   ---------------------
                  |                     |
                  |        TCP/IP       |
                  |                     |
                   ---------------------
                            ^
                            | <-------------- NDIS Interface
                            V
                   ---------------------
                  |                     |
                  |    Sample NDISWDM   |
                  |       Miniport      |
                  |                     |
                   ---------------------
                            ^
                            | <--------------- IRPs
                            V
                   ---------------------
                  |                     |
                  |        NDISPROT     |
                  |                     |
                   ---------------------
                            ^               
                            | <--------------- NDIS Interface
                            V
                   ---------------------
                  |                     |
                  |    NDIS Miniport    |
                  |    for physical NIC |
                  |                     |
                   ---------------------
                            ^
                            | <-------------- Talk to the hardware using I/O resources               
                            V               
                      ---------------
                     |    H/w NIC    |
                      ---------------
                             |||||||
                             -------          
                            
2) The following diagram shows how this driver as an upper device filter of PCIDRV sample work as a miniport driver for Intel 10/100 Ethernet adapter. The driver stack consists of NDIS-WDM driver as an upper device filter and PCIDRV as the function driver for the device. The NDIS-WDM driver registers with NDIS as a miniport so that the stack can be bound to all the protocol drivers and receive NDIS requests. The PCIDRV maps all the hardware resources and performs the job of reading and writing to the hardware. All the NDIS requests received by the NDIS-WDM driver is converted into IRPs and forwarded to the PCIDRV driver.
                   --------------------
                  |                   |
                  |        TCP/IP     |
                  |                   |
                   --------------------
                            ^
                            | <-------------- NDIS Interface (I/Os done using NDIS Packets)
                            V
                   ---------------------
                  |                     |
                  |   NDISWDM Miniport  |
                  |    (NDISEDGE.SYS)   | <-- Installed as an Upper Device Filter
                  |                     |
                   ---------------------
                            ^
                            | <--------------- IRPs (I/Os done using IRPs)
                            V
                   ---------------------
                  |                     |
                  |     PCIDRV.SYS      | <-- Installed as a function driver
                  |                     |
                   ---------------------
   
                            ^
                            | <-------------- Talk to the hardware using I/O resources    
                            V    
                      ---------------
                     |    H/w NIC    |
                      ---------------
                             |||||||
                             -------          

 

Note: This sample provides an example of a minimal driver intended for educational purposes. Neither the driver nor its sample test programs are intended for use in a production environment.

The driver can be installed on Windows 2000 and later operating systems.

BUILDING THE SAMPLE

Click the Free Build Environment or Checked Build Environment icon under your Development Kit's program group to set basic environment variables needed by the build utility.

Change to the directory containing the device source code, such as CD Src\kmdf\NDISEDGE.

Run build -ceZ, or use the macro BLD. Using these tools invokes the Microsoft make routines that produce log files called Buildxxx_yyy_zzz.log, and also Buildxx_yyy_zzz.wrn and Buildxx_yyy_zzz.err if there are any warnings or errors. Where xxx stands for fre or chk depending on the environment chosen, yyy stands for the OS version (W2K, WXP, or Wnet), and zzz stands for platform version (x86, IA64, or AMD64).

If the build succeeds, the driver, ndisedge.sys, will be placed in a platform specific subdirectory of your %TargetPath% directory specified in the 'Sources' file.

Depending on the build environment, the 50 subdirectory produces either NDIS5.0 or NDIS 5.1 compatible driver. If built in the Windows 2000 build environment, it will produce NDIS 5.0 compatible driver. If it's built in the Windows XP or Window Server 2003 build environment, it will produce NDIS 5.1 compatible driver.

The 60 subdirectory can be built only in the Windows Vista build environment. The sample built in this subdirectory will be NDIS 6.0 compatible and will work on Windows Vista and later operating systems.

INSTALLATION

This sample can installed in either as virtual miniport driver interfacing with NDISPROT or as an upper device filter interfacing with PCIDRV. Steps on how to install this driver in each of these modes is given below.

Virtual network miniport driver interfacing with NDISPROT

In this mode, you can get the driver to talk to NDISPROT sample to communicate with the real NIC for reading and writing network packets. For this, you have to enable -DINTERFACE_WITH_NDISPROT=1 in the sources file.

After installing the NDISEDGE driver, you have to one of the followings to use it as your primary miniport driver:

Installation steps
  1. Install the NDISPROT sample from the Windows Server 2003 DDK and start the driver. Instruction on how to install and load the driver is given in the NDISPROT.HTM that comes with the sample. Make sure to build the driver with EX_CALLBACK interface defined in the 'Sources' file. This enables the driver to notify NDISEDGE whenever it gets loaded. Read the Code Tour section in this document for further information.
  2. Double-click Network Connections in Control panel, right-click the Local Area Connection applet of the physical NIC, and select Properties. Clear the TCP/IP bindings check box.
  3. Install the NDISEDGE miniport driver. Steps for installing the driver on Windows 2000, XP, and Server 2003 DDK are listed below:

    To install the driver on a Windows 2000 machine

     

    1. Build the driver in a Win2K build environment to get the NDIS version 5.0 of the driver.
    2. Copy the KMDF coinstaller (wdfcoinstallerMMmmm.dll), the driver and the NDISEDGE.INF file to a floppy disk or to a directory on the target test machine.
    3. Open Control Panel, and double-click Add New Hardware.
    4. Click Next.
    5. Select Add a new device.
    6. Select No, I Want to Select the Hardware from a list.
    7. Select Network Devices, and then click Next.
    8. Click Have Disk, and point to the directory that contains NDISEDGE.INF file.

    To install the driver on a Windows XP or Server 2003 machine

    1. Copy the KMDF coinstaller (wdfcoinstallerMMmmm.dll), the NDIS version 5.1 of the driver and the INF file to a floppy disk or to a directory on the target machine.
    2. Open Control Panel and double-click Add Hardware.
    3. At the Welcome to the Add Hardware Wizard screen, click Next.
    4. Select Yes, I have already connected the hardware, and click Next.
    5. Select Add a new hardware device from the list, and click Next.
    6. Select Install the hardware that I manually select from a list (Advanced), and click Next.
    7. Select Network adapters, and click Next.
    8. Click Have Disk, make sure that A:\ is in the Copy manufacturer's files from box, and click OK.
    9. Click on the desired entry, and click Next.
    10. At The wizard is ready to install your hardware screen, click Next.
    11. Click Finish.

    Alternatively, you can use the DEVCON.EXE from the DDK to install the driver programmatically.

    c:\>DEVCON.EXE   INSTALL   ndisedge.inf   "root\ndisedge"

    The system copies the NDISEDGE.sys file to %systemroot%\system32\drivers directory and loads the driver. Instead of root-enumerating the driver as described above, you can use the toaster bus driver to bus enumerate the driver.

  4. Check the configuration of the miniport by running IPCONFIG /All. You should be able to browse the internet or copy files from another machine.
This the default configuration - NDISPROT driver is started before NDISEDGE miniport - and the miniport is using the MAC address of the real NIC. If you reboot the machine, you will notice that the network connectivity through the miniport is broken. This is because the NDISPROT hasn't been loaded or loaded after the miniport. When the miniport fails to open the NDISPROT interface during init, it reports a locally administered MAC address as the current address and completes the initialization. After that, even if the miniport is able to successfully open the NDISPROT interface in the ExCallback, it cannot report the Real NIC's MAC address. As a result, no network communication will take place because the real NIC will not receive or send packets that doesn't match with it's MAC address. In such a scenario, you can re-establish the network connectivity by disabling and re-enabling the miniport instance in the device manager to make sure that the miniport opens the target device during MiniportInitialize and reports the target NIC's MAC address.

If you like to get this configuration to work across reboots, you should configure the NDISEDGE driver to set the target NIC filter to promiscuous mode. You can do that by using Advanced Property of the miniport in the device manager or by changing the value in the INF file before installing the miniport.

Filter driver interfacing with PCIDRV

In this mode, you use the NETDRV.INF available with PCIDRV sample and install the driver as an upper device filter of PCIDRV.

To install on Windows 2000 System:

  1. Build NDISEDGE.SYS as described above in a Win2K build environment to get the NDIS version 5.0 driver.
  2. Build PCIDRV.SYS in a Win2K build environment to restrict the driver to use only Win2K specific interfaces.
  3. Copy the wdfcoinstallerMmmm.dll, the drivers and the NETDRV.INF file to a floppy disk or to a directory on the target test machine. Driver should be copied under appropriate subdirectory (i386, ia64, amd64).
  4. Launch the Device Manager (by clicking on Windows Start, Run option and type Devmgmt.msc).
  5. Select the Intel network controller in the device manager and double click to get the properties dialog.
  6. Select Driver Tab.
  7. Click on Update Driver... button. This will take you to Upgrade Device Driver Wizard.
  8. Click Next.
  9. Select Display a list of the known drivers for this device so that I can choose a specific driver, and then click Next.
  10. Click Have Disk, and point to the directory that contains NETDRV.INF file.
  11. Select Sample WDM PCI Driver For Ethernet Adapter With NDIS Upper Edge, and then click Next.
  12. If you get a Warning dialog about installing driver that's not compatible with the hardware. Click No and exit the Wizard.
  13. Otherwise, you will get another warning dialog about installing unsigned driver. Click Yes and then Click Next to complete the driver upgrade.

On Windows XP, Server 2003 or Vista system:

  1. Build NDISEDGE.SYS as described above in a XP or Server 2003 build environment to get the NDIS version 5.1 driver.
  2. Build PCIDRV.SYS in XP or Server 2003 build environment.
  3. Copy the wdfcoinstallerMMmm.dll, drivers and the NETDRV.INF file to a floppy disk or to a directory on the target test machine. Driver should be copied under appropriate subdirectory (i386, ia64, amd64).
  4. Launch the Device Manager (by clicking on Windows Start, Run option and type Devmgmt.msc).
  5. Select the Intel network controller in the device manager, right click to get the Properties menu and select Updater Driver....
  6. Select Driver Tab.
  7. Click on Update Driver... button. This will take you to Hardware Update Wizard.
  8. Select Install from a list of specific location (Advanced), and then click Next.
  9. Select Don't search. I will choose the driver to install, and then click Next.
  10. Click Have Disk, and point to the directory that contains NETDRV.INF file.
  11. Select Sample WDM PCI Driver For Ethernet Adapter With NDIS Upper Edge, and then click Next.
  12. If you get a Warning dialog about installing driver that's not compatible with the hardware. Click No and exit the Wizard.
  13. Otherwise, you will get a warning dialog about installing unsigned driver. Click Continue Anyway and complete the driver upgrade.

TESTING

Install NDIS Tester from the WHQL Web site and run all the client and server tests.

CODE TOUR

The information below describes some of the key operations performed in the driver.

Initialization

  1. Allocates memory for miniport context structure. This is where the driver stores information about a specific instance of the device.
  2. In the NICInitializeAdapter, the driver tries to open the NDISPROT device by using IoTarget interfaces("\Device\NdisProt").
  3. If the call fails because the NDISPROT is not loaded, the driver registers an executive callback interface to be notified whenever the NDISPROT loads. If the call succeeds, the driver gets the target deviceobject related to the file handle returned by ZwOpenFile. The driver then sends IOCTL_NDISPROT_QUERY_BINDING to query the list of miniport device names and a message that NDISPROT is bound to in a loop.
  4. At every iteration in the loop, the driver makes sure that the miniport name and description it received from the NDISPROT is not one of its own (in case multiple instances of NDISEDGE are installed). The driver then makes an IOCTL_NDISPROT_OPEN_DEVICE request to open the target device. If the request fails, the driver continues the loop until it finds a free one.
  5. If the IOCTL_NDISPROT_OPEN_DEVICE request succeeds, the driver allocates resources for handling send and receive requests, sends IOCTL requests to NDISPROT to get the link speed, sets the miniport to Promiscuous mode (if enabled in the registry), and finally creates a worker thread to poll for read packets from the NDISPROT.

Resolving driver load order issue between NDISEDGE and NDISPROT:

NDISEDGE and NDISPROT driver are two unrelated drivers. NDISEDGE is a Plug and Play driver and NDISPROT is an Windows®NT®4.0 compatible non-Plug and Play driver. As a result, it's not possible to use a Plug and Play notification mechanism to resolve load order dependency between the drivers. If the NDISEDGE is installed as a root-enumerated driver, then it will get loaded much earlier in the boot sequence than the NDISPROT driver. When the NDISEDGE tries to open the NDISPROT in MiniportInitialize handler, it will fail with a STATUS_OBJECT_NAME_NOT_FOUND error because the NDISPROT device is not present.

Instead of using timer DPCs and work items to periodically retry opening NDISPROT, this driver uses a new executive callback mechanism to resolve the load order issue. Both NDISEDGE and NDISPROT create a Callback object (ExCreateCallback) called \Callback\NdisProtCallbackObject and register their callback handlers (ExRegisterCallback). The driver that loads first creates the object and the drivers loaded afterwards open the same object, register, and then send notification to the other drivers. Based on the notification ID received in the callback, both NDISEDGE and NDISPROT identify the source of notification and take appropriate action. For example, when the NDISEDGE driver receives a notification, it checks to see if the source driver of this notification is NDISPROT and if so, it tries to complete its initialization and indicate the final media status of its miniport to NDIS.

Request Handler

Most of the requests are handled directly by the NDISEDGE and completed synchronously. The driver also has the ability to forward any requests to the target driver. For forwarding requests, such as link speed, it queues a work item to get to PASSIVE_LEVEL of execution, and from the workitem it sends an IOCTL request to NDISPROT and waits for the IRP to complete. When the IRP returns, it indicates to NDIS about the completion of the request.

Send Packet Handler

In the SendPacket handler, the driver copies the packet into a free TCB block (because NDISPROT cannot handle chained MDLs), initializes a preallocated IRP (IRP_MJ_WRITE) and MDL to describe the TCB data buffer and sends the IRP to the NDISPROT driver asynchronously. When the write completes, the original send packet that was saved in the TCB control block is completed and the TCB and IRP is freed for reuse.

Receive Packet handler:

The driver pre-allocates a certain number (NIC_MAX_BUSY_SENDS) of RCB (Receive Control Blocks) buffers, IRPs (IRP_MJ_READ) and MDLs (to describe the RCB data buffer) during Miniport Initialize for receiving packets from the target driver (NDISPROT). It then queues a workitmem (NICPostReadsWorkItemCallBack) to post all the read IRPs to the target driver. When a read request completes, the completion routine (NICReadRequestCompletion) is called. This routine checks to see whether the received packet is acceptable based on the current packet filter set by the protocol, and decides to either indicate the packet to NDIS or discard the packet. When the indicated packet returns from NDIS through MPReturnPacket handler, the driver reclaims the associated RCB block and the read IRP for reuse, and checks to see if the number of outstanding Read IRPs to the NDISPROT has gone below a certain thershold (NIC_SEND_LOW_WATERMARK). If so, it queues a workitem to post more read IRPs and keeps the read path going.

Adapting this driver for an USB device

If you are using this sample to build an NDIS miniport driver for an USB device:

RESOURCES

For the latest release of the Windows device Driver Development Kit, see http://www.microsoft.com/ddk/.

If you have questions on using or adapting this sample for your project, you can either contact Microsoft Technical Support or post your questions in the Microsoft driver development newsgroup.

FILE MANIFEST

File        Description

ndiswdm.htm    Sample Tour documentation for this sample (this file).
Sources        Generic file for building the code sample.
ndisedge.inf    INF file for installing the driver.
ndiswdm.RC    Resource file to specify driver version, etc.
ndiswdm.h    Include file for defining structures, constants and function prototypes.
ndiswdm.c    Main file that contains driver entry and other miniport functions.
init.c            Source file for allocating and initializing resources.
send.c            Source file for handling Send requests from NDIS.
receive.c    Source file for handling IRPs received by the lower WDM driver indicating to NDIS.
request.c       Source file for handling set & query information requests from NDIS.
excallbk.c    Source file for handling ex callback notification to resolve driver load order.

Top of page

© 2003 Microsoft Corporation. All rights reserved.