blob: 8ac10791fd95615c4167d7ae7f7b4515ab7a8846 [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>
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070010#include <base/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>
14
Alex Deymof4867c42013-06-28 14:41:39 -070015#include "update_engine/prefs.h"
Jay Srinivasan43488792012-06-19 00:25:31 -070016#include "update_engine/system_state.h"
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070017#include "update_engine/utils.h"
18
Jay Srinivasan43488792012-06-19 00:25:31 -070019using std::set;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070020using std::string;
21
22namespace chromeos_update_engine {
23
24namespace {
25
26// Gets the DbusGProxy for FlimFlam. Must be free'd with ProxyUnref()
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080027bool GetFlimFlamProxy(DBusWrapperInterface* dbus_iface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070028 const char* path,
29 const char* interface,
30 DBusGProxy** out_proxy) {
31 DBusGConnection* bus;
32 DBusGProxy* proxy;
33 GError* error = NULL;
34
35 bus = dbus_iface->BusGet(DBUS_BUS_SYSTEM, &error);
36 if (!bus) {
37 LOG(ERROR) << "Failed to get system bus";
38 return false;
39 }
Gilad Arnoldb752fb32014-03-03 12:23:39 -080040 proxy = dbus_iface->ProxyNewForName(bus, shill::kFlimflamServiceName, path,
41 interface);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070042 *out_proxy = proxy;
43 return true;
44}
45
46// On success, caller owns the GHashTable at out_hash_table.
47// Returns true on success.
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080048bool GetProperties(DBusWrapperInterface* dbus_iface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070049 const char* path,
50 const char* interface,
51 GHashTable** out_hash_table) {
52 DBusGProxy* proxy;
53 GError* error = NULL;
54
55 TEST_AND_RETURN_FALSE(GetFlimFlamProxy(dbus_iface,
56 path,
57 interface,
58 &proxy));
59
Gilad Arnoldb752fb32014-03-03 12:23:39 -080060 gboolean rc = dbus_iface->ProxyCall_0_1(proxy,
61 "GetProperties",
62 &error,
63 out_hash_table);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070064 dbus_iface->ProxyUnref(proxy);
65 if (rc == FALSE) {
66 LOG(ERROR) << "dbus_g_proxy_call failed";
67 return false;
68 }
69
70 return true;
71}
72
73// Returns (via out_path) the default network path, or empty string if
74// there's no network up.
75// Returns true on success.
Gilad Arnold1b9d6ae2014-03-03 13:46:07 -080076bool GetDefaultServicePath(DBusWrapperInterface* dbus_iface, string* out_path) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070077 GHashTable* hash_table = NULL;
78
79 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
Ben Chanc6007e42013-09-19 23:49:22 -070080 shill::kFlimflamServicePath,
81 shill::kFlimflamManagerInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070082 &hash_table));
83
84 GValue* value = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table,
85 "Services"));
86 GArray* array = NULL;
87 bool success = false;
mukesh agrawal88226ff2012-03-19 17:50:06 -070088 if (G_VALUE_HOLDS(value, DBUS_TYPE_G_OBJECT_PATH_ARRAY) &&
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070089 (array = reinterpret_cast<GArray*>(g_value_get_boxed(value))) &&
90 (array->len > 0)) {
91 *out_path = g_array_index(array, const char*, 0);
92 success = true;
93 }
mukesh agrawal88226ff2012-03-19 17:50:06 -070094
Andrew de los Reyesd57d1472010-10-21 13:34:08 -070095 g_hash_table_unref(hash_table);
96 return success;
97}
98
99NetworkConnectionType ParseConnectionType(const char* type_str) {
Ben Chanc6007e42013-09-19 23:49:22 -0700100 if (!strcmp(type_str, shill::kTypeEthernet)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700101 return kNetEthernet;
Ben Chanc6007e42013-09-19 23:49:22 -0700102 } else if (!strcmp(type_str, shill::kTypeWifi)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700103 return kNetWifi;
Ben Chanc6007e42013-09-19 23:49:22 -0700104 } else if (!strcmp(type_str, shill::kTypeWimax)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700105 return kNetWimax;
Ben Chanc6007e42013-09-19 23:49:22 -0700106 } else if (!strcmp(type_str, shill::kTypeBluetooth)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700107 return kNetBluetooth;
Ben Chanc6007e42013-09-19 23:49:22 -0700108 } else if (!strcmp(type_str, shill::kTypeCellular)) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700109 return kNetCellular;
110 }
111 return kNetUnknown;
112}
113
Alex Deymo6ae91202014-03-10 19:21:25 -0700114NetworkTethering ParseTethering(const char* tethering_str) {
115 if (!strcmp(tethering_str, shill::kTetheringNotDetectedState)) {
116 return NetworkTethering::kNotDetected;
117 } else if (!strcmp(tethering_str, shill::kTetheringSuspectedState)) {
118 return NetworkTethering::kSuspected;
119 } else if (!strcmp(tethering_str, shill::kTetheringConfirmedState)) {
120 return NetworkTethering::kConfirmed;
121 }
122 LOG(WARNING) << "Unknown Tethering value: " << tethering_str;
123 return NetworkTethering::kUnknown;
124}
125
126bool GetServicePathProperties(DBusWrapperInterface* dbus_iface,
127 const string& path,
128 NetworkConnectionType* out_type,
129 NetworkTethering* out_tethering) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700130 GHashTable* hash_table = NULL;
131
132 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
133 path.c_str(),
Ben Chanc6007e42013-09-19 23:49:22 -0700134 shill::kFlimflamServiceInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700135 &hash_table));
136
Alex Deymo6ae91202014-03-10 19:21:25 -0700137 // Populate the out_tethering.
Alex Deymo1c4e6382013-07-15 12:09:51 -0700138 GValue* value = (GValue*)g_hash_table_lookup(hash_table,
Alex Deymo6ae91202014-03-10 19:21:25 -0700139 shill::kTetheringProperty);
140 const char* tethering_str = NULL;
141
142 if (value != NULL)
143 tethering_str = g_value_get_string(value);
144 if (tethering_str != NULL) {
145 *out_tethering = ParseTethering(tethering_str);
146 } else {
147 // Set to Unknown if not present.
148 *out_tethering = NetworkTethering::kUnknown;
149 }
150
151 // Populate the out_type property.
152 value = (GValue*)g_hash_table_lookup(hash_table,
153 shill::kTypeProperty);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700154 const char* type_str = NULL;
155 bool success = false;
156 if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700157 success = true;
Ben Chanc6007e42013-09-19 23:49:22 -0700158 if (!strcmp(type_str, shill::kTypeVPN)) {
Alex Deymo1c4e6382013-07-15 12:09:51 -0700159 value = (GValue*)g_hash_table_lookup(hash_table,
160 shill::kPhysicalTechnologyProperty);
161 if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
162 *out_type = ParseConnectionType(type_str);
163 } else {
164 LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
165 << " connection (service: " << path << "). Returning default"
166 << " kNetUnknown value.";
167 *out_type = kNetUnknown;
168 }
169 } else {
170 *out_type = ParseConnectionType(type_str);
171 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700172 }
173 g_hash_table_unref(hash_table);
174 return success;
175}
176
177} // namespace {}
178
Jay Srinivasan43488792012-06-19 00:25:31 -0700179ConnectionManager::ConnectionManager(SystemState *system_state)
180 : system_state_(system_state) {}
181
Alex Deymo6ae91202014-03-10 19:21:25 -0700182bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type,
183 NetworkTethering tethering) const {
Jay Srinivasan43488792012-06-19 00:25:31 -0700184 switch (type) {
185 case kNetBluetooth:
186 return false;
187
188 case kNetCellular: {
189 set<string> allowed_types;
190 const policy::DevicePolicy* device_policy =
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800191 system_state_->device_policy();
Alex Deymof4867c42013-06-28 14:41:39 -0700192
193 // A device_policy is loaded in a lazy way right before an update check,
194 // so the device_policy should be already loaded at this point. If it's
195 // not, return a safe value for this setting.
Jay Srinivasan43488792012-06-19 00:25:31 -0700196 if (!device_policy) {
Alex Deymof4867c42013-06-28 14:41:39 -0700197 LOG(INFO) << "Disabling updates over cellular networks as there's no "
198 "device policy loaded yet.";
Jay Srinivasan43488792012-06-19 00:25:31 -0700199 return false;
200 }
201
Alex Deymof4867c42013-06-28 14:41:39 -0700202 if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
203 // The update setting is enforced by the device policy.
Jay Srinivasan43488792012-06-19 00:25:31 -0700204
Alex Deymof4867c42013-06-28 14:41:39 -0700205 if ((type == kNetCellular &&
Ben Chanc6007e42013-09-19 23:49:22 -0700206 !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