Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions Source/ManagedNativeWifi/BssNetworkInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,16 @@ public class BssNetworkInfo
/// <summary>
/// Channel
/// </summary>
public int Channel { get; }

/// <summary>
/// Constructor
/// </summary>
public int Channel { get; }

/// <summary>
/// Width of the channel (KHz)
/// </summary>
public int Width { get; internal set; }

/// <summary>
/// Constructor
/// </summary>
public BssNetworkInfo(
NetworkIdentifier ssid,
BssType bssType,
Expand All @@ -68,7 +73,8 @@ public BssNetworkInfo(
int linkQuality,
int frequency,
float band,
int channel)
int channel,
int width)
{
this.Ssid = ssid;
this.BssType = bssType;
Expand All @@ -78,7 +84,8 @@ public BssNetworkInfo(
this.LinkQuality = linkQuality;
this.Frequency = frequency;
this.Band = band;
this.Channel = channel;
this.Channel = channel;
this.Width = width;
}
}

Expand Down Expand Up @@ -111,7 +118,8 @@ public BssNetworkPack(
int linkQuality,
int frequency,
float band,
int channel) : base(
int channel,
int width) : base(
ssid: ssid,
bssType: bssType,
bssid: bssid,
Expand All @@ -120,7 +128,8 @@ public BssNetworkPack(
linkQuality: linkQuality,
frequency: frequency,
band: band,
channel: channel)
channel: channel,
width)
{
this.InterfaceInfo = interfaceInfo;
}
Expand All @@ -137,6 +146,7 @@ internal BssNetworkPack(
linkQuality: bssNetworkInfo.LinkQuality,
frequency: bssNetworkInfo.Frequency,
band: bssNetworkInfo.Band,
channel: bssNetworkInfo.Channel)
channel: bssNetworkInfo.Channel,
width: bssNetworkInfo.Width)
{ }
}
50 changes: 49 additions & 1 deletion Source/ManagedNativeWifi/NativeWifi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,13 +477,61 @@ private static bool TryConvertBssNetwork(WLAN_BSS_ENTRY bssEntry, out BssNetwork
linkQuality: (int)bssEntry.uLinkQuality,
frequency: (int)bssEntry.ulChCenterFrequency,
band: band,
channel: channel);
channel: channel,
width: GetChannelWidth(bssEntry));
return true;
}
bssNetworkInfo = null;
return false;
}

/// <summary>
/// Extracts the channel width from the Information Element data of the bssEntry.
/// </summary>
/// <remarks>
/// This code is based on the Python code here:
/// https://github.com/opetryna/win32wifi/blob/4f6bedab47c8506738e7a14b07714d032a74f8a7/win32wifi/Win32Wifi.py#L152
/// </remarks>
private static int GetChannelWidth(WLAN_BSS_ENTRY bssEntry)
{
int result = 20;
InformationElement? ht_operation = null;
InformationElement? vht_operation = null;

foreach(var field in bssEntry.GetInformationElements())
{
if (field.Id == 61)
ht_operation = field;
else if (field.Id == 192)
vht_operation = field;
}

if (ht_operation != null)
{
int secondary_channel_offset = ht_operation[1] & ((1 << 1) | (1 << 0));
if (secondary_channel_offset != 0)
result = 40;
}

if (vht_operation != null)
{

byte vht_channel_width = vht_operation[0];

byte channel_center_frequency_segment_1 = vht_operation[2];

if (vht_channel_width == 1)
result = 80;

if (channel_center_frequency_segment_1 != 0)
result = 160;
}

// Convert from MHz to KHz
return result * 1000;
}


#endregion

#region Get connection/connection quality
Expand Down
89 changes: 87 additions & 2 deletions Source/ManagedNativeWifi/Win32/NativeMethod.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
Expand Down Expand Up @@ -368,8 +369,28 @@ public struct WLAN_BSS_ENTRY
public ushort usCapabilityInformation;
public uint ulChCenterFrequency;
public WLAN_RATE_SET wlanRateSet;
public uint ulIeOffset;
public uint ulIeSize;

/// <summary>
/// Information Element data values.
/// </summary>
/// <remarks>
/// This array will contain 2 uint values when marshalled from unsafe memory
/// for these fields:
/// public uint ulIeOffset;
/// public uint ulIeSize;
/// The WLAN_AVAILABLE_NETWORK_LIST constructor will read the memory pointed to
/// by these values into the array so that the Information Entity values are available
/// to the caller.
/// See:
/// https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/ns-wlanapi-wlan_bss_entry
/// </remarks>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] informationElements;

public IEnumerable<InformationElement> GetInformationElements()
{
return InformationElement.Iterate(informationElements);
}
}

public struct WLAN_BSS_LIST
Expand All @@ -395,8 +416,72 @@ public WLAN_BSS_LIST(IntPtr ppBssList)
+ (itemSize * i) /* Offset for preceding items */);

wlanBssEntries[i] = Marshal.PtrToStructure<WLAN_BSS_ENTRY>(wlanBssEntry);
// Copy the information Entity data
var ulIeOffset = BitConverter.ToUInt32(wlanBssEntries[i].informationElements, 0);
var ulIeSize = BitConverter.ToUInt32(wlanBssEntries[i].informationElements, 4);
var infoPtr = new IntPtr(wlanBssEntry.ToInt64()
+ ulIeOffset);
if (ulIeSize > 0)
{
var infoData = new byte[ulIeSize];
Marshal.Copy(infoPtr, infoData, 0, infoData.Length);
wlanBssEntries[i].informationElements = infoData;
}
else
{
wlanBssEntries[i].informationElements = Array.Empty<byte>();
}
}
}

}

/// <summary>
/// Information element fields look like this
/// {id: byte, length: byte, info: byte[lenth]}
/// </summary>
internal class InformationElement
{
private byte[] data;
private InformationElement(byte[] data, int offset = 0)
{
this.offset = offset;
this.data = data;
}

public static IEnumerable<InformationElement> Iterate(byte[] data)
{
var field = new InformationElement(data, 0);
while (!field.AtEnd())
{
yield return field.BookMark();
field.Next();
}
}

private int offset;
public byte Id { get => data[offset]; }
public byte Length { get => data[offset + 1]; }

public byte this[int idx]
{
get => data[offset + 2 + idx];
}

private void Next()
{
offset += Length + 2;
}

private bool AtEnd()
{
return data.Length == 0 || offset >= data.Length;
}

private InformationElement BookMark()
{
return new InformationElement (data, offset);
}
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
Expand Down