blob: 1b436dc04ad28db1c9430481ee8b3349ade4e879 [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()
27bool GetFlimFlamProxy(DbusGlibInterface* dbus_iface,
28 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.
48bool GetProperties(DbusGlibInterface* dbus_iface,
49 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.
76bool GetDefaultServicePath(DbusGlibInterface* dbus_iface, string* out_path) {
77 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
114bool GetServicePathType(DbusGlibInterface* dbus_iface,
115 const string& path,
116 NetworkConnectionType* out_type) {
117 GHashTable* hash_table = NULL;
118
119 TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
120 path.c_str(),
Ben Chanc6007e42013-09-19 23:49:22 -0700121 shill::kFlimflamServiceInterface,
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700122 &hash_table));
123
Alex Deymo1c4e6382013-07-15 12:09:51 -0700124 GValue* value = (GValue*)g_hash_table_lookup(hash_table,
Ben Chanc6007e42013-09-19 23:49:22 -0700125 shill::kTypeProperty);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700126 const char* type_str = NULL;
127 bool success = false;
128 if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700129 success = true;
Ben Chanc6007e42013-09-19 23:49:22 -0700130 if (!strcmp(type_str, shill::kTypeVPN)) {
Alex Deymo1c4e6382013-07-15 12:09:51 -0700131 value = (GValue*)g_hash_table_lookup(hash_table,
132 shill::kPhysicalTechnologyProperty);
133 if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
134 *out_type = ParseConnectionType(type_str);
135 } else {
136 LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
137 << " connection (service: " << path << "). Returning default"
138 << " kNetUnknown value.";
139 *out_type = kNetUnknown;
140 }
141 } else {
142 *out_type = ParseConnectionType(type_str);
143 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700144 }
145 g_hash_table_unref(hash_table);
146 return success;
147}
148
149} // namespace {}
150
Jay Srinivasan43488792012-06-19 00:25:31 -0700151ConnectionManager::ConnectionManager(SystemState *system_state)
152 : system_state_(system_state) {}
153
154bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type) const {
155 switch (type) {
156 case kNetBluetooth:
157 return false;
158
159 case kNetCellular: {
160 set<string> allowed_types;
161 const policy::DevicePolicy* device_policy =
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800162 system_state_->device_policy();
Alex Deymof4867c42013-06-28 14:41:39 -0700163
164 // A device_policy is loaded in a lazy way right before an update check,
165 // so the device_policy should be already loaded at this point. If it's
166 // not, return a safe value for this setting.
Jay Srinivasan43488792012-06-19 00:25:31 -0700167 if (!device_policy) {
Alex Deymof4867c42013-06-28 14:41:39 -0700168 LOG(INFO) << "Disabling updates over cellular networks as there's no "
169 "device policy loaded yet.";
Jay Srinivasan43488792012-06-19 00:25:31 -0700170 return false;
171 }
172
Alex Deymof4867c42013-06-28 14:41:39 -0700173 if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
174 // The update setting is enforced by the device policy.
Jay Srinivasan43488792012-06-19 00:25:31 -0700175
Alex Deymof4867c42013-06-28 14:41:39 -0700176 if ((type == kNetCellular &&
Ben Chanc6007e42013-09-19 23:49:22 -0700177 !ContainsKey(allowed_types, shill::kTypeCellular))) {
Alex Deymof4867c42013-06-28 14:41:39 -0700178 LOG(INFO) << "Disabling updates over cellular connection as it's not "
179 "allowed in the device policy.";
180 return false;
181 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700182
Alex Deymof4867c42013-06-28 14:41:39 -0700183 LOG(INFO) << "Allowing updates over cellular per device policy.";
184 return true;
185 } else {
186 // There's no update setting in the device policy, using the local user
187 // setting.
188 PrefsInterface* prefs = system_state_->prefs();
189
190 if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
191 LOG(INFO) << "Disabling updates over cellular connection as there's "
192 "no device policy setting nor user preference present.";
193 return false;
194 }
195
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700196 bool stored_value;
197 if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission,
198 &stored_value)) {
Alex Deymof4867c42013-06-28 14:41:39 -0700199 return false;
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700200 }
Alex Deymof4867c42013-06-28 14:41:39 -0700201
202 if (!stored_value) {
203 LOG(INFO) << "Disabling updates over cellular connection per user "
204 "setting.";
205 return false;
206 }
207 LOG(INFO) << "Allowing updates over cellular per user setting.";
208 return true;
209 }
Jay Srinivasan43488792012-06-19 00:25:31 -0700210 }
211
212 default:
213 return true;
214 }
215}
216
217const char* ConnectionManager::StringForConnectionType(
218 NetworkConnectionType type) const {
Ben Chanc6007e42013-09-19 23:49:22 -0700219 static const char* const kValues[] = {shill::kTypeEthernet,
220 shill::kTypeWifi,
221 shill::kTypeWimax,
222 shill::kTypeBluetooth,
223 shill::kTypeCellular};
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700224 if (type < 0 || type >= static_cast<int>(arraysize(kValues))) {
225 return "Unknown";
226 }
227 return kValues[type];
228}
229
Jay Srinivasan43488792012-06-19 00:25:31 -0700230bool ConnectionManager::GetConnectionType(
231 DbusGlibInterface* dbus_iface,
232 NetworkConnectionType* out_type) const {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700233 string default_service_path;
234 TEST_AND_RETURN_FALSE(GetDefaultServicePath(dbus_iface,
235 &default_service_path));
236 TEST_AND_RETURN_FALSE(GetServicePathType(dbus_iface,
237 default_service_path,
238 out_type));
239 return true;
240}
241
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700242} // namespace chromeos_update_engine