2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
24 #include "PlatformDefs.h"
25 #include "NetworkWin32.h"
26 #include "utils/log.h"
27 #include "threads/SingleLock.h"
28 #include "utils/CharsetConverter.h"
29 #include "utils/StringUtils.h"
31 // undefine if you want to build without the wlan stuff
32 // might be needed for VS2003
33 #define HAS_WIN32_WLAN_API
35 #ifdef HAS_WIN32_WLAN_API
37 #pragma comment (lib,"Wlanapi.lib")
43 CNetworkInterfaceWin32::CNetworkInterfaceWin32(CNetworkWin32* network, IP_ADAPTER_INFO adapter)
48 m_adaptername = adapter.Description;
51 CNetworkInterfaceWin32::~CNetworkInterfaceWin32(void)
55 CStdString& CNetworkInterfaceWin32::GetName(void)
57 if (!g_charsetConverter.isValidUtf8(m_adaptername))
58 g_charsetConverter.unknownToUTF8(m_adaptername);
62 bool CNetworkInterfaceWin32::IsWireless()
64 return (m_adapter.Type == IF_TYPE_IEEE80211);
67 bool CNetworkInterfaceWin32::IsEnabled()
72 bool CNetworkInterfaceWin32::IsConnected()
74 CStdString strIP = m_adapter.IpAddressList.IpAddress.String;
75 return (strIP != "0.0.0.0");
78 CStdString CNetworkInterfaceWin32::GetMacAddress()
81 unsigned char* mAddr = m_adapter.Address;
82 result = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", mAddr[0], mAddr[1], mAddr[2], mAddr[3], mAddr[4], mAddr[5]);
86 void CNetworkInterfaceWin32::GetMacAddressRaw(char rawMac[6])
88 memcpy(rawMac, m_adapter.Address, 6);
91 CStdString CNetworkInterfaceWin32::GetCurrentIPAddress(void)
93 return m_adapter.IpAddressList.IpAddress.String;
96 CStdString CNetworkInterfaceWin32::GetCurrentNetmask(void)
98 return m_adapter.IpAddressList.IpMask.String;
101 CStdString CNetworkInterfaceWin32::GetCurrentWirelessEssId(void)
103 CStdString result = "";
105 #ifdef HAS_WIN32_WLAN_API
108 HANDLE hClientHdl = NULL;
111 PWLAN_CONNECTION_ATTRIBUTES pAttributes;
114 if(WlanOpenHandle(1,NULL,&dwVersion, &hClientHdl) == ERROR_SUCCESS)
116 PWLAN_INTERFACE_INFO_LIST ppInterfaceList;
117 if(WlanEnumInterfaces(hClientHdl,NULL, &ppInterfaceList ) == ERROR_SUCCESS)
119 for(unsigned int i=0; i<ppInterfaceList->dwNumberOfItems;i++)
121 GUID guid = ppInterfaceList->InterfaceInfo[i].InterfaceGuid;
123 StringFromGUID2(guid, (LPOLESTR)&wcguid, 64);
124 CStdStringW strGuid = wcguid;
125 CStdStringW strAdaptername = m_adapter.AdapterName;
126 if( strGuid == strAdaptername)
128 if(WlanQueryInterface(hClientHdl,&ppInterfaceList->InterfaceInfo[i].InterfaceGuid,wlan_intf_opcode_current_connection, NULL, &dwSize, (PVOID*)&pAttributes, NULL ) == ERROR_SUCCESS)
130 result = (char*)pAttributes->wlanAssociationAttributes.dot11Ssid.ucSSID;
131 WlanFreeMemory((PVOID*)&pAttributes);
134 OutputDebugString("Can't query wlan interface\n");
138 WlanCloseHandle(&hClientHdl, NULL);
141 OutputDebugString("Can't open wlan handle\n");
147 CStdString CNetworkInterfaceWin32::GetCurrentDefaultGateway(void)
149 return m_adapter.GatewayList.IpAddress.String;
152 CNetworkWin32::CNetworkWin32(void)
154 queryInterfaceList();
157 CNetworkWin32::~CNetworkWin32(void)
159 CleanInterfaceList();
160 m_netrefreshTimer.Stop();
163 void CNetworkWin32::CleanInterfaceList()
165 vector<CNetworkInterface*>::iterator it = m_interfaces.begin();
166 while(it != m_interfaces.end())
168 CNetworkInterface* nInt = *it;
170 it = m_interfaces.erase(it);
174 std::vector<CNetworkInterface*>& CNetworkWin32::GetInterfaceList(void)
176 CSingleLock lock (m_critSection);
177 if(m_netrefreshTimer.GetElapsedSeconds() >= 5.0f)
178 queryInterfaceList();
183 void CNetworkWin32::queryInterfaceList()
185 CleanInterfaceList();
186 m_netrefreshTimer.StartZero();
188 PIP_ADAPTER_INFO adapterInfo;
189 PIP_ADAPTER_INFO adapter = NULL;
191 ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
193 adapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof (IP_ADAPTER_INFO));
194 if (adapterInfo == NULL)
197 if (GetAdaptersInfo(adapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
200 adapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
201 if (adapterInfo == NULL)
203 OutputDebugString("Error allocating memory needed to call GetAdaptersinfo\n");
208 if ((GetAdaptersInfo(adapterInfo, &ulOutBufLen)) == NO_ERROR)
210 adapter = adapterInfo;
213 m_interfaces.push_back(new CNetworkInterfaceWin32(this, *adapter));
214 adapter = adapter->Next;
220 std::vector<CStdString> CNetworkWin32::GetNameServers(void)
222 std::vector<CStdString> result;
224 FIXED_INFO *pFixedInfo;
226 IP_ADDR_STRING *pIPAddr;
228 pFixedInfo = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
229 if (pFixedInfo == NULL)
231 OutputDebugString("Error allocating memory needed to call GetNetworkParams\n");
234 ulOutBufLen = sizeof (FIXED_INFO);
235 if (GetNetworkParams(pFixedInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
238 pFixedInfo = (FIXED_INFO *) malloc(ulOutBufLen);
239 if (pFixedInfo == NULL)
241 OutputDebugString("Error allocating memory needed to call GetNetworkParams\n");
246 if (GetNetworkParams(pFixedInfo, &ulOutBufLen) == NO_ERROR)
248 result.push_back(pFixedInfo->DnsServerList.IpAddress.String);
249 pIPAddr = pFixedInfo->DnsServerList.Next;
252 result.push_back(pIPAddr->IpAddress.String);
253 pIPAddr = pIPAddr->Next;
262 void CNetworkWin32::SetNameServers(std::vector<CStdString> nameServers)
267 bool CNetworkWin32::PingHost(unsigned long host, unsigned int timeout_ms /* = 2000 */)
269 char SendData[] = "poke";
270 HANDLE hIcmpFile = IcmpCreateFile();
271 BYTE ReplyBuffer [sizeof(ICMP_ECHO_REPLY) + sizeof(SendData)];
273 SetLastError(ERROR_SUCCESS);
275 DWORD dwRetVal = IcmpSendEcho(hIcmpFile, host, SendData, sizeof(SendData),
276 NULL, ReplyBuffer, sizeof(ReplyBuffer), timeout_ms);
278 DWORD lastErr = GetLastError();
279 if (lastErr != ERROR_SUCCESS && lastErr != IP_REQ_TIMED_OUT)
280 CLog::Log(LOGERROR, "%s - IcmpSendEcho failed - %s", __FUNCTION__, WUSysMsg(lastErr).c_str());
282 IcmpCloseHandle (hIcmpFile);
286 PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
287 return (pEchoReply->Status == IP_SUCCESS);
292 bool CNetworkInterfaceWin32::GetHostMacAddress(unsigned long host, CStdString& mac)
294 IPAddr src_ip = inet_addr(GetCurrentIPAddress().c_str());
295 BYTE bPhysAddr[6]; // for 6-byte hardware addresses
296 ULONG PhysAddrLen = 6; // default to length of six bytes
298 memset(&bPhysAddr, 0xff, sizeof (bPhysAddr));
300 DWORD dwRetVal = SendARP(host, src_ip, &bPhysAddr, &PhysAddrLen);
301 if (dwRetVal == NO_ERROR)
303 if (PhysAddrLen == 6)
305 mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X",
306 bPhysAddr[0], bPhysAddr[1], bPhysAddr[2],
307 bPhysAddr[3], bPhysAddr[4], bPhysAddr[5]);
311 CLog::Log(LOGERROR, "%s - SendArp completed successfully, but mac address has length != 6 (%d)", __FUNCTION__, PhysAddrLen);
314 CLog::Log(LOGERROR, "%s - SendArp failed with error (%d)", __FUNCTION__, dwRetVal);
319 std::vector<NetworkAccessPoint> CNetworkInterfaceWin32::GetAccessPoints(void)
321 std::vector<NetworkAccessPoint> result;
322 #ifdef HAS_WIN32_WLAN_API
326 // According to Mozilla: "We could be executing on either Windows XP or Windows
327 // Vista, so use the lower version of the client WLAN API. It seems that the
328 // negotiated version is the Vista version irrespective of what we pass!"
329 // http://dxr.mozilla.org/mozilla-central/source/netwerk/wifi/nsWifiScannerWin.cpp#l51
330 static const int xpWlanClientVersion = 1;
331 DWORD negotiated_version;
333 HANDLE wlan_handle = NULL;
335 // Get the handle to the WLAN API
336 dwResult = WlanOpenHandle(xpWlanClientVersion, NULL, &negotiated_version, &wlan_handle);
337 if (dwResult != ERROR_SUCCESS || !wlan_handle)
339 CLog::Log(LOGERROR, "Could not load the client WLAN API");
343 // Get the list of interfaces (WlanEnumInterfaces allocates interface_list)
344 WLAN_INTERFACE_INFO_LIST *interface_list = NULL;
345 dwResult = WlanEnumInterfaces(wlan_handle, NULL, &interface_list);
346 if (dwResult != ERROR_SUCCESS || !interface_list)
348 WlanCloseHandle(wlan_handle, NULL);
349 CLog::Log(LOGERROR, "Failed to get the list of interfaces");
353 for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i)
355 GUID guid = interface_list->InterfaceInfo[i].InterfaceGuid;
357 StringFromGUID2(guid, (LPOLESTR)&wcguid, 64);
358 CStdStringW strGuid = wcguid;
359 CStdStringW strAdaptername = m_adapter.AdapterName;
360 if (strGuid == strAdaptername)
362 WLAN_BSS_LIST *bss_list;
363 HRESULT rv = WlanGetNetworkBssList(wlan_handle,
364 &interface_list->InterfaceInfo[i].InterfaceGuid,
365 NULL, // Get all SSIDs
366 dot11_BSS_type_any, // unused
367 false, // bSecurityEnabled - unused
370 if (rv != ERROR_SUCCESS || !bss_list)
372 for (unsigned int j = 0; j < bss_list->dwNumberOfItems; ++j)
374 const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j];
375 // Add the access point info to the list of results
376 CStdString essId((char*)bss_entry.dot11Ssid.ucSSID, (unsigned int)bss_entry.dot11Ssid.uSSIDLength);
377 CStdString macAddress;
378 // macAddress is big-endian, write in byte chunks
379 macAddress = StringUtils::Format("%02x-%02x-%02x-%02x-%02x-%02x",
380 bss_entry.dot11Bssid[0], bss_entry.dot11Bssid[1], bss_entry.dot11Bssid[2],
381 bss_entry.dot11Bssid[3], bss_entry.dot11Bssid[4], bss_entry.dot11Bssid[5]);
382 int signalLevel = bss_entry.lRssi;
383 EncMode encryption = ENC_NONE; // TODO
384 int channel = NetworkAccessPoint::FreqToChannel((float)bss_entry.ulChCenterFrequency * 1000);
385 result.push_back(NetworkAccessPoint(essId, macAddress, signalLevel, encryption, channel));
387 WlanFreeMemory(bss_list);
392 // Free the interface list
393 WlanFreeMemory(interface_list);
396 WlanCloseHandle(wlan_handle, NULL);
403 void CNetworkInterfaceWin32::GetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
405 ipAddress = "0.0.0.0";
406 networkMask = "0.0.0.0";
407 defaultGateway = "0.0.0.0";
410 encryptionMode = ENC_NONE;
411 assignment = NETWORK_DISABLED;
414 PIP_ADAPTER_INFO adapterInfo;
415 PIP_ADAPTER_INFO adapter = NULL;
417 ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
419 adapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof (IP_ADAPTER_INFO));
420 if (adapterInfo == NULL)
423 if (GetAdaptersInfo(adapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
426 adapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
427 if (adapterInfo == NULL)
429 OutputDebugString("Error allocating memory needed to call GetAdaptersinfo\n");
434 if ((GetAdaptersInfo(adapterInfo, &ulOutBufLen)) == NO_ERROR)
436 adapter = adapterInfo;
439 if(m_adapter.Index == adapter->Index)
441 ipAddress = adapter->IpAddressList.IpAddress.String;
442 networkMask = adapter->IpAddressList.IpMask.String;
443 defaultGateway = adapter->GatewayList.IpAddress.String;
444 if (adapter->DhcpEnabled)
445 assignment = NETWORK_DHCP;
447 assignment = NETWORK_STATIC;
450 adapter = adapter->Next;
455 #ifdef HAS_WIN32_WLAN_API
458 HANDLE hClientHdl = NULL;
461 PWLAN_CONNECTION_ATTRIBUTES pAttributes;
464 if(WlanOpenHandle(1,NULL,&dwVersion, &hClientHdl) == ERROR_SUCCESS)
466 PWLAN_INTERFACE_INFO_LIST ppInterfaceList;
467 if(WlanEnumInterfaces(hClientHdl,NULL, &ppInterfaceList ) == ERROR_SUCCESS)
469 for(unsigned int i=0; i<ppInterfaceList->dwNumberOfItems;i++)
471 GUID guid = ppInterfaceList->InterfaceInfo[i].InterfaceGuid;
473 StringFromGUID2(guid, (LPOLESTR)&wcguid, 64);
474 CStdStringW strGuid = wcguid;
475 CStdStringW strAdaptername = m_adapter.AdapterName;
476 if( strGuid == strAdaptername)
478 if(WlanQueryInterface(hClientHdl,&ppInterfaceList->InterfaceInfo[i].InterfaceGuid,wlan_intf_opcode_current_connection, NULL, &dwSize, (PVOID*)&pAttributes, NULL ) == ERROR_SUCCESS)
480 essId = (char*)pAttributes->wlanAssociationAttributes.dot11Ssid.ucSSID;
481 if(pAttributes->wlanSecurityAttributes.bSecurityEnabled)
483 switch(pAttributes->wlanSecurityAttributes.dot11AuthAlgorithm)
485 case DOT11_AUTH_ALGO_80211_SHARED_KEY:
486 encryptionMode = ENC_WEP;
488 case DOT11_AUTH_ALGO_WPA:
489 case DOT11_AUTH_ALGO_WPA_PSK:
490 encryptionMode = ENC_WPA;
492 case DOT11_AUTH_ALGO_RSNA:
493 case DOT11_AUTH_ALGO_RSNA_PSK:
494 encryptionMode = ENC_WPA2;
497 WlanFreeMemory((PVOID*)&pAttributes);
500 OutputDebugString("Can't query wlan interface\n");
504 WlanCloseHandle(&hClientHdl, NULL);
507 OutputDebugString("Can't open wlan handle\n");
509 // Todo: get the key (WlanGetProfile, CryptUnprotectData?)
513 void CNetworkInterfaceWin32::SetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
518 void CNetworkInterfaceWin32::WriteSettings(FILE* fw, NetworkAssignment assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)