locked
Available network list RRS feed

  • Question

  • Hi all!

    I'm using the NativeWifi API (wlanapi.h) for some WiFi stuff (obviously) that I need and I stumbled across an obscure function-structure pair that isn't properly documented anywhere.

    I want to retrieve a list of visible networks and I'm using WlanGetAvailableNetworkList(), but when I typed this in, Intellisense suggested a V2 which perked my interest. This is also true for the structure used with this function: _WLAN_AVAILABLE_NETWORK.

    Assuming that any version 2 is either an extension or improvement, I decided to use that instead, but before I did, I wanted to read about the differences in has with version 1... which I couldn't... kind of. I could check out the structure itself and I noticed that there were 3 additional fields (AccessNetworkOptions, dot11HESSID, VenueInfo). The only documentation I could find was this: docs.microsoft.com/en-us/previous-versions/mt595904(v%3Dvs.85) but those three fields are marked TBD. Interestingly, the minimum windows version is Windows 10 (!?)

    So what can I surmise from all this? Should I use V2 instead of V1, is it even available? What do those 3 fields contain exactly? Should I be concerned about the minimum version being Windows 10 (I am targeting lower Windows versions in my app). It sounds a bit unlikely (for an API as old as NativeWifi) for a function to be that new, so I'm not excluding that this could be a misleading label...

    Friday, June 5, 2020 10:14 AM

Answers

  • Hi,

    Thanks for posting here.

    In the latest Windows SDK, the WLAN_AVAILABLE_NETWORK_V2 was located in wlanapi.h:

    typedef struct _WLAN_AVAILABLE_NETWORK_V2 {
        WCHAR strProfileName[WLAN_MAX_NAME_LENGTH];
        DOT11_SSID dot11Ssid;
        DOT11_BSS_TYPE dot11BssType;
        ULONG uNumberOfBssids;
        BOOL bNetworkConnectable;
        WLAN_REASON_CODE wlanNotConnectableReason;
        ULONG uNumberOfPhyTypes;
        DOT11_PHY_TYPE dot11PhyTypes[WLAN_MAX_PHY_TYPE_NUMBER];
        // bMorePhyTypes is set to TRUE if the PHY types for the network
        // exceeds WLAN_MAX_PHY_TYPE_NUMBER.
        // In this case, uNumerOfPhyTypes is WLAN_MAX_PHY_TYPE_NUMBER and the
        // first WLAN_MAX_PHY_TYPE_NUMBER PHY types are returned.
        BOOL bMorePhyTypes;
        WLAN_SIGNAL_QUALITY wlanSignalQuality;
        BOOL bSecurityEnabled;
        DOT11_AUTH_ALGORITHM dot11DefaultAuthAlgorithm;
        DOT11_CIPHER_ALGORITHM dot11DefaultCipherAlgorithm;
        DWORD dwFlags;
    
        // V2 fields
        DOT11_ACCESSNETWORKOPTIONS                 AccessNetworkOptions;
        DOT11_HESSID                               dot11HESSID;
        DOT11_VENUEINFO                            VenueInfo;
    
        DWORD dwReserved;
    } WLAN_AVAILABLE_NETWORK_V2, *PWLAN_AVAILABLE_NETWORK_V2;

    And the type definition in V2 fields:

    //
    //  Similar to DOT11_INTERWORKING_ACCESSNETWORKOPTIONS, but it doesn't have bit fields, which are not allowed for RPC interfaces
    //
    typedef struct DOT11_ACCESSNETWORKOPTIONS { // 802.11-2012 Figure 8-352
        UINT8 AccessNetworkType;                 // 802.11-2012 Table 8-174
        UINT8 Internet;                          // 1 = Internet connectivity
        UINT8 ASRA;                              // Additional Step Required for Access
        UINT8 ESR;                               // Emergency Services Reachable
        UINT8 UESA;                              // Unauthenticated Emergency Services Available
    } DOT11_ACCESSNETWORKOPTIONS, *PDOT11_ACCESSNETWORKOPTIONS;
    
    typedef struct DOT11_VENUEINFO            { // 802.11-2012 Figure 8-72
        UINT8 VenueGroup;                       // 802.11-2012 Table 8-52
        UINT8 VenueType;                        // 802.11-2012 Table 8-53
    } DOT11_VENUEINFO, *PDOT11_VENUEINFO;
    ...
    #define DOT11_HESSID_LENGTH   6
    typedef UCHAR DOT11_HESSID[DOT11_HESSID_LENGTH];
    typedef DOT11_HESSID* PDOT11_HESSID;

    The description explains the meaning of the members, “802.11-2012” represents "802.11-2012-IEEE Standard for Information technology"
    You can google "802.11 standards 2012 pdf" to get the Standard document. Then search for something like "Figure 8-352" and other sections metioned in the SDK.

    Table 8-174—Access network type:

    0 Private network
    1 Private network with guest access
    2 Chargeable public 
    3 Free public network
    4 Personal device network
    5 Emergency services only network
    6 to 13 Reserved
    14 Test or experimental
    15 Wildcard

    And for dot11HESSID, it is also metioned in the Standard:

    The HESSID field, which is the identifier for a homogeneous ESS, specifies the value of HESSID; see
    10.24.2. A STA uses this field to indicate the desired HESSID in an active scan per 10.1.4. The HESSID
    field for an AP is set to the value of dot11HESSID. This optional field is not used by mesh STAs.

    "This is a control variable.
    It is written by an external management entity or the SME. Changes take
    effect for the next MLME-START.request primitive.
    This attribute is used by an AP and is the 6-octet homogeneous ESS identifier field, whose value is set to one of the BSSIDs in the ESS. It is required that the same value of HESSID be used for all BSSs in the homogeneous ESS."


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by kirillandy Monday, June 8, 2020 9:19 AM
    Monday, June 8, 2020 3:09 AM

