blob: 45c971a9c1f2ceb5da07bacd3168f305857dda18 [file] [log] [blame]
Jay Srinivasan43488792012-06-19 00:25:31 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Jay Srinivasan43488792012-06-19 00:25:31 -07005#include "update_engine/connection_manager.h"
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07006
7#include <string>
8
Jay Srinivasan43488792012-06-19 00:25:31 -07009#include <base/stl_util.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070010#include <base/strings/string_util.h>
Jay Srinivasan43488792012-06-19 00:25:31 -070011#include <chromeos/dbus/service_constants.h>
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070012#include <dbus/dbus-glib.h>
13#include <glib.h>
Gilad Arnold1f847232014-04-07 12:07:49 -070014#include <policy/device_policy.h>
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070015
Alex Deymof4867c42013-06-28 14:41:39 -070016#include "update_engine/prefs.h"
Jay Srinivasan43488792012-06-19 00:25:31 -070017#include "update_engine/system_state.h"
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070018#include "update_engine/utils.h"
19
Jay Srinivasan43488792012-06-19 00:25:31 -070020using std::set;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070021using std::string;
22
23namespace chromeos_update_engine {
24
25namespace {
26
27// Gets the DbusGProxy for FlimFlam. Must be free'd with ProxyUnref()
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080028bool GetFlimFlamProxy(DBusWrapperInterface* dbus_iface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070029 const char* path,
30 const char* interface,
31 DBusGProxy** out_proxy) {
32 DBusGConnection* bus;
33 DBusGProxy* proxy;
34 GError* error = NULL;
35
36 bus = dbus_iface->BusGet(DBUS_BUS_SYSTEM, &error);
37 if (!bus) {
38 LOG(ERROR) << "Failed to get system bus";
39 return false;
40 }
Gilad Arnoldb752fb32014-03-03 12:23:39 -080041 proxy = dbus_iface->ProxyNewForName(bus, shill::kFlimflamServiceName, path,
42 interface);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070043 *out_proxy = proxy;
44 return true;
45}
46
47// On success, caller owns the GHashTable at out_hash_table.
48// Returns true on success.
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080049bool GetProperties(DBusWrapperInterface* dbus_iface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070050 const char* path,
51 const char* interface,
52 GHashTable** out_hash_table) {
53 DBusGProxy* proxy;
54 GError* error = NULL;
55
56 TEST_AND_RETURN_FALSE(GetFlimFlamProxy(dbus_iface,
57 path,
58 interface,
59 &proxy));
60
Gilad Arnoldb752fb32014-03-03 12:23:39 -080061 gboolean rc = dbus_iface->ProxyCall_0_1(proxy,
62 "GetProperties",
63 &error,
64 out_hash_table);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070065 dbus_iface->ProxyUnref(proxy);
66 if (rc == FALSE) {
67 LOG(ERROR) << "dbus_g_proxy_call failed";
68 return false;
69 }
70
71 return true;
72}
73
74// Returns (via out_path) the default network path, or empty string if
75// there's no network up.
76// Returns true on success.
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080077bool GetDefaultServicePath(DBusWrapperInterface* dbus_iface, string* out_path) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070078 GHashTable* hash_table = NULL;
79
80 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
Ben Chanc6007e42013-09-19 23:49:22 -070081 shill::kFlimflamServicePath,
82 shill::kFlimflamManagerInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070083 &hash_table));
84
85 GValue* value = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table,
86 "Services"));
87 GArray* array = NULL;
88 bool success = false;
mukesh agrawal88226ff2012-03-19 17:50:06 -070089 if (G_VALUE_HOLDS(value, DBUS_TYPE_G_OBJECT_PATH_ARRAY) &&
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070090 (array = reinterpret_cast<GArray*>(g_value_get_boxed(value))) &&
91 (array->len > 0)) {
92 *out_path = g_array_index(array, const char*, 0);
93 success = true;
94 }
mukesh agrawal88226ff2012-03-19 17:50:06 -070095
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070096 g_hash_table_unref(hash_table);
97 return success;
98}
99
100NetworkConnectionType ParseConnectionType(const char* type_str) {
Ben Chanc6007e42013-09-19 23:49:22 -0700101 if (!strcmp(type_str, shill::kTypeEthernet)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700102 return kNetEthernet;
Ben Chanc6007e42013-09-19 23:49:22 -0700103 } else if (!strcmp(type_str, shill::kTypeWifi)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700104 return kNetWifi;
Ben Chanc6007e42013-09-19 23:49:22 -0700105 } else if (!strcmp(type_str, shill::kTypeWimax)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700106 return kNetWimax;
Ben Chanc6007e42013-09-19 23:49:22 -0700107 } else if (!strcmp(type_str, shill::kTypeBluetooth)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700108 return kNetBluetooth;
Ben Chanc6007e42013-09-19 23:49:22 -0700109 } else if (!strcmp(type_str, shill::kTypeCellular)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700110 return kNetCellular;
111 }
112 return kNetUnknown;
113}
114
Alex Deymo6ae91202014-03-10 19:21:25 -0700115NetworkTethering ParseTethering(const char* tethering_str) {
116 if (!strcmp(tethering_str, shill::kTetheringNotDetectedState)) {
117 return NetworkTethering::kNotDetected;
118 } else if (!strcmp(tethering_str, shill::kTetheringSuspectedState)) {
119 return NetworkTethering::kSuspected;
120 } else if (!strcmp(tethering_str, shill::kTetheringConfirmedState)) {
121 return NetworkTethering::kConfirmed;
122 }
123 LOG(WARNING) << "Unknown Tethering value: " << tethering_str;
124 return NetworkTethering::kUnknown;
125}
126
127bool GetServicePathProperties(DBusWrapperInterface* dbus_iface,
128 const string& path,
129 NetworkConnectionType* out_type,
130 NetworkTethering* out_tethering) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700131 GHashTable* hash_table = NULL;
132
133 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
134 path.c_str(),
Ben Chanc6007e42013-09-19 23:49:22 -0700135 shill::kFlimflamServiceInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700136 &hash_table));
137
Alex Deymo6ae91202014-03-10 19:21:25 -0700138 // Populate the out_tethering.
Alex Deymo1c4e6382013-07-15 12:09:51 -0700139 GValue* value = (GValue*)g_hash_table_lookup(hash_table,
Alex Deymo6ae91202014-03-10 19:21:25 -0700140 shill::kTetheringProperty);
141 const char* tethering_str = NULL;
142
143 if (value != NULL)
144 tethering_str = g_value_get_string(value);
145 if (tethering_str != NULL) {
146 *out_tethering = ParseTethering(tethering_str);
147 } else {
148 // Set to Unknown if not present.
149 *out_tethering = NetworkTethering::kUnknown;
150 }
151
152 // Populate the out_type property.
153 value = (GValue*)g_hash_table_lookup(hash_table,
154 shill::kTypeProperty);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700155 const char* type_str = NULL;
156 bool success = false;
157 if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700158 success = true;
Ben Chanc6007e42013-09-19 23:49:22 -0700159 if (!strcmp(type_str, shill::kTypeVPN)) {
Alex Deymo1c4e6382013-07-15 12:09:51 -0700160 value = (GValue*)g_hash_table_lookup(hash_table,
161 shill::kPhysicalTechnologyProperty);
162 if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
163 *out_type = ParseConnectionType(type_str);
164 } else {
165 LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
166 << " connection (service: " << path << "). Returning default"
167 << " kNetUnknown value.";
168 *out_type = kNetUnknown;
169 }
170 } else {
171 *out_type = ParseConnectionType(type_str);
172 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700173 }
174 g_hash_table_unref(hash_table);
175 return success;
176}
177
178} // namespace {}
179
Jay Srinivasan43488792012-06-19 00:25:31 -0700180ConnectionManager::ConnectionManager(SystemState *system_state)
181 : system_state_(system_state) {}
182
Alex Deymo6ae91202014-03-10 19:21:25 -0700183bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type,
184 NetworkTethering tethering) const {
Jay Srinivasan43488792012-06-19 00:25:31 -0700185 switch (type) {
186 case kNetBluetooth:
187 return false;
188
189 case kNetCellular: {
190 set<string> allowed_types;
191 const policy::DevicePolicy* device_policy =
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800192 system_state_->device_policy();
Alex Deymof4867c42013-06-28 14:41:39 -0700193
194 // A device_policy is loaded in a lazy way right before an update check,
195 // so the device_policy should be already loaded at this point. If it's
196 // not, return a safe value for this setting.
Jay Srinivasan43488792012-06-19 00:25:31 -0700197 if (!device_policy) {
Alex Deymof4867c42013-06-28 14:41:39 -0700198 LOG(INFO) << "Disabling updates over cellular networks as there's no "
199 "device policy loaded yet.";
Jay Srinivasan43488792012-06-19 00:25:31 -0700200 return false;
201 }
202
Alex Deymof4867c42013-06-28 14:41:39 -0700203 if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
204 // The update setting is enforced by the device policy.
Jay Srinivasan43488792012-06-19 00:25:31 -0700205
Gilad Arnold9a423ff2014-03-27 15:27:35 -0700206 if (!ContainsKey(allowed_types, shill::kTypeCellular)) {
Alex Deymof4867c42013-06-28 14:41:39 -0700207 LOG(INFO) << "Disabling updates over cellular connection as it's not "
208 "allowed in the device policy.";
209 return false;
210 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700211
Alex Deymof4867c42013-06-28 14:41:39 -0700212 LOG(INFO) << "Allowing updates over cellular per device policy.";
213 return true;
214 } else {
215 // There's no update setting in the device policy, using the local user
216 // setting.
217 PrefsInterface* prefs = system_state_->prefs();
218
219 if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
220 LOG(INFO) << "Disabling updates over cellular connection as there's "
221 "no device policy setting nor user preference present.";
222 return false;
223 }
224
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700225 bool stored_value;
226 if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission,
227 &stored_value)) {
Alex Deymof4867c42013-06-28 14:41:39 -0700228 return false;
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700229 }
Alex Deymof4867c42013-06-28 14:41:39 -0700230
231 if (!stored_value) {
232 LOG(INFO) << "Disabling updates over cellular connection per user "
233 "setting.";
234 return false;
235 }
236 LOG(INFO) << "Allowing updates over cellular per user setting.";
237 return true;
238 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700239 }
240
241 default:
Alex Deymo6ae91202014-03-10 19:21:25 -0700242 if (tethering == NetworkTethering::kConfirmed) {
243 // Treat this connection as if it is a cellular connection.
244 LOG(INFO) << "Current connection is confirmed tethered, using Cellular "
245 "setting.";
246 return IsUpdateAllowedOver(kNetCellular, NetworkTethering::kUnknown);
247 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700248 return true;
249 }
250}
251
252const char* ConnectionManager::StringForConnectionType(
253 NetworkConnectionType type) const {
Ben Chanc6007e42013-09-19 23:49:22 -0700254 static const char* const kValues[] = {shill::kTypeEthernet,
255 shill::kTypeWifi,
256 shill::kTypeWimax,
257 shill::kTypeBluetooth,
258 shill::kTypeCellular};
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700259 if (type < 0 || type >= static_cast<int>(arraysize(kValues))) {
260 return "Unknown";
261 }
262 return kValues[type];
263}
264
Alex Deymo6ae91202014-03-10 19:21:25 -0700265const char* ConnectionManager::StringForTethering(
266 NetworkTethering tethering) const {
267 switch (tethering) {
268 case NetworkTethering::kNotDetected:
269 return shill::kTetheringNotDetectedState;
270 case NetworkTethering::kSuspected:
271 return shill::kTetheringSuspectedState;
272 case NetworkTethering::kConfirmed:
273 return shill::kTetheringConfirmedState;
274 case NetworkTethering::kUnknown:
275 return "Unknown";
276 }
277 // The program shouldn't reach this point, but the compiler isn't smart
278 // enough to infer that.
279 return "Unknown";
280}
281
282bool ConnectionManager::GetConnectionProperties(
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -0800283 DBusWrapperInterface* dbus_iface,
Alex Deymo6ae91202014-03-10 19:21:25 -0700284 NetworkConnectionType* out_type,
285 NetworkTethering* out_tethering) const {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700286 string default_service_path;
287 TEST_AND_RETURN_FALSE(GetDefaultServicePath(dbus_iface,
288 &default_service_path));
Alex Deymo6ae91202014-03-10 19:21:25 -0700289 TEST_AND_RETURN_FALSE(GetServicePathProperties(dbus_iface,
290 default_service_path,
291 out_type, out_tethering));
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700292 return true;
293}
294
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700295} // namespace chromeos_update_engine