Home | History | Annotate | Download | only in cellular
      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