All replies

  • If you don't need the new fields, then why would you bother with it?  A "2" function doesn't necessarily mean "better", and it will restrict your program to Win 10 systems.

    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Friday, June 5, 2020 7:51 PM
  • It's a bit hard to decide if I need them or not if I can't be sure of what information they hold, which was my original question :)

    I'm not assuming it is undoubtedly better, as I said, it might just as well be a simple extension (there was obviously some reason a V2 was made) but thanks for confirming the Windows 10 restriction, Tim. That alone means that I'll stick with V1.

    Sunday, June 7, 2020 10:36 AM
  • Well, one big question. Even if a function is only available on Windows, 10, why just stick with an earlier version of that function? For an example of this, Windows 10 added better high DPI awareness in 1607. Functions like GetWindowDpiAwarenessContext and GetThreadDpiAwarenessContext were added. But since these were added in Windows 10, does this mean that an application targeting Windows 8.1 as a base is unable to use them? No.

    Windows has runtime dynamic linking. There is nothing stopping you from using GetProcAddress to determine detect the existence of a function and using it through that function pointer. Microsoft use the term "lighting up" to refer to dynamically detecting features at runtime and then using them if available.

    This isn't some kind of theoretical thing either. The CRT uses this technique to access newer functions while still being able to work on older versions of Windows. If you look in the file winapi_thunks.cpp in the publicly available UCRT source, available along with the Windows SDK, you will notice that it uses GetProcAddress to try to detect newer features and fall back to older features if the newer one is unavailable.

    Also, I think one of the reasons why this function was kind of documented was due to changing development plans. It is likely that it was originally added to preview versions of Windows 10, but along the way Microsoft decided to add it to the UWP API instead. They had to leave it documented for those people who used it in applications targeting the preview versions of Windows 10, but actually want developers to use the UWP versions.

    Before you think, oh no, UWP means I would have to write a Windows Store application so I definitely won't use it, this functionality is marked as DualApiPartition, this means that it is available for desktop applications to use. The WiFi API is under Windows.Devices.WiFi.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Sunday, June 7, 2020 2:00 PM
  • Hi,

    Thanks for posting here.

    In the latest Windows SDK, the WLAN_AVAILABLE_NETWORK_V2 was located in wlanapi.h:

    typedef struct _WLAN_AVAILABLE_NETWORK_V2 {
        WCHAR strProfileName[WLAN_MAX_NAME_LENGTH];
        DOT11_SSID dot11Ssid;
        DOT11_BSS_TYPE dot11BssType;
        ULONG uNumberOfBssids;
        BOOL bNetworkConnectable;
        WLAN_REASON_CODE wlanNotConnectableReason;
        ULONG uNumberOfPhyTypes;
        DOT11_PHY_TYPE dot11PhyTypes[WLAN_MAX_PHY_TYPE_NUMBER];
        // bMorePhyTypes is set to TRUE if the PHY types for the network
        // exceeds WLAN_MAX_PHY_TYPE_NUMBER.
        // In this case, uNumerOfPhyTypes is WLAN_MAX_PHY_TYPE_NUMBER and the
        // first WLAN_MAX_PHY_TYPE_NUMBER PHY types are returned.
        BOOL bMorePhyTypes;
        WLAN_SIGNAL_QUALITY wlanSignalQuality;
        BOOL bSecurityEnabled;
        DOT11_AUTH_ALGORITHM dot11DefaultAuthAlgorithm;
        DOT11_CIPHER_ALGORITHM dot11DefaultCipherAlgorithm;
        DWORD dwFlags;
    
        // V2 fields
        DOT11_ACCESSNETWORKOPTIONS                 AccessNetworkOptions;
        DOT11_HESSID                               dot11HESSID;
        DOT11_VENUEINFO                            VenueInfo;
    
        DWORD dwReserved;
    } WLAN_AVAILABLE_NETWORK_V2, *PWLAN_AVAILABLE_NETWORK_V2;

    And the type definition in V2 fields:

    //
    //  Similar to DOT11_INTERWORKING_ACCESSNETWORKOPTIONS, but it doesn't have bit fields, which are not allowed for RPC interfaces
    //
    typedef struct DOT11_ACCESSNETWORKOPTIONS { // 802.11-2012 Figure 8-352
        UINT8 AccessNetworkType;                 // 802.11-2012 Table 8-174
        UINT8 Internet;                          // 1 = Internet connectivity
        UINT8 ASRA;                              // Additional Step Required for Access
        UINT8 ESR;                               // Emergency Services Reachable
        UINT8 UESA;                              // Unauthenticated Emergency Services Available
    } DOT11_ACCESSNETWORKOPTIONS, *PDOT11_ACCESSNETWORKOPTIONS;
    
    typedef struct DOT11_VENUEINFO            { // 802.11-2012 Figure 8-72
        UINT8 VenueGroup;                       // 802.11-2012 Table 8-52
        UINT8 VenueType;                        // 802.11-2012 Table 8-53
    } DOT11_VENUEINFO, *PDOT11_VENUEINFO;
    ...
    #define DOT11_HESSID_LENGTH   6
    typedef UCHAR DOT11_HESSID[DOT11_HESSID_LENGTH];
    typedef DOT11_HESSID* PDOT11_HESSID;

    The description explains the meaning of the members, “802.11-2012” represents "802.11-2012-IEEE Standard for Information technology"
    You can google "802.11 standards 2012 pdf" to get the Standard document. Then search for something like "Figure 8-352" and other sections metioned in the SDK.

    Table 8-174—Access network type:

    0 Private network
    1 Private network with guest access
    2 Chargeable public 
    3 Free public network
    4 Personal device network
    5 Emergency services only network
    6 to 13 Reserved
    14 Test or experimental
    15 Wildcard

    And for dot11HESSID, it is also metioned in the Standard:

    The HESSID field, which is the identifier for a homogeneous ESS, specifies the value of HESSID; see
    10.24.2. A STA uses this field to indicate the desired HESSID in an active scan per 10.1.4. The HESSID
    field for an AP is set to the value of dot11HESSID. This optional field is not used by mesh STAs.

    "This is a control variable.
    It is written by an external management entity or the SME. Changes take
    effect for the next MLME-START.request primitive.
    This attribute is used by an AP and is the 6-octet homogeneous ESS identifier field, whose value is set to one of the BSSIDs in the ESS. It is required that the same value of HESSID be used for all BSSs in the homogeneous ESS."


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by kirillandy Monday, June 8, 2020 9:19 AM
    Monday, June 8, 2020 3:09 AM
  • Hi Darran, thanks for the extra insight and ideas. The GetProcAddress method sounds very handy, I'll keep it in mind. I don't see how it could be applicable here though, seeing how it's used with DLLs, whereas NativeWifi is a LIB...

    I haven't heard about the DualApiPartition, I'll look into it. Thanks again!

    Monday, June 8, 2020 9:18 AM
  • Thanks for the clarification! To my shame I hadn't noticed the comments next to the fields of the different structures, they provided all the necessary links to other documents

    Now this feels like a bit of a pointless thread, to be honest :)

    Monday, June 8, 2020 9:23 AM
  • whereas NativeWifi is a LIB...

    Is it? Are you perhaps confusing import libraries with static libraries? The library wlanapi.lib does not contain code, it contains information for the linker to refer to the associated DLL.

    If we use WlanGetAvailableNetworkList as an example, the entry in wlanapi.lib is:

    Archive member name at 2DFC: wlanapi.dll/
    FFFFFFFF time/date
             uid
             gid
           0 mode
          3C size
    correct header end

      Version      : 0
      Machine      : 8664 (x64)
      TimeDateStamp: D657BF3C
      SizeOfData   : 00000028
      DLL name     : wlanapi.dll
      Symbol name  : WlanGetAvailableNetworkList
      Type         : code
      Name type    : name
      Hint         : 128
      Name         : WlanGetAvailableNetworkList

    Notice how it refers to the .dll? What's more, if you list the exports of wlanapi.dll, you should find:

    129   80 00008360 WlanGetAvailableNetworkList

    What the .lib file is simple, it makes the link between your application's call and the actual function in the DLL. If you want extra proof of that then in Visual Studio, set a break point on this function.

    The wlanapi.dll! is useful to make sure that it selects the function in the DLL, if you don't use this then the breakpoint may be placed on the function pointer that it uses to call the function from the DLL. If this happens just step into it and you should end up at the DLL. Anyway, run the application and let it hit the breakpoint, when you look at the disassembly view you should see something similar to:

    Notice the address that it is on? If you look at Visual Studio's module list then you should see something similar to:

    This puts the function address right in the memory address range of wlanapi.dll, this means that it is calling the function from wlanapi.dll. Don't take the memory addresses given here as absolute, because this is an x64 application and because of ASLR then things can change. The code that I was using to do this was:

    #include <Windows.h>
    #include <wlanapi.h>
    
    #pragma comment(lib, "wlanapi.lib")
    
    int main()
    {
    	WlanGetAvailableNetworkList(nullptr, nullptr, 0, nullptr, nullptr);
    
    	return 0;
    }

    Sure it is bad, but that doesn't matter, all it had to do was call the function. Notice how I am linking to wlanapi.lib though.

    Another thing you can do to check is check the imports for the executable. One way of doing this is using dumpbin /imports. For this test executable which linked against wlanapi.lib, dumpbin showed:

        wlanapi.dll
                 1401713A0 Import Address Table
                 1401717E0 Import Name Table
                         0 time date stamp
                         0 Index of first forwarder reference

                              80 WlanGetAvailableNetworkList

    So the Windows Native WiFi functionality is very much DLL based.

    The majority of Windows' functionality is implemented in DLLs, and you can mostly tell by the documentation. For example, WlanGetAvailableNetworkList's requirements section lists wlanapi.lib as the library and wlanapi.dll as the DLL. This doesn't mean you have a choice. This means that you must link against wlanapi.lib to resolve any direct calls to the function.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, June 8, 2020 3:54 PM
  • Thank you for the clear demonstration Darran! I need to brush up on libraries in general it seems, I really do :). Lighting up is back on the table.

    (Why would I even assume a system library was a lib? If there's one thing I've been taught about dlls, it's that they're much easier to update and modify due to their independence, makes a lot more sense :D)

    Tuesday, June 9, 2020 8:34 AM