We continue
the series of articles about NDIS. In this topic, we consider the versions of NDIS, and the principles of packet transfer between stack drivers and the NET_BUFFER architecture.

Introduction
')
First, let's look at the versions of NDIS and their features due to the fact that there are a little more than one of them.
- NDIS 5.1. Windows XP, Server 2003. Most drivers are written for this version and no one is taken to port them, because there is nothing much to port there - almost everything will have to be rewritten again;
- NDIS 5.2. Windows Server 2003 SP2. Under this version, most likely no driver is written, since Here the drivers from 5.1 work fine;
- NDIS 6.0. Windows Vista. The NDIS subsystem in Windows Vista has undergone tremendous changes, new types of drivers have been added, and performance has been improved;
- NDIS 6.1. Windows Vista SP2, Server 2008. Same story as with NDIS 5.2;
- NDIS 6.20. Windows 7. Small changes regarding NDIS 6.0, support for the latest in emulation mode.
Old trash in the form of W2K with its NDIS 4.0 I will not touch, because there is no sense to support it. Microsoft also stops supporting NDIS 5.1 in Windows 8.
As you can see from the list, a huge gap lies between NDIS 5.x and NDIS 6.x. In fact, from the general, they only have an architectural feature and a library of functions. The rest of the filling was moved to improve performance. By the way, this increase was investigated by 20%, so that at least in something Vista is better than its predecessor. Driver-filters were added to the architecture, which were lacking in previous versions. The principles of packet transfer have changed dramatically, namely: if before the intermediate driver had to implement at least three functions of receiving and sending packets, now the number of these functions is in any case one. This is made possible by the new packet-passing architecture called NET_BUFFER. We will talk about it below.
NET_BUFFER architecture
So what is it? In fact, NET_BUFFER is a replacement for the previous NDIS_BUFFER'y, but first things first. What happened? The driver implements three functions of sending and receiving packets. Speaking Russian, we call these functions like this:
- AcceptPackage;
- Accept Packages;
- Confirm Accept Packages;
- SendPackage;
- SendPackages;
- Confirm the Package Sending.
It is clear that in order to receive one packet, it was necessary to perform a bunch of actions. And for intermediate drivers, in general, disassemble the package to the bone, assemble your own (for you can’t touch something that’s not yours) and send it. Therefore, the NET_BUFFER architecture was introduced in NDIS 6.x.
According to this architecture, it is sufficient to implement 2 functions each for receiving and sending a packet (now it is not a packet, but a buffer, therefore, take these words as synonyms below when it comes to NDIS 6+). Yes, I lied about 2x, but these two do not do anything special and wander from the driver to the driver without changes. So, the functions of receiving and sending, I will write here their signatures for a general understanding:
VOID FilterSendNetBufferLists( IN NDIS_HANDLE FilterModuleContext, IN PNET_BUFFER_LIST NetBufferLists, IN NDIS_PORT_NUMBER PortNumber, IN ULONG SendFlags ); VOID FilterReceiveNetBufferLists( IN NDIS_HANDLE FilterModuleContext, IN PNET_BUFFER_LIST NetBufferLists, IN NDIS_PORT_NUMBER PortNumber, IN ULONG NumberOfNetBufferLists, IN ULONG ReceiveFlags );
The first parameters are essentially a pointer that will pass you NDIS. When registering the driver, or rather when it is attached to the queue, you can specify this very pointer. So we always have a reference to a user variable, which, as we know, has unlimited scope. Very comfortably.
The second parameters are pointers to NET_BUFFER lists. We will deal with this later.
All other parameters are rarely used, so we will not consider them.
We turn to the architecture itself.
The picture below roughly describes the architecture:

Each NET_BUFFER can describe a package like the image below:

Our package is stored in the shaded space. As you can see, this is not necessarily a continuous block of memory; one packet can be scattered throughout the system address space. It is also advised to store packages in non-paged memory (for reference: when trying to access the paged memory at IRQL> = DISPATCH_LEVEL, we will get a blue screen with the code D1. DRIVER_IRQL_NOT_LESS_OR_EQUAL, the most frequent driver-writer error).
Immediately the question why leave empty space in front of the package? So that when the IP packet goes down, it turns into an Ethernet frame to send. And in order not to rebuild this case, the Ethernet header is simply written before the packet. Thoughtfully enough. The same principle is implemented in the top level drivers. All information about the so-called. The backfill (also known as DataOffset) of the space, offset, and buffer length is stored in the NET_BUFFER structure. I also want to note that the buffer size can be changed, i.e. the beginning of the buffer can be moved to the left, or the end to the right. Special functions exported by the NDIS kernel are used for this.
Instead of conclusion
This article intends to miss a huge amount of detail that I encountered in the process of studying the NDIS subsystem. I do not publish them, because the amount of material, however, would not fit in any reasonable framework. At the same time I try to shed light on some key features that I consider basic to understand the essence of what is happening.
Additional literature read here:
www.codemachine.com/article_ndis6nbls.htmlmsdn.microsoft.com/en-us/library/ff564881 (v = vs.85) .aspx
Until next time.