因为是基于windows平台的开发,第一手的参考资料肯定是msdn的https://docs.microsoft.com/zh-cn/windows/desktop/NativeWiFi/portal。
第一天我们的需求很简单,扫描当前无线网卡扫到的AP,并获取当前连接的BSSID。
先做一下科普,了解一下wlan网络结构。https://blog.csdn.net/zwl1584671413/article/details/77936950。分上下两篇,基本入门了。
先普及几个概念。
站点,可以理解为一切连接到wifi热点的设备。比如手机,笔记本电脑,平板等。
接入点,又叫AP,或者叫热点。可以理解为一切向外广播wifi信号的设备,具备报文收发、转播,好像还要有网络拓扑结构的设备。比如路由器,装备了无线网卡的电脑(需要开启对应的服务)。
站点加AP或者多个AP可以组成一个服务单元,叫基本服务集(BSS)。站点和AP组网的叫基础结构型基本服务集(infrastructure BSS)。多个AP组网独立型基本服务集(Independent BSS,简称IBSS),也叫Ad - hoc 网络,这种网络最早是为了军事需要而架设的特殊网络。战争题材的电视剧里,通信要发报包括战地电话,都是拉的专线,基本就是Ad-hoc这种网络。通过一根网线连接两个电脑,通过设置一样的网关,在同一网段,这两台电脑就相当于组网了,然后可以互相通信,比如通过FileZilla组成Ftp服务端和客户端,可以互相上传文件,都属于Ad-hoc网络。
现在实际网络环境都是BSS+IBSS混合使用,一起发挥各自的优点。比如基站作为远距离的中继,有一定的覆盖范围,不同区域的BSS和IBSS需要通信时,需要通过分布式系统,路由到合理的基站,再通过蜂窝网络覆盖到服务单元,如果小区内BSS末端的用户,由于距离相对较远,信号会衰减,一些实时的信息传输就回有延迟了,所以小区里一般都是Ad-hoc网络入户(因为各个结点都是平级的)。
以上可能不太专业,就是个人对无线网络的肤浅认识,难免有错误。
然后回来解决我们自己的问题。站点扫描在AP广播范围内的信号(SSID)。然后获取当前链接的AP的BSSID。
主要四个函数
WlanOpenHandle();// 获取本地无线网卡的句柄
WlanEnumInterfaces(); // 遍历网卡,可能有多块
WlanGetAvailableNetworkList(); // 获取某块网卡扫描到的AP;
pIfInfo->isState == wlan_interface_state_connected; // 用来判断某个信号是否为当前链接的AP
PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;dwResult = WlanQueryInterface(hClient,
&pIfInfo->InterfaceGuid,
wlan_intf_opcode_current_connection,
NULL,
&connectInfoSize,
(PVOID *)&pConnectInfo,
&opCode); ; // 如果是,查询端口,返回当前AP的接口信息,然后就可以做后续操作
获取AP信息,参考如下链接 https://docs.microsoft.com/zh-cn/windows/desktop/api/wlanapi/nf-wlanapi-wlanqueryinterface。
#include<windows.h>
#include<wlanapi.h>
#include<stdio.h>
#include "include/cef_parser.h" // json func
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
int GetWlanListEx()
{
int iState(200);
// construct wlan list
CefRefPtr<CefDictionaryValue> pDictRt = CefDictionaryValue::Create();
// Declare and initialize variables.
HANDLE hClient = NULL;
DWORD dwMaxClient = 2; //
DWORD dwCurVersion = 0;
DWORD dwResult = 0;
DWORD dwRetVal = 0;
int iRet = 0;
WCHAR GuidString[39] = { 0 };
unsigned int i, j, k;
/* variables used for WlanEnumInterfaces */
PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
PWLAN_INTERFACE_INFO pIfInfo = NULL;
PWLAN_AVAILABLE_NETWORK_LIST pBssList = NULL;
PWLAN_AVAILABLE_NETWORK pBssEntry = NULL;
int iRSSI = 0;
dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
iState = 251;
return 1;
// You can use FormatMessage here to find out why the function failed
}
dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
iState = 252;
return 1;
// You can use FormatMessage here to find out why the function failed
}
else {
wprintf(L"Num Entries: %lu\n", pIfList->dwNumberOfItems);
wprintf(L"Current Index: %lu\n", pIfList->dwIndex);
for (i = 0; i < (int)pIfList->dwNumberOfItems; i++)
{
pIfInfo = (WLAN_INTERFACE_INFO *)&pIfList->InterfaceInfo[i];
wprintf(L" Interface Index[%u]:\t %lu\n", i, i);
iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR)&GuidString,
sizeof(GuidString) / sizeof(*GuidString));
// For c rather than C++ source code, the above line needs to be
// iRet = StringFromGUID2(&pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString,
// sizeof(GuidString)/sizeof(*GuidString));
if (iRet == 0)
wprintf(L"StringFromGUID2 failed\n");
else {
wprintf(L" InterfaceGUID[%d]: %ws\n", i, GuidString);
}
wprintf(L" Interface Description[%d]: %ws", i,
pIfInfo->strInterfaceDescription);
wprintf(L"\n");
wprintf(L" Interface State[%d]:\t ", i);
switch (pIfInfo->isState) {
case wlan_interface_state_not_ready:
wprintf(L"Not ready\n");
break;
case wlan_interface_state_connected:
wprintf(L"Connected\n");
break;
case wlan_interface_state_ad_hoc_network_formed:
wprintf(L"First node in a ad hoc network\n");
break;
case wlan_interface_state_disconnecting:
wprintf(L"Disconnecting\n");
break;
case wlan_interface_state_disconnected:
wprintf(L"Not connected\n");
break;
case wlan_interface_state_associating:
wprintf(L"Attempting to associate with a network\n");
break;
case wlan_interface_state_discovering:
wprintf(L"Auto configuration is discovering settings for the network\n");
break;
case wlan_interface_state_authenticating:
wprintf(L"In process of authenticating\n");
break;
default:
wprintf(L"Unknown state %ld\n", pIfInfo->isState);
break;
}
wprintf(L"\n");
dwResult = WlanGetAvailableNetworkList(hClient,
&pIfInfo->InterfaceGuid,
0,
NULL,
&pBssList);
// variables used for WlanQueryInterfaces for opcode = wlan_intf_opcode_current_connection
PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
// If interface state is connected, call WlanQueryInterface
// to get current connection attributes
if (pIfInfo->isState == wlan_interface_state_connected)
{
dwResult = WlanQueryInterface(hClient,
&pIfInfo->InterfaceGuid,
wlan_intf_opcode_current_connection,
NULL,
&connectInfoSize,
(PVOID *)&pConnectInfo,
&opCode);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanQueryInterface failed with error: %u\n", dwResult);
dwRetVal = 1;
// You can use FormatMessage to find out why the function failed
}
else {
wprintf(L" WLAN_CONNECTION_ATTRIBUTES for this interface\n");
wprintf(L" Interface State:\t ");
switch (pConnectInfo->isState) {
case wlan_interface_state_not_ready:
wprintf(L"Not ready\n");
break;
case wlan_interface_state_connected:
wprintf(L"Connected\n");
break;
case wlan_interface_state_ad_hoc_network_formed:
wprintf(L"First node in a ad hoc network\n");
break;
case wlan_interface_state_disconnecting:
wprintf(L"Disconnecting\n");
break;
case wlan_interface_state_disconnected:
wprintf(L"Not connected\n");
break;
case wlan_interface_state_associating:
wprintf(L"Attempting to associate with a network\n");
break;
case wlan_interface_state_discovering:
wprintf
(L"Auto configuration is discovering settings for the network\n");
break;
case wlan_interface_state_authenticating:
wprintf(L"In process of authenticating\n");
break;
default:
wprintf(L"Unknown state %ld\n", pIfInfo->isState);
break;
}
wprintf(L" Connection Mode:\t ");
switch (pConnectInfo->wlanConnectionMode) {
case wlan_connection_mode_profile:
wprintf(L"A profile is used to make the connection\n");
break;
case wlan_connection_mode_temporary_profile:
wprintf(L"A temporary profile is used to make the connection\n");
break;
case wlan_connection_mode_discovery_secure:
wprintf(L"Secure discovery is used to make the connection\n");
break;
case wlan_connection_mode_discovery_unsecure:
wprintf(L"Unsecure discovery is used to make the connection\n");
break;
case wlan_connection_mode_auto:
wprintf
(L"connection initiated by wireless service automatically using a persistent profile\n");
break;
case wlan_connection_mode_invalid:
wprintf(L"Invalid connection mode\n");
break;
default:
wprintf(L"Unknown connection mode %ld\n",
pConnectInfo->wlanConnectionMode);
break;
}
wprintf(L" Profile name used:\t %ws\n", pConnectInfo->strProfileName);
wprintf(L" Association Attributes for this connection\n");
wprintf(L" SSID:\t\t ");
if (pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength == 0)
wprintf(L"\n");
else {
for (k = 0;
k < pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength;
k++) {
wprintf(L"%c",
(int)pConnectInfo->wlanAssociationAttributes.dot11Ssid.
ucSSID[k]);
}
wprintf(L"\n");
}
wprintf(L" BSS Network type:\t ");
switch (pConnectInfo->wlanAssociationAttributes.dot11BssType) {
case dot11_BSS_type_infrastructure:
wprintf(L"Infrastructure\n");
break;
case dot11_BSS_type_independent:
wprintf(L"Infrastructure\n");
break;
default:
wprintf(L"Other = %lu\n",
pConnectInfo->wlanAssociationAttributes.dot11BssType);
break;
}
wprintf(L" MAC address:\t ");
for (k = 0; k < sizeof(pConnectInfo->wlanAssociationAttributes.dot11Bssid);
k++) {
if (k == 5)
wprintf(L"%.2X\n",
pConnectInfo->wlanAssociationAttributes.dot11Bssid[k]);
else
wprintf(L"%.2X-",
pConnectInfo->wlanAssociationAttributes.dot11Bssid[k]);
}
wprintf(L" PHY network type:\t ");
switch (pConnectInfo->wlanAssociationAttributes.dot11PhyType) {
case dot11_phy_type_fhss:
wprintf(L"Frequency-hopping spread-spectrum (FHSS)\n");
break;
case dot11_phy_type_dsss:
wprintf(L"Direct sequence spread spectrum (DSSS)\n");
break;
case dot11_phy_type_irbaseband:
wprintf(L"Infrared (IR) baseband\n");
break;
case dot11_phy_type_ofdm:
wprintf(L"Orthogonal frequency division multiplexing (OFDM)\n");
break;
case dot11_phy_type_hrdsss:
wprintf(L"High-rate DSSS (HRDSSS) = \n");
break;
case dot11_phy_type_erp:
wprintf(L"Extended rate PHY type\n");
break;
case dot11_phy_type_ht:
wprintf(L"802.11n PHY type\n");
break;
default:
wprintf(L"Unknown = %lu\n",
pConnectInfo->wlanAssociationAttributes.dot11PhyType);
break;
}
wprintf(L" PHY index:\t\t %u\n",
pConnectInfo->wlanAssociationAttributes.uDot11PhyIndex);
wprintf(L" Signal Quality:\t %d\n",
pConnectInfo->wlanAssociationAttributes.wlanSignalQuality);
wprintf(L" Receiving Rate:\t %ld\n",
pConnectInfo->wlanAssociationAttributes.ulRxRate);
wprintf(L" Transmission Rate:\t %ld\n",
pConnectInfo->wlanAssociationAttributes.ulTxRate);
wprintf(L"\n");
wprintf(L" Security Attributes for this connection\n");
wprintf(L" Security enabled:\t ");
if (pConnectInfo->wlanSecurityAttributes.bSecurityEnabled == 0)
wprintf(L"No\n");
else
wprintf(L"Yes\n");
wprintf(L" 802.1X enabled:\t ");
if (pConnectInfo->wlanSecurityAttributes.bOneXEnabled == 0)
wprintf(L"No\n");
else
wprintf(L"Yes\n");
wprintf(L" Authentication Algorithm: ");
switch (pConnectInfo->wlanSecurityAttributes.dot11AuthAlgorithm) {
case DOT11_AUTH_ALGO_80211_OPEN:
wprintf(L"802.11 Open\n");
break;
case DOT11_AUTH_ALGO_80211_SHARED_KEY:
wprintf(L"802.11 Shared\n");
break;
case DOT11_AUTH_ALGO_WPA:
wprintf(L"WPA\n");
break;
case DOT11_AUTH_ALGO_WPA_PSK:
wprintf(L"WPA-PSK\n");
break;
case DOT11_AUTH_ALGO_WPA_NONE:
wprintf(L"WPA-None\n");
break;
case DOT11_AUTH_ALGO_RSNA:
wprintf(L"RSNA\n");
break;
case DOT11_AUTH_ALGO_RSNA_PSK:
wprintf(L"RSNA with PSK\n");
break;
default:
wprintf(L"Other (%lu)\n", pConnectInfo->wlanSecurityAttributes.dot11AuthAlgorithm);
break;
}
wprintf(L" Cipher Algorithm:\t ");
switch (pConnectInfo->wlanSecurityAttributes.dot11CipherAlgorithm) {
case DOT11_CIPHER_ALGO_NONE:
wprintf(L"None\n");
break;
case DOT11_CIPHER_ALGO_WEP40:
wprintf(L"WEP-40\n");
break;
case DOT11_CIPHER_ALGO_TKIP:
wprintf(L"TKIP\n");
break;
case DOT11_CIPHER_ALGO_CCMP:
wprintf(L"CCMP\n");
break;
case DOT11_CIPHER_ALGO_WEP104:
wprintf(L"WEP-104\n");
break;
case DOT11_CIPHER_ALGO_WEP:
wprintf(L"WEP\n");
break;
default:
wprintf(L"Other (0x%x)\n", pConnectInfo->wlanSecurityAttributes.dot11CipherAlgorithm);
break;
}
wprintf(L"\n");
}
} // WlanQueryInterface
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanGetAvailableNetworkList failed with error: %u\n",
dwResult);
iState = 253;
dwRetVal = 1;
// You can use FormatMessage to find out why the function failed
}
else {
wprintf(L"WLAN_AVAILABLE_NETWORK_LIST for this interface\n");
wprintf(L" Num Entries: %lu\n\n", pBssList->dwNumberOfItems);
for (j = 0; j < pBssList->dwNumberOfItems; j++) {
pBssEntry =
(WLAN_AVAILABLE_NETWORK *)& pBssList->Network[j];
wprintf(L" Profile Name[%u]: %ws\n", j, pBssEntry->strProfileName);
wprintf(L" SSID[%u]:\t\t ", j);
if (pBssEntry->dot11Ssid.uSSIDLength == 0)
wprintf(L"\n");
else {
for (k = 0; k < pBssEntry->dot11Ssid.uSSIDLength; k++) {
wprintf(L"%c", (int)pBssEntry->dot11Ssid.ucSSID[k]);
}
wprintf(L"\n");
}
wprintf(L" BSS Network type[%u]:\t ", j);
switch (pBssEntry->dot11BssType) {
case dot11_BSS_type_infrastructure:
wprintf(L"Infrastructure (%u)\n", pBssEntry->dot11BssType);
break;
case dot11_BSS_type_independent:
wprintf(L"Infrastructure (%u)\n", pBssEntry->dot11BssType);
break;
default:
wprintf(L"Other (%lu)\n", pBssEntry->dot11BssType);
break;
}
wprintf(L" Number of BSSIDs[%u]:\t %u\n", j, pBssEntry->uNumberOfBssids);
wprintf(L" Connectable[%u]:\t ", j);
if (pBssEntry->bNetworkConnectable)
wprintf(L"Yes\n");
else {
wprintf(L"No\n");
wprintf(L" Not connectable WLAN_REASON_CODE value[%u]:\t %u\n", j,
pBssEntry->wlanNotConnectableReason);
}
wprintf(L" Number of PHY types supported[%u]:\t %u\n", j, pBssEntry->uNumberOfPhyTypes);
if (pBssEntry->wlanSignalQuality == 0)
iRSSI = -100;
else if (pBssEntry->wlanSignalQuality == 100)
iRSSI = -50;
else
iRSSI = -100 + (pBssEntry->wlanSignalQuality / 2);
wprintf(L" Signal Quality[%u]:\t %u (RSSI: %i dBm)\n", j,
pBssEntry->wlanSignalQuality, iRSSI);
wprintf(L" Security Enabled[%u]:\t ", j);
if (pBssEntry->bSecurityEnabled)
wprintf(L"Yes\n");
else
wprintf(L"No\n");
wprintf(L" Default AuthAlgorithm[%u]: ", j);
switch (pBssEntry->dot11DefaultAuthAlgorithm) {
case DOT11_AUTH_ALGO_80211_OPEN:
wprintf(L"802.11 Open (%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
case DOT11_AUTH_ALGO_80211_SHARED_KEY:
wprintf(L"802.11 Shared (%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
case DOT11_AUTH_ALGO_WPA:
wprintf(L"WPA (%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
case DOT11_AUTH_ALGO_WPA_PSK:
wprintf(L"WPA-PSK (%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
case DOT11_AUTH_ALGO_WPA_NONE:
wprintf(L"WPA-None (%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
case DOT11_AUTH_ALGO_RSNA:
wprintf(L"RSNA (%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
case DOT11_AUTH_ALGO_RSNA_PSK:
wprintf(L"RSNA with PSK(%u)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
default:
wprintf(L"Other (%lu)\n", pBssEntry->dot11DefaultAuthAlgorithm);
break;
}
wprintf(L" Default CipherAlgorithm[%u]: ", j);
switch (pBssEntry->dot11DefaultCipherAlgorithm) {
case DOT11_CIPHER_ALGO_NONE:
wprintf(L"None (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
case DOT11_CIPHER_ALGO_WEP40:
wprintf(L"WEP-40 (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
case DOT11_CIPHER_ALGO_TKIP:
wprintf(L"TKIP (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
case DOT11_CIPHER_ALGO_CCMP:
wprintf(L"CCMP (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
case DOT11_CIPHER_ALGO_WEP104:
wprintf(L"WEP-104 (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
case DOT11_CIPHER_ALGO_WEP:
wprintf(L"WEP (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
default:
wprintf(L"Other (0x%x)\n", pBssEntry->dot11DefaultCipherAlgorithm);
break;
}
wprintf(L" Flags[%u]:\t 0x%x", j, pBssEntry->dwFlags);
if (pBssEntry->dwFlags) {
if (pBssEntry->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
wprintf(L" - Currently connected");
if (pBssEntry->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
wprintf(L" - Has profile");
}
wprintf(L"\n");
wprintf(L"\n");
}
}
}
}
if (pBssList != NULL) {
WlanFreeMemory(pBssList);
pBssList = NULL;
}
if (pIfList != NULL) {
WlanFreeMemory(pIfList);
pIfList = NULL;
}
return dwRetVal;
}
为了对比AP信息是否准确,参考链接google, 关键字“Determining which AP a client is associated with”。
windows
cmd
netsh wlan show interfaces
其他平台
祝愉快。