device_info.cc revision 326b6cfba5ab73c9e41a7585d1bc95871631122a
1// 2// Copyright (C) 2014 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "apmanager/device_info.h" 18 19#include <linux/rtnetlink.h> 20 21#include <string> 22 23#include <base/bind.h> 24#include <base/files/file_util.h> 25#include <base/logging.h> 26#include <shill/net/ndisc.h> 27#include <shill/net/netlink_attribute.h> 28#include <shill/net/netlink_manager.h> 29#include <shill/net/nl80211_message.h> 30#include <shill/net/rtnl_handler.h> 31#include <shill/net/rtnl_listener.h> 32#include <shill/net/rtnl_message.h> 33 34#include "apmanager/manager.h" 35 36using base::Bind; 37using shill::ByteString; 38using shill::NetlinkManager; 39using shill::NetlinkMessage; 40using shill::Nl80211Message; 41using shill::RTNLHandler; 42using shill::RTNLMessage; 43using shill::RTNLListener; 44using std::map; 45using std::string; 46 47namespace apmanager { 48 49const char DeviceInfo::kDeviceInfoRoot[] = "/sys/class/net"; 50const char DeviceInfo::kInterfaceUevent[] = "uevent"; 51const char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n"; 52 53DeviceInfo::DeviceInfo(Manager* manager) 54 : link_callback_(Bind(&DeviceInfo::LinkMsgHandler, Unretained(this))), 55 device_info_root_(kDeviceInfoRoot), 56 manager_(manager), 57 netlink_manager_(NetlinkManager::GetInstance()), 58 rtnl_handler_(RTNLHandler::GetInstance()) { 59} 60 61DeviceInfo::~DeviceInfo() {} 62 63void DeviceInfo::Start() { 64 // Start netlink manager. 65 netlink_manager_->Init(); 66 uint16_t nl80211_family_id = netlink_manager_->GetFamily( 67 Nl80211Message::kMessageTypeString, 68 Bind(&Nl80211Message::CreateMessage)); 69 if (nl80211_family_id == NetlinkMessage::kIllegalMessageType) { 70 LOG(FATAL) << "Didn't get a legal message type for 'nl80211' messages."; 71 } 72 Nl80211Message::SetMessageType(nl80211_family_id); 73 netlink_manager_->Start(); 74 75 // Start enumerating WiFi devices (PHYs). 76 EnumerateDevices(); 77 78 // Start RTNL for monitoring network interfaces. 79 rtnl_handler_->Start(RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | 80 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE | 81 RTMGRP_ND_USEROPT); 82 link_listener_.reset( 83 new RTNLListener(RTNLHandler::kRequestLink, link_callback_)); 84 // Request link infos. 85 rtnl_handler_->RequestDump(RTNLHandler::kRequestLink); 86} 87 88void DeviceInfo::Stop() { 89 link_listener_.reset(); 90} 91 92void DeviceInfo::EnumerateDevices() { 93 shill::GetWiphyMessage get_wiphy; 94 get_wiphy.attributes()->SetFlagAttributeValue(NL80211_ATTR_SPLIT_WIPHY_DUMP, 95 true); 96 get_wiphy.AddFlag(NLM_F_DUMP); 97 netlink_manager_->SendNl80211Message( 98 &get_wiphy, 99 Bind(&DeviceInfo::OnWiFiPhyInfoReceived, AsWeakPtr()), 100 Bind(&NetlinkManager::OnAckDoNothing), 101 Bind(&NetlinkManager::OnNetlinkMessageError)); 102} 103 104void DeviceInfo::OnWiFiPhyInfoReceived(const shill::Nl80211Message& msg) { 105 // Verify NL80211_CMD_NEW_WIPHY. 106 if (msg.command() != shill::NewWiphyMessage::kCommand) { 107 LOG(ERROR) << "Received unexpected command:" 108 << msg.command(); 109 return; 110 } 111 112 string device_name; 113 if (!msg.const_attributes()->GetStringAttributeValue(NL80211_ATTR_WIPHY_NAME, 114 &device_name)) { 115 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME"; 116 return; 117 } 118 119 if (GetDevice(device_name)) { 120 LOG(INFO) << "Device " << device_name << " already enumerated."; 121 return; 122 } 123 124 scoped_refptr<Device> device = new Device(manager_, device_name); 125 device->ParseWiphyCapability(msg); 126 127 // Register device 128 RegisterDevice(device); 129} 130 131void DeviceInfo::LinkMsgHandler(const RTNLMessage& msg) { 132 DCHECK(msg.type() == RTNLMessage::kTypeLink); 133 134 // Get interface name. 135 if (!msg.HasAttribute(IFLA_IFNAME)) { 136 LOG(ERROR) << "Link event message does not have IFLA_IFNAME!"; 137 return; 138 } 139 ByteString b(msg.GetAttribute(IFLA_IFNAME)); 140 string iface_name(reinterpret_cast<const char*>(b.GetConstData())); 141 142 int dev_index = msg.interface_index(); 143 if (msg.mode() == RTNLMessage::kModeAdd) { 144 AddLinkMsgHandler(iface_name, dev_index); 145 } else if (msg.mode() == RTNLMessage::kModeDelete) { 146 DelLinkMsgHandler(iface_name, dev_index); 147 } else { 148 NOTREACHED(); 149 } 150} 151 152void DeviceInfo::AddLinkMsgHandler(const string& iface_name, int iface_index) { 153 // Ignore non-wifi interfaces. 154 if (!IsWifiInterface(iface_name)) { 155 LOG(INFO) << "Ignore link event for non-wifi interface: " << iface_name; 156 return; 157 } 158 159 // Return if interface already existed. Could receive multiple add link event 160 // for a single interface. 161 if (interface_infos_.find(iface_index) != interface_infos_.end()) { 162 LOG(INFO) << "AddLinkMsgHandler: interface " << iface_name 163 << " is already added"; 164 return; 165 } 166 167 // Add interface. 168 Device::WiFiInterface wifi_interface; 169 wifi_interface.iface_name = iface_name; 170 wifi_interface.iface_index = iface_index; 171 interface_infos_[iface_index] = wifi_interface; 172 173 // Get interface info. 174 GetWiFiInterfaceInfo(iface_index); 175} 176 177void DeviceInfo::DelLinkMsgHandler(const string& iface_name, int iface_index) { 178 LOG(INFO) << "DelLinkMsgHandler iface_name: " << iface_name 179 << "iface_index: " << iface_index; 180 map<uint32_t, Device::WiFiInterface>::iterator iter = 181 interface_infos_.find(iface_index); 182 if (iter != interface_infos_.end()) { 183 // Deregister interface from the Device. 184 scoped_refptr<Device> device = GetDevice(iter->second.device_name); 185 if (device) { 186 device->DeregisterInterface(iter->second); 187 } 188 interface_infos_.erase(iter); 189 } 190} 191 192bool DeviceInfo::IsWifiInterface(const string& iface_name) { 193 string contents; 194 if (!GetDeviceInfoContents(iface_name, kInterfaceUevent, &contents)) { 195 LOG(INFO) << "Interface " << iface_name << " has no uevent file"; 196 return false; 197 } 198 199 if (contents.find(kInterfaceUeventWifiSignature) == string::npos) { 200 LOG(INFO) << "Interface " << iface_name << " is not a WiFi interface"; 201 return false; 202 } 203 204 return true; 205} 206 207bool DeviceInfo::GetDeviceInfoContents(const string& iface_name, 208 const string& path_name, 209 string* contents_out) { 210 return base::ReadFileToString( 211 device_info_root_.Append(iface_name).Append(path_name), 212 contents_out); 213} 214 215void DeviceInfo::GetWiFiInterfaceInfo(int interface_index) { 216 shill::GetInterfaceMessage msg; 217 if (!msg.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX, 218 interface_index)) { 219 LOG(ERROR) << "Unable to set interface index attribute for " 220 "GetInterface message. Interface type cannot be " 221 "determined!"; 222 return; 223 } 224 225 netlink_manager_->SendNl80211Message( 226 &msg, 227 Bind(&DeviceInfo::OnWiFiInterfaceInfoReceived, AsWeakPtr()), 228 Bind(&NetlinkManager::OnAckDoNothing), 229 Bind(&NetlinkManager::OnNetlinkMessageError)); 230} 231 232void DeviceInfo::OnWiFiInterfaceInfoReceived(const shill::Nl80211Message& msg) { 233 if (msg.command() != NL80211_CMD_NEW_INTERFACE) { 234 LOG(ERROR) << "Message is not a new interface response"; 235 return; 236 } 237 238 uint32_t interface_index; 239 if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX, 240 &interface_index)) { 241 LOG(ERROR) << "Message contains no interface index"; 242 return; 243 } 244 uint32_t interface_type; 245 if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFTYPE, 246 &interface_type)) { 247 LOG(ERROR) << "Message contains no interface type"; 248 return; 249 } 250 251 map<uint32_t, Device::WiFiInterface>::iterator iter = 252 interface_infos_.find(interface_index); 253 if (iter == interface_infos_.end()) { 254 LOG(ERROR) << "Receive WiFi interface info for non-exist interface: " 255 << interface_index; 256 return; 257 } 258 iter->second.iface_type = interface_type; 259 260 // Request PHY info, to know which Device to register this interface to. 261 GetWiFiInterfacePhyInfo(interface_index); 262} 263 264void DeviceInfo::GetWiFiInterfacePhyInfo(uint32_t iface_index) { 265 shill::GetWiphyMessage get_wiphy; 266 get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX, 267 iface_index); 268 netlink_manager_->SendNl80211Message( 269 &get_wiphy, 270 Bind(&DeviceInfo::OnWiFiInterfacePhyInfoReceived, 271 AsWeakPtr(), 272 iface_index), 273 Bind(&NetlinkManager::OnAckDoNothing), 274 Bind(&NetlinkManager::OnNetlinkMessageError)); 275} 276 277void DeviceInfo::OnWiFiInterfacePhyInfoReceived( 278 uint32_t iface_index, const shill::Nl80211Message& msg) { 279 // Verify NL80211_CMD_NEW_WIPHY. 280 if (msg.command() != shill::NewWiphyMessage::kCommand) { 281 LOG(ERROR) << "Received unexpected command:" 282 << msg.command(); 283 return; 284 } 285 286 map<uint32_t, Device::WiFiInterface>::iterator iter = 287 interface_infos_.find(iface_index); 288 if (iter == interface_infos_.end()) { 289 // Interface is gone by the time we received its PHY info. 290 LOG(ERROR) << "Interface [" << iface_index 291 << "] is deleted when PHY info is received"; 292 return; 293 } 294 295 string device_name; 296 if (!msg.const_attributes()->GetStringAttributeValue(NL80211_ATTR_WIPHY_NAME, 297 &device_name)) { 298 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME"; 299 return; 300 } 301 302 scoped_refptr<Device> device = GetDevice(device_name); 303 // Create device if it is not enumerated yet. 304 if (!device) { 305 device = new Device(manager_, device_name); 306 device->ParseWiphyCapability(msg); 307 308 // Register device 309 RegisterDevice(device); 310 } 311 iter->second.device_name = device_name; 312 313 device->RegisterInterface(iter->second); 314} 315 316void DeviceInfo::RegisterDevice(scoped_refptr<Device> device) { 317 if (!device) { 318 return; 319 } 320 devices_[device->GetDeviceName()] = device; 321 // Register device with manager. 322 manager_->RegisterDevice(device); 323} 324 325scoped_refptr<Device> DeviceInfo::GetDevice(const string& device_name) { 326 map<string, scoped_refptr<Device>>::iterator iter = 327 devices_.find(device_name); 328 if (iter == devices_.end()) { 329 return nullptr; 330 } 331 return iter->second; 332} 333 334} // namespace apmanager 335