<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>The NDIS blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/ndis/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/ndis/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 16 Apr 2019 05:21:59 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Goodbye</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/goodbye</link>
      <pubDate>Mon, 07 Jan 2019 19:59:24 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/?p=565</guid>
      <description><![CDATA[Microsoft is retiring this blogging platform, so the NDIS blog will be removed soon.  If you have...]]></description>
      <content:encoded><![CDATA[Microsoft is retiring this blogging platform, so the NDIS blog will be removed soon.  If you have any articles that you need to reference, please save them locally.]]></content:encoded>
    </item>
    <item>
      <title>My favorite perfcounters</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/my-favorite-perfcounters</link>
      <pubDate>Tue, 06 Jun 2017 18:27:22 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/?p=515</guid>
      <description><![CDATA[… are the NDIS counters.&nbsp; Like you even had to ask.We love performance counters on the Windows...]]></description>
      <content:encoded><![CDATA[<h2>… are the NDIS counters.&nbsp; Like you even had to ask.</h2><p>We love performance counters on the Windows Networking team. We routinely use performance counters to monitor &amp; diagnose issues. Nearly every networking feature has its own counter set, and Windows ships with far too many counter sets to document here. Fortunately, I don’t have to document them all – this is the NDIS blog, so I’ll lean on my NDIS bias.<p>These are the Windows Networking counter sets of particular interest to NDIS developers: <ul><li><strong>Network Adapter and Network Interface</strong></li><li><strong>Per Processor Network Interface Card Activity</strong> and <strong>Per Processor Network Activity Cycles</strong></li><li><strong>Physical Network Interface Card Activity</strong></li><li><strong>RDMA Activity</strong></li><li><strong>Processor Information</strong></li></ul><p>Let’s chat a bit about each of these.<h2>The <b>Network Adapter</b> and <b>Network Interface</b> counter sets.</h2><p>These are very similar. In fact, the only difference is that Network Adapter shows more types of NICs than Network Interface does. Since Network Adapter has more stuff, I generally prefer it over Network Interface. The only reason to use Network Interface is if you need to write code that works on very old OS versions – Network Adapter was “only” added back in 2006.<p>The data in these counter sets is pulled together from a few sources:<ul><li>Many counters are populated from <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365945(v=vs.85).aspx">GetIfTable2</a>, which itself ultimately boils down to querying OID_GEN_STATISTICS from the NIC driver.</li><li><strong>RSC counters</strong>: These are calculated internally by TCPIP.</li><li><strong>Current Bandwidth</strong>: This is the arithmetic mean of the NIC driver’s NDIS_LINK_STATE XmitLinkSpeed and RcvLinkSpeed.</li><li><strong>Output Queue Length</strong>: This is not currently implemented, and should be ignored.</li></ul><h2>The <b>Per Processor Network Interface Card Activity</b> and <b>Per Processor Network Activity Cycles</b> counter sets.</h2><p>What a mouthful. These two counter sets are more advanced than Network Adapter, and you can use these to dig deeper into a performance issue. Your frontline troops should be your Network Adapter counters.&nbsp; But if that’s not enough, it’s time to call in the Per Processor NDIS counters.<p>As their names suggest, these counters track data per processor. That’s super helpful when diagnosing RSS or interrupt delivery problems. The <b>Activity</b> counter tracks how many times a particular event occurs, like how many packets are received. The <b>Cycles</b> counter tracks how many CPU cycles are spent on a particular task, like how many CPU cycles are spent in a call to the NIC driver’s interrupt handler. These two counter sets work great in tandem – you can typically divide the Cycles data by the Activity data to get cycles-per-operation.<p>One caveat about interrupts and DPCs: Not all hardware has interrupts (in the traditional sense, at least). Typically only a PCI bus based NIC will use interrupts or DPCs. For all other types of NICs, these counters will report zero. Furthermore, NDIS drivers can choose to either use NDIS APIs (like NdisMRegisterInterruptEx) or to use WDM APIs to handle interrupts and DPCs. If the driver doesn’t use NDIS APIs, then NDIS won’t be able to track the interrupts and DPCs, and these counters will be zero. So these counters may not report values for some vendors’ drivers.<p>One caveat about the cycle counters: The cycle counters are measured in terms of the nominal clock tick of your processor. On x86 and x64, this is the units of the <b>rdtsc</b> instruction. On arm32, this is the units of the <b>pmccntr</b> register. Cycle counters are not directly comparable between machines with different processors. If your processor throttles itself down to a lower effective clock in order to save power (e.g, Intel’s P-states), then the cycle counter might not be meaningful. You should only make comparisons between cycle counters under carefully-controlled lab conditions.<p>One final caveat: These counters were added in Windows 7, but their implementation was changed a bit in Windows 8. Although you’ll find counters of the same name on Windows 7, the definitions below apply only to Windows 8 or Windows Server 2012 and later. I do not suggest you use these counters on Windows 7, unless you’ve first carefully verified that the counter seems to give reliable results.<p>Because these counters are so low-level, it’s worth spending a bit of time explaining what each of them means. Here’s the rundown.<p><strong>Interrupts/sec</strong>: The number of times the <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff559407(v=vs.85).aspx">MiniportMessageInterrupt</a> or <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff559395(v=vs.85).aspx">MiniportInterrupt</a> handler was invoked <i>and</i> returned TRUE to indicate that the interrupt was recognized.<p><strong>Interrupt Cycles/sec</strong>: The number of CPU cycles spent in MiniportMessageInterrupt or MiniportInterrupt.<p><strong>Interrupt DPC Latency Cycles/sec</strong>: The number of CPU cycles between the end of an ISR and the start of a DPC. If this value is unexpectedly high, it may indicate that other DPCs or ISRs are starving the NIC’s DPC. Use WPA to see a timeline of all ISRs and DPCs on the CPU.<p><strong>DPCs Queued/sec</strong>: The number of times that a DPC was executed. (The name is a tiny bit misleading; it’s not the number of times a DPC was queued.)<p><strong>DPCs Queued on Other CPUs/sec</strong>: The number of processors that are targeted by NdisMQueueDpcEx, excluding the current processor. For example, suppose a NIC driver is running on processor 5 and calls NdisMQueueDpcEx with a mask that targets processors 4, 5, and 7. Then this counter will increment by 2, for processors 4 and 7. This will often be zero. If it is a very high number, it may indicate that RSS is running in a less-than-optimal mode. Ideally, a NIC that supports RSS will interrupt the correct processor directly, without needing to schedule a cross-processor DPC.<p><strong>DPCs Deferred/sec</strong>: The number of times that NDIS decided to execute a DPC at passive level, due to <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/network/receive-side-throttle-in-ndis-6-20">Receive Side Throttling</a> (RST). Generally you should expect this to be at zero for Server-class machines.<p><strong>Interrupt DPC Cycles/sec</strong>: The number of CPU cycles spent in <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff559411(v=vs.85).aspx">MiniportMessageInterruptDpc</a> or <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff559398(v=vs.85).aspx">MiniportInterruptDpc</a>. Typically this includes both send-complete and receive-indicate activity.<p><strong>Received Packets/sec</strong>: Watch out: this one is subtle! It’s the total number of packets that the NDIS indicated to each protocol driver. For example, if the NIC indicates up an IPv4 frame, but there is no IPv4 protocol driver bound to the NIC, then that frame is not counted; the counter will be zero. More interestingly, if there are <i>two</i> protocols bound to the NIC that both want IPv4 frames (e.g., the TCPIP driver and Wireshark’s NPF driver), then each packet gets counted twice. The gotcha is that if you launch Wireshark, this counter will double. Not because you’re receiving more traffic at the physical layer, but because NDIS is indicating the same traffic to twice as many protocol drivers.<p><strong>Receive Indications/sec</strong>: The total number of times that NDIS indicated packets to a protocol driver. You can divide Received Packets/sec by Receive Indications/sec to get the average batch size. Low-performance client NICs might not batch packets at all, in which case the average batch size will be 1.0. Increasing the Interrupt Moderation setting should increase the batch size.<p><strong>Low Resource Received Packets/sec</strong>: This is the total number of packets indicated to a protocol driver while the NDIS_RECEIVE_FLAGS_RESOURCES flag is set. Some NIC drivers never use this flag, and a few NIC drivers will use this flag always. In some cases, NDIS always sets the flag internally. Despite the name, the flag doesn’t necessarily mean that the NIC is low on resources, although some drivers use it to signal that. In general, you’ll need to know exactly how the NIC driver and NDIS use the flag to interpret this counter.  Note that the OS may spend more cycles processing a received packet if the NDIS_RECEIVE_FLAG_RESOURCES flag is set, so you should generally prefer that this counter is at or near zero. If your servers typically have this flag at zero, but suddenly it spikes to a high value, that is a red flag that some network driver is spending too long processing received packets, or has leaked received packets.<p><strong>Low Resource Receive Indications/sec</strong>: The number of times that NDIS indicates packets to a protocol driver with the NDIS_RECEIVE_FLAGS_RESOURCES flag.<p><strong>Stack Receive Indication Cycles/sec</strong>: The number of CPU cycles spent in any ProtocolIndicateReceiveNetBufferLists handler. <p><strong>NDIS Receive Indication Cycles/sec</strong>: The number of CPU cycles spent in NdisMIndicateReceiveNetBufferLists. Typically this would include each filter driver, as well as any protocol drivers. However, if a filter driver defers a receive indication, the time spent in in protocol drivers will not be included.<p><strong>Returned Packets/sec</strong>: The number of receive packets that were processed by the OS, and returned to the NIC driver stack. Specifically, the number of packets that were passed to a call to NdisReturnNetBufferLists. This should almost exactly correlate with Received Packets/sec <i>minus</i> Low Resource Received Packets/sec.<p><strong>Return Packet Calls/sec</strong>: The number of times a protocol driver called NdisReturnNetBufferLists.<p><strong>NDIS Return Packet Cycles/sec</strong>: The number of CPU cycles spent in NdisReturnNetBufferLists. Typically this includes all time spent in filter drivers, the NIC driver, and NDIS itself. However, if a filter driver defers the return operation, or the network adapter is in a low power state due to NDIS Selective Suspend, then this counter will not include all CPU cycles.<p><strong>Miniport Return Packet Cycles/sec</strong>: Despite the name, this counter is implemented to be largely similar to NDIS Return Packet Cycles/sec. This counter includes filters drivers, the NIC driver, and NDIS itself; and the same caveats apply.<p><strong>Sent Packets/sec</strong>: The number of packets that were sent via NdisSendNetBufferLists. Note that, in rare cases, an NDIS lightweight filter driver may itself drop or originate new send packets. Those will not be accounted for in this counter; this counter measures the top of the filter stack.<p><strong>Send Request Calls/sec</strong>: The total number of calls to NdisSendNetBufferLists.<p><strong>Miniport Send Cycles/sec</strong>: The total number of CPU cycles spent in MiniportSendNetBufferLists. This includes much of the time sending packets, but will not account for CPU cycles spent in any workitem, timer, interrupt, or DMA callback. Therefore, (like any cycle counter) it is not comparable across different NIC drivers.<p><strong>NDIS Send Cycles/sec</strong>: The total number of CPU cycles spent in NdisSendNetBufferLists. Typically, this includes all time spent in filters, the miniport driver, and NDIS itself. However, if any filter defers a packet and reinjects it later, then those CPU cycles won’t be included here. For example, the built-in QoS Pacer filter defers some NBLs and reinjects them from a timer.<p><strong>Sent Complete Packets/sec</strong>: The total number of packets that were returned to a protocol driver, via <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff570268(v=vs.85).aspx">ProtocolSendNetBufferListsComplete</a>.<p><strong>Send Complete Calls/sec</strong>: The total number of calls to any ProtocolSendNetBufferListsComplete handler.<p><strong>Stack Send Complete Cycles/sec</strong>: The total number of CPU cycles spent in ProtocolSendNetBufferListsComplete handlers.<p><strong>NDIS Send Complete Cycles/sec</strong>: The total number of CPU cycles spent in NdisMSendNetBufferListsComplete. This may include time spent in filter drivers and protocols, if the filter drivers handle send completion synchronously.  In that case, this counter’s value will be slightly larger than the Stack Send Complete Cycles/sec counter’s value, and their difference tells you how many cycles were spent in the filter stack and NDIS itself. However, if a filter driver defers send completion, this counter will not include time spent in protocols.<p><strong>Build Scatter Gather List Calls/sec</strong>: The number of times the NIC driver calls NdisMAllocateNetBufferSGList. Typically this would be comparable to the number of sent packets per second.<p><strong>Build Scatter Gather Cycles/sec</strong>: The number of cycles spent inside NdisMAllocateNetBufferSGList. Note that this may also include the time spent in MiniportProcessSGList, if the map registers are immediately available and the MiniportProcessSGList handler is called inline. However, if MiniportProcessSGList is deferred and called later, this counter does not then include cycles spent waiting or the cycles spent in MiniportProcessSGList. This counter is difficult to interpret, and I generally do not suggest you use it.<p><strong>RSS Indirection Table Change Calls/sec</strong>: The number of times that a protocol driver updates the RSS indirection table on a NIC. Specifically, the number of times that OID_GEN_RECEIVE_SCALE_PARAMETERS is sent and the NDIS_RSS_PARAM_FLAG_ITABLE_UNCHANGED flag is clear. This should typically be a low number – RSS table updates are pure overhead, and ideally they don’t happen often. If you have many short-lived TCP connections and high CPU usage, the OS may need to update the table more often.<p><strong>Miniport RSS Indirection Table Change Cycles</strong>: The total number of cycles spent in a MiniportOidRequest handler, for an OID_GEN_RECIEVE_SCALE_PARAMETERS request that updates the RSS indirection table. Note that this counter can be unreliable if the CPU cycle counter is not synchronized across all CPUs on the system, since indirection table changes are run at PASSIVE_LEVEL and are not affinitized to a particular processor.<p><strong>Packets Coalesced/sec</strong>: The result of OID_PACKET_COALESCING_FILTER_MATCH_COUNT.<p>Phew! We made it… now on to the next counter set!<h2>The <font style="font-weight: bold">Physical Network Interface Card Activity </font>counter set.</h2><p>At present, this counter set is mostly useful for NIC drivers that implement NDIS Selective Suspend. In the future, we may add other counters to it, but right now it’s all power management.<p><strong>Low Power Transitions (Lifetime)</strong>: The number of times that a network adapter has entered a low power state (D2 or D3). This can be as result of NDIS Selective Suspend, connected standby, system S3 or S4, or D3-on-disconnect. This counter is reset each time the device is halted (i.e., receives IRP_MN_REMOVE_DEVICE or the system powers off).<p><strong>% Time Suspended (Lifetime)</strong>: The percent of time since the NIC was started that the NIC is in any low power state. For devices that implement NDIS Selective Suspend, this ought to be a highish percentage when the device isn’t under heavy use.<p><strong>% Time Suspended (Instantaneous)</strong>: Similar to the above, except the time interval is equal to your sample interval. E.g., if you use the -SampleInterval parameter to the Get-Counter PowerShell cmdlet to set the sample interval to 5 seconds, then this counter returns what percent of the last 5 seconds that the device was in low power.<p><strong>Device Power State</strong>: Returns the current D-state of the device. If the device is in D0, this counter returns 0. If the device is in D2, this counter returns 2.  If the device is in D3, this counter returns… I bet you can guess. This one’s useful for keeping an eye on NDIS Selective Suspend. Toss it into a perfmon graph, and you can see exactly what the D-state is at each moment.<h2>The <font style="font-weight: bold">RDMA Activity </font>counter set.</h2><p>The individual counters in this one all come from <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/hh451565(v=vs.85).aspx">OID_NDK_STATISTICS</a>, which is supplied by the NIC driver.<h2>The <font style="font-weight: bold">Processor Information </font>counter set.</h2><p>This is not a networking-specific counter set, but it’s invaluable when diagnosing network performance problems. In particular, the <strong>% Interrupt Time</strong>, <strong>% DPC Time</strong>, and <strong>Interrupts/sec</strong> counters are quite useful. Note that Interrupts/sec is a system-wide counter that includes IPIs, so it can be difficult to infer what exactly causes an unexpectedly-large number of interrupts. Fortunately <a href="https://docs.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-analyzer">WPA</a> lets you drill into the finest minutiae of any interrupt storm.<h2>Honorable mentions</h2><p>We’ve covered the counters that are tied to NDIS, but that’s hardly the end of the story. The counter sets listed below are likely of interest to anyone who’s looking at the Windows network stack. Don’t be afraid to rummage through all the counters that come with the OS – there’s some good stuff in there!&nbsp; For example, if you’re investigating a problem with TCP checksum offload, you’ll want to keep an eye on the <strong>TCP checksum errors</strong> counter.<ul><li>IPv4 <i>and</i> IPv6</li><li>TCPv4 <i>and</i> TCPv6</li><li>UDPv4 <i>and</i> UDPv6</li><li>WFPv4 <i>and</i> WFPv6</li><li>TCPIP Performance Diagnostics <i>and</i> TCPIP Performance Diagnostics (Per-CPU)</li><li>Hyper-V Virtual Network Adapter</li><li>Hyper-V Virtual Network Adapter Drop Reasons</li><li>Hyper-V Virtual Network Adapter VRSS</li><li>Hyper-V Virtual Switch</li><li>Hyper-V Virtual Switch Port</li><li>Hyper-V Virtual Switch Processor</li><li>Network Virtualization</li></ul><p>Enough! No more lists of counters! Next time we’ll have fewer words and more pictures as we visualize the flow of statistics and counters in Windows.</p>]]></content:encoded>
    </item>
    <item>
      <title>It’s perfcounter week on the NDIS blog!</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/its-perfcounter-week-on-the-ndis-blog</link>
      <pubDate>Mon, 05 Jun 2017 18:04:23 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/?p=505</guid>
      <description><![CDATA[Actually every week is perfcounter week.Performance counters are an essential tool for devs, ops, …...]]></description>
      <content:encoded><![CDATA[<h2>Actually every week is perfcounter week.</h2><p><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa373083(v=vs.85).aspx">Performance counters</a> are an essential tool for devs, ops, … and marketing. Yet they’re often not well understood. Fortunately, under the hood, performance counters are very simple: a perfcounter is just a number that counts things.<p>Before we get too far along, let’s agree on a bit of terminology:<p>A <b>counter</b> is a single measurement, like the number of interrupts per second.<br>A <b>counter set</b> is a group of related counters, like a group of 9 counters relating to TCP/IP. The CLR calls this a <b>category name</b>, and some Win32 APIs call this a <b>performance object</b>. They all refer to the same thing. I’ll stick with the counter set term on this blog.<br>A counter <b>instance</b> is a specific thing that can be measured, like a network adapter.<p>Conventionally, you can specify a counter using the <b>counter path</b> notation. The formal grammar is <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa373193(v=vs.85).aspx">documented here</a>, but most commonly in Networking, you’ll use the subset that looks like this:<p><code>Counter Set<b>(</b>Counter Instance<b>)\</b>Counter</code><p>So for example, <em>Network Interface(BitBlaster 2000)\Bytes Sent/sec</em> belongs to the <em>Network Interface</em> counter set, targets the <em>BitBlaster 2000</em> instance, and measures the <em>Bytes Sent/sec</em> counter.<h2>Counters in a GUI</h2><p>Enough terminology; let’s do things. If you’ve used perfcounters before, you’ve probably come across Performance Monitor, aka perfmon.&nbsp; You can use this built-in tool to rummage around and visualize the various perfcounters. It’s great if you don’t quite know which counter you’re looking for, or if you need a quick overview of what some counter is doing. Here’s how I use it:<ol><li>Launch perfmon.exe.</li><li>In the tree on the left, select Performance Monitor to get to the graph.</li><li>In the graph’s toolbar, click the Delete button (it looks like a red X) to remove any pre-added counters. We’ll add our own.</li><li>Then click the Add button (it looks like a green +) to add more interesting counters.</li><li>In the dialog that appears, the upper-left quadrant shows all counter sets. If you expand one of the dropdowns inside a counter set, you can see an individual counter. Once you select an individual counter, you can see all applicable counter instances in the lower-left quadrant.</li><li>Select a counter instance, then click the Add button to add the counter to the list of counters to monitor.</li><li>Once you’ve added all the counters you like, click OK.</li></ol><p>That will look like this:<p><a href="https://msdnshared.blob.core.windows.net/media/2017/06/1-perfmon.png"><img width="244" height="184" title="Screenshot of performance monitor's Add Counters dialog" alt="The Add Counters dialog lets you drill down into counter sets, counters, and instances.  Once you select an instance you like, click the Add button to add it to the list of counters to monitor." src="https://msdnshared.blob.core.windows.net/media/2017/06/1-perfmon_thumb.png" border="0"></a><p>To make the graph look right, you may have to fiddle with the scale a bit. Right-click on the counter at the bottom of the main window, select Properties, and change the Scale dropdown on its properties page.<h2>Counters in PowerShell</h2><p>Perfmon is great for high-level explorations, but you’ll eventually run up against its limitations. For example, it won’t send you an email if a counter goes out of tolerance. For the most flexibility, we need to go beyond a GUI.<p>Performance counters have been around for a while, so there are plenty of APIs, libraries, and tools you can choose from. I will use PowerShell for illustration, but you can use whatever API you prefer. Generally the concepts exposed in PowerShell will map onto any API.<p>Let’s poll a counter from PowerShell:<p class="ps">PS C:\&gt; Get-Counter '\Processor(0)\% DPC Time'<br>Timestamp CounterSamples<br>--------- --------------<br>6/4/2017 10:14:10 \\jtippet-d\processor(0)\% dpc time :<br>1.56111154738975<p>The counter values come back as real numbers, so you can perform all the usual arithmetic on them. For example, you can check if the counter value exceeds 10%:<p class="ps">Get-Counter '\Processor(0)\% DPC Time' -Continuous | % {<br>$percentDpcTime = $_.CounterSamples[0].CookedValue<br>if ($percentDpcTime -gt 10) { <br>Send-MailMessage -To 'me@example.com' -Subject 'Alert' -BodyAsHtml "% time at DPC: $percentDpctime"<br>} }<p>(Don’t actually build a production monitoring system like this – there’s off-the-shelf software that has way more features.)<p>Now that we have some of the basics down, next time we’ll take a look at the goodies you can use to measure the heartbeat of the Windows network stack.</p>]]></content:encoded>
    </item>
    <item>
      <title>A new video on NDIS debugging</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/a-new-video-on-ndis-debugging</link>
      <pubDate>Tue, 21 Mar 2017 15:28:27 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/?p=476</guid>
      <description><![CDATA[The Defrag Tools show was kind enough to host me for a quick chat about debugging NDIS drivers....]]></description>
      <content:encoded><![CDATA[The Defrag Tools show was kind enough to host me for a quick chat about debugging NDIS drivers.  <a href="https://channel9.msdn.com/Shows/Defrag-Tools/Defrag-Tools-175-Debugging-the-Network-Stack">Check it out</a>!]]></content:encoded>
    </item>
    <item>
      <title>Eliminating empty handlers</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/eliminating-empty-handlers</link>
      <pubDate>Mon, 13 Feb 2017 00:01:10 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/?p=153</guid>
      <description><![CDATA[Don’t come back empty-handlered
NDIS drivers have several opportunities to supply advanced...]]></description>
      <content:encoded><![CDATA[<h2>Don’t come back empty-handlered</h2>
NDIS drivers have several opportunities to supply advanced functionality through optional handlers. But if you don’t want the advanced functionality, you don’t need to bother implementing an empty handler.

Why does it matter to you? It matters because it makes your code (slightly) more difficult to maintain. “Dummy” code is more lines of worthless boilerplate code that distracts you from your “real” code. There’s also a tiny performance cost, as NDIS has to set up the function call and jump into your code.

Let’s look at an example. Filter drivers are a good model, because the majority of their handlers are optional. From <a href="https://msdn.microsoft.com/en-us/library/ff565515.aspx">MSDN</a>, we see that the FilterSendNetBufferLists/ FilterSendNetBufferListsComplete handlers are optional.

Suppose your filter looks like this:

[code language="cpp"]
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
    // ...
    FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;
    FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
    // ...

    Status = NdisFRegisterFilterDriver(
        DriverObject,
        (NDIS_HANDLE)FilterDriverObject,
        &amp;FChars,
        &amp;FilterDriverHandle);
    // ...
}

VOID
FilterSendNetBufferLists(
    IN NDIS_HANDLE FilterModuleContext,
    IN PNET_BUFFER_LIST NetBufferLists,
    IN NDIS_PORT_NUMBER PortNumber,
    IN ULONG SendFlags
)
{
    // Dummy function; just pass the NBLs through
    NdisFSendNetBufferLists(
        pFilter-&gt;FilterHandle,
        NetBufferLists,
        PortNumber,
        SendFlags);
}

VOID
FilterSendNetBufferListsComplete(
    IN NDIS_HANDLE FilterModuleContext,
    IN PNET_BUFFER_LIST NetBufferLists,
    IN ULONG SendCompleteFlags
)
{
    // Dummy function; just pass the NBLs through
    NdisFSendNetBufferListsComplete(
        pFilter-&gt;FilterHandle,
        PrevNbl,
        SendCompleteFlags);
}
[/code]

As you can see, the FilterSendNetBufferLists and FilterSendNetBufferListsComplete functions don’t do anything useful. How could we improve the code? Simple: just delete the dummy functions and register NULL for the function handlers.

[code language="cpp" highlight="9,10"]
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
)
{
    NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
    // ...
    FChars.SendNetBufferListsHandler = NULL;
    FChars.SendNetBufferListsCompleteHandler = NULL;
    // ...

    Status = NdisFRegisterFilterDriver(
        DriverObject,
        (NDIS_HANDLE)FilterDriverObject,
        &amp;FChars,
        &amp;FilterDriverHandle);
    // ...
}
[/code]
Much better!]]></content:encoded>
    </item>
    <item>
      <title>Mapping from NDIS OIDs to WMI classes</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/mapping-from-ndis-oids-to-wmi-classes</link>
      <pubDate>Sat, 21 Mar 2015 00:55:46 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/2015/03/21/mapping-from-ndis-oids-to-wmi-classes/</guid>
      <description><![CDATA[In which we write a PowerShell script, install the WDK, attach a kernel debugger, reverse-engineer...]]></description>
      <content:encoded><![CDATA[<h2>In which we write a PowerShell script, install the WDK, attach a kernel debugger, reverse-engineer the OS, and prove Goldbach’s conjecture</h2>  <p>We’ve previously talked about <a href="https://blogs.msdn.com/b/ndis/archive/2011/04/06/exploring-ndis-s-wmi-classes.aspx">how to rummage through all the NDIS WMI classes</a>, but there’s one topic we haven’t fully covered.&#160; Suppose you’re looking for the WMI class that maps to a specific OID — how do you find the right class?</p>  <p>There are a few ways you can do this.&#160; The first is just to take a guess based on the name.&#160; Suppose we want to find the WMI class that corresponds to OID_GEN_VLAN_ID.&#160; Let’s search for any WMI class that has “VLAN” in the name:</p>  <p class="ps">Get-WmiObject -Namespace root\wmi -List&#160; | Where-Object {$_.name -Match &quot;VLAN&quot; }</p>  <p>My machine has only one matching class, MSNdis_VlanIdentifier, and indeed that’s the right one.</p>  <p>But this technique relies somewhat on luck.&#160; What if you don’t find any matches — should you keep searching, or does that mean there really is no WMI class for that OID?&#160; So that takes us to the more methodical approach.</p>  <p>If you <a href="https://msdn.microsoft.com/en-us/windows/hardware/gg454513.aspx">install the Windows Driver Kit (WDK)</a>, then it will give you several rather helpful files:</p>  <table class="bordertable"><tbody>     <tr>       <td>wmicore.mof</td>        <td>Defines each of the built-in NDIS WMI classes</td>     </tr>      <tr>       <td>ndisguids.h</td>        <td>Defines the names of the GUIDs that underlie built-in NDIS WMI classes</td>     </tr>      <tr>       <td>ndis.h and ntddndis.h</td>        <td>Defines various OIDs, structures, and flags that will be useful in decoding some WMI classes</td>     </tr>   </tbody></table>  <p>Let’s start in wmicore.mof.&#160; Open it in a text editor to find a comment indicating which WMI class implements OID_GEN_VLAN_ID.&#160; Again, we find MSNdis_VlanIdentifier.</p>  <pre>///     OID_GEN_VLAN_ID:
[WMI, Dynamic, Provider(&quot;WMIProv&quot;), guid(&quot;{765dc702-c5e8-4b67-843b-3f5a4ff2648b}&quot;),
 Description(&quot;NDIS VLAN Identifier&quot;) : amended]
class  MSNdis_VlanIdentifier : MSNdis
{
    [ read, write, Description(&quot;The IEEE 802.1Q VLAN ID assigned to this NIC.&quot;) : amended,
        WmiDataId(1)]    uint32    NdisVlanId;
};</pre>

<p>By searching through this file, you can find <em>all </em>the built-in WMI classes that NDIS provides.</p>

<p>Not so fast, you say.&#160; You want to be methodical, and relying on code comments is not exactly bulletproof.&#160; What about MSNdis_VendorID, which is in wmicore.mof, but is missing a comment mentioning which OID it is tied to?</p>

<p>Here’s where ndisguids.h comes in handy.&#160; Note that each WMI class in wmicore.mof has a GUID.&#160; For example, MSNdis_VendorID has GUID {5ec1035e-a61a-11d0-8dd4-00c04fc3358c}.&#160; You can find that same GUID in ndisguids.h (although the numbers are presented a little differently):</p>

<pre>DEFINE_GUID(GUID_NDIS_GEN_VENDOR_ID,<br />    0x5ec1035e, 0xa61a, 0x11d0, 0x8d, 0xd4, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c);</pre>

<p>Unlike the WMI class names, the GUID names in ndisguid.h have the same naming scheme as OID names.&#160; So GUID_NDIS_GEN_VENDOR_ID corresponds to OID_GEN_VENDOR_ID.&#160; You can do a similar transformation for each GUID that is related to an OID.</p>

<p>Let’s summarize what we have gotten so far.&#160; NDIS provides WMI classes on every miniport.&#160; NDIS translates an OID into a GUID, and WMI translates that GUID into a WMI class.&#160; You can download the WDK to see OIDs in ntddndis.h, the GUIDs in ndisguid.h, and the WMI classes themselves in wmicore.mof.</p>

<p>Is that all?&#160; Well… not quite.&#160; These are valid techniques to explore the NDIS-provided WMI classes… but what about miniport- or LWF-provided classes?&#160; Some miniport drivers implement their own private WMI classes.&#160; Is there a way to peek at those?</p>

<p>Yup.&#160; But to do this, we’ll need to trot out a kernel debugger.&#160; Run !ndiskd.miniport -wmi &lt;miniporthandle&gt; to see <em>all </em>the WMI classes the miniport provides.</p>

<pre>0: kd&gt; !ndiskd.miniport ffffe000be3761a0 -wmi

<b>WMI</b>

    f4a8027a-23b7-11d1-9ed9-00a0c9010057   OID 0xffa0c90a
                       OID, ARRAY, CUSTOM
    GUID_NDIS_ENUMERATE_ADAPTER            [N/A]
                       READ, NOT_SETTABLE, NDIS_ONLY
    GUID_NDIS_NOTIFY_ADAPTER_REMOVAL       [N/A]
                       STATUS, EVENT_ENABLED, NOT_SETTABLE, NDIS_ONLY
    GUID_NDIS_GEN_LINK_SPEED               OID_GEN_LINK_SPEED
                       OID, READ, NOT_SETTABLE
    GUID_NDIS_GEN_VENDOR_ID                OID_GEN_VENDOR_ID
                       OID, READ, NOT_SETTABLE</pre>

<p>In practice, a miniport will have hundreds of GUIDs; the excerpt above highlights just a few of the types of WMI classes you might find.&#160; A class marked with the OID flag is (unsurprisingly) translated to an OID.&#160; In the excerpt above, you can see that my miniport supports OID_GEN_VENDOR_ID, as well as a vendor-custom OID 0xffa0c80a.&#160; (The miniport also supports the <a href="https://blogs.msdn.com/b/ndis/archive/2011/06/29/wmi-events.aspx">WMI event</a> GUID_NDIS_NOTIFY_ADAPTER_REMOVAL.)</p>

<p>Let’s suppose we want to find the corresponding WMI class for that vendor-private GUID/OID.&#160; It’s little surprise that PowerShell can do it in a hurry.&#160; Just drop in the GUID that you got from !ndiskd.&#160; (If !ndiskd hid the GUID behind its friendly name, as it did for GUID_NDIS_GEN_VENDOR_ID, you can unmask it by running !ndiskd.help GUID_NDIS_GEN_VENDOR_ID.)</p>

<p class="ps">Get-WmiObject -Namespace root\wmi -List&#160; | 
  <br />&#160;&#160;&#160; Where-Object {$_.Qualifiers['guid'].Value -eq '{f4a8027a-23b7-11d1-9ed9-00a0c9010057}' }</p>

<p>If you happen to have that vendor’s NIC driver installed, you'll see their WMI class pop up.&#160; If not, well, try again with one of the system-provided GUIDs.</p>

<p>Now we’ve seen three ways to map WMI classes to OIDs:</p>

<ul>
  <li>Guess a likely class name and search for it with PowerShell </li>

  <li>Search for the OID in ndisguid.h, then find the matching GUID in wmicore.mof </li>

  <li>Use !ndiskd.miniport -wmi to find all the GUIDs that are available on a particular miniport </li>
</ul>

<p>I’m out of space for today, so I’ll have to save my proof of Goldbach’s conjecture for next week.</p>]]></content:encoded>
    </item>
    <item>
      <title>Using C++ in an NDIS driver</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/using-c-in-an-ndis-driver</link>
      <pubDate>Sun, 27 Jul 2014 14:19:06 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/2014/07/27/using-c-in-an-ndis-driver/</guid>
      <description><![CDATA[Are NDIS drivers allowed to use C++?
The first question is easy: can NDIS drivers be written in...]]></description>
      <content:encoded><![CDATA[<h2>Are NDIS drivers allowed to use C++?</h2>
The first question is easy: <strong>can</strong> NDIS drivers be written in C++?  The answer: yes.  In this case, NDIS doesn’t have any official stance on C++, so we just fall back on the WDK’s general rules.  As of Windows Driver Kit 8, Microsoft officially supports using a subset of the C++ language in drivers.  (“Subset?  What subset?”  There’s more precise information <a href="https://msdn.microsoft.com/en-us/library/jj620896.aspx">here</a>.)

The inevitable follow-up question is more nuanced: <strong>should</strong> NDIS drivers be written in C++?  The answer is: it depends.  Here are some facts that will help you derive a more specific answer:
<ul>
 	<li>The NDIS API is a C API.  There is no NDIS API that magically gets better or worse when you’re coming from C++ versus C.</li>
 	<li>The NDIS team has no future plans to make a feature that <em>requires</em> C++.  We are well-aware that many of our developers are dedicated fans of C, and have <em>strong</em> opinions on C++.  Don't worry — C isn’t going anywhere.</li>
 	<li>The NDIS team may, in the future, add <em>minor</em> conveniences that only light up in C++.  For example, the WDK macro ARRAYSIZE is defined differently for a C++ driver, which gives it better abilities to detect misuse with pointers.  NDIS.H may start adding macros that offer minor improvements for C++ code, just like WDM.H already has today.</li>
 	<li>Several major IHVs build their production NDIS miniport drivers using C++.</li>
 	<li>Several major IHVs build their production NDIS miniport drivers using C.</li>
 	<li>Microsoft builds some drivers in C and some drivers in C++.</li>
 	<li>Our NDIS sample drivers are all in C.  (This is largely for historical reasons, as these drivers were created before C++ was officially supported.  If we were creating a new sample today, we’d consider writing it in C++.)</li>
</ul>
In summary, then, either language works fine, and it all comes down to a matter of your preference.]]></content:encoded>
    </item>
    <item>
      <title>Using WDF in an NDIS driver</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/using-wdf-in-an-ndis-driver</link>
      <pubDate>Sun, 20 Jul 2014 13:25:25 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/2014/07/20/using-wdf-in-an-ndis-driver/</guid>
      <description><![CDATA[Can, Should, and How?
WDF is a framework that makes it easier to write Windows drivers.  NDIS is a...]]></description>
      <content:encoded><![CDATA[<h2>Can, Should, and How?</h2>
<a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff557565(v=vs.85).aspx">WDF</a> is a framework that makes it easier to write Windows drivers.  <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff565448(v=vs.85).aspx">NDIS</a> is a framework for writing low-level Windows network drivers.  The purposes of these frameworks overlap a bit, and some people (okay, probably many people) are confused about the relationship between NDIS and WDF.  Today we’ll set down a few guidelines.  But first – let’s dispel one tenacious myth.
<div style="margin: 10px 40px;padding: 10px;background-color: #eeeeee">

<strong>Myth</strong>: Some people think that NDIS drivers cannot use WDF.

In reality, <strong>you can use WDF in your NDIS driver</strong>.  I know this works rather well, because I have personally written several WDF-based NDIS drivers.

</div>
So where do people get the idea that WDF is incompatible with NDIS?  There are a few sources of this idea:
<ul>
 	<li>When writing an NDIS miniport driver, certain parts of WDF are not compatible with NDIS.  You must put WDF into a mode sometimes referred to as “miniport mode”.  Not all WDF APIs are available in miniport mode.  See the step-by-step checklist <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff540778(v=vs.85).aspx">here</a>.  Note that this restriction only applies to NDIS miniport (and IM) drivers; protocols and LWFs can use the full breadth of WDF functionality.</li>
 	<li>Miniport drivers must also put NDIS into a special mode, called <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff560532(v=vs.85).aspx">NDIS-WDM mode</a>.  This is a poor name, because it seems to indicate that you <em>must </em>use WDM.  The reality is that NDIS-WDM mode just means your driver can use <em>any </em>non-NDIS framework.  (At the time that NDIS-WDM mode was invented, there were no other frameworks besides WDM, so the name didn’t seem to be too constraining.  If it helps, you can think of it as NDIS-WD* mode.)</li>
 	<li>Most of the NDIS drivers that are included with Windows (like TCPIP) don’t use WDF.  But this isn’t because Windows developers are avoiding WDF; it’s because most inbox drivers simply predate WDF.  If we were writing the network stack from scratch, we’d use more WDF.  New drivers like MSLLDP, an NDIS protocol driver included with Windows 8, are indeed based on WDF.</li>
</ul>
Now that we know you <em>can</em> combine WDF with NDIS, let’s talk about <em>whether</em> you should combine WDF with NDIS.  In nearly all cases, an NDIS driver will work with or without WDF.  So you rarely have the decision forced upon you by the technology.  Ultimately, it will come down to what you decide, based (hopefully) on a good engineering judgment call.  Let’s collect some evidence to help you make that decision.
<div style="margin: 10px 40px;padding: 10px;background-color: #eeeeee">
<h3>Reasons you <em>should</em> use WDF in your NDIS driver</h3>
<ul class="checklist">
 	<li>Your engineering team is already familiar with WDF.</li>
 	<li>You will be developing several drivers, including non-networking drivers.  (Might as well learn WDF now, and maybe you can share some library code between your drivers.)</li>
 	<li>Your driver already uses WDF.</li>
 	<li>You are writing an NDIS miniport that uses IRPs on its lower edge (USB, SDIO, etc.)</li>
 	<li>You are writing a protocol or LWF that interacts with non-NDIS parts of the OS (usermode IOCTLs, WSK requests, etc.)</li>
 	<li>Your code would benefit from <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff542889(v=vs.85).aspx">WDF’s clever object management system</a> to avoid memory leaks.</li>
 	<li>You are new to Windows driver development, and have no idea where to start 😰</li>
</ul>
</div>
Generally speaking, it’s a good idea to consider WDF.  But there are a few reasons why WDF might not be very useful to your NDIS driver:
<div style="margin: 10px 40px;padding: 10px;background-color: #eeeeee">
<h3>Reasons that WDF won’t help in your NDIS driver</h3>
<ul class="checklistx">
 	<li>Your engineering team is already very familiar with NDIS, but has no experience with WDF.</li>
 	<li>You are maintaining a mature driver that does not use WDF.</li>
 	<li>You are writing a simple NDIS miniport on a directly-connected bus (like PCI).</li>
 	<li>You are writing a protocol or LWF that has minimal interaction with the rest of the OS.  This driver mostly only calls NDIS APIs.</li>
 	<li>Your codebase must be compatible with platforms where WDF is not available (like Windows CE).</li>
</ul>
</div>
Mind you, it’s still quite possible to link against WDF in these situations.  But you’ll probably find that there aren’t a lot of opportunities to actually use WDF APIs.  Integrating with WDF doesn’t give a lot of value if you don’t call its APIs.  In those cases, the pragmatic engineering decision may be to just not use WDF.

Okay, so let’s suppose you’ve decided to give WDF a spin.  You’ll eventually notice that WDF overlaps somewhat with NDIS.  For example, both frameworks have APIs for workitems (NdisQueueIoWorkItem versus WdfWorkItemEnqueue).  Which API should you use?  Again, in many cases, either framework’s APIs will work.  Again, it’s an engineering decision that ought to consider several factors, including maintaining consistency with your other code, etc.  But if you are new to NDIS and WDF, you can use this quick-reference table as a starting place for your decision-making process.
<table class="bordertable">
<tbody>
<tr>
<th>API family</th>
<th>Use NDIS APIs?</th>
<th>Use WDF APIs?</th>
<th>Use WDM APIs?</th>
</tr>
<tr>
<td>Work items</td>
<td style="background-color: #ffeeee">Avoid</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #ffeeee">Do not use</td>
</tr>
<tr>
<td>Timers</td>
<td style="background-color: #ffeeee">Avoid</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #ffeeee">Do not use</td>
</tr>
<tr>
<td>Memory allocation</td>
<td style="background-color: #ffeeee">Avoid</td>
<td style="background-color: #eeffee">Preferred</td>
<td>Okay</td>
</tr>
<tr>
<td>Locks &amp; interlocks</td>
<td style="background-color: #ffeeee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff560699(v=vs.85).aspx">Avoid</a> (but <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff560698(v=vs.85).aspx">RW locks</a> are okay)</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #eeffee">Preferred</td>
</tr>
<tr>
<td>Events</td>
<td style="background-color: #ffeeee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff562732(v=vs.85).aspx">Avoid</a></td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #eeffee">Preferred</td>
</tr>
<tr>
<td>String handling</td>
<td style="background-color: #ffeeee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff562741(v=vs.85).aspx">Avoid</a></td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff550046(v=vs.85).aspx">Preferred</a></td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff562954(v=vs.85).aspx">Preferred</a></td>
</tr>
<tr>
<td>DMA</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #ffeeee">Avoid</td>
</tr>
<tr>
<td>Interrupts</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #ffeeee">Not permitted</td>
<td style="background-color: #ffeeee">Not permitted</td>
</tr>
<tr>
<td>DPCs (for miniports)</td>
<td style="background-color: #eeffee">Preferred for interrupts</td>
<td>Okay for non-interrupts</td>
<td style="background-color: #ffeeee">Avoid</td>
</tr>
<tr>
<td>DPCs (for non-miniports)</td>
<td style="background-color: #ffeeee">Avoid</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #ffeeee">Avoid</td>
</tr>
<tr>
<td>Processor information</td>
<td style="background-color: #ffeeee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff564577(v=vs.85).aspx">Avoid</a> (except <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff562669(v=vs.85).aspx">RSS APIs</a>)</td>
<td style="background-color: #ffeeee">(no equivalent)</td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff552076(v=vs.85).aspx">Preferred</a></td>
</tr>
<tr>
<td>IRPs and IOCTLs (for miniports)</td>
<td style="background-color: #eeffee">Required</td>
<td style="background-color: #ffeeee">Not permitted</td>
<td style="background-color: #ffeeee">Not permitted</td>
</tr>
<tr>
<td>IRPs and IOCTLs (for non-miniports)</td>
<td style="background-color: #ffeeee">Avoid</td>
<td style="background-color: #eeffee">Preferred</td>
<td style="background-color: #ffeeee">Avoid</td>
</tr>
<tr>
<td>Direct bus/port access</td>
<td><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff564678(v=vs.85).aspx">Okay</a></td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/dn265677(v=vs.85).aspx">Preferred</a></td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff566386(v=vs.85).aspx">Preferred</a></td>
</tr>
<tr>
<td>Reading configuration</td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff563717(v=vs.85).aspx">Preferred</a> for <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff570842(v=vs.85).aspx">standard keywords</a></td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff549919(v=vs.85).aspx">Preferred</a> for other registry values</td>
<td>Okay for other registry values</td>
</tr>
<tr>
<td>File I/O</td>
<td style="background-color: #ffeeee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff563728(v=vs.85).aspx">Avoid</a></td>
<td style="background-color: #ffeeee">(no equivalent)</td>
<td style="background-color: #eeffee"><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424(v=vs.85).aspx">Preferred</a></td>
</tr>
</tbody>
</table>
Remember, the above table only contains guidelines.  It is still acceptable to ship a driver that uses an API marked "Avoid".  You should use the table to help nudge your decision-making when you have no other compelling reasons to use a particular API family.]]></content:encoded>
    </item>
    <item>
      <title>The NDIS API naming convention</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/the-ndis-api-naming-convention</link>
      <pubDate>Fri, 20 Jun 2014 20:07:36 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/2014/06/20/the-ndis-api-naming-convention/</guid>
      <description><![CDATA[NdisFWhat?  Your secret decoder ring to NDIS functions
The first time you come across NDIS, you...]]></description>
      <content:encoded><![CDATA[<h2>NdisFWhat?  Your secret decoder ring to NDIS functions</h2>
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, <em>five hundred</em>!)  Of those, all but three start with the name “Ndis”.  So that’s our first convention: NDIS APIs are almost always named Ndis<em>Something</em>.  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 <strong>N</strong> means it’s an exported API, and lower-case <strong>n</strong> 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 <em>and </em>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:
<p class="kd">00 tcpip!FlReceiveNetBufferListChain
01 ndis!ndisMIndicateNetBufferListsToOpen
02 ndis!ndisIndicateSortedNetBufferLists
03 ndis!ndisMDispatchReceiveNetBufferListsInternal
04 ndis!ndisMTopReceiveNetBufferLists
05 ndis!ndisCallReceiveHandler
06 ndis!ndisIterativeDPInvokeHandlerOnTracker
07 ndis!ndisInvokeNextReceiveHandler
08 ndis!ndisMIndicateReceiveNetBufferListsInternal
09 ndis!NdisMIndicateReceiveNetBufferLists
0a netvsc!ReceivePacketMessage</p>
That’s not all; it takes more than an <strong>N</strong> to spell <em>Naming convention</em>.  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:
<table class="bordertable">
<tbody>
<tr>
<th>Code</th>
<th>Purpose</th>
</tr>
<tr>
<td>M</td>
<td>Miniport drivers</td>
</tr>
<tr>
<td>F</td>
<td>Filter drivers</td>
</tr>
<tr>
<td>IM</td>
<td>Intermediate drivers</td>
</tr>
<tr>
<td>If</td>
<td><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff570466(v=vs.85).aspx">Network interface providers</a></td>
</tr>
<tr>
<td>Co</td>
<td>CoNDIS drivers</td>
</tr>
<tr>
<td>Cl</td>
<td>CoNDIS call clients</td>
</tr>
<tr>
<td>Cm</td>
<td>CoNDIS call managers</td>
</tr>
<tr>
<td>MCo</td>
<td>CoNDIS miniport drivers</td>
</tr>
<tr>
<td>MCm</td>
<td>CoNDIS integrated call managers</td>
</tr>
</tbody>
</table>
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 Ndis<strong>M</strong>SetTimer is for miniport drivers, while Ndis<strong>IM</strong>NotifyPnPEvent is for intermediate drivers.  And I bet you can answer the question at the start of this article: what <em>is</em> 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
<p class="kd"><strong>00 DriverY+0x22af</strong>
01 ndis!ndisMSendNBLToMiniport+0xb1
02 ndis!NdisFSendNetBufferLists+0x64
<strong>03 DriverX+0x1b6d</strong>
04 ndis!NdisFSendNetBufferLists+0x64
05 pacer!PcFilterSendNetBufferLists+0x9d
06 ndis!ndisSendNBLToFilter+0x69
07 ndis!NdisSendNetBufferLists+0x85
08 tcpip!FlpSendPacketsHelper+0x675</p>
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!]]></content:encoded>
    </item>
    <item>
      <title>Using the checked version of NDIS.SYS</title>
      <link>https://docs.microsoft.com/archive/blogs/ndis/using-the-checked-version-of-ndis-sys</link>
      <pubDate>Mon, 16 Jun 2014 20:46:46 GMT</pubDate>
      <dc:creator><![CDATA[Jeffrey Tippet [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ndis/2014/06/16/using-the-checked-version-of-ndis-sys/</guid>
      <description><![CDATA[I assert that this is a good way to find bugs  Installing the checked version of the operating...]]></description>
      <content:encoded><![CDATA[<h2>I assert that this is a good way to find bugs</h2>  <p>Installing the checked version of the operating system is an effective technique to quickly find bugs in your network driver.&#160; If you’re not familiar with checked builds (and even if you are), you should read <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff543457(v=vs.85).aspx">the excellent documentation here</a>.&#160; Seriously, read it; I won’t repeat it here.</p>  <h3>What do you get with the checked build of NDIS?</h3>  <p>The main difference is that NDIS’s implementation has (as of Windows 8.1) approximately 2200 extra asserts.&#160; While some of these asserts verify NDIS’s internal bookkeeping is consistent, many of them verify that your driver uses NDIS’s APIs correctly.&#160; For example, NDIS asserts the current IRQL is correct when <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff565965(v=vs.85).aspx">each MiniportXxx callback</a> returns, to help catch the class of bug where your miniport driver leaks an IRQLs or spinlock.</p>  <p>Prior to Windows 7, using the checked build of NDIS is also the only way to see NDIS’s debug traces.&#160; But as of Windows 7, <a href="https://blogs.msdn.com/b/ndis/archive/2011/04/06/diagnostics-with-wpp.aspx">these traces are now available from WPP</a>, so there’s no longer a need to use the checked build solely for tracing.</p>  <h3>What’s the downside of using a checked build?</h3>  <p>There are two downsides to using checked builds: performance and false-positives.</p>  <p>Checked builds <em>are </em>noticeably slower.&#160; But they aren’t as bad as you might think.&#160; We still compile checked builds with most compiler optimizations enabled, so the only slowdowns are a few extra verifications here and there.&#160; Still, the operating system has zillions of assertions, so those do add up.&#160; You definitely don’t want to use a checked build for any performance-related work.&#160; But they’re just fine for initial work on a new feature or functional testing.</p>  <p>False positives are also a problem.&#160; Sometimes you’ll see assertions that fail for reasons that don’t seem to be related to your driver.&#160; When you see an unfamiliar assertion, you’ll first want to spent a moment to convince yourself that the assertion failure is <em>really</em> caused by your driver.&#160; For example, if there’s an assertion in win32k.sys about an invalid HRGN, that’s probably not caused by any network driver.&#160; Prior to Windows 8, the operating system was kind of “noisy”; a nontrivial percentage of its assertions would fire for benign reasons.&#160; We worked hard to clean that up in Windows 8, so the asserts have a better signal-to-noise ratio.&#160; (Like many Windows engineers, I used a checked build of the OS as my primary workstation for some time during Windows 8 development.&#160; That was fun.)</p>  <p>If you discover an assertion in NDIS.SYS that you believe is a false positive, please let me know here and I’ll try to clean that up.&#160; (Unfortunately I’m not knowledgeable about non-networking drivers, so I can’t promise I can help you with any random assertion that you come across.)</p>  <h3>How can you get the checked build of NDIS?</h3>  <p><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff549603(v=vs.85).aspx">MSDN has the story</a> on how to download a copy of the checked build.&#160; From there, you have two options:</p>  <ul>   <li><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff547210(v=vs.85).aspx">Install the complete operating system</a> to get maximum verifications across the OS; or</li>    <li>Selectively replace a few drivers.</li> </ul>  <p>Since MSDN already explains the first option, I won’t repeat those instructions here.&#160; Let’s talk about the second option: how to selectively replace a few drivers.</p>  <p>First, identify the drivers that you want to replace.&#160; Here’s a table of drivers you can consider replacing:</p>  <table class="bordertable"><tbody>     <tr>       <th>Driver</th>        <th>When to replace</th>     </tr>      <tr>       <td><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff547188(v=vs.85).aspx">The kernel &amp; HAL</a></td>        <td>Always</td>     </tr>      <tr>       <td>NDIS.SYS</td>        <td>Always</td>     </tr>      <tr>       <td>TCPIP.SYS</td>        <td>Miniport, LWF, and WFP callout drivers</td>     </tr>      <tr>       <td>NETIO.SYS (Windows Vista and later)</td>        <td>Whenever TCPIP.SYS is replaced</td>     </tr>      <tr>       <td>FWPKCLNT.SYS</td>        <td>WFP callout drivers</td>     </tr>      <tr>       <td>(your bus driver, e.g., PCI.SYS)</td>        <td>Miniport drivers</td>     </tr>      <tr>       <td>NWIFI.SYS</td>        <td>Native 802.11 drivers</td>     </tr>      <tr>       <td>VWIFIBUS.SYS          <br />VWIFIFLT.SYS           <br />VWIFIMP.SYS</td>        <td>Native 802.11 drivers that implement MAC virtualization (WFD or SoftAP)</td>     </tr>      <tr>       <td>NDISUIO.SYS</td>        <td>WWAN drivers</td>     </tr>      <tr>       <td>WMBCLASS.SYS</td>        <td>WWAN drivers that implement the class driver model</td>     </tr>      <tr>       <td>VSWITCH.SYS</td>        <td><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/hh598161(v=vs.85).aspx">Hyper-V extensible switch extension</a></td>     </tr>   </tbody></table>  <p>Keep in mind — these are just guidelines.&#160; You are not required to test with any particular set of drivers, and you might want to fine-tune the list depending on what subsystem you’re targeting.&#160; If you are unsure about which binaries to replace, remember you can always just install the entire checked OS, which gives you the maximum checked build coverage.</p>  <p>Now that you know which drivers to replace, you can extract them from the checked build media.&#160; If you obtained installable media, you can mount the included INSTALL.WIM with DISM.EXE to get at the individual drivers, or you can just install the OS into a throw-away VM to get convenient access to its drivers.</p>  <p>Finally, you'll need to actually replace these drivers on your target OS.&#160; Don’t do this on a production OS machine; we can’t officially support this.&#160; The easiest way to replace binaries is to hook up a kernel debugger and use <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff552148(v=vs.85).aspx">the .kdfiles feature</a>.&#160; For example, here’s the mapfile that I use to replace NDIS.SYS on a test machine:</p>  <pre style="margin: 10px; padding: 10px; border: 2px dotted black; background-color: rgb(255, 251, 204);">map<br />\Windows\system32\DRIVERS\NDIS.SYS<br />c:\path\to\ndis.sys</pre>

<p>Note that the name of the driver will depend on how the driver is loaded.&#160; Use <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff540315(v=vs.85).aspx">CTRL+D or CTRL+ALT+D</a> in the debugger and reboot the target machine to see the official name of each driver.</p>

<p><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff547188(v=vs.85).aspx">Note that the process for replacing the kernel &amp; HAL is special</a>.</p>

<p>Oh, and sorry for the awful pun in the subtitle.</p>]]></content:encoded>
    </item>
  </channel>
</rss>