Jump to content

Wlan network channel width

Recommended Posts

I have this code that list wifi networks from connected interface that works quite well but I don't find any documentation about how to get the channel width. Some obscure things that I found is about parsing IE data blob of BSS entry structure and more specifically HT_Operation nd VHT_Operation elements but doesn't seems to work always. Is there any way to get channel width from BSS entries or maybe some specifications about these information elements?

#include <Array.au3>

Global Enum $wlan_interface_state_not_ready, _
  $wlan_interface_state_connected, _
  $wlan_interface_state_ad_hoc_network_formed, _
  $wlan_interface_state_disconnecting, _
  $wlan_interface_state_disconnected, _
  $wlan_interface_state_associating, _
  $wlan_interface_state_discovering, _

Global Enum $dot11_phy_type_unknown, _
  $dot11_phy_type_fhss, _
  $dot11_phy_type_dsss, _
  $dot11_phy_type_irbaseband, _
  $dot11_phy_type_ofdm, _
  $dot11_phy_type_hrdsss, _
  $dot11_phy_type_erp, _
  $dot11_phy_type_ht, _
  $dot11_phy_type_vht, _
  $dot11_phy_type_dmg, _

Global Enum $dot11_BSS_type_infrastructure = 1, _
  $dot11_BSS_type_independent, _

Global $aRet, $hWlanapi, $hWlan
$hWlanapi = DllOpen('Wlanapi.dll')
$aRet = DllCall($hWlanapi, 'dword', 'WlanOpenHandle', 'dword', 2, 'ptr', Null, 'dword*', Null, 'ptr*', Null)
If $aRet[0] = 0 Then $hWlan = $aRet[4]

$tInterfaceGUID = WlanGetConnectedInterface($hWlanapi, $hWlan)
$aNetworks = WlanGetAvailableNetworkList($hWlanapi, $hWlan, $tInterfaceGUID)

DllCall($hWlanapi, 'dword', 'WlanCloseHandle', 'handle', $hWlan, 'ptr', Null)

Func WlanGetConnectedInterface($hWlanapi, $hWlan)
    Local $aRet = DllCall($hWlanapi, 'dword', 'WlanEnumInterfaces', 'handle', $hWlan, 'ptr', Null, 'ptr*', Null)
    If $aRet[0] = 0 Then
        Local $tWLAN_INTERFACE_INFO_LIST = DllStructCreate('dword dwNumberOfItems; dword dwIndex', $aRet[3])
        Local $dwNumberOfItems = DllStructGetData($tWLAN_INTERFACE_INFO_LIST, 'dwNumberOfItems')
        For $Index = 0 To $dwNumberOfItems - 1
            $Ptr = $aRet[3] + $Index * 532 + 8
            $tWLAN_INTERFACE_INFO = DllStructCreate('wchar strInterfaceDescription[256]; dword isState;', $Ptr + 16)
            If DllStructGetData($tWLAN_INTERFACE_INFO, 'isState') = $wlan_interface_state_connected Then
                $tGUID = DllStructCreate('byte GUID[16]', $Ptr)
        Return $tGUID
    Return SetError(1, 0, Null)

Func WlanGetAvailableNetworkList($hWlanapi, $hWlan, $tGUID, $dwFlags = Null)
    Local $aRet = DllCall($hWlanapi, 'dword', 'WlanGetNetworkBssList', 'handle', $hWlan, 'struct*', $tGUID, 'struct*', Null, 'dword', Null, 'bool', Null, 'ptr', Null, 'ptr*', Null)
    If $aRet[0] = 0 Then
        Local $Ptr
        Local $tWLAN_BSS_ENTRY, $StructSize
        Local $tWLAN_BSS_LIST = DllStructCreate('dword dwTotalSize; dword dwNumberOfItems', $aRet[7])
        Local $dwNumberOfItems = DllStructGetData($tWLAN_BSS_LIST, 'dwNumberOfItems')
        Local $dwTotalSize = DllStructGetData($tWLAN_BSS_LIST, 'dwTotalSize')
        Local $aNetworks[$dwNumberOfItems + 1][11]
        $aNetworks[0][0] = $dwNumberOfItems
        For $Index = 0 To $dwNumberOfItems - 1
            $Ptr = $aRet[7] + $Index * $StructSize + 8
            $tWLAN_BSS_ENTRY = DllStructCreate('ulong uSSIDLength; char ucSSID[32]; ulong uPhyId; byte dot11Bssid[6]; dword dot11BssType; dword dot11BssPhyType; long lRssi; ulong uLinkQuality;' & _
            'boolean bInRegDomain; ushort usBeaconPeriod; uint64 ullTimestamp; uint64 ullHostTimestamp; ushort usCapabilityInformation; ulong ulChCenterFrequency; ulong uRateSetLength; ushort usRateSet[126];' & _
            'ulong ulIeOffset; ulong ulIeSize', $Ptr)
            $StructSize = DllStructGetSize($tWLAN_BSS_ENTRY)
            $ulIeOffset = DllStructGetData($tWLAN_BSS_ENTRY, 'ulIeOffset')
            $aNetworks[$Index + 1][0] = DllStructGetData($tWLAN_BSS_ENTRY, 'ucSSID')
            $aNetworks[$Index + 1][1] = StringRegExpReplace(StringTrimLeft(DllStructGetData($tWLAN_BSS_ENTRY, 'dot11Bssid'), 2), '[[:xdigit:]]{2}', '\0-', 5)
            $aNetworks[$Index + 1][2] = DllStructGetData($tWLAN_BSS_ENTRY, 'dot11BssType')
            $aNetworks[$Index + 1][3] = DllStructGetData($tWLAN_BSS_ENTRY, 'dot11BssPhyType')
            $aNetworks[$Index + 1][4] = DllStructGetData($tWLAN_BSS_ENTRY, 'lRssi') > 0 ? DllStructGetData($tWLAN_BSS_ENTRY, 'lRssi') - 256 : DllStructGetData($tWLAN_BSS_ENTRY, 'lRssi')
            $aNetworks[$Index + 1][5] = DllStructGetData($tWLAN_BSS_ENTRY, 'uLinkQuality')
            $aNetworks[$Index + 1][6] = DllStructGetData($tWLAN_BSS_ENTRY, 'ulChCenterFrequency')
            $aNetworks[$Index + 1][7] = DllStructGetData($tWLAN_BSS_ENTRY, 'ulIeSize')
            $aNetworks[$Index + 1][8] = DllStructCreate('byte IE[' & ($aNetworks[$Index + 1][7]) & ']', $Ptr + $ulIeOffset)
            $aNetworks[$Index + 1][9] = GetCurrentChannel($aNetworks[$Index + 1][3], $aNetworks[$Index + 1][6])
            $aNetworks[$Index + 1][10] = GetChannelWidth(ParseInformationElements($aNetworks[$Index + 1][8], $aNetworks[$Index + 1][7]))
        Return $aNetworks

