| OLD | NEW |
| 1 /* | 1 /* |
| 2 * | 2 * |
| 3 * Connection Manager | 3 * Connection Manager |
| 4 * | 4 * |
| 5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. | 5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. |
| 6 * | 6 * |
| 7 * This program is free software; you can redistribute it and/or modify | 7 * This program is free software; you can redistribute it and/or modify |
| 8 * it under the terms of the GNU General Public License version 2 as | 8 * it under the terms of the GNU General Public License version 2 as |
| 9 * published by the Free Software Foundation. | 9 * published by the Free Software Foundation. |
| 10 * | 10 * |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 #ifdef HAVE_CONFIG_H | 22 #ifdef HAVE_CONFIG_H |
| 23 #include <config.h> | 23 #include <config.h> |
| 24 #endif | 24 #endif |
| 25 | 25 |
| 26 #include <string.h> | 26 #include <string.h> |
| 27 | 27 |
| 28 #include <glib.h> | 28 #include <glib.h> |
| 29 #include <gdbus.h> | 29 #include <gdbus.h> |
| 30 | 30 |
| 31 #include <connman/assert.h> |
| 32 |
| 31 #include "connman.h" | 33 #include "connman.h" |
| 32 | 34 |
| 33 #define PROFILE_DEFAULT_IDENT "default" | 35 #define PROFILE_DEFAULT_IDENT "default" |
| 36 #define PROFILE_MAX 3 /* 2 is probably sufficient */ |
| 34 | 37 |
| 35 #define _DBG_PROFILE(fmt, arg...) DBG(DBG_PROFILE, fmt, ## arg) | 38 #define _DBG_PROFILE(fmt, arg...) DBG(DBG_PROFILE, fmt, ## arg) |
| 36 | 39 |
| 37 struct connman_profile { | 40 struct connman_profile { |
| 38 » char *ident; | 41 » struct connman_storage_ident ident; |
| 39 char *path; | 42 char *path; |
| 40 char *name; | 43 char *name; |
| 41 connman_bool_t offlinemode; | 44 connman_bool_t offlinemode; |
| 42 }; | 45 }; |
| 43 | 46 |
| 44 static GHashTable *profile_hash = NULL; | 47 static GHashTable *profile_hash = NULL; |
| 48 |
| 49 static struct connman_profile *profile_stack[PROFILE_MAX]; |
| 50 static int cur_profile = -1; |
| 51 |
| 52 static struct connman_storage_ident default_ident = { |
| 53 .ident = PROFILE_DEFAULT_IDENT |
| 54 }; |
| 45 static struct connman_profile *default_profile = NULL; | 55 static struct connman_profile *default_profile = NULL; |
| 46 | 56 |
| 47 static DBusConnection *connection = NULL; | 57 static DBusConnection *connection = NULL; |
| 48 | 58 |
| 59 static int ident_equal(const struct connman_storage_ident *a, |
| 60 const struct connman_storage_ident *b) |
| 61 { |
| 62 return (g_strcmp0(a->user, b->user) == 0 && |
| 63 g_strcmp0(a->ident, b->ident) == 0); |
| 64 } |
| 65 |
| 49 static void append_path(gpointer key, gpointer value, gpointer user_data) | 66 static void append_path(gpointer key, gpointer value, gpointer user_data) |
| 50 { | 67 { |
| 51 struct connman_profile *profile = value; | 68 struct connman_profile *profile = value; |
| 52 DBusMessageIter *iter = user_data; | 69 DBusMessageIter *iter = user_data; |
| 53 | 70 |
| 54 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, | 71 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, |
| 55 &profile->path); | 72 &profile->path); |
| 56 } | 73 } |
| 57 | 74 |
| 58 void __connman_profile_list(DBusMessageIter *iter, void *arg) | 75 void __connman_profile_list(DBusMessageIter *iter, void *arg) |
| 59 { | 76 { |
| 60 _DBG_PROFILE(""); | |
| 61 | |
| 62 g_hash_table_foreach(profile_hash, append_path, iter); | 77 g_hash_table_foreach(profile_hash, append_path, iter); |
| 63 } | 78 } |
| 64 | 79 |
| 65 static void profiles_changed(void) | 80 static void profiles_changed(void) |
| 66 { | 81 { |
| 67 _DBG_PROFILE(""); | |
| 68 | |
| 69 connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH, | 82 connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH, |
| 70 CONNMAN_MANAGER_INTERFACE, "Profiles", | 83 CONNMAN_MANAGER_INTERFACE, "Profiles", |
| 71 DBUS_TYPE_OBJECT_PATH, __connman_profile_list, NULL); | 84 DBUS_TYPE_OBJECT_PATH, __connman_profile_list, NULL); |
| 72 } | 85 } |
| 73 | 86 |
| 74 static void name_changed(struct connman_profile *profile) | |
| 75 { | |
| 76 _DBG_PROFILE("profile %p", profile); | |
| 77 | |
| 78 connman_dbus_send_property_changed_variant(profile->path, | |
| 79 CONNMAN_PROFILE_INTERFACE, "Name", | |
| 80 DBUS_TYPE_STRING, &profile->name); | |
| 81 } | |
| 82 | |
| 83 static void offlinemode_changed(struct connman_profile *profile) | |
| 84 { | |
| 85 _DBG_PROFILE("profile %p", profile); | |
| 86 | |
| 87 connman_dbus_send_property_changed_variant(profile->path, | |
| 88 CONNMAN_PROFILE_INTERFACE, "OfflineMode", | |
| 89 DBUS_TYPE_BOOLEAN, &profile->offlinemode); | |
| 90 } | |
| 91 | |
| 92 connman_bool_t __connman_profile_get_offlinemode(void) | 87 connman_bool_t __connman_profile_get_offlinemode(void) |
| 93 { | 88 { |
| 94 » if (default_profile == NULL) | 89 » return (default_profile == NULL) ? FALSE : default_profile->offlinemode; |
| 95 » » return FALSE; | |
| 96 | |
| 97 » _DBG_PROFILE("offlinemode %d", default_profile->offlinemode); | |
| 98 | |
| 99 » return default_profile->offlinemode; | |
| 100 } | 90 } |
| 101 | 91 |
| 102 int __connman_profile_set_offlinemode(connman_bool_t offlinemode) | 92 int __connman_profile_set_offlinemode(connman_bool_t offlinemode) |
| 103 { | 93 { |
| 104 _DBG_PROFILE("offlinemode %d", offlinemode); | 94 _DBG_PROFILE("offlinemode %d", offlinemode); |
| 105 | 95 |
| 106 » if (default_profile == NULL) | 96 » /* TODO(sleffler) disallow if no default profile? */ |
| 107 » » return -EINVAL; | 97 » if (default_profile != NULL) { |
| 108 | 98 » » /* |
| 109 » if (default_profile->offlinemode == offlinemode) | 99 » » * OfflineMode is only saved to the default profile; |
| 110 » » return -EALREADY; | 100 » » * this ensures it is preserved across user changes. |
| 111 | 101 » » */ |
| 112 » default_profile->offlinemode = offlinemode; | 102 » » if (default_profile->offlinemode == offlinemode) |
| 113 » offlinemode_changed(default_profile); | 103 » » » return -EALREADY; |
| 114 | 104 |
| 115 » __connman_device_set_offlinemode(offlinemode); | 105 » » default_profile->offlinemode = offlinemode; |
| 116 | 106 |
| 107 » » connman_dbus_send_property_changed_variant( |
| 108 » » default_profile->path, |
| 109 » » CONNMAN_PROFILE_INTERFACE, "OfflineMode", |
| 110 » » DBUS_TYPE_BOOLEAN, &offlinemode); |
| 111 » } |
| 112 » return __connman_device_set_offlinemode(offlinemode); |
| 113 } |
| 114 |
| 115 /* |
| 116 * Return the active profile; it's on the top of the stack. |
| 117 */ |
| 118 static inline struct connman_profile *active_profile(void) |
| 119 { |
| 120 » return cur_profile >= 0 ? profile_stack[cur_profile] : NULL; |
| 121 } |
| 122 |
| 123 /* |
| 124 * Load/Save objects. When loading we walk the stack of profiles |
| 125 * until we find a successful load. Saving always happens to the |
| 126 * top-most/active profile. |
| 127 */ |
| 128 |
| 129 static inline int load_continue(int err) |
| 130 { |
| 131 » /* NB: ENXIO for no file, ESRCH for no group/key */ |
| 132 » return (err == -ENXIO || err == -ESRCH); |
| 133 } |
| 134 |
| 135 int __connman_profile_load_service(struct connman_service *service) |
| 136 { |
| 137 » int i, err; |
| 138 |
| 139 » _DBG_PROFILE("service %p", service); |
| 140 |
| 141 » err = 0; |
| 142 » for (i = cur_profile; i >= 0; i--) { |
| 143 » » const struct connman_profile *profile = profile_stack[i]; |
| 144 |
| 145 » » err = __connman_storage_load_service(service, &profile->ident); |
| 146 » » if (!load_continue(err)) |
| 147 » » » break; |
| 148 » } |
| 149 » return err; |
| 150 } |
| 151 |
| 152 int __connman_profile_save_service(struct connman_service *service) |
| 153 { |
| 154 » struct connman_profile *profile = active_profile(); |
| 155 |
| 156 » _DBG_PROFILE("service %p profile %p", service, profile); |
| 157 |
| 158 » return (profile == NULL) ? 0 : |
| 159 » __connman_storage_save_service(service, &profile->ident); |
| 160 } |
| 161 |
| 162 int __connman_profile_load_device(struct connman_device *device) |
| 163 { |
| 164 » int i, err; |
| 165 |
| 166 » _DBG_PROFILE("device %p", device); |
| 167 |
| 168 » err = 0; |
| 169 » for (i = cur_profile; i >= 0; i--) { |
| 170 » » const struct connman_profile *profile = profile_stack[i]; |
| 171 |
| 172 » » err = __connman_storage_load_device(device, &profile->ident); |
| 173 » » if (!load_continue(err)) |
| 174 » » » break; |
| 175 » } |
| 176 » return err; |
| 177 } |
| 178 |
| 179 int __connman_profile_save_device(struct connman_device *device) |
| 180 { |
| 181 » struct connman_profile *profile = active_profile(); |
| 182 |
| 183 » _DBG_PROFILE("device %p profile %p", device, profile); |
| 184 |
| 185 » return (profile == NULL) ? 0: |
| 186 » __connman_storage_save_device(device, &profile->ident); |
| 187 } |
| 188 |
| 189 int __connman_profile_load_ipconfig(struct connman_ipconfig *ipconfig) |
| 190 { |
| 191 » int i, err; |
| 192 |
| 193 » _DBG_PROFILE("ipconfig %p", ipconfig); |
| 194 |
| 195 » err = 0; |
| 196 » for (i = cur_profile; i >= 0; i--) { |
| 197 » » const struct connman_profile *profile = profile_stack[i]; |
| 198 |
| 199 » » err = __connman_storage_load_ipconfig(ipconfig, |
| 200 » » &profile->ident); |
| 201 » » if (!load_continue(err)) |
| 202 » » » break; |
| 203 » } |
| 204 » return err; |
| 205 } |
| 206 |
| 207 int __connman_profile_save_ipconfig(const struct connman_ipconfig *ipconfig) |
| 208 { |
| 209 » struct connman_profile *profile = active_profile(); |
| 210 |
| 211 » _DBG_PROFILE("ipconfig %p profile %p", ipconfig, profile); |
| 212 |
| 213 » return (profile == NULL) ? 0 : |
| 214 » __connman_storage_save_ipconfig(ipconfig, &profile->ident); |
| 215 } |
| 216 |
| 217 int __connman_profile_append_hidden_ssids(GSList **hidden_ssids, |
| 218 void (*append_hidden_ssids)(GKeyFile *keyfile, GSList **hidden_ssids)) |
| 219 { |
| 220 » int i; |
| 221 |
| 222 » _DBG_PROFILE(""); |
| 223 |
| 224 » for (i = cur_profile; i >= 0; i--) { |
| 225 » » const struct connman_profile *profile = profile_stack[i]; |
| 226 » » GKeyFile *keyfile; |
| 227 |
| 228 » » keyfile = __connman_storage_open(&profile->ident); |
| 229 » » if (keyfile != NULL) { |
| 230 » » » append_hidden_ssids(keyfile, hidden_ssids); |
| 231 » » » __connman_storage_close(&profile->ident, keyfile, |
| 232 » » » FALSE); |
| 233 » » } |
| 234 » } |
| 117 return 0; | 235 return 0; |
| 118 } | 236 } |
| 119 | 237 |
| 238 /* |
| 239 * Save the default profile if registered. |
| 240 */ |
| 120 int __connman_profile_save_default(void) | 241 int __connman_profile_save_default(void) |
| 121 { | 242 { |
| 122 _DBG_PROFILE(""); | |
| 123 | |
| 124 if (default_profile != NULL) | 243 if (default_profile != NULL) |
| 125 __connman_storage_save_profile(default_profile); | 244 __connman_storage_save_profile(default_profile); |
| 126 | |
| 127 return 0; | 245 return 0; |
| 128 } | 246 } |
| 129 | 247 |
| 130 const char *__connman_profile_active_ident(void) | 248 /* |
| 131 { | 249 * Save the active profile (if any). |
| 132 » _DBG_PROFILE(""); | 250 */ |
| 133 | 251 int __connman_profile_save_active(void) |
| 134 » return PROFILE_DEFAULT_IDENT; | 252 { |
| 135 } | 253 » struct connman_profile *profile = active_profile(); |
| 136 | 254 » return (profile == NULL) ? -EINVAL : |
| 255 » __connman_storage_save_profile(profile); |
| 256 } |
| 257 |
| 258 /* |
| 259 * Return the identifier for the active profile or NULL |
| 260 * if there is none. |
| 261 */ |
| 262 const struct connman_storage_ident *__connman_profile_active_ident(void) |
| 263 { |
| 264 » struct connman_profile *profile = active_profile(); |
| 265 » return profile != NULL ? &profile->ident : NULL; |
| 266 } |
| 267 |
| 268 /* |
| 269 * Return the object path for the active profile or NULL |
| 270 * if there is none. |
| 271 */ |
| 137 const char *__connman_profile_active_path(void) | 272 const char *__connman_profile_active_path(void) |
| 138 { | 273 { |
| 139 » _DBG_PROFILE(""); | 274 » struct connman_profile *profile = active_profile(); |
| 140 | 275 » return profile != NULL ? profile->path : NULL; |
| 141 » if (default_profile == NULL) | |
| 142 » » return NULL; | |
| 143 | |
| 144 » return default_profile->path; | |
| 145 } | 276 } |
| 146 | 277 |
| 147 static guint changed_timeout = 0; | 278 static guint changed_timeout = 0; |
| 148 | 279 |
| 280 static void clear_timeout(void) |
| 281 { |
| 282 if (changed_timeout > 0) { |
| 283 g_source_remove(changed_timeout); |
| 284 changed_timeout = 0; |
| 285 } |
| 286 } |
| 287 |
| 149 static void append_services(DBusMessageIter *iter, void *arg) | 288 static void append_services(DBusMessageIter *iter, void *arg) |
| 150 { | 289 { |
| 151 » const struct connman_profile *profile = arg; | 290 » __connman_service_list(iter, arg); |
| 152 » if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) | |
| 153 » » __connman_service_list(iter, arg); | |
| 154 } | 291 } |
| 155 static gboolean services_changed(gpointer user_data) | 292 static gboolean services_changed(gpointer user_data) |
| 156 { | 293 { |
| 157 » struct connman_profile *profile = default_profile; | 294 » struct connman_profile *profile = active_profile(); |
| 158 | 295 |
| 159 changed_timeout = 0; | 296 changed_timeout = 0; |
| 160 | 297 |
| 161 if (profile != NULL) { | 298 if (profile != NULL) { |
| 162 connman_dbus_send_property_changed_array(profile->path, | 299 connman_dbus_send_property_changed_array(profile->path, |
| 163 CONNMAN_PROFILE_INTERFACE, "Services", | 300 CONNMAN_PROFILE_INTERFACE, "Services", |
| 164 » » DBUS_TYPE_OBJECT_PATH, append_services, profile); | 301 » » DBUS_TYPE_OBJECT_PATH, append_services, NULL); |
| 165 | 302 » } |
| 166 » » if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) | 303 |
| 167 » » » connman_dbus_send_property_changed_array( | 304 » connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH, |
| 168 » » » CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE, | 305 » CONNMAN_MANAGER_INTERFACE, "Services", |
| 169 » » » "Services", | 306 » DBUS_TYPE_OBJECT_PATH, append_services, NULL); |
| 170 » » » DBUS_TYPE_OBJECT_PATH, append_services, profile); | |
| 171 » } | |
| 172 return FALSE; | 307 return FALSE; |
| 173 } | 308 } |
| 174 | 309 |
| 310 /* |
| 311 * Handle changes to the profile. Generate PropertyChanged signals |
| 312 * on Manager.Services and Profile.Services for the currently active |
| 313 * profile. To minimize overhead requests may be coalesced using a |
| 314 * 1 second delay on the signals. |
| 315 */ |
| 175 void __connman_profile_changed(gboolean delayed) | 316 void __connman_profile_changed(gboolean delayed) |
| 176 { | 317 { |
| 177 » _DBG_PROFILE(""); | 318 » _DBG_PROFILE("delayed %d changed_timeout %d", delayed, changed_timeout); |
| 178 | 319 |
| 179 » if (changed_timeout > 0) { | 320 » clear_timeout(); |
| 180 » » g_source_remove(changed_timeout); | 321 |
| 181 » » changed_timeout = 0; | 322 » if (delayed == TRUE) { |
| 182 » } | 323 » » changed_timeout = g_timeout_add_seconds(1, services_changed, |
| 183 | 324 » » NULL); |
| 184 » if (delayed == FALSE) { | 325 » } else |
| 185 services_changed(NULL); | 326 services_changed(NULL); |
| 186 return; | |
| 187 } | |
| 188 | |
| 189 changed_timeout = g_timeout_add_seconds(1, services_changed, NULL); | |
| 190 } | 327 } |
| 191 | 328 |
| 192 int __connman_profile_add_device(struct connman_device *device) | 329 int __connman_profile_add_device(struct connman_device *device) |
| 193 { | 330 { |
| 194 struct connman_service *service; | 331 struct connman_service *service; |
| 195 | 332 |
| 196 _DBG_PROFILE("device %p", device); | 333 _DBG_PROFILE("device %p", device); |
| 197 | 334 |
| 198 service = __connman_service_create_from_device(device); | 335 service = __connman_service_create_from_device(device); |
| 199 if (service == NULL) | 336 if (service == NULL) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 | 404 |
| 268 static void __profile_entry_list(DBusMessageIter *iter, void *arg) | 405 static void __profile_entry_list(DBusMessageIter *iter, void *arg) |
| 269 { | 406 { |
| 270 struct connman_profile *profile = arg; | 407 struct connman_profile *profile = arg; |
| 271 GKeyFile *keyfile; | 408 GKeyFile *keyfile; |
| 272 gchar **groups; | 409 gchar **groups; |
| 273 int i; | 410 int i; |
| 274 | 411 |
| 275 _DBG_PROFILE("profile %p", profile); | 412 _DBG_PROFILE("profile %p", profile); |
| 276 | 413 |
| 277 » keyfile = __connman_storage_open(profile->ident); | 414 » keyfile = __connman_storage_open(&profile->ident); |
| 278 if (keyfile == NULL) | 415 if (keyfile == NULL) |
| 279 return; | 416 return; |
| 280 | 417 |
| 281 groups = g_key_file_get_groups(keyfile, NULL); | 418 groups = g_key_file_get_groups(keyfile, NULL); |
| 282 for (i = 0; groups[i] != NULL; i++) { | 419 for (i = 0; groups[i] != NULL; i++) { |
| 283 const char *gname = groups[i]; | 420 const char *gname = groups[i]; |
| 284 switch (get_service_type(gname)) { | 421 switch (get_service_type(gname)) { |
| 285 case CONNMAN_SERVICE_TYPE_UNKNOWN: | 422 case CONNMAN_SERVICE_TYPE_UNKNOWN: |
| 286 case CONNMAN_SERVICE_TYPE_ETHERNET: | 423 case CONNMAN_SERVICE_TYPE_ETHERNET: |
| 287 break; | 424 break; |
| 288 case CONNMAN_SERVICE_TYPE_BLUETOOTH: | 425 case CONNMAN_SERVICE_TYPE_BLUETOOTH: |
| 289 case CONNMAN_SERVICE_TYPE_WIMAX: | 426 case CONNMAN_SERVICE_TYPE_WIMAX: |
| 290 /* NB: don't care about these right now */ | 427 /* NB: don't care about these right now */ |
| 291 break; | 428 break; |
| 292 case CONNMAN_SERVICE_TYPE_CELLULAR: | 429 case CONNMAN_SERVICE_TYPE_CELLULAR: |
| 293 case CONNMAN_SERVICE_TYPE_WIFI: | 430 case CONNMAN_SERVICE_TYPE_WIFI: |
| 294 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, | 431 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, |
| 295 &gname); | 432 &gname); |
| 296 break; | 433 break; |
| 297 } | 434 } |
| 298 } | 435 } |
| 299 g_strfreev(groups); | 436 g_strfreev(groups); |
| 300 » __connman_storage_close(profile->ident, keyfile, FALSE); | 437 » __connman_storage_close(&profile->ident, keyfile, FALSE); |
| 301 } | 438 } |
| 302 | 439 |
| 303 static DBusMessage *get_properties(DBusConnection *conn, | 440 static DBusMessage *get_properties(DBusConnection *conn, |
| 304 DBusMessage *msg, void *data) | 441 DBusMessage *msg, void *data) |
| 305 { | 442 { |
| 306 struct connman_profile *profile = data; | 443 struct connman_profile *profile = data; |
| 307 DBusMessage *reply; | 444 DBusMessage *reply; |
| 308 DBusMessageIter array, dict; | 445 DBusMessageIter array, dict; |
| 309 | 446 |
| 310 _DBG_PROFILE("conn %p", conn); | 447 _DBG_PROFILE("conn %p", conn); |
| 311 | 448 |
| 312 reply = dbus_message_new_method_return(msg); | 449 reply = dbus_message_new_method_return(msg); |
| 313 if (reply == NULL) | 450 if (reply == NULL) |
| 314 return NULL; | 451 return NULL; |
| 315 | 452 |
| 316 dbus_message_iter_init_append(reply, &array); | 453 dbus_message_iter_init_append(reply, &array); |
| 317 | 454 |
| 318 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, | 455 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, |
| 319 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING | 456 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| 320 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING | 457 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING |
| 321 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); | 458 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); |
| 322 | 459 |
| 323 if (profile->name != NULL) | 460 if (profile->name != NULL) |
| 324 connman_dbus_dict_append_variant(&dict, "Name", | 461 connman_dbus_dict_append_variant(&dict, "Name", |
| 325 DBUS_TYPE_STRING, &profile->name); | 462 DBUS_TYPE_STRING, &profile->name); |
| 326 | 463 |
| 327 » connman_dbus_dict_append_variant(&dict, "OfflineMode", | 464 » if (profile == default_profile) |
| 328 » DBUS_TYPE_BOOLEAN, &profile->offlinemode); | 465 » » connman_dbus_dict_append_variant(&dict, "OfflineMode", |
| 466 » » DBUS_TYPE_BOOLEAN, &profile->offlinemode); |
| 329 | 467 |
| 330 » connman_dbus_dict_append_variant_array(&dict, "Services", | 468 » if (profile == active_profile()) |
| 331 » DBUS_TYPE_OBJECT_PATH, __connman_service_list, NULL); | 469 » » connman_dbus_dict_append_variant_array(&dict, "Services", |
| 470 » » DBUS_TYPE_OBJECT_PATH, __connman_service_list, NULL); |
| 332 | 471 |
| 333 connman_dbus_dict_append_variant_array(&dict, "Entries", | 472 connman_dbus_dict_append_variant_array(&dict, "Entries", |
| 334 DBUS_TYPE_STRING, __profile_entry_list, profile); | 473 DBUS_TYPE_STRING, __profile_entry_list, profile); |
| 335 | 474 |
| 336 dbus_message_iter_close_container(&array, &dict); | 475 dbus_message_iter_close_container(&array, &dict); |
| 337 | 476 |
| 338 return reply; | 477 return reply; |
| 339 } | 478 } |
| 340 | 479 |
| 341 static DBusMessage *set_property(DBusConnection *conn, | 480 static DBusMessage *set_property(DBusConnection *conn, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 365 const char *name; | 504 const char *name; |
| 366 | 505 |
| 367 if (type != DBUS_TYPE_STRING) | 506 if (type != DBUS_TYPE_STRING) |
| 368 return __connman_error_invalid_arguments(msg); | 507 return __connman_error_invalid_arguments(msg); |
| 369 | 508 |
| 370 dbus_message_iter_get_basic(&value, &name); | 509 dbus_message_iter_get_basic(&value, &name); |
| 371 | 510 |
| 372 g_free(profile->name); | 511 g_free(profile->name); |
| 373 profile->name = g_strdup(name); | 512 profile->name = g_strdup(name); |
| 374 | 513 |
| 375 » » if (profile->name != NULL) | 514 » » if (profile->name != NULL) { |
| 376 » » » name_changed(profile); | 515 » » » connman_dbus_send_property_changed_variant( |
| 377 | 516 » » » profile->path, CONNMAN_PROFILE_INTERFACE, "Name", |
| 378 » » __connman_storage_save_profile(profile); | 517 » » » DBUS_TYPE_STRING, &profile->name); |
| 379 » } else if (g_str_equal(name, "OfflineMode") == TRUE) { | 518 » » } |
| 380 » » connman_bool_t offlinemode; | |
| 381 | |
| 382 » » if (type != DBUS_TYPE_BOOLEAN) | |
| 383 » » » return __connman_error_invalid_arguments(msg); | |
| 384 | |
| 385 » » dbus_message_iter_get_basic(&value, &offlinemode); | |
| 386 | |
| 387 » » if (profile->offlinemode == offlinemode) | |
| 388 » » » return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); | |
| 389 | |
| 390 » » profile->offlinemode = offlinemode; | |
| 391 » » offlinemode_changed(profile); | |
| 392 | 519 |
| 393 __connman_storage_save_profile(profile); | 520 __connman_storage_save_profile(profile); |
| 394 } else | 521 } else |
| 395 return __connman_error_invalid_property(msg); | 522 return __connman_error_invalid_property(msg); |
| 396 | 523 |
| 397 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); | 524 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); |
| 398 } | 525 } |
| 399 | 526 |
| 400 static DBusMessage *get_entry(DBusConnection *conn, | 527 static DBusMessage *get_entry(DBusConnection *conn, |
| 401 DBusMessage *msg, void *data) | 528 DBusMessage *msg, void *data) |
| 402 { | 529 { |
| 403 #define ADD_STR(name, val) do { \ | 530 #define ADD_STR(name, val) do { \ |
| 404 connman_dbus_dict_append_variant(&dict, name, DBUS_TYPE_STRING, val); \ | 531 connman_dbus_dict_append_variant(&dict, name, DBUS_TYPE_STRING, val); \ |
| 405 } while (0) | 532 } while (0) |
| 406 #define VAL_STR(name) do { \ | 533 #define VAL_STR(name) do { \ |
| 407 val = g_key_file_get_string(keyfile, ident, name, NULL); \ | 534 val = g_key_file_get_string(keyfile, ident, name, NULL); \ |
| 408 if (val != NULL) \ | 535 if (val != NULL) \ |
| 409 ADD_STR(name, &val); \ | 536 ADD_STR(name, &val); \ |
| 410 } while (0) | 537 } while (0) |
| 411 struct connman_profile *profile = data; | 538 struct connman_profile *profile = data; |
| 412 GKeyFile *keyfile; | 539 GKeyFile *keyfile; |
| 413 const char *ident, *val; | 540 const char *ident, *val; |
| 414 gchar **tokens; | 541 gchar **tokens; |
| 415 DBusMessageIter iter, array, dict; | 542 DBusMessageIter iter, array, dict; |
| 416 DBusMessage *reply; | 543 DBusMessage *reply; |
| 417 connman_bool_t autoconnect, hidden_ssid; | 544 connman_bool_t autoconnect, hidden_ssid; |
| 545 int len; |
| 418 | 546 |
| 419 _DBG_PROFILE("profile %p", profile); | 547 _DBG_PROFILE("profile %p", profile); |
| 420 | 548 |
| 421 if (dbus_message_iter_init(msg, &iter) == FALSE) | 549 if (dbus_message_iter_init(msg, &iter) == FALSE) |
| 422 return __connman_error_invalid_arguments(msg); | 550 return __connman_error_invalid_arguments(msg); |
| 423 | 551 |
| 424 dbus_message_iter_get_basic(&iter, &ident); | 552 dbus_message_iter_get_basic(&iter, &ident); |
| 425 | 553 |
| 426 » keyfile = __connman_storage_open(profile->ident); | 554 » keyfile = __connman_storage_open(&profile->ident); |
| 427 if (keyfile == NULL) { | 555 if (keyfile == NULL) { |
| 428 » » _DBG_PROFILE("cannot open keyfile %s", profile->ident); | 556 » » _DBG_PROFILE("cannot open keyfile %s:%s", |
| 557 » » profile->ident.user, profile->ident.ident); |
| 429 return __connman_error_not_found(msg); /* XXX */ | 558 return __connman_error_not_found(msg); /* XXX */ |
| 430 } | 559 } |
| 431 | 560 |
| 432 if (g_key_file_has_group(keyfile, ident) == FALSE) { | 561 if (g_key_file_has_group(keyfile, ident) == FALSE) { |
| 433 _DBG_PROFILE("ident %s not found", ident); | 562 _DBG_PROFILE("ident %s not found", ident); |
| 434 » » __connman_storage_close(profile->ident, keyfile, FALSE); | 563 » » __connman_storage_close(&profile->ident, keyfile, FALSE); |
| 435 return __connman_error_not_found(msg); | 564 return __connman_error_not_found(msg); |
| 436 } | 565 } |
| 437 | 566 |
| 438 /* | 567 /* |
| 439 * Split group name into components; e.g. | 568 * Split group name into components; e.g. |
| 440 * <type>_<device>_<ssid>_<mode>_<security> for wifi | 569 * <type>_<device>_<ssid>_<mode>_<security> for wifi |
| 441 */ | 570 */ |
| 442 tokens = g_strsplit(ident, "_", 0); | 571 tokens = g_strsplit(ident, "_", 0); |
| 443 » /* NB: tokens[0] is NULL if ident is "" */ | 572 » len = g_strv_length(tokens); |
| 444 » if (tokens == NULL || tokens[0] == NULL) { | 573 » if (len < 2) { |
| 445 » » _DBG_PROFILE("ident %s malformed", ident); | 574 » » _DBG_PROFILE("ident %s malformed, len %d", ident, len); |
| 446 » » __connman_storage_close(profile->ident, keyfile, FALSE); | 575 » » g_strfreev(tokens); |
| 576 » » __connman_storage_close(&profile->ident, keyfile, FALSE); |
| 447 return __connman_error_invalid_arguments(msg); | 577 return __connman_error_invalid_arguments(msg); |
| 448 } | 578 } |
| 449 | 579 |
| 450 reply = dbus_message_new_method_return(msg); | 580 reply = dbus_message_new_method_return(msg); |
| 451 if (reply == NULL) { | 581 if (reply == NULL) { |
| 452 _DBG_PROFILE("cannot allocate reply"); | 582 _DBG_PROFILE("cannot allocate reply"); |
| 453 g_strfreev(tokens); | 583 g_strfreev(tokens); |
| 454 » » __connman_storage_close(profile->ident, keyfile, FALSE); | 584 » » __connman_storage_close(&profile->ident, keyfile, FALSE); |
| 455 return NULL; | 585 return NULL; |
| 456 } | 586 } |
| 457 | 587 |
| 458 dbus_message_iter_init_append(reply, &array); | 588 dbus_message_iter_init_append(reply, &array); |
| 459 | 589 |
| 460 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, | 590 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, |
| 461 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING | 591 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| 462 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING | 592 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING |
| 463 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); | 593 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); |
| 464 | 594 |
| 465 val = tokens[0]; | 595 val = tokens[0]; |
| 466 connman_dbus_dict_append_variant(&dict, "Type", DBUS_TYPE_STRING, &val); | 596 connman_dbus_dict_append_variant(&dict, "Type", DBUS_TYPE_STRING, &val); |
| 467 | 597 |
| 468 switch (__connman_service_string2type(val)) { | 598 switch (__connman_service_string2type(val)) { |
| 469 case CONNMAN_SERVICE_TYPE_WIFI: | 599 case CONNMAN_SERVICE_TYPE_WIFI: |
| 470 » » if (g_strv_length(tokens) != 5) { | 600 » » if (len != 5 && len != 6) { |
| 471 » » » /* TODO(sleffler) accept > 5? */ | 601 » » » _DBG_PROFILE("bad token cnt %d for ident %s", |
| 472 » » » _DBG_PROFILE("bad token cnt %d", g_strv_length(tokens)); | 602 » » » len, ident); |
| 473 break; | 603 break; |
| 474 } | 604 } |
| 475 val = tokens[3]; | 605 val = tokens[3]; |
| 476 ADD_STR("Mode", &val); | 606 ADD_STR("Mode", &val); |
| 477 val = tokens[4]; | 607 val = tokens[4]; |
| 608 /* NB: g_strsplit breaks 802_1x into 802+1x; restore */ |
| 609 if (g_strcmp0(val, "802") == 0) |
| 610 val = "802_1x"; |
| 478 ADD_STR("Security", &val); | 611 ADD_STR("Security", &val); |
| 479 break; | 612 break; |
| 480 case CONNMAN_SERVICE_TYPE_CELLULAR: | 613 case CONNMAN_SERVICE_TYPE_CELLULAR: |
| 481 /* TODO(sleffler) extract cellular attributes */ | 614 /* TODO(sleffler) extract cellular attributes */ |
| 482 break; | 615 break; |
| 483 default: | 616 default: |
| 484 break; | 617 break; |
| 485 } | 618 } |
| 486 | 619 |
| 487 /* NB: always set AutoConnect in reply */ | 620 /* NB: always set AutoConnect in reply */ |
| 488 val = g_key_file_get_string(keyfile, ident, "AutoConnect", NULL); | 621 val = g_key_file_get_string(keyfile, ident, "AutoConnect", NULL); |
| 489 autoconnect = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE); | 622 autoconnect = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE); |
| 490 connman_dbus_dict_append_variant(&dict, "AutoConnect", | 623 connman_dbus_dict_append_variant(&dict, "AutoConnect", |
| 491 DBUS_TYPE_BOOLEAN, &autoconnect); | 624 DBUS_TYPE_BOOLEAN, &autoconnect); |
| 492 | 625 |
| 493 VAL_STR("Name"); | 626 VAL_STR("Name"); |
| 494 VAL_STR("Passphrase"); | 627 VAL_STR("Passphrase"); |
| 495 VAL_STR("Failure"); | 628 VAL_STR("Failure"); |
| 496 VAL_STR("Modified"); | 629 VAL_STR("Modified"); |
| 497 | 630 |
| 498 val = g_key_file_get_string(keyfile, ident, "WiFi.HiddenSSID", NULL); | 631 val = g_key_file_get_string(keyfile, ident, "WiFi.HiddenSSID", NULL); |
| 499 hidden_ssid = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE); | 632 hidden_ssid = (g_strcmp0(val, "true") == 0 ? TRUE : FALSE); |
| 500 connman_dbus_dict_append_variant(&dict, "WiFi.HiddenSSID", | 633 connman_dbus_dict_append_variant(&dict, "WiFi.HiddenSSID", |
| 501 DBUS_TYPE_BOOLEAN, &hidden_ssid); | 634 DBUS_TYPE_BOOLEAN, &hidden_ssid); |
| 502 | 635 |
| 503 dbus_message_iter_close_container(&array, &dict); | 636 dbus_message_iter_close_container(&array, &dict); |
| 504 | 637 |
| 505 g_strfreev(tokens); | 638 g_strfreev(tokens); |
| 506 » __connman_storage_close(profile->ident, keyfile, FALSE); | 639 » __connman_storage_close(&profile->ident, keyfile, FALSE); |
| 507 | 640 |
| 508 return reply; | 641 return reply; |
| 509 #undef VAL_STR | 642 #undef VAL_STR |
| 510 #undef ADD_STR | 643 #undef ADD_STR |
| 511 } | 644 } |
| 512 | 645 |
| 513 static DBusMessage *delete_entry(DBusConnection *conn, | 646 static DBusMessage *delete_entry(DBusConnection *conn, |
| 514 DBusMessage *msg, void *data) | 647 DBusMessage *msg, void *data) |
| 515 { | 648 { |
| 516 struct connman_profile *profile = data; | 649 struct connman_profile *profile = data; |
| 517 DBusMessageIter iter; | 650 DBusMessageIter iter; |
| 518 const char *identifier; | 651 const char *identifier; |
| 519 struct connman_service *service; | 652 struct connman_service *service; |
| 520 GKeyFile *keyfile; | 653 GKeyFile *keyfile; |
| 521 gboolean status; | 654 gboolean status; |
| 522 | 655 |
| 523 » _DBG_PROFILE("profile %s", profile->ident); | 656 » _DBG_PROFILE("profile %s:%s", profile->ident.user, |
| 657 » profile->ident.ident); |
| 524 | 658 |
| 525 if (dbus_message_iter_init(msg, &iter) == FALSE) | 659 if (dbus_message_iter_init(msg, &iter) == FALSE) |
| 526 return __connman_error_invalid_arguments(msg); | 660 return __connman_error_invalid_arguments(msg); |
| 527 | 661 |
| 528 dbus_message_iter_get_basic(&iter, &identifier); | 662 dbus_message_iter_get_basic(&iter, &identifier); |
| 529 | 663 |
| 530 if (__connman_security_check_privilege(msg, | 664 if (__connman_security_check_privilege(msg, |
| 531 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) | 665 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) |
| 532 return __connman_error_permission_denied(msg); | 666 return __connman_error_permission_denied(msg); |
| 533 | 667 |
| 534 service = __connman_service_lookup(identifier); | 668 service = __connman_service_lookup(identifier); |
| 535 if (service != NULL) { | 669 if (service != NULL) { |
| 536 /* NB: this does not remove the service */ | 670 /* NB: this does not remove the service */ |
| 537 __connman_service_reset(service); | 671 __connman_service_reset(service); |
| 538 } | 672 } |
| 539 | 673 |
| 540 /* Remove directly from profile */ | 674 /* Remove directly from profile */ |
| 541 » keyfile = __connman_storage_open(profile->ident); | 675 » keyfile = __connman_storage_open(&profile->ident); |
| 542 if (keyfile == NULL) { | 676 if (keyfile == NULL) { |
| 543 _DBG_PROFILE("cannot open key file"); | 677 _DBG_PROFILE("cannot open key file"); |
| 544 return __connman_error_invalid_arguments(msg); | 678 return __connman_error_invalid_arguments(msg); |
| 545 } | 679 } |
| 546 | 680 |
| 547 status = g_key_file_remove_group(keyfile, identifier, NULL); | 681 status = g_key_file_remove_group(keyfile, identifier, NULL); |
| 548 » __connman_storage_close(profile->ident, keyfile, status); | 682 » __connman_storage_close(&profile->ident, keyfile, status); |
| 549 | 683 |
| 550 if (status == FALSE) { | 684 if (status == FALSE) { |
| 551 _DBG_PROFILE("cannot remove %s", identifier); | 685 _DBG_PROFILE("cannot remove %s", identifier); |
| 552 return __connman_error_not_found(msg); | 686 return __connman_error_not_found(msg); |
| 553 } | 687 } |
| 554 | 688 |
| 555 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); | 689 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); |
| 556 } | 690 } |
| 557 | 691 |
| 558 static GDBusMethodTable profile_methods[] = { | 692 static GDBusMethodTable profile_methods[] = { |
| 559 { "GetProperties", "", "a{sv}", get_properties }, | 693 { "GetProperties", "", "a{sv}", get_properties }, |
| 560 { "SetProperty", "sv", "", set_property }, | 694 { "SetProperty", "sv", "", set_property }, |
| 561 { "GetEntry", "s", "a{sv}", get_entry }, | 695 { "GetEntry", "s", "a{sv}", get_entry }, |
| 562 { "DeleteEntry", "s", "", delete_entry }, | 696 { "DeleteEntry", "s", "", delete_entry }, |
| 563 { }, | 697 { }, |
| 564 }; | 698 }; |
| 565 | 699 |
| 566 static GDBusSignalTable profile_signals[] = { | 700 static GDBusSignalTable profile_signals[] = { |
| 567 { "PropertyChanged", "sv" }, | 701 { "PropertyChanged", "sv" }, |
| 568 { }, | 702 { }, |
| 569 }; | 703 }; |
| 570 | 704 |
| 705 static void free_ident(struct connman_storage_ident *ident) |
| 706 { |
| 707 /* NB: blech, don't reclaim, it's statically allocated */ |
| 708 if (!ident_equal(ident, &default_ident)) { |
| 709 g_free(ident->user); |
| 710 g_free(ident->ident); |
| 711 } |
| 712 } |
| 713 |
| 571 static void free_profile(struct connman_profile *profile) | 714 static void free_profile(struct connman_profile *profile) |
| 572 { | 715 { |
| 716 free_ident(&profile->ident); |
| 717 g_free(profile->path); |
| 573 g_free(profile->name); | 718 g_free(profile->name); |
| 574 g_free(profile->path); | |
| 575 g_free(profile->ident); | |
| 576 g_free(profile); | 719 g_free(profile); |
| 577 } | 720 } |
| 578 | 721 |
| 579 static void unregister_profile(gpointer data) | 722 static void unregister_profile(gpointer data) |
| 580 { | 723 { |
| 581 struct connman_profile *profile = data; | 724 struct connman_profile *profile = data; |
| 582 | 725 |
| 583 _DBG_PROFILE("profile %p", profile); | 726 _DBG_PROFILE("profile %p", profile); |
| 584 | 727 |
| 585 » connman_info("Removing profile %s", profile->ident); | 728 » connman_info("Remove profile %s:%s", profile->ident.user, |
| 729 » profile->ident.ident); |
| 586 | 730 |
| 587 g_dbus_unregister_interface(connection, profile->path, | 731 g_dbus_unregister_interface(connection, profile->path, |
| 588 CONNMAN_PROFILE_INTERFACE); | 732 CONNMAN_PROFILE_INTERFACE); |
| 589 | 733 |
| 590 » if (g_strcmp0(profile->ident, PROFILE_DEFAULT_IDENT) == 0) | 734 » if (profile == default_profile) |
| 591 default_profile = NULL; | 735 default_profile = NULL; |
| 592 | 736 |
| 593 free_profile(profile); | 737 free_profile(profile); |
| 594 } | 738 } |
| 595 | 739 |
| 596 static int create_profile(const char *ident, const char *name, | 740 static char *getpath(const struct connman_storage_ident *ident) |
| 597 » » » » » » » const char **path) | 741 { |
| 742 » if (ident->user != NULL) { |
| 743 » » /* NB: check for two tokens done in validate_ident */ |
| 744 » » return g_strdup_printf("/profile/%s/%s", |
| 745 » » ident->user, ident->ident); |
| 746 » } else |
| 747 » » return g_strdup_printf("/profile/%s", ident->ident); |
| 748 } |
| 749 |
| 750 /* |
| 751 * Create an in-memory profile using the specified identifier |
| 752 * and name. The object path and a reference to the profile |
| 753 * data structure are returned on success. |
| 754 */ |
| 755 static int create_profile(struct connman_storage_ident *ident, |
| 756 const char *name, const char **path, struct connman_profile **pprofile) |
| 598 { | 757 { |
| 599 struct connman_profile *profile; | 758 struct connman_profile *profile; |
| 600 | 759 |
| 601 » _DBG_PROFILE("ident %s name %s", ident, name); | 760 » _DBG_PROFILE("ident %s:%s name %s", ident->user, ident->ident, name); |
| 602 | 761 |
| 603 profile = g_try_new0(struct connman_profile, 1); | 762 profile = g_try_new0(struct connman_profile, 1); |
| 604 » if (profile == NULL) | 763 » if (profile == NULL) { |
| 764 » » free_ident(ident); |
| 605 return -ENOMEM; | 765 return -ENOMEM; |
| 766 } |
| 606 | 767 |
| 607 » profile->ident = g_strdup(ident); | 768 » profile->ident = *ident; |
| 608 » profile->path = g_strdup_printf("/profile/%s", ident); | 769 » profile->path = getpath(ident); |
| 609 | 770 » /* TODO(sleffler) check ident.user */ |
| 610 » if (profile->ident == NULL || profile->path == NULL) { | 771 » if (profile->ident.ident == NULL || profile->path == NULL) { |
| 611 free_profile(profile); | 772 free_profile(profile); |
| 612 return -ENOMEM; | 773 return -ENOMEM; |
| 613 } | 774 } |
| 614 | 775 |
| 615 if (g_hash_table_lookup(profile_hash, profile->path) != NULL) { | 776 if (g_hash_table_lookup(profile_hash, profile->path) != NULL) { |
| 616 free_profile(profile); | 777 free_profile(profile); |
| 617 return -EEXIST; | 778 return -EEXIST; |
| 618 } | 779 } |
| 619 | 780 |
| 620 profile->name = g_strdup(name); | 781 profile->name = g_strdup(name); |
| 621 | 782 |
| 622 __connman_storage_load_profile(profile); | 783 __connman_storage_load_profile(profile); |
| 623 | 784 |
| 624 g_hash_table_insert(profile_hash, g_strdup(profile->path), profile); | 785 g_hash_table_insert(profile_hash, g_strdup(profile->path), profile); |
| 625 | 786 |
| 626 » connman_info("Adding profile %s", ident); | 787 » connman_info("Add profile %s:%s", ident->user, ident->ident); |
| 627 | 788 |
| 628 » if (g_strcmp0(ident, PROFILE_DEFAULT_IDENT) == 0) | 789 » if (ident_equal(ident, &default_ident)) |
| 629 default_profile = profile; | 790 default_profile = profile; |
| 630 | 791 |
| 631 g_dbus_register_interface(connection, profile->path, | 792 g_dbus_register_interface(connection, profile->path, |
| 632 CONNMAN_PROFILE_INTERFACE, | 793 CONNMAN_PROFILE_INTERFACE, |
| 633 profile_methods, profile_signals, | 794 profile_methods, profile_signals, |
| 634 NULL, profile, NULL); | 795 NULL, profile, NULL); |
| 635 | 796 |
| 636 if (path != NULL) | 797 if (path != NULL) |
| 637 *path = profile->path; | 798 *path = profile->path; |
| 638 | 799 |
| 639 _DBG_PROFILE("profile %p path %s", profile, profile->path); | 800 _DBG_PROFILE("profile %p path %s", profile, profile->path); |
| 640 | 801 |
| 802 *pprofile = profile; |
| 641 return 0; | 803 return 0; |
| 642 } | 804 } |
| 643 | 805 |
| 644 static gboolean validate_ident(const char *ident) | 806 /* |
| 807 * Check a profile identifier token. This must be non-null and |
| 808 * made up of alpha-numeric chars suitable for use in a D-bus |
| 809 * object path. |
| 810 */ |
| 811 static gboolean validate_token(const char *ident) |
| 645 { | 812 { |
| 646 unsigned int i; | 813 unsigned int i; |
| 647 unsigned int len = strlen(ident); | 814 unsigned int len = strlen(ident); |
| 648 | 815 |
| 649 if (len < 1) | 816 if (len < 1) |
| 650 return FALSE; | 817 return FALSE; |
| 651 | 818 |
| 652 for (i = 0; i < len; i++) { | 819 for (i = 0; i < len; i++) { |
| 653 if (ident[i] >= '0' && ident[i] <= '9') | 820 if (ident[i] >= '0' && ident[i] <= '9') |
| 654 continue; | 821 continue; |
| 655 if (ident[i] >= 'a' && ident[i] <= 'z') | 822 if (ident[i] >= 'a' && ident[i] <= 'z') |
| 656 continue; | 823 continue; |
| 657 if (ident[i] >= 'A' && ident[i] <= 'Z') | 824 if (ident[i] >= 'A' && ident[i] <= 'Z') |
| 658 continue; | 825 continue; |
| 659 return FALSE; | 826 return FALSE; |
| 660 } | 827 } |
| 661 | 828 |
| 662 return TRUE; | 829 return TRUE; |
| 663 } | 830 } |
| 664 | 831 |
| 832 /* |
| 833 * Validate the profile identifier. It must be suitable |
| 834 * for use in a D-Bus object path and, optionally, be of |
| 835 * the form ~user/ident to signify a per-user profile. |
| 836 */ |
| 837 static gboolean parse_ident(const char *str, |
| 838 struct connman_storage_ident *ident) |
| 839 { |
| 840 gboolean is_valid; |
| 841 |
| 842 if (str[0] == '~') { |
| 843 /* syntax is ~user/name for profile in cryptohome */ |
| 844 gchar **tokens = g_strsplit_set(str, "~/", 4); |
| 845 if (g_strv_length(tokens) == 3) { |
| 846 is_valid = (validate_token(tokens[1]) == TRUE && |
| 847 validate_token(tokens[2]) == TRUE); |
| 848 if (is_valid) { |
| 849 ident->user = g_strdup(tokens[1]); |
| 850 ident->ident = g_strdup(tokens[2]); |
| 851 } |
| 852 } else |
| 853 is_valid = FALSE; |
| 854 g_strfreev(tokens); |
| 855 } else { |
| 856 is_valid = validate_token(str); |
| 857 if (is_valid) { |
| 858 ident->user = NULL; |
| 859 ident->ident = g_strdup(str); |
| 860 } |
| 861 } |
| 862 return is_valid; |
| 863 } |
| 864 |
| 865 /* |
| 866 * Lookup a profile on the stack by object path. |
| 867 */ |
| 868 static struct connman_profile *lookup_stack_by_path(const char *path) |
| 869 { |
| 870 int i; |
| 871 |
| 872 for (i = cur_profile; i >= 0; i--) |
| 873 if (g_strcmp0(profile_stack[i]->path, path) == 0) |
| 874 return profile_stack[i]; |
| 875 return NULL; |
| 876 } |
| 877 |
| 878 /* |
| 879 * Push a profile on the stack and make it the ``active profile''. |
| 880 * The profile may be currently registered in memory or previously |
| 881 * created by CreateProfile. The profile may not already be on |
| 882 * the stack. |
| 883 */ |
| 884 int __connman_profile_push(const char *ident, const char *name, |
| 885 const char **path) |
| 886 { |
| 887 struct connman_profile *profile; |
| 888 struct connman_storage_ident sid; |
| 889 char *tmp_path; |
| 890 int err; |
| 891 |
| 892 _DBG_PROFILE("ident %s name %s", ident, name); |
| 893 |
| 894 if (parse_ident(ident, &sid) == FALSE) { |
| 895 connman_error("%s: invalid profile name %s", __func__, ident); |
| 896 return -EINVAL; |
| 897 } |
| 898 |
| 899 if (cur_profile+1 >= PROFILE_MAX) { |
| 900 connman_error("%s: too many profiles (max %d)", __func__, |
| 901 PROFILE_MAX); |
| 902 free_ident(&sid); |
| 903 return -EMFILE; |
| 904 } |
| 905 |
| 906 /* |
| 907 * Check for in-memory profile by way of a CreateProfile request. |
| 908 */ |
| 909 tmp_path = getpath(&sid); |
| 910 if (tmp_path == NULL) { |
| 911 connman_error("%s: no memory for %s", __func__, ident); |
| 912 free_ident(&sid); |
| 913 return -ENOMEM; |
| 914 } |
| 915 |
| 916 profile = g_hash_table_lookup(profile_hash, tmp_path); |
| 917 g_free(tmp_path); |
| 918 if (profile == NULL) { |
| 919 /* |
| 920 * Not in memory; accept an existing file. |
| 921 */ |
| 922 if (__connman_storage_exists(&sid) == FALSE) { |
| 923 connman_error("%s: profile %s does not exist", |
| 924 __func__, ident); |
| 925 free_ident(&sid); |
| 926 return -ENOENT; |
| 927 } |
| 928 |
| 929 err = create_profile(&sid, name, path, &profile); |
| 930 if (err < 0) { |
| 931 connman_error("%s: cannot open, error %d", |
| 932 __func__, err); |
| 933 /* NB: create_profile reclaims sid */ |
| 934 return err; |
| 935 } |
| 936 } else { |
| 937 free_ident(&sid); /* NB: not needed below */ |
| 938 /* |
| 939 * Check this profile is not already on the stack. |
| 940 */ |
| 941 if (lookup_stack_by_path(profile->path) != NULL) { |
| 942 connman_error("%s: already pushed", __func__); |
| 943 return -EEXIST; |
| 944 } |
| 945 if (path != NULL) |
| 946 *path = profile->path; |
| 947 } |
| 948 |
| 949 profile_stack[++cur_profile] = profile; |
| 950 |
| 951 profiles_changed(); |
| 952 |
| 953 /* NB: this is a noop if we are online (or trying to get online) */ |
| 954 __connman_service_auto_connect_any(); |
| 955 |
| 956 return 0; |
| 957 } |
| 958 |
| 959 /* |
| 960 * Pop the profile from the top of the stack and remove it from |
| 961 * the in-memory table. Any associated services are invalidated |
| 962 * (credentials revoked and connections closed). After a pop we |
| 963 * generate a PropertyChanged signal for Manager.Profiles. |
| 964 * |
| 965 * An optional identifier may be specified. If specified it is |
| 966 * checked against the active profile and if not the same then |
| 967 * the request is rejected. This is useful to ensure the right |
| 968 * profile is pop'd (as might happen on logout if an associated |
| 969 * push failed for some reason). |
| 970 */ |
| 971 int __connman_profile_pop(const char *ident) |
| 972 { |
| 973 struct connman_profile *profile; |
| 974 |
| 975 _DBG_PROFILE("ident %s", ident); |
| 976 |
| 977 if (cur_profile < 0) { |
| 978 connman_error("%s: profile stack empty", __func__); |
| 979 return -EINVAL; |
| 980 } |
| 981 |
| 982 profile = profile_stack[cur_profile]; |
| 983 |
| 984 if (ident != NULL) { |
| 985 struct connman_storage_ident sid; |
| 986 |
| 987 if (parse_ident(ident, &sid) == FALSE) { |
| 988 connman_error("%s: invalid profile name %s", |
| 989 __func__, ident); |
| 990 return -EINVAL; |
| 991 } |
| 992 if (ident_equal(&profile->ident, &sid) == FALSE) { |
| 993 connman_error("%s: %s is not the active profile", |
| 994 __func__, ident); |
| 995 free_ident(&sid); |
| 996 return -ENXIO; |
| 997 } |
| 998 free_ident(&sid); |
| 999 } |
| 1000 |
| 1001 __connman_service_invalidate_profile(&profile->ident); |
| 1002 |
| 1003 g_hash_table_remove(profile_hash, profile->path); |
| 1004 cur_profile--; |
| 1005 |
| 1006 profiles_changed(); |
| 1007 |
| 1008 /* NB: no need to kick auto-connect; it will happen due to invalidate */ |
| 1009 |
| 1010 return 0; |
| 1011 } |
| 1012 |
| 1013 /* |
| 1014 * Create a profile file and register it in memory. The |
| 1015 * file is created with minimal contents. |
| 1016 * TODO(sleffler) disallow overwriting an existing file? |
| 1017 */ |
| 665 int __connman_profile_create(const char *name, const char **path) | 1018 int __connman_profile_create(const char *name, const char **path) |
| 666 { | 1019 { |
| 667 struct connman_profile *profile; | 1020 struct connman_profile *profile; |
| 1021 struct connman_storage_ident sid; |
| 668 int err; | 1022 int err; |
| 669 | 1023 |
| 670 _DBG_PROFILE("name %s", name); | 1024 _DBG_PROFILE("name %s", name); |
| 671 | 1025 |
| 672 » if (validate_ident(name) == FALSE) | 1026 » if (parse_ident(name, &sid) == FALSE) { |
| 673 » » return -EINVAL; | 1027 » » connman_error("%s: invalid profile name %s)", __func__, name); |
| 674 | 1028 » » return -EINVAL; |
| 675 » err = create_profile(name, NULL, path); | 1029 » } |
| 676 » if (err < 0) | 1030 |
| 1031 » err = create_profile(&sid, NULL, path, &profile); |
| 1032 » if (err < 0) { |
| 1033 » » connman_error("%s: cannot open, error %d", __func__, err); |
| 1034 » » /* NB: create_profile reclaims sid */ |
| 677 return err; | 1035 return err; |
| 678 | 1036 » } |
| 679 » profile = g_hash_table_lookup(profile_hash, *path); | |
| 680 » if (profile == NULL) | |
| 681 » » return -EIO; | |
| 682 | 1037 |
| 683 __connman_storage_save_profile(profile); | 1038 __connman_storage_save_profile(profile); |
| 684 | 1039 |
| 685 profiles_changed(); | 1040 profiles_changed(); |
| 686 | 1041 |
| 687 return 0; | 1042 return 0; |
| 688 } | 1043 } |
| 689 | 1044 |
| 690 int __connman_profile_remove(const char *path) | 1045 /* |
| 691 { | 1046 * Delete a profile and remove from memory. The default |
| 692 » struct connman_profile *profile; | 1047 * profile may not be removed/deleted. Likewise, one |
| 693 | 1048 * cannot remove a profile pushed on the stack. |
| 694 » _DBG_PROFILE("path %s", path); | 1049 */ |
| 695 | 1050 int __connman_profile_remove(const char *ident) |
| 696 » if (default_profile != NULL && | 1051 { |
| 697 » » » » g_strcmp0(path, default_profile->path) == 0) | 1052 » struct connman_profile *profile; |
| 698 » » return -EINVAL; | 1053 » struct connman_storage_ident sid; |
| 699 | 1054 » char *tmp_path; |
| 700 » profile = g_hash_table_lookup(profile_hash, path); | 1055 » int err = 0; |
| 701 » if (profile == NULL) | 1056 |
| 702 » » return -ENXIO; | 1057 » _DBG_PROFILE("ident %s", ident); |
| 703 | 1058 |
| 704 » __connman_storage_delete(profile->ident); | 1059 » if (parse_ident(ident, &sid) == FALSE) { |
| 705 | 1060 » » connman_error("%s: invalid profile name %s)", __func__, ident); |
| 706 » g_hash_table_remove(profile_hash, path); | 1061 » » return -EINVAL; |
| 707 | 1062 » } |
| 708 » profiles_changed(); | 1063 |
| 709 | 1064 » if (ident_equal(&sid, &default_ident)) { |
| 710 » return 0; | 1065 » » /* TODO(sleffler) should this be permitted? */ |
| 711 } | 1066 » » connman_error("%s: cannot delete default profile", __func__); |
| 712 | 1067 » » err = -EINVAL; |
| 1068 » » goto done; |
| 1069 » } |
| 1070 |
| 1071 » /* |
| 1072 » * Check for in-memory profile by way of a CreateProfile request. |
| 1073 » */ |
| 1074 » tmp_path = getpath(&sid); |
| 1075 » if (tmp_path == NULL) { |
| 1076 » » connman_error("%s: no memory for %s", __func__, ident); |
| 1077 » » err = -ENOMEM; |
| 1078 » » goto done; |
| 1079 » } |
| 1080 » profile = g_hash_table_lookup(profile_hash, tmp_path); |
| 1081 » g_free(tmp_path); |
| 1082 |
| 1083 » if (profile != NULL) { |
| 1084 » » /* |
| 1085 » » * Check this profile is not on the stack. |
| 1086 » » */ |
| 1087 » » if (lookup_stack_by_path(profile->path) != NULL) { |
| 1088 » » » connman_error("%s: cannot delete (on the stack)", |
| 1089 » » » __func__); |
| 1090 » » » err = -EEXIST; |
| 1091 » » » goto done; |
| 1092 » » } |
| 1093 » » g_hash_table_remove(profile_hash, profile->path); |
| 1094 |
| 1095 » » profiles_changed(); |
| 1096 » } |
| 1097 |
| 1098 » __connman_storage_delete(&sid); |
| 1099 done: |
| 1100 » free_ident(&sid); |
| 1101 » return err; |
| 1102 } |
| 1103 |
| 1104 /* |
| 1105 * Initialize the profile stack by pushing the default |
| 1106 * (global) profile. Unlike connman we do not read in |
| 1107 * all available .profile's in the global dir. |
| 1108 */ |
| 713 static int profile_init(void) | 1109 static int profile_init(void) |
| 714 { | 1110 { |
| 715 » GDir *dir; | 1111 » struct connman_profile *profile; |
| 716 » const gchar *file; | 1112 » int err; |
| 717 | 1113 |
| 718 » _DBG_PROFILE(""); | 1114 » err = create_profile(&default_ident, "Default", NULL, &profile); |
| 719 | 1115 » if (err == 0) |
| 720 » dir = g_dir_open(STORAGEDIR, 0, NULL); | 1116 » » profile_stack[++cur_profile] = profile; |
| 721 » if (dir != NULL) { | 1117 » return err; |
| 722 » » while ((file = g_dir_read_name(dir)) != NULL) { | |
| 723 » » » GString *str; | |
| 724 » » » gchar *ident; | |
| 725 | |
| 726 » » » if (g_str_has_suffix(file, ".profile") == FALSE) | |
| 727 » » » » continue; | |
| 728 | |
| 729 » » » ident = g_strrstr(file, ".profile"); | |
| 730 » » » if (ident == NULL) | |
| 731 » » » » continue; | |
| 732 | |
| 733 » » » str = g_string_new_len(file, ident - file); | |
| 734 » » » if (str == NULL) | |
| 735 » » » » continue; | |
| 736 | |
| 737 » » » ident = g_string_free(str, FALSE); | |
| 738 | |
| 739 » » » if (validate_ident(ident) == TRUE) | |
| 740 » » » » create_profile(ident, NULL, NULL); | |
| 741 | |
| 742 » » » g_free(ident); | |
| 743 » » } | |
| 744 | |
| 745 » » g_dir_close(dir); | |
| 746 » } | |
| 747 | |
| 748 » if (g_hash_table_size(profile_hash) == 0) | |
| 749 » » create_profile(PROFILE_DEFAULT_IDENT, "Default", NULL); | |
| 750 | |
| 751 » profiles_changed(); | |
| 752 | |
| 753 » return 0; | |
| 754 } | 1118 } |
| 755 | 1119 |
| 756 static int profile_load(struct connman_profile *profile) | 1120 static int profile_load(struct connman_profile *profile) |
| 757 { | 1121 { |
| 758 GKeyFile *keyfile; | 1122 GKeyFile *keyfile; |
| 759 GError *error = NULL; | 1123 GError *error = NULL; |
| 760 connman_bool_t offlinemode; | 1124 connman_bool_t offlinemode; |
| 761 char *name; | 1125 char *name; |
| 762 | 1126 |
| 763 _DBG_PROFILE("profile %p", profile); | 1127 _DBG_PROFILE("profile %p", profile); |
| 764 | 1128 |
| 765 » keyfile = __connman_storage_open(profile->ident); | 1129 » keyfile = __connman_storage_open(&profile->ident); |
| 766 if (keyfile == NULL) | 1130 if (keyfile == NULL) |
| 767 return -EIO; | 1131 return -EIO; |
| 768 | 1132 |
| 769 name = g_key_file_get_string(keyfile, "global", "Name", NULL); | 1133 name = g_key_file_get_string(keyfile, "global", "Name", NULL); |
| 770 if (name != NULL) { | 1134 if (name != NULL) { |
| 771 g_free(profile->name); | 1135 g_free(profile->name); |
| 772 profile->name = name; | 1136 profile->name = name; |
| 773 } | 1137 } |
| 774 | 1138 |
| 775 offlinemode = g_key_file_get_boolean(keyfile, "global", | 1139 offlinemode = g_key_file_get_boolean(keyfile, "global", |
| 776 "OfflineMode", &error); | 1140 "OfflineMode", &error); |
| 777 if (error == NULL) | 1141 if (error == NULL) |
| 778 profile->offlinemode = offlinemode; | 1142 profile->offlinemode = offlinemode; |
| 779 g_clear_error(&error); | 1143 g_clear_error(&error); |
| 780 | 1144 |
| 781 » __connman_storage_close(profile->ident, keyfile, FALSE); | 1145 » __connman_storage_close(&profile->ident, keyfile, FALSE); |
| 782 | 1146 |
| 783 return 0; | 1147 return 0; |
| 784 } | 1148 } |
| 785 | 1149 |
| 786 static int profile_save(struct connman_profile *profile) | 1150 static int profile_save(struct connman_profile *profile) |
| 787 { | 1151 { |
| 788 GKeyFile *keyfile; | 1152 GKeyFile *keyfile; |
| 789 | 1153 |
| 790 _DBG_PROFILE("profile %p", profile); | 1154 _DBG_PROFILE("profile %p", profile); |
| 791 | 1155 |
| 792 » keyfile = __connman_storage_open(profile->ident); | 1156 » keyfile = __connman_storage_open(&profile->ident); |
| 793 if (keyfile == NULL) | 1157 if (keyfile == NULL) |
| 794 return -EIO; | 1158 return -EIO; |
| 795 | 1159 |
| 796 if (profile->name != NULL) | 1160 if (profile->name != NULL) |
| 797 g_key_file_set_string(keyfile, "global", | 1161 g_key_file_set_string(keyfile, "global", |
| 798 "Name", profile->name); | 1162 "Name", profile->name); |
| 799 | 1163 |
| 800 g_key_file_set_boolean(keyfile, "global", | 1164 g_key_file_set_boolean(keyfile, "global", |
| 801 "OfflineMode", profile->offlinemode); | 1165 "OfflineMode", profile->offlinemode); |
| 802 | 1166 |
| 803 » __connman_storage_close(profile->ident, keyfile, TRUE); | 1167 » __connman_storage_close(&profile->ident, keyfile, TRUE); |
| 804 | 1168 |
| 805 return 0; | 1169 return 0; |
| 806 } | 1170 } |
| 807 | 1171 |
| 808 static struct connman_storage profile_storage = { | 1172 static struct connman_storage profile_storage = { |
| 809 .name = "profile", | 1173 .name = "profile", |
| 810 .priority = CONNMAN_STORAGE_PRIORITY_LOW, | 1174 .priority = CONNMAN_STORAGE_PRIORITY_LOW, |
| 811 .profile_init = profile_init, | 1175 .profile_init = profile_init, |
| 812 .profile_load = profile_load, | 1176 .profile_load = profile_load, |
| 813 .profile_save = profile_save, | 1177 .profile_save = profile_save, |
| 814 }; | 1178 }; |
| 815 | 1179 |
| 816 int __connman_profile_init(void) | 1180 int __connman_profile_init(void) |
| 817 { | 1181 { |
| 818 _DBG_PROFILE(""); | 1182 _DBG_PROFILE(""); |
| 819 | 1183 |
| 820 connection = connman_dbus_get_connection(); | 1184 connection = connman_dbus_get_connection(); |
| 821 if (connection == NULL) | 1185 if (connection == NULL) |
| 822 return -1; | 1186 return -1; |
| 823 | 1187 |
| 824 if (connman_storage_register(&profile_storage) < 0) | 1188 if (connman_storage_register(&profile_storage) < 0) |
| 825 connman_error("Failed to register profile storage"); | 1189 connman_error("Failed to register profile storage"); |
| 826 | 1190 |
| 827 profile_hash = g_hash_table_new_full(g_str_hash, g_str_equal, | 1191 profile_hash = g_hash_table_new_full(g_str_hash, g_str_equal, |
| 828 g_free, unregister_profile); | 1192 g_free, unregister_profile); |
| 829 | 1193 |
| 830 return 0; | 1194 return 0; |
| 831 } | 1195 } |
| 832 | 1196 |
| 1197 int __connman_profile_push_batch(char **profiles) |
| 1198 { |
| 1199 int i; |
| 1200 |
| 1201 if (profiles == NULL) |
| 1202 return 0; |
| 1203 |
| 1204 for (i = 0; profiles[i] != NULL; i++) { |
| 1205 int err = __connman_profile_push(profiles[i], NULL, NULL); |
| 1206 if (err != 0) |
| 1207 return err; |
| 1208 } |
| 1209 return 0; |
| 1210 } |
| 1211 |
| 833 void __connman_profile_cleanup(void) | 1212 void __connman_profile_cleanup(void) |
| 834 { | 1213 { |
| 835 _DBG_PROFILE(""); | 1214 _DBG_PROFILE(""); |
| 836 | 1215 |
| 837 if (connection == NULL) | 1216 if (connection == NULL) |
| 838 return; | 1217 return; |
| 839 | 1218 |
| 1219 while (cur_profile >= 0) |
| 1220 __connman_profile_pop(NULL); |
| 1221 |
| 840 g_hash_table_destroy(profile_hash); | 1222 g_hash_table_destroy(profile_hash); |
| 841 profile_hash = NULL; | 1223 profile_hash = NULL; |
| 842 | 1224 |
| 1225 clear_timeout(); /* cancel any pending timer */ |
| 1226 |
| 843 connman_storage_unregister(&profile_storage); | 1227 connman_storage_unregister(&profile_storage); |
| 844 | 1228 |
| 845 dbus_connection_unref(connection); | 1229 dbus_connection_unref(connection); |
| 846 } | 1230 } |
| OLD | NEW |