Windows wlan 获取bssid 以及浅谈wifi定位

上一篇简单说了一下如何使用windows native API 扫描站点广播的信号,比较浅显。这一篇简单说一下,如何获取bssid以及wifi定位的原理。

bssid是一个AP信号的唯一标示,一般通过wifi定位,就是检测设备把连接的AP信号的bssid和当前GPS位置上传到服务器,其他设备需要连接目标AP并上传GPS位置信息进行比较,如果一致就认为在范围内,就会允许签到、打卡等操作。这个思路借鉴自这篇博客https://blog.csdn.net/gupar/article/details/50854480,这里说win8.1一下的版本无法获取bssid,待验证。

通过native API获取bssid的方式现在知道两种。一种是通过处于已连接状态的信号,通过接口查询链接属性,属性里可以获取bssid,但仅限于已连接的AP。显然无法获取全部扫描到的AP信号。第二种方式可以获取到所有扫描到的AP信号的bssid,是通过另一个接口,如下

            std::wstring bssid;
            PWLAN_BSS_LIST ppWlanBssList;

            DWORD dwResult2 = WlanGetNetworkBssList(hClient, &pIfInfo->InterfaceGuid,
                &pBssEntry->dot11Ssid,
                pBssEntry->dot11BssType,
                pBssEntry->bSecurityEnabled,
                NULL,
                &ppWlanBssList);

第三个参数很重要,如果是传入的某个AP的ssid则,只能获取当前AP的bssid,如果传入NULL,则会返回当前网卡扫描到的所有AP的bssid。

发现这个接口也很偶然。开始我一直关注这个接口

dwResult = WlanQueryInterface(hClient,
                    &pIfInfo->InterfaceGuid,
                    wlan_intf_opcode_current_connection,
                    NULL,
                    &connectInfoSize,
                    (PVOID *)&pConnectInfo,
                    &opCode);

 但发现他只能返回【current_connection】状态的接口。后来又去MSDN去查有哪些数据结构中包含【bssid】的属性,就发现了WLAN_BSS_LIST。然后继续找,哪些接口会返回这个结构,就找到了【WlanGetNetworkBssList】,然后百度搜了一下就找到上面的链接,顺便用法也有了。后来仔细看了一下官方文档,发现如果第三个参数为NULL,则接口会默认返回所有扫到的bssid。

通过这种方式获取的bssid,会发现同一个AP会有两个bssid,也就是一个路由器有两块无线网卡。百度了很久,基本有两种说法,一是认为高级点儿路由器有两种模式,除了正常模式外,还可以开启访客模式。另外一种说现在的路由器支持2.4GHz和5.0GHz频率的信号,所以会有两块无线网卡。这个地方有点儿疑惑,最终也没太搞懂。姑且认为这两个bssid对应的是同一个AP。

这里附上源码,因为我的应用中嵌入了CEF,所以json数据结构就使用了cef的实现(所以不太纯,引入cef的依赖,仅供参考吧)。

#include<windows.h>  
#include<wlanapi.h>  
#include<stdio.h> 
#include "include/cef_parser.h" // json func
#include <xstring>

#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")


