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