OLD | NEW |
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/media/router/discovery/discovery_network_list.h" | 5 #include "chrome/browser/media/router/discovery/discovery_network_list.h" |
6 | 6 |
7 // TODO(btolsch): Implement this for Windows. | 7 #include <winsock2.h> |
| 8 #include <ws2tcpip.h> |
| 9 |
| 10 #include <iphlpapi.h> // NOLINT |
| 11 |
| 12 #include <windot11.h> // NOLINT |
| 13 #include <wlanapi.h> // NOLINT |
| 14 |
| 15 #include <algorithm> |
| 16 #include <utility> |
| 17 #include <vector> |
| 18 |
| 19 #include "base/memory/ptr_util.h" |
| 20 #include "base/strings/string_number_conversions.h" |
| 21 |
| 22 namespace { |
| 23 |
| 24 void IfTable2Deleter(PMIB_IF_TABLE2 interface_table) { |
| 25 if (interface_table) { |
| 26 FreeMibTable(interface_table); |
| 27 } |
| 28 } |
| 29 |
| 30 void WlanApiDeleter(void* p) { |
| 31 if (p) { |
| 32 WlanFreeMemory(p); |
| 33 } |
| 34 } |
| 35 |
| 36 struct MAC { |
| 37 MAC() : data{} {} |
| 38 MAC(const uint8_t* src, ULONG length) : data{} { assign(src, length); } |
| 39 void assign(const uint8_t* src, ULONG length) { |
| 40 DCHECK_LE(length, 6UL); |
| 41 memcpy(data, src, length); |
| 42 } |
| 43 bool operator==(const MAC& o) const { return memcmp(o.data, data, 6) == 0; } |
| 44 uint8_t data[6]; |
| 45 }; |
| 46 |
| 47 std::vector<std::pair<GUID, MAC>> GetInterfaceGuidMap() { |
| 48 PMIB_IF_TABLE2 interface_table_raw = nullptr; |
| 49 auto result = GetIfTable2(&interface_table_raw); |
| 50 if (result != ERROR_SUCCESS) { |
| 51 DVLOG(2) << "GetIfTable2() failed"; |
| 52 return {}; |
| 53 } |
| 54 auto interface_table = |
| 55 std::unique_ptr<MIB_IF_TABLE2, decltype(&IfTable2Deleter)>( |
| 56 interface_table_raw, IfTable2Deleter); |
| 57 |
| 58 std::vector<std::pair<GUID, MAC>> guid_map; |
| 59 guid_map.reserve(interface_table->NumEntries); |
| 60 for (ULONG i = 0; i < interface_table->NumEntries; ++i) { |
| 61 const auto* interface_row = &interface_table->Table[i]; |
| 62 guid_map.push_back( |
| 63 std::make_pair(interface_row->InterfaceGuid, |
| 64 MAC{interface_row->PhysicalAddress, |
| 65 interface_row->PhysicalAddressLength})); |
| 66 } |
| 67 |
| 68 return guid_map; |
| 69 } |
| 70 |
| 71 std::vector<std::pair<MAC, std::string>> GetConnectionInfo() { |
| 72 HANDLE client_handle = nullptr; |
| 73 constexpr DWORD client_version = 2; |
| 74 DWORD current_version = 0; |
| 75 |
| 76 auto result = |
| 77 WlanOpenHandle(client_version, nullptr, ¤t_version, &client_handle); |
| 78 if (result != ERROR_SUCCESS) { |
| 79 DVLOG(2) << "Failed to open Wlan client handle"; |
| 80 return {}; |
| 81 } |
| 82 |
| 83 PWLAN_INTERFACE_INFO_LIST wlan_interface_list_raw = nullptr; |
| 84 result = WlanEnumInterfaces(client_handle, nullptr, &wlan_interface_list_raw); |
| 85 if (result != ERROR_SUCCESS) { |
| 86 DVLOG(2) << "Failed to enumerate wireless interfaces"; |
| 87 return {}; |
| 88 } |
| 89 auto wlan_interface_list = |
| 90 std::unique_ptr<WLAN_INTERFACE_INFO_LIST, decltype(&WlanApiDeleter)>( |
| 91 wlan_interface_list_raw, WlanApiDeleter); |
| 92 |
| 93 auto guid_mac_map = GetInterfaceGuidMap(); |
| 94 |
| 95 std::vector<std::pair<MAC, std::string>> mac_ssid_map; |
| 96 for (DWORD i = 0; i < wlan_interface_list->dwNumberOfItems; ++i) { |
| 97 const auto* interface_info = &wlan_interface_list->InterfaceInfo[i]; |
| 98 MAC interface_mac; |
| 99 bool found_mac = false; |
| 100 for (const auto& guid_entry : guid_mac_map) { |
| 101 if (guid_entry.first == interface_info->InterfaceGuid) { |
| 102 interface_mac = guid_entry.second; |
| 103 found_mac = true; |
| 104 break; |
| 105 } |
| 106 } |
| 107 if (!found_mac) { |
| 108 continue; |
| 109 } |
| 110 |
| 111 WLAN_CONNECTION_ATTRIBUTES* connection_info = nullptr; |
| 112 DWORD connection_info_size = 0; |
| 113 result = WlanQueryInterface( |
| 114 client_handle, &interface_info->InterfaceGuid, |
| 115 wlan_intf_opcode_current_connection, nullptr, &connection_info_size, |
| 116 reinterpret_cast<void**>(&connection_info), nullptr); |
| 117 if (result != ERROR_SUCCESS) { |
| 118 // We can't get the SSID for this interface so its network ID will |
| 119 // fall back to its MAC address below. |
| 120 DVLOG(2) << "Failed to get wireless connection info"; |
| 121 continue; |
| 122 } |
| 123 auto connection_attributes = |
| 124 std::unique_ptr<WLAN_CONNECTION_ATTRIBUTES, decltype(&WlanApiDeleter)>( |
| 125 connection_info, WlanApiDeleter); |
| 126 const auto* ssid = |
| 127 &connection_attributes->wlanAssociationAttributes.dot11Ssid; |
| 128 mac_ssid_map.push_back(std::make_pair( |
| 129 interface_mac, |
| 130 std::string(reinterpret_cast<const char*>(&ssid->ucSSID[0]), |
| 131 ssid->uSSIDLength))); |
| 132 } |
| 133 return mac_ssid_map; |
| 134 } |
| 135 |
| 136 } // namespace |
| 137 |
8 std::vector<DiscoveryNetworkInfo> GetDiscoveryNetworkInfoList() { | 138 std::vector<DiscoveryNetworkInfo> GetDiscoveryNetworkInfoList() { |
9 return std::vector<DiscoveryNetworkInfo>(); | 139 // Max number of times to retry GetAdaptersAddresses due to |
10 } | 140 // ERROR_BUFFER_OVERFLOW. If GetAdaptersAddresses returns this indefinitely |
| 141 // due to an unforseen reason, we don't want to be stuck in an endless loop. |
| 142 static constexpr int kMaxGetAdaptersAddressTries = 10; |
| 143 // Use an initial buffer size of 15KB, as recommended by MSDN. See: |
| 144 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).
aspx |
| 145 static constexpr int kInitialBufferSize = 15000; |
| 146 constexpr ULONG address_flags = // TODO: include all interfaces flag? |
| 147 GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | |
| 148 GAA_FLAG_SKIP_DNS_SERVER; |
| 149 std::vector<DiscoveryNetworkInfo> network_ids; |
| 150 |
| 151 ULONG addresses_buffer_size = kInitialBufferSize; |
| 152 char initial_buf[kInitialBufferSize]; |
| 153 std::unique_ptr<char[]> addresses_buffer; |
| 154 |
| 155 PIP_ADAPTER_ADDRESSES adapter_addresses = |
| 156 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(initial_buf); |
| 157 auto result = GetAdaptersAddresses(AF_UNSPEC, address_flags, nullptr, |
| 158 adapter_addresses, &addresses_buffer_size); |
| 159 |
| 160 for (int i = 1; |
| 161 result == ERROR_BUFFER_OVERFLOW && i < kMaxGetAdaptersAddressTries; |
| 162 ++i) { |
| 163 addresses_buffer.reset(new char[addresses_buffer_size]); |
| 164 adapter_addresses = |
| 165 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(addresses_buffer.get()); |
| 166 result = GetAdaptersAddresses(AF_UNSPEC, address_flags, nullptr, |
| 167 adapter_addresses, &addresses_buffer_size); |
| 168 } |
| 169 |
| 170 if (result != NO_ERROR) { |
| 171 return std::vector<DiscoveryNetworkInfo>(); |
| 172 } |
| 173 |
| 174 auto mac_ssid_map = GetConnectionInfo(); |
| 175 for (const IP_ADAPTER_ADDRESSES* current_adapter = adapter_addresses; |
| 176 current_adapter != nullptr; current_adapter = current_adapter->Next) { |
| 177 if (current_adapter->OperStatus != IfOperStatusUp || |
| 178 (current_adapter->IfType != IF_TYPE_ETHERNET_CSMACD && |
| 179 current_adapter->IfType != IF_TYPE_IEEE80211)) { |
| 180 continue; |
| 181 } |
| 182 std::string name(current_adapter->AdapterName); |
| 183 // We have to use a slightly roundabout way to get the SSID for each |
| 184 // adapter: |
| 185 // - Enumerate wifi devices to get list of interface GUIDs. |
| 186 // - Enumerate interfaces to get interface GUID -> physical address map. |
| 187 // - Map interface GUIDs to SSID. |
| 188 // - Use GUID -> MAC map to do MAC -> interface GUID -> SSID. |
| 189 // Although it's theoretically possible to have multiple interfaces per |
| 190 // adapter, most wireless cards don't actually allow multiple |
| 191 // managed-mode interfaces. However, in the event that there really |
| 192 // are multiple interfaces per adapter, we will simply choose the first |
| 193 // one in this list. |
| 194 if (current_adapter->IfType == IF_TYPE_IEEE80211) { |
| 195 MAC adapter_mac(current_adapter->PhysicalAddress, |
| 196 current_adapter->PhysicalAddressLength); |
| 197 bool found_ssid = false; |
| 198 for (const auto& ssid_entry : mac_ssid_map) { |
| 199 if (ssid_entry.first == adapter_mac) { |
| 200 network_ids.push_back({name, ssid_entry.second}); |
| 201 found_ssid = true; |
| 202 break; |
| 203 } |
| 204 } |
| 205 if (found_ssid) { |
| 206 continue; |
| 207 } |
| 208 } |
| 209 network_ids.push_back( |
| 210 {name, base::HexEncode(current_adapter->PhysicalAddress, |
| 211 current_adapter->PhysicalAddressLength)}); |
| 212 } |
| 213 |
| 214 StableSortDiscoveryNetworkInfo(network_ids.begin(), network_ids.end()); |
| 215 |
| 216 return network_ids; |
| 217 } |
OLD | NEW |