blob: 45b64675cc55484076646fcbeb9bac9db74251ed [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
Alex Vakulenkod2779df2014-06-16 13:19:00 -07007#include <set>
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07008#include <string>
9
Jay Srinivasan43488792012-06-19 00:25:31 -070010#include <base/stl_util.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070011#include <base/strings/string_util.h>
Jay Srinivasan43488792012-06-19 00:25:31 -070012#include <chromeos/dbus/service_constants.h>
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070013#include <dbus/dbus-glib.h>
14#include <glib.h>
Gilad Arnold1f847232014-04-07 12:07:49 -070015#include <policy/device_policy.h>
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070016
Alex Deymof4867c42013-06-28 14:41:39 -070017#include "update_engine/prefs.h"
Jay Srinivasan43488792012-06-19 00:25:31 -070018#include "update_engine/system_state.h"
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070019#include "update_engine/utils.h"
20
Jay Srinivasan43488792012-06-19 00:25:31 -070021using std::set;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070022using std::string;
23
24namespace chromeos_update_engine {
25
26namespace {
27
28// Gets the DbusGProxy for FlimFlam. Must be free'd with ProxyUnref()
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080029bool GetFlimFlamProxy(DBusWrapperInterface* dbus_iface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070030 const char* path,
31 const char* interface,
32 DBusGProxy** out_proxy) {
33 DBusGConnection* bus;
34 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070035 GError* error = nullptr;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070036
37 bus = dbus_iface->BusGet(DBUS_BUS_SYSTEM, &error);
38 if (!bus) {
39 LOG(ERROR) << "Failed to get system bus";
40 return false;
41 }
Gilad Arnoldb752fb32014-03-03 12:23:39 -080042 proxy = dbus_iface->ProxyNewForName(bus, shill::kFlimflamServiceName, path,
43 interface);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070044 *out_proxy = proxy;
45 return true;
46}
47
48// On success, caller owns the GHashTable at out_hash_table.
49// Returns true on success.
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080050bool GetProperties(DBusWrapperInterface* dbus_iface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070051 const char* path,
52 const char* interface,
53 GHashTable** out_hash_table) {
54 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070055 GError* error = nullptr;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070056
57 TEST_AND_RETURN_FALSE(GetFlimFlamProxy(dbus_iface,
58 path,
59 interface,
60 &proxy));
61
Gilad Arnoldb752fb32014-03-03 12:23:39 -080062 gboolean rc = dbus_iface->ProxyCall_0_1(proxy,
63 "GetProperties",
64 &error,
65 out_hash_table);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070066 dbus_iface->ProxyUnref(proxy);
67 if (rc == FALSE) {
68 LOG(ERROR) << "dbus_g_proxy_call failed";
69 return false;
70 }
71
72 return true;
73}
74
75// Returns (via out_path) the default network path, or empty string if
76// there's no network up.
77// Returns true on success.
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080078bool GetDefaultServicePath(DBusWrapperInterface* dbus_iface, string* out_path) {
Alex Vakulenko88b591f2014-08-28 16:48:57 -070079 GHashTable* hash_table = nullptr;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070080
81 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
Ben Chanc6007e42013-09-19 23:49:22 -070082 shill::kFlimflamServicePath,
83 shill::kFlimflamManagerInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070084 &hash_table));
85
86 GValue* value = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table,
87 "Services"));
Alex Vakulenko88b591f2014-08-28 16:48:57 -070088 GPtrArray* array = nullptr;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070089 bool success = false;
mukesh agrawal88226ff2012-03-19 17:50:06 -070090 if (G_VALUE_HOLDS(value, DBUS_TYPE_G_OBJECT_PATH_ARRAY) &&
Alex Deymo5665d0c2014-05-28 17:45:43 -070091 (array = reinterpret_cast<GPtrArray*>(g_value_get_boxed(value))) &&
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070092 (array->len > 0)) {
Alex Deymo5665d0c2014-05-28 17:45:43 -070093 *out_path = static_cast<const char*>(g_ptr_array_index(array, 0));
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070094 success = true;
95 }
mukesh agrawal88226ff2012-03-19 17:50:06 -070096
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070097 g_hash_table_unref(hash_table);
98 return success;
99}
100
101NetworkConnectionType ParseConnectionType(const char* type_str) {
Ben Chanc6007e42013-09-19 23:49:22 -0700102 if (!strcmp(type_str, shill::kTypeEthernet)) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700103 return NetworkConnectionType::kEthernet;
Ben Chanc6007e42013-09-19 23:49:22 -0700104 } else if (!strcmp(type_str, shill::kTypeWifi)) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700105 return NetworkConnectionType::kWifi;
Ben Chanc6007e42013-09-19 23:49:22 -0700106 } else if (!strcmp(type_str, shill::kTypeWimax)) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700107 return NetworkConnectionType::kWimax;
Ben Chanc6007e42013-09-19 23:49:22 -0700108 } else if (!strcmp(type_str, shill::kTypeBluetooth)) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700109 return NetworkConnectionType::kBluetooth;
Ben Chanc6007e42013-09-19 23:49:22 -0700110 } else if (!strcmp(type_str, shill::kTypeCellular)) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700111 return NetworkConnectionType::kCellular;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700112 }
Alex Deymo75eac7e2015-07-29 13:39:14 -0700113 return NetworkConnectionType::kUnknown;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700114}
115
Alex Deymo6ae91202014-03-10 19:21:25 -0700116NetworkTethering ParseTethering(const char* tethering_str) {
117 if (!strcmp(tethering_str, shill::kTetheringNotDetectedState)) {
118 return NetworkTethering::kNotDetected;
119 } else if (!strcmp(tethering_str, shill::kTetheringSuspectedState)) {
120 return NetworkTethering::kSuspected;
121 } else if (!strcmp(tethering_str, shill::kTetheringConfirmedState)) {
122 return NetworkTethering::kConfirmed;
123 }
124 LOG(WARNING) << "Unknown Tethering value: " << tethering_str;
125 return NetworkTethering::kUnknown;
126}
127
128bool GetServicePathProperties(DBusWrapperInterface* dbus_iface,
129 const string& path,
130 NetworkConnectionType* out_type,
131 NetworkTethering* out_tethering) {
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700132 GHashTable* hash_table = nullptr;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700133
134 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
135 path.c_str(),
Ben Chanc6007e42013-09-19 23:49:22 -0700136 shill::kFlimflamServiceInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700137 &hash_table));
138
Alex Deymo6ae91202014-03-10 19:21:25 -0700139 // Populate the out_tethering.
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700140 GValue* value =
141 reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table,
142 shill::kTetheringProperty));
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700143 const char* tethering_str = nullptr;
Alex Deymo6ae91202014-03-10 19:21:25 -0700144
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700145 if (value != nullptr)
Alex Deymo6ae91202014-03-10 19:21:25 -0700146 tethering_str = g_value_get_string(value);
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700147 if (tethering_str != nullptr) {
Alex Deymo6ae91202014-03-10 19:21:25 -0700148 *out_tethering = ParseTethering(tethering_str);
149 } else {
150 // Set to Unknown if not present.
151 *out_tethering = NetworkTethering::kUnknown;
152 }
153
154 // Populate the out_type property.
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700155 value = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table,
156 shill::kTypeProperty));
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700157 const char* type_str = nullptr;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700158 bool success = false;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700159 if (value != nullptr && (type_str = g_value_get_string(value)) != nullptr) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700160 success = true;
Ben Chanc6007e42013-09-19 23:49:22 -0700161 if (!strcmp(type_str, shill::kTypeVPN)) {
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700162 value = reinterpret_cast<GValue*>(
163 g_hash_table_lookup(hash_table, shill::kPhysicalTechnologyProperty));
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700164 if (value != nullptr &&
165 (type_str = g_value_get_string(value)) != nullptr) {
Alex Deymo1c4e6382013-07-15 12:09:51 -0700166 *out_type = ParseConnectionType(type_str);
167 } else {
168 LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
169 << " connection (service: " << path << "). Returning default"
Alex Deymo75eac7e2015-07-29 13:39:14 -0700170 << " NetworkConnectionType::kUnknown value.";
171 *out_type = NetworkConnectionType::kUnknown;
Alex Deymo1c4e6382013-07-15 12:09:51 -0700172 }
173 } else {
174 *out_type = ParseConnectionType(type_str);
175 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700176 }
177 g_hash_table_unref(hash_table);
178 return success;
179}
180
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700181} // namespace
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700182
Jay Srinivasan43488792012-06-19 00:25:31 -0700183ConnectionManager::ConnectionManager(SystemState *system_state)
184 : system_state_(system_state) {}
185
Alex Deymo6ae91202014-03-10 19:21:25 -0700186bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type,
187 NetworkTethering tethering) const {
Jay Srinivasan43488792012-06-19 00:25:31 -0700188 switch (type) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700189 case NetworkConnectionType::kBluetooth:
Jay Srinivasan43488792012-06-19 00:25:31 -0700190 return false;
191
Alex Deymo75eac7e2015-07-29 13:39:14 -0700192 case NetworkConnectionType::kCellular: {
Jay Srinivasan43488792012-06-19 00:25:31 -0700193 set<string> allowed_types;
194 const policy::DevicePolicy* device_policy =
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800195 system_state_->device_policy();
Alex Deymof4867c42013-06-28 14:41:39 -0700196
197 // A device_policy is loaded in a lazy way right before an update check,
198 // so the device_policy should be already loaded at this point. If it's
199 // not, return a safe value for this setting.
Jay Srinivasan43488792012-06-19 00:25:31 -0700200 if (!device_policy) {
Alex Deymof4867c42013-06-28 14:41:39 -0700201 LOG(INFO) << "Disabling updates over cellular networks as there's no "
202 "device policy loaded yet.";
Jay Srinivasan43488792012-06-19 00:25:31 -0700203 return false;
204 }
205
Alex Deymof4867c42013-06-28 14:41:39 -0700206 if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
207 // The update setting is enforced by the device policy.
Jay Srinivasan43488792012-06-19 00:25:31 -0700208
Gilad Arnold9a423ff2014-03-27 15:27:35 -0700209 if (!ContainsKey(allowed_types, shill::kTypeCellular)) {
Alex Deymof4867c42013-06-28 14:41:39 -0700210 LOG(INFO) << "Disabling updates over cellular connection as it's not "
211 "allowed in the device policy.";
212 return false;
213 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700214
Alex Deymof4867c42013-06-28 14:41:39 -0700215 LOG(INFO) << "Allowing updates over cellular per device policy.";
216 return true;
217 } else {
218 // There's no update setting in the device policy, using the local user
219 // setting.
220 PrefsInterface* prefs = system_state_->prefs();
221
222 if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
223 LOG(INFO) << "Disabling updates over cellular connection as there's "
224 "no device policy setting nor user preference present.";
225 return false;
226 }
227
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700228 bool stored_value;
229 if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission,
230 &stored_value)) {
Alex Deymof4867c42013-06-28 14:41:39 -0700231 return false;
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700232 }
Alex Deymof4867c42013-06-28 14:41:39 -0700233
234 if (!stored_value) {
235 LOG(INFO) << "Disabling updates over cellular connection per user "
236 "setting.";
237 return false;
238 }
239 LOG(INFO) << "Allowing updates over cellular per user setting.";
240 return true;
241 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700242 }
243
244 default:
Alex Deymo6ae91202014-03-10 19:21:25 -0700245 if (tethering == NetworkTethering::kConfirmed) {
246 // Treat this connection as if it is a cellular connection.
247 LOG(INFO) << "Current connection is confirmed tethered, using Cellular "
248 "setting.";
Alex Deymo75eac7e2015-07-29 13:39:14 -0700249 return IsUpdateAllowedOver(NetworkConnectionType::kCellular,
250 NetworkTethering::kUnknown);
Alex Deymo6ae91202014-03-10 19:21:25 -0700251 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700252 return true;
253 }
254}
255
Alex Deymof6ee0162015-07-31 12:35:22 -0700256// static
Jay Srinivasan43488792012-06-19 00:25:31 -0700257const char* ConnectionManager::StringForConnectionType(
Alex Deymof6ee0162015-07-31 12:35:22 -0700258 NetworkConnectionType type) {
Alex Deymo75eac7e2015-07-29 13:39:14 -0700259 switch (type) {
260 case NetworkConnectionType::kEthernet:
261 return shill::kTypeEthernet;
262 case NetworkConnectionType::kWifi:
263 return shill::kTypeWifi;
264 case NetworkConnectionType::kWimax:
265 return shill::kTypeWimax;
266 case NetworkConnectionType::kBluetooth:
267 return shill::kTypeBluetooth;
268 case NetworkConnectionType::kCellular:
269 return shill::kTypeCellular;
270 case NetworkConnectionType::kUnknown:
271 return "Unknown";
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700272 }
Alex Deymo75eac7e2015-07-29 13:39:14 -0700273 return "Unknown";
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700274}
275
Alex Deymof6ee0162015-07-31 12:35:22 -0700276// static
277const char* ConnectionManager::StringForTethering(NetworkTethering tethering) {
Alex Deymo6ae91202014-03-10 19:21:25 -0700278 switch (tethering) {
279 case NetworkTethering::kNotDetected:
280 return shill::kTetheringNotDetectedState;
281 case NetworkTethering::kSuspected:
282 return shill::kTetheringSuspectedState;
283 case NetworkTethering::kConfirmed:
284 return shill::kTetheringConfirmedState;
285 case NetworkTethering::kUnknown:
286 return "Unknown";
287 }
288 // The program shouldn't reach this point, but the compiler isn't smart
289 // enough to infer that.
290 return "Unknown";
291}
292
293bool ConnectionManager::GetConnectionProperties(
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -0800294 DBusWrapperInterface* dbus_iface,
Alex Deymo6ae91202014-03-10 19:21:25 -0700295 NetworkConnectionType* out_type,
296 NetworkTethering* out_tethering) const {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700297 string default_service_path;
298 TEST_AND_RETURN_FALSE(GetDefaultServicePath(dbus_iface,
299 &default_service_path));
Alex Deymo6ae91202014-03-10 19:21:25 -0700300 TEST_AND_RETURN_FALSE(GetServicePathProperties(dbus_iface,
301 default_service_path,
302 out_type, out_tethering));
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700303 return true;
304}
305
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700306} // namespace chromeos_update_engine