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 "shill/cellular/cellular_bearer.h"
18
19 #include <ModemManager/ModemManager.h>
20
21 #include <base/bind.h>
22
23 #include "shill/control_interface.h"
24 #include "shill/dbus_properties_proxy_interface.h"
25 #include "shill/logging.h"
26
27 using std::string;
28 using std::vector;
29
30 namespace shill {
31
32 namespace Logging {
33 static auto kModuleLogScope = ScopeLogger::kCellular;
ObjectID(const CellularBearer * c)34 static string ObjectID(const CellularBearer* c) { return "(cellular_bearer)"; }
35 }
36
37 namespace {
38
39 const char kPropertyAddress[] = "address";
40 const char kPropertyDNS1[] = "dns1";
41 const char kPropertyDNS2[] = "dns2";
42 const char kPropertyDNS3[] = "dns3";
43 const char kPropertyGateway[] = "gateway";
44 const char kPropertyMethod[] = "method";
45 const char kPropertyPrefix[] = "prefix";
46
ConvertMMBearerIPConfigMethod(uint32_t method)47 IPConfig::Method ConvertMMBearerIPConfigMethod(uint32_t method) {
48 switch (method) {
49 case MM_BEARER_IP_METHOD_PPP:
50 return IPConfig::kMethodPPP;
51 case MM_BEARER_IP_METHOD_STATIC:
52 return IPConfig::kMethodStatic;
53 case MM_BEARER_IP_METHOD_DHCP:
54 return IPConfig::kMethodDHCP;
55 default:
56 return IPConfig::kMethodUnknown;
57 }
58 }
59
60 } // namespace
61
CellularBearer(ControlInterface * control_interface,const string & dbus_path,const string & dbus_service)62 CellularBearer::CellularBearer(ControlInterface* control_interface,
63 const string& dbus_path,
64 const string& dbus_service)
65 : control_interface_(control_interface),
66 dbus_path_(dbus_path),
67 dbus_service_(dbus_service),
68 connected_(false),
69 ipv4_config_method_(IPConfig::kMethodUnknown),
70 ipv6_config_method_(IPConfig::kMethodUnknown) {
71 CHECK(control_interface_);
72 }
73
~CellularBearer()74 CellularBearer::~CellularBearer() {}
75
Init()76 bool CellularBearer::Init() {
77 SLOG(this, 3) << __func__ << ": path='" << dbus_path_
78 << "', service='" << dbus_service_ << "'";
79
80 dbus_properties_proxy_.reset(
81 control_interface_->CreateDBusPropertiesProxy(dbus_path_, dbus_service_));
82 // It is possible that ProxyFactory::CreateDBusPropertiesProxy() returns
83 // nullptr as the bearer DBus object may no longer exist.
84 if (!dbus_properties_proxy_) {
85 LOG(WARNING) << "Failed to create DBus properties proxy for bearer '"
86 << dbus_path_ << "'. Bearer is likely gone.";
87 return false;
88 }
89
90 dbus_properties_proxy_->set_properties_changed_callback(base::Bind(
91 &CellularBearer::OnPropertiesChanged, base::Unretained(this)));
92 UpdateProperties();
93 return true;
94 }
95
GetIPConfigMethodAndProperties(const KeyValueStore & properties,IPAddress::Family address_family,IPConfig::Method * ipconfig_method,std::unique_ptr<IPConfig::Properties> * ipconfig_properties) const96 void CellularBearer::GetIPConfigMethodAndProperties(
97 const KeyValueStore& properties,
98 IPAddress::Family address_family,
99 IPConfig::Method* ipconfig_method,
100 std::unique_ptr<IPConfig::Properties>* ipconfig_properties) const {
101 DCHECK(ipconfig_method);
102 DCHECK(ipconfig_properties);
103
104 uint32_t method = MM_BEARER_IP_METHOD_UNKNOWN;
105 if (properties.ContainsUint(kPropertyMethod)) {
106 method = properties.GetUint(kPropertyMethod);
107 } else {
108 SLOG(this, 2) << "Bearer '" << dbus_path_
109 << "' does not specify an IP configuration method.";
110 }
111
112 *ipconfig_method = ConvertMMBearerIPConfigMethod(method);
113 ipconfig_properties->reset();
114
115 if (*ipconfig_method != IPConfig::kMethodStatic)
116 return;
117
118 if (!properties.ContainsString(kPropertyAddress) ||
119 !properties.ContainsString(kPropertyGateway)) {
120 SLOG(this, 2) << "Bearer '" << dbus_path_
121 << "' static IP configuration does not specify valid "
122 "address/gateway information.";
123 *ipconfig_method = IPConfig::kMethodUnknown;
124 return;
125 }
126
127 ipconfig_properties->reset(new IPConfig::Properties);
128 (*ipconfig_properties)->address_family = address_family;
129 (*ipconfig_properties)->address = properties.GetString(kPropertyAddress);
130 (*ipconfig_properties)->gateway = properties.GetString(kPropertyGateway);
131
132 uint32_t prefix;
133 if (!properties.ContainsUint(kPropertyPrefix)) {
134 prefix = IPAddress::GetMaxPrefixLength(address_family);
135 } else {
136 prefix = properties.GetUint(kPropertyPrefix);
137 }
138 (*ipconfig_properties)->subnet_prefix = prefix;
139
140 if (properties.ContainsString(kPropertyDNS1)) {
141 (*ipconfig_properties)->dns_servers.push_back(
142 properties.GetString(kPropertyDNS1));
143 }
144 if (properties.ContainsString(kPropertyDNS2)) {
145 (*ipconfig_properties)->dns_servers.push_back(
146 properties.GetString(kPropertyDNS2));
147 }
148 if (properties.ContainsString(kPropertyDNS3)) {
149 (*ipconfig_properties)->dns_servers.push_back(
150 properties.GetString(kPropertyDNS3));
151 }
152 }
153
ResetProperties()154 void CellularBearer::ResetProperties() {
155 connected_ = false;
156 data_interface_.clear();
157 ipv4_config_method_ = IPConfig::kMethodUnknown;
158 ipv4_config_properties_.reset();
159 ipv6_config_method_ = IPConfig::kMethodUnknown;
160 ipv6_config_properties_.reset();
161 }
162
UpdateProperties()163 void CellularBearer::UpdateProperties() {
164 ResetProperties();
165
166 if (!dbus_properties_proxy_)
167 return;
168
169 KeyValueStore properties =
170 dbus_properties_proxy_->GetAll(MM_DBUS_INTERFACE_BEARER);
171 if (properties.IsEmpty()) {
172 LOG(WARNING) << "Could not get properties of bearer '" << dbus_path_
173 << "'. Bearer is likely gone and thus ignored.";
174 return;
175 }
176
177 OnPropertiesChanged(MM_DBUS_INTERFACE_BEARER,
178 properties,
179 vector<string>());
180 }
181
OnPropertiesChanged(const string & interface,const KeyValueStore & changed_properties,const vector<string> &)182 void CellularBearer::OnPropertiesChanged(
183 const string& interface,
184 const KeyValueStore& changed_properties,
185 const vector<string>& /*invalidated_properties*/) {
186 SLOG(this, 3) << __func__ << ": path=" << dbus_path_
187 << ", interface=" << interface;
188
189 if (interface != MM_DBUS_INTERFACE_BEARER)
190 return;
191
192 if (changed_properties.ContainsBool(MM_BEARER_PROPERTY_CONNECTED)) {
193 connected_ = changed_properties.GetBool(MM_BEARER_PROPERTY_CONNECTED);
194 }
195
196 string data_interface;
197 if (changed_properties.ContainsString(MM_BEARER_PROPERTY_INTERFACE)) {
198 data_interface_ =
199 changed_properties.GetString(MM_BEARER_PROPERTY_INTERFACE);
200 }
201
202 if (changed_properties.ContainsKeyValueStore(MM_BEARER_PROPERTY_IP4CONFIG)) {
203 KeyValueStore ipconfig =
204 changed_properties.GetKeyValueStore(MM_BEARER_PROPERTY_IP4CONFIG);
205 GetIPConfigMethodAndProperties(ipconfig,
206 IPAddress::kFamilyIPv4,
207 &ipv4_config_method_,
208 &ipv4_config_properties_);
209 }
210 if (changed_properties.ContainsKeyValueStore(MM_BEARER_PROPERTY_IP6CONFIG)) {
211 KeyValueStore ipconfig =
212 changed_properties.GetKeyValueStore(MM_BEARER_PROPERTY_IP6CONFIG);
213 GetIPConfigMethodAndProperties(ipconfig,
214 IPAddress::kFamilyIPv6,
215 &ipv6_config_method_,
216 &ipv6_config_properties_);
217 }
218 }
219
220 } // namespace shill
221