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