Andreik Posted March 21, 2022 Share Posted March 21, 2022 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? expandcollapse popup#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, _ $wlan_interface_state_authenticating 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, _ $dot11_phy_type_he Global Enum $dot11_BSS_type_infrastructure = 1, _ $dot11_BSS_type_independent, _ $dot11_BSS_type_any 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) _ArrayDisplay($aNetworks) DllCall($hWlanapi, 'dword', 'WlanCloseHandle', 'handle', $hWlan, 'ptr', Null) DllClose($hWlanapi) Func WlanGetConnectedInterface($hWlanapi, $hWlan) Local $Ptr, $tGUID, $tWLAN_INTERFACE_INFO 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) ExitLoop EndIf Next Return $tGUID EndIf Return SetError(1, 0, Null) EndFunc 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])) Next Return $aNetworks EndIf EndFunc 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 WEnd Return $aIEElements EndFunc 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) EndFunc 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] EndIf Next If $HT_Operation Then Local $STA_ChannelWidth = BitAND($HT_Operation, BitShift(1, -2)) <> 0 ? 1 : 0 If $STA_ChannelWidth <> 0 Then $ChannelWidth = 40 EndIf 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' EndSwitch EndIf EndIf Return $ChannelWidth EndFunc When the words fail... music speaks. Link to comment Share on other sites More sharing options...
TheXman Posted March 21, 2022 Share Posted March 21, 2022 (edited) 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 March 21, 2022 by TheXman CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein Link to comment Share on other sites More sharing options...
Andreik Posted March 23, 2022 Author Share Posted March 23, 2022 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now