Func ParseInformationElements($IE_Blob, $ulIeSize)
    Local $IE_Element, $IE_Length, $IE_Info, $IE_Offset
    Local $IE_Data = DllStructGetData($IE_Blob, 'IE')
    Local $aIEElements[1][3]
    While $IE_Offset < $ulIeSize
        $aIEElements[0][0] += 1
        ReDim $aIEElements[$aIEElements[0][0] + 1][3]
        Local $IE_Element = BinaryMid($IE_Data, $IE_Offset + 1, 1)
        Local $IE_Length = Number(BinaryMid($IE_Data, $IE_Offset + 2, 1))
        Local $IE_Info = BinaryMid($IE_Data, $IE_Offset + 3, $IE_Length)
        $aIEElements[$aIEElements[0][0]][0] = $IE_Element
        $aIEElements[$aIEElements[0][0]][1] = $IE_Length
        $aIEElements[$aIEElements[0][0]][2] = $IE_Info
        $IE_Offset += $IE_Length + 2
    Return $aIEElements

Func GetCurrentChannel($dot11BssPhyType, $ulChCenterFrequency)
    If $dot11BssPhyType = $dot11_phy_type_fhss Then Return
    If $ulChCenterFrequency > 2400000 And $ulChCenterFrequency < 2484000 Then Return (($ulChCenterFrequency - 2407000) / 5000)
    If $ulChCenterFrequency > 2484000 And $ulChCenterFrequency <= 2495000 Then Return 14
    If $ulChCenterFrequency > 5000000 And $ulChCenterFrequency <= 5900000 Then Return (($ulChCenterFrequency - 5000000) / 5000)

Func GetChannelWidth($aIEElements)
    Local $ChannelWidth = 20
    If IsArray($aIEElements) Then
        Local $HT_Operation, $VHT_Operation
        For $Index = 1 To $aIEElements[0][0]
            If $aIEElements[$Index][0] = 0x3D Then      ; HT_Operation
                $HT_Operation = $aIEElements[$Index][2]
            ElseIf $aIEElements[$Index][0] = 0xC0 Then  ; VHT_Operation
                $VHT_Operation = $aIEElements[$Index][2]
        If $HT_Operation Then
            Local $STA_ChannelWidth = BitAND($HT_Operation, BitShift(1, -2)) <> 0 ? 1 : 0
            If $STA_ChannelWidth <> 0 Then $ChannelWidth = 40
        If $VHT_Operation Then
            Local $STA_ChannelWidth = Number(BinaryMid($VHT_Operation, 1, 1))
            Switch $STA_ChannelWidth
                Case 1
                    $ChannelWidth = 80
                Case 2
                    $ChannelWidth = 160
                Case 3
                    $ChannelWidth = '80+80'
    Return $ChannelWidth


When the words fail... music speaks.

Link to comment
Share on other sites

This is a bit outside of the scope of AutoIt, but since I know a little bit about the subject I'll point you to where you can find the specification.  You can find everything you want to know about the IEEE 802.11 Standard (and a WHOLE lot more) in the 39 MB 802.11 - 2020 IEEE Standard PDF document on the IEEE Xplore site.  Luckily, that particular document can be downloaded for free, but you will still need to create an account to do so.  Section 9.4.2 goes into detail about "Information Elements" (IE), including the HT & VHT operations and capabilities elements.  It should give you all the information you need to walk through the IEs to find and parse the information you're looking for.

I don't know how invested or set you are in getting your WiFi information using the wlanapi.dll APIs, but if you are open to other ways, then you might find Nirsoft's WifiInfoView quite useful.  It can show you all of the information that you're probably looking for either graphically or using the command line.  Using the "/stab" parameter, you can quickly & easily generate a tab-separated-value file with just about everything you would want to know from a WiFi scan.  You can also capture the TSV information from stdout if you don't want to produce a file.  If nothing else, the graphical version lets you click on a given AP and will show you the binary IE data.  That will make it easier for you to verify whether you are parsing the IEs correctly if you choose to continue using the wlanapi.dll APIs.

Edited by TheXman
Link to comment
Share on other sites

Indeed, this is not necessarily about AutoIt. I know about WifiInfoView, actually I use it to compare my results. As you pointed I got the IEEE 802.11 specs and I got some insights but some aspects are still obscure. Probably it's not the best idea to get this info through native wlan APIs and WMI might be more appropriate. Anyway thank you for help.

When the words fail... music speaks.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...