NdisFWhat? Your secret decoder ring to NDIS functions
The first time you come across NDIS, you might find yourself lost in the enormous number of NDIS APIs, OIDs, status codes, and data structures. What’s the difference between NdisMIndicateStatus and NdisFIndicateStatus? Fortunately, NDIS has naming conventions that make it a little easier to organize the APIs. Let’s take a look.
NDIS.SYS exports approximately 500 APIs on Windows 8.1. (Yes, five hundred!) Of those, all but three start with the name “Ndis”. So that’s our first convention: NDIS APIs are almost always named NdisSomething. That might seem obvious, but there’s a very subtle piece of information encoded in that name: NDIS’s internal routines are prefixed with “ndis”. See the difference? Upper-case N means it’s an exported API, and lower-case n means it’s an internal API.
Why should you care about NDIS’s internal routines? Well most of the time, you don’t. But when you start debugging your driver, you’ll inevitably be looking at some callstacks with NDIS routines (both exported and internal). If you don’t know what the callstack is doing, you might get some clues by looking at related MSDN documentation. Try looking at this callstack and see if you can guess which API is most likely to be documented on MSDN:
That’s not all; it takes more than an N to spell Naming convention. Following the “Ndis” prefix there is often a code indicating which type of driver is associated with the API. Here’s a reference table of the codes:
|If||Network interface providers|
|Cl||CoNDIS call clients|
|Cm||CoNDIS call managers|
|MCo||CoNDIS miniport drivers|
|MCm||CoNDIS integrated call managers|
Functions that don’t have a code are meant to be called from multiple types of drivers, or from protocol drivers. (For some reason, protocol drivers never earned their own code. I’m not sure why, but who am I to argue with two decades of tradition?)
So now without even consulting the documentation, you can guess that NdisMSetTimer is for miniport drivers, while NdisIMNotifyPnPEvent is for intermediate drivers. And I bet you can answer the question at the start of this article: what is the difference between NdisMIndicateStatus and NdisFIndicateStatus?
Enough trivia games; let’s return to practical applications of this knowledge. Suppose you are debugging a callstack that looks like this
Although you might not be familiar with DriverX or DriverY, you can use NDIS naming conventions to guess their roles. At frame 03, DriverX calls an NdisFXxx function in frame 02. Therefore, DriverX is a filter driver. You can also see an ndisMXxx internal NDIS function at frame 01, so you know that NDIS has finished calling all the filters, and has moved on to the miniport before calling DriverY in frame 00. So it’s reasonable to conclude that DriverY is a miniport driver.
Another very practical application: knowing the codes will help you narrow down the APIs that you need to worry about when you’re writing code. If you’re writing a lightweight filter driver, you can safely ignore the approximately 130 APIs that are exclusively for miniports (NdisMSomething). That makes it a bit easier to find the API you’re looking for.
Now you know the ABC’s of NDIS!