int getWlanContent(CefString& strRes)
{
	int iState(200);
	CefRefPtr<CefDictionaryValue> pDictRt = CefDictionaryValue::Create();

	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;

		pDictRt->SetInt("state", iState);
		pDictRt->SetDictionary("result", CefDictionaryValue::Create());

		CefRefPtr<CefValue> pValue = CefValue::Create();
		if (nullptr != pValue)
		{
			pValue->SetDictionary(pDictRt);
			strRes = CefWriteJSON(pValue, JSON_WRITER_DEFAULT);
		}	

		return iState;
		// 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;

		pDictRt->SetInt("state", iState);
		pDictRt->SetDictionary("result", CefDictionaryValue::Create());
		
		CefRefPtr<CefValue> pValue = CefValue::Create();
		if (nullptr != pValue)
		{
			pValue->SetDictionary(pDictRt);
			strRes = CefWriteJSON(pValue, JSON_WRITER_DEFAULT);
		}

		return iState;
		// You can use FormatMessage here to find out why the function failed
	}

	if ((int)pIfList->dwNumberOfItems < 1)
	{
		wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
		iState = 256;

		pDictRt->SetInt("state", iState);
		pDictRt->SetDictionary("result", CefDictionaryValue::Create());

		CefRefPtr<CefValue> pValue = CefValue::Create();
		if (nullptr != pValue)
		{
			pValue->SetDictionary(pDictRt);
			strRes = CefWriteJSON(pValue, JSON_WRITER_DEFAULT);
		}

		return iState;
	}

	CefRefPtr<CefListValue> pGuid = CefListValue::Create();
	for (i = 0; i < (int)pIfList->dwNumberOfItems; i++)
	{
		pIfInfo = (WLAN_INTERFACE_INFO *)&pIfList->InterfaceInfo[i];
		if (nullptr == pIfInfo)
		{
			continue;
		}

		const std::wstring strGuid = L"{9245fe4a-d402-451c-b9ed-9c1a04247482}";
		GUID stGuid = { 0 };

		//TCHAR sz[MAX_PATH] = { 0 };
		LPOLESTR streGuid;
		StringFromCLSID(pIfInfo->InterfaceGuid, &streGuid);
		std::wstring strTgt = OLE2T(streGuid);

		// avaiable wlan
		dwResult = WlanGetAvailableNetworkList(hClient,
			&pIfInfo->InterfaceGuid,
			0,
			NULL,
			&pBssList);
		if (ERROR_SUCCESS != dwResult)
		{
			wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
			iState = 253;
			continue;
		}

		CefRefPtr<CefListValue> pDictA = CefListValue::Create();

		for (auto m = 0; m < pBssList->dwNumberOfItems; m++)
		{
			CefRefPtr<CefDictionaryValue> pItem = CefDictionaryValue::Create();

			pBssEntry =(WLAN_AVAILABLE_NETWORK *)& pBssList->Network[m];
			if (nullptr == pBssEntry)
			{
				continue;
			}

			std::wstring ssid;
			TCHAR sz[30] = { 0 };
			for (auto k = 0;
				k < pBssEntry->dot11Ssid.uSSIDLength;
				k++) {
				swprintf_s(sz, L"%c",
					(int)pBssEntry->dot11Ssid.ucSSID[k]);
				ssid.append(sz);
			}
			ULONG lSqn = pBssEntry->wlanSignalQuality;

			if (ssid.empty())
			{
				continue;
			}

			// bssid
			std::wstring bssid;
			PWLAN_BSS_LIST ppWlanBssList;

			DWORD dwResult2 = WlanGetNetworkBssList(hClient, &pIfInfo->InterfaceGuid,
				&pBssEntry->dot11Ssid,
				pBssEntry->dot11BssType,
				pBssEntry->bSecurityEnabled,
				NULL,
				&ppWlanBssList);

			CefRefPtr<CefListValue> pBssidArr = CefListValue::Create();
			if (dwResult2 == ERROR_SUCCESS)
			{
				for (int z = 0; z < ppWlanBssList->dwNumberOfItems; z++)
				{
					WLAN_BSS_ENTRY bssEntry = ppWlanBssList->wlanBssEntries[z];

					TCHAR sz[MAX_PATH] = { 0 };
					swprintf_s(sz, L"%02X:%02X:%02X:%02X:%02X:%02X",
						bssEntry.dot11Bssid[0],
						bssEntry.dot11Bssid[1],
						bssEntry.dot11Bssid[2],
						bssEntry.dot11Bssid[3],
						bssEntry.dot11Bssid[4],
						bssEntry.dot11Bssid[5]);

					bssid = sz;

					CefRefPtr<CefValue> pBidValue = CefValue::Create();
					pBidValue->SetString(bssid);
					pBssidArr->SetValue(z, pBidValue);
					//vecBSSIDs.push_back(bssid);
				}
			}

			if (bssid.empty() || (pBssidArr->GetSize() <1))
			{
				continue;
			}

			pItem->SetString("name", ssid);
			pItem->SetInt("sglqlt", lSqn);
			pItem->SetList("bssid", pBssidArr);
			pItem->SetString("netid", strTgt);

			pDictA->SetDictionary(m, pItem);
		}

		pGuid->SetList(i, pDictA);
		
	}

	CefRefPtr<CefValue> pValueT = CefValue::Create();
	pValueT->SetList(pGuid);

	pDictRt->SetInt("state", iState);
	pDictRt->SetValue("result", pValueT);
	//pDictRt->SetValue("result", pValueT);

	CefRefPtr<CefValue> pValueRes = CefValue::Create();
	pValueRes->SetDictionary(pDictRt);
	strRes = CefWriteJSON(pValueRes, JSON_WRITER_DEFAULT);

	return iState;

}

在此简单记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老朱自强不息

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值