I have following code for determining IPv4 for Wireless interfaces on local machine
private List<IPAddressInformation> GetWifiIPAddresses()
{
var list = new List<IPAddressInformation>();
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var networkInterface in networkInterfaces)
{
if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
{
var interfaceAddressList = networkInterface.GetIPProperties().UnicastAddresses;
list.AddRange(interfaceAddressList.Where(interfaceIp => interfaceIp.Address.AddressFamily == AddressFamily.InterNetwork));
}
}
return list;
}
Everything works like a charm in Windows 7, however in Windows 8 my WLAN interface is determined as Ethernet adapter. (NetworkInterfaceType == NetworkInterfaceType.Ethernet instead of NetworkInterfaceType.Wireless80211)
Here is a ipconfig screen for my WLAN
But it's a Wireless adapter, and in Windows 7 ipconfig shows it as a wireless interface.
Any clue on how can I solve it? Is it a driver problem or a Windows 8 specifications? How else can I determine WLAN IP addresses on local machine?
Thanks!
EDIT:
It was because of Hyper-V Virtual Switch. Hyper-V Virtual Switch covers real physical adapter so .NET is unable to determine it as WiFi adapter.
When I removed switch in "Hyper-V Virtual Switch Manager" from my physical wireless adapter to vEthernet it works fine like in Windows 7.
But that turned virtual switch might be big problem of determining proper IP for actual physical devices.
Faced exactly the same issue yesterday and solved it successfully.
Basically we're getting another interface type because Hyper-V does some bridging stuff when creating virtual switches. That's why when one iterates over NetworkInterface.GetAllNetworkInterfaces()
there is no wlan interface at all, and a new interface with the same IP address is a virtual one which also is participating in a bridge with wireless adapter.
So we need to do the following:
Network interfaces in Windows are organized in something like a stack. That is, some interfaces could sit above anothers, and likely actual hardware interface will be located at the bottom of this stuff.
The stack itself is represented by an array of records like
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IFSTACK_ROW
{
public uint HigherLayerInterfaceIndex;
public uint LowerLayerInterfaceIndex;
}
where HigherLayerInterfaceIndex
is strictly above LowerLayerInterfaceIndex
.
Having this information and a source interface index actual hardware interface index could be determined easily:
HigherLayerInterfaceIndex
equal to current index - set the current index to LowerLayerInterfaceIndex
of this record and repeat againHigherLayerInterfaceIndex
equal to current index - current index is the resultUse WinAPI method GetIfStackTable in order to retrieve network interfaces stack information. The following P/Invoke definitions might help:
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IFSTACK_ROW
{
public uint HigherLayerInterfaceIndex;
public uint LowerLayerInterfaceIndex;
}
[StructLayout(LayoutKind.Sequential)]
public struct MIB_IFSTACK_TABLE
{
public uint NumEntries;
public MIB_IFSTACK_ROW Table;
}
[DllImport("iphlpapi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern Win32Error GetIfStackTable(out IntPtr table);
[DllImport("iphlpapi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void FreeMibTable(IntPtr memory);
Since (obviously) records count may vary from call to call one will have to read count (uint32) from IntPtr first, and then marshal record-by-record. The following code should help to get the idea (although it won't compile because of our internal stuff):
public static IEnumerable<MIB_IFSTACK_ROW> EnumIfStackTable()
{
var error = GetIfStackTable(out var table);
error.ToHRESULT().ThrowIfFailed();
Contract.Assert(table != null);
Contract.Assert(!table.IsInvalid);
using (table)
{
var pointer = table.DangerousGetHandle();
var entries = (uint)Marshal.ReadInt32(pointer);
var rowPointer = IntPtr.Add(pointer, IfStackTableOffset);
for (var i = 0; i < entries; i++)
{
yield return (MIB_IFSTACK_ROW)Marshal.PtrToStructure(rowPointer, typeof(MIB_IFSTACK_ROW));
rowPointer = IntPtr.Add(rowPointer, IfStackRowSize);
}
}
}
Table offset and row size is calculated this way:
internal static readonly int IfStackRowSize = Marshal.SizeOf(typeof(MIB_IFSTACK_ROW));
internal static readonly int IfStackTableOffset = (int)Marshal.OffsetOf(typeof(MIB_IFSTACK_TABLE), nameof(MIB_IFSTACK_TABLE.Table));
Don't forget to call FreeMibTable
when you're finished with interfaces stack.
There are a several places where we could try to find interface type having its index, but the most reliable way is to get this information straight from WinAPI. I suggest to use GetIfTable2 WinAPI function - which allows us to enumerate every single network interface present in system, and examine its properties. Unfortunately P/Invoke would be too huge for this answer this time, but the main idea (and marshaling) is the same as in the previous paragraph.
Having the array of MIB_IF_ROW2 structures one could easily find desired interface by iterating over such array and comparing InterfaceIndex
property with desired interface index. When the interface is found - just take Type
property value and cast it to NetworkInterfaceType
- and that's it, you're awesome!
Why not use other approaches: