1 // 2 // Copyright (C) 2012 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 "shill/cellular/modem.h" 18 19 #include <base/bind.h> 20 #include <base/strings/stringprintf.h> 21 22 #include "shill/cellular/cellular.h" 23 #include "shill/control_interface.h" 24 #include "shill/logging.h" 25 #include "shill/manager.h" 26 #include "shill/net/rtnl_handler.h" 27 28 using base::Bind; 29 using base::Unretained; 30 using std::string; 31 using std::vector; 32 33 namespace shill { 34 35 namespace Logging { 36 static auto kModuleLogScope = ScopeLogger::kModem; 37 static string ObjectID(Modem* m) { return m->path().c_str(); } 38 } 39 40 // TODO(petkov): Consider generating these in mm/mm-modem.h. 41 const char Modem::kPropertyLinkName[] = "Device"; 42 const char Modem::kPropertyIPMethod[] = "IpMethod"; 43 const char Modem::kPropertyType[] = "Type"; 44 45 // statics 46 constexpr char Modem::kFakeDevNameFormat[]; 47 const char Modem::kFakeDevAddress[] = "000000000000"; 48 const int Modem::kFakeDevInterfaceIndex = -1; 49 size_t Modem::fake_dev_serial_ = 0; 50 51 Modem::Modem(const string& service, 52 const string& path, 53 ModemInfo* modem_info, 54 ControlInterface* control_interface) 55 : service_(service), 56 path_(path), 57 modem_info_(modem_info), 58 type_(Cellular::kTypeInvalid), 59 pending_device_info_(false), 60 rtnl_handler_(RTNLHandler::GetInstance()), 61 control_interface_(control_interface) { 62 LOG(INFO) << "Modem created: at " << path; 63 } 64 65 Modem::~Modem() { 66 LOG(INFO) << "Modem destructed: " << path_; 67 if (device_) { 68 device_->DestroyService(); 69 modem_info_->manager()->device_info()->DeregisterDevice(device_); 70 } 71 } 72 73 void Modem::Init() { 74 dbus_properties_proxy_.reset( 75 control_interface_->CreateDBusPropertiesProxy(path(), service())); 76 dbus_properties_proxy_->set_modem_manager_properties_changed_callback( 77 Bind(&Modem::OnModemManagerPropertiesChanged, Unretained(this))); 78 dbus_properties_proxy_->set_properties_changed_callback( 79 Bind(&Modem::OnPropertiesChanged, Unretained(this))); 80 } 81 82 void Modem::OnDeviceInfoAvailable(const string& link_name) { 83 SLOG(this, 2) << __func__; 84 if (pending_device_info_ && link_name_ == link_name) { 85 // pending_device_info_ is only set if we've already been through 86 // CreateDeviceFromModemProperties() and saved our initial 87 // properties already 88 pending_device_info_ = false; 89 CreateDeviceFromModemProperties(initial_properties_); 90 } 91 } 92 93 Cellular* Modem::ConstructCellular(const string& link_name, 94 const string& address, 95 int interface_index) { 96 LOG(INFO) << "Creating a cellular device on link " << link_name 97 << " interface index " << interface_index << "."; 98 return new Cellular(modem_info_, 99 link_name, 100 address, 101 interface_index, 102 type_, 103 service_, 104 path_); 105 } 106 107 void Modem::CreateDeviceFromModemProperties( 108 const InterfaceToProperties& properties) { 109 SLOG(this, 2) << __func__; 110 111 if (device_.get()) { 112 return; 113 } 114 115 InterfaceToProperties::const_iterator properties_it = 116 properties.find(GetModemInterface()); 117 if (properties_it == properties.end()) { 118 LOG(ERROR) << "Unable to find modem interface properties."; 119 return; 120 } 121 122 string mac_address; 123 int interface_index = -1; 124 if (GetLinkName(properties_it->second, &link_name_)) { 125 GetDeviceParams(&mac_address, &interface_index); 126 if (interface_index < 0) { 127 LOG(ERROR) << "Unable to create cellular device -- no interface index."; 128 return; 129 } 130 if (mac_address.empty()) { 131 // Save our properties, wait for OnDeviceInfoAvailable to be called. 132 LOG(WARNING) 133 << "No hardware address, device creation pending device info."; 134 initial_properties_ = properties; 135 pending_device_info_ = true; 136 return; 137 } 138 // Got the interface index and MAC address. Fall-through to actually 139 // creating the Cellular object. 140 } else { 141 // Probably a PPP dongle. 142 LOG(INFO) << "Cellular device without link name; assuming PPP dongle."; 143 link_name_ = base::StringPrintf(kFakeDevNameFormat, fake_dev_serial_++); 144 mac_address = kFakeDevAddress; 145 interface_index = kFakeDevInterfaceIndex; 146 } 147 148 if (modem_info_->manager()->device_info()->IsDeviceBlackListed(link_name_)) { 149 LOG(INFO) << "Not creating cellular device for blacklisted interface " 150 << link_name_ << "."; 151 return; 152 } 153 154 device_ = ConstructCellular(link_name_, mac_address, interface_index); 155 // Give the device a chance to extract any capability-specific properties. 156 for (properties_it = properties.begin(); properties_it != properties.end(); 157 ++properties_it) { 158 device_->OnPropertiesChanged( 159 properties_it->first, properties_it->second, vector<string>()); 160 } 161 162 modem_info_->manager()->device_info()->RegisterDevice(device_); 163 } 164 165 bool Modem::GetDeviceParams(string* mac_address, int* interface_index) { 166 // TODO(petkov): Get the interface index from DeviceInfo, similar to the MAC 167 // address below. 168 *interface_index = rtnl_handler_->GetInterfaceIndex(link_name_); 169 if (*interface_index < 0) { 170 return false; 171 } 172 173 ByteString address_bytes; 174 if (!modem_info_->manager()->device_info()->GetMACAddress(*interface_index, 175 &address_bytes)) { 176 return false; 177 } 178 179 *mac_address = address_bytes.HexEncode(); 180 return true; 181 } 182 183 void Modem::OnPropertiesChanged( 184 const string& interface, 185 const KeyValueStore& changed_properties, 186 const vector<string>& invalidated_properties) { 187 SLOG(this, 2) << __func__; 188 SLOG(this, 3) << "PropertiesChanged signal received."; 189 if (device_.get()) { 190 device_->OnPropertiesChanged(interface, 191 changed_properties, 192 invalidated_properties); 193 } 194 } 195 196 void Modem::OnModemManagerPropertiesChanged( 197 const string& interface, 198 const KeyValueStore& properties) { 199 vector<string> invalidated_properties; 200 OnPropertiesChanged(interface, properties, invalidated_properties); 201 } 202 203 } // namespace shill 204