Packet filtering
Your understanding is correct. A NIC does a fair amount of filtering in hardware, to spare the CPU from excessive filtering. Generally, a typical Ethernet NIC will have a programmable packet filter that only allows packets if they meet certain criteria, like these:
- The destination MAC address matches one of a set of programmable destination addresses (typically you'd put your own unicast address into the target set, as well as several multicast addresses).
- The destination address is the broadcast address (for Ethernet, that's
ff-ff-ff-ff-ff-ff
).
- The destination address is any multicast address (for Ethernet, the first byte has its LSB set)
In typical operation, Windows will program a NIC to accept traffic destined to the NIC's unicast address, the broadcast address, and a handful of multicast address (e.g., for IPv6 Neighbor Discovery and UPnP).
The hardware packet filter's only purpose is to reduce CPU usage of the host. Windows does not rely on the hardware packet filter for functional correctness. If a badly-behaved NIC were to always indicate all packets unfiltered, Windows would automatically fall back to filtering in software.
Updating the packet filter
Windows may modify the packet filter on the hardware. For example, if you run Netmon or Wireshark and enable their "Promiscuous mode", NDIS will instruct the NIC to indicate all traffic, even if the destination is a non-local unicast address.
If you would like an interesting lab experiment, open up PowerShell and run this command to query the current packet filter:
Get-WmiObject -Namespace root\wmi -Class MSNdis_CurrentPacketFilter |
Format-List InstanceName, NdisCurrentPacketFilter
You can pipe that to another command to make the output more readable:
% { @{ $_.InstanceName = "{0:X8}" -f $_.NdisCurrentPacketFilter } }
The packet filter is presented as an integer, which a bitmask of the NDIS_PACKET_TYPE_XXX
constants from the SDK/WDK header file ntddndis.h. Now if you enable promiscuous mode in Netmon or Wireshark, you should see the packet filter change to include the NDIS_PACKET_TYPE_PROMISCUOUS
flag (0x20). Disabling Netmon or Wireshark will restore the pre-existing packet filter.
Other filtering types
I've just described the most basic level of packet filtering, which nearly all Ethernet NICs support. (Microsoft requires this minimal level of support with the "Device.Network.LAN.Base.PacketFiltering" logo requirement.) More sophisticated hardware can do cool stuff.
For example, hardware that supports multiple receive queues has multiple receive filters. The NIC indicates the packets that match each filter separately, on separate CPUs, to make it easier for a hypervisor to distribute traffic to virtualized guest operating systems.
Disclaimer
Your question mentions both OS X and NDIS, a Windows technology. My remarks only apply to NDIS and Windows, as I work for Microsoft.