5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
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
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 static DBusConnection *connection = NULL;
32 static GSequence *service_list = NULL;
33 static GHashTable *service_hash = NULL;
35 struct connman_service {
39 enum connman_service_type type;
40 enum connman_service_mode mode;
41 enum connman_service_security security;
42 enum connman_service_state state;
43 connman_uint8_t strength;
44 connman_bool_t favorite;
48 struct connman_device *device;
49 struct connman_network *network;
52 static void append_path(gpointer value, gpointer user_data)
54 struct connman_service *service = value;
55 DBusMessageIter *iter = user_data;
57 if (service->path == NULL)
60 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
64 void __connman_service_list(DBusMessageIter *iter)
68 g_sequence_foreach(service_list, append_path, iter);
71 static const char *type2string(enum connman_service_type type)
74 case CONNMAN_SERVICE_TYPE_UNKNOWN:
76 case CONNMAN_SERVICE_TYPE_ETHERNET:
78 case CONNMAN_SERVICE_TYPE_WIFI:
80 case CONNMAN_SERVICE_TYPE_WIMAX:
87 static const char *mode2string(enum connman_service_mode mode)
90 case CONNMAN_SERVICE_MODE_UNKNOWN:
92 case CONNMAN_SERVICE_MODE_MANAGED:
94 case CONNMAN_SERVICE_MODE_ADHOC:
101 static const char *security2string(enum connman_service_security security)
104 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
106 case CONNMAN_SERVICE_SECURITY_NONE:
108 case CONNMAN_SERVICE_SECURITY_WEP:
110 case CONNMAN_SERVICE_SECURITY_WPA:
112 case CONNMAN_SERVICE_SECURITY_WPA2:
119 static const char *state2string(enum connman_service_state state)
122 case CONNMAN_SERVICE_STATE_UNKNOWN:
124 case CONNMAN_SERVICE_STATE_IDLE:
126 case CONNMAN_SERVICE_STATE_CARRIER:
128 case CONNMAN_SERVICE_STATE_ASSOCIATION:
129 return "association";
130 case CONNMAN_SERVICE_STATE_CONFIGURATION:
131 return "configuration";
132 case CONNMAN_SERVICE_STATE_READY:
134 case CONNMAN_SERVICE_STATE_DISCONNECT:
136 case CONNMAN_SERVICE_STATE_FAILURE:
143 static void state_changed(struct connman_service *service)
146 DBusMessageIter entry, value;
147 const char *str, *key = "State";
149 if (service->path == NULL)
152 str = state2string(service->state);
156 signal = dbus_message_new_signal(service->path,
157 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
161 dbus_message_iter_init_append(signal, &entry);
163 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
165 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
166 DBUS_TYPE_STRING_AS_STRING, &value);
167 dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
168 dbus_message_iter_close_container(&entry, &value);
170 g_dbus_send_message(connection, signal);
173 static DBusMessage *get_properties(DBusConnection *conn,
174 DBusMessage *msg, void *data)
176 struct connman_service *service = data;
178 DBusMessageIter array, dict;
181 DBG("conn %p", conn);
183 reply = dbus_message_new_method_return(msg);
187 dbus_message_iter_init_append(reply, &array);
189 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
190 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
191 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
192 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
194 str = type2string(service->type);
196 connman_dbus_dict_append_variant(&dict, "Type",
197 DBUS_TYPE_STRING, &str);
199 str = mode2string(service->mode);
201 connman_dbus_dict_append_variant(&dict, "Mode",
202 DBUS_TYPE_STRING, &str);
204 str = security2string(service->security);
206 connman_dbus_dict_append_variant(&dict, "Security",
207 DBUS_TYPE_STRING, &str);
209 str = state2string(service->state);
211 connman_dbus_dict_append_variant(&dict, "State",
212 DBUS_TYPE_STRING, &str);
214 if (service->strength > 0)
215 connman_dbus_dict_append_variant(&dict, "Strength",
216 DBUS_TYPE_BYTE, &service->strength);
218 connman_dbus_dict_append_variant(&dict, "Favorite",
219 DBUS_TYPE_BOOLEAN, &service->favorite);
221 if (service->name != NULL)
222 connman_dbus_dict_append_variant(&dict, "Name",
223 DBUS_TYPE_STRING, &service->name);
225 if (service->passphrase != NULL &&
226 __connman_security_check_privilege(msg,
227 CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
228 connman_dbus_dict_append_variant(&dict, "Passphrase",
229 DBUS_TYPE_STRING, &service->passphrase);
231 dbus_message_iter_close_container(&array, &dict);
236 static DBusMessage *set_property(DBusConnection *conn,
237 DBusMessage *msg, void *data)
239 struct connman_service *service = data;
240 DBusMessageIter iter, value;
244 DBG("conn %p", conn);
246 if (dbus_message_iter_init(msg, &iter) == FALSE)
247 return __connman_error_invalid_arguments(msg);
249 dbus_message_iter_get_basic(&iter, &name);
250 dbus_message_iter_next(&iter);
251 dbus_message_iter_recurse(&iter, &value);
253 if (__connman_security_check_privilege(msg,
254 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
255 return __connman_error_permission_denied(msg);
257 type = dbus_message_iter_get_arg_type(&value);
259 if (g_str_equal(name, "Passphrase") == TRUE) {
260 const char *passphrase;
262 if (type != DBUS_TYPE_STRING)
263 return __connman_error_invalid_arguments(msg);
265 if (__connman_security_check_privilege(msg,
266 CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
267 return __connman_error_permission_denied(msg);
269 dbus_message_iter_get_basic(&value, &passphrase);
271 g_free(service->passphrase);
272 service->passphrase = g_strdup(passphrase);
274 if (service->network != NULL)
275 connman_network_set_string(service->network,
276 "WiFi.Passphrase", service->passphrase);
279 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
282 static DBusMessage *connect_service(DBusConnection *conn,
283 DBusMessage *msg, void *data)
285 struct connman_service *service = data;
287 if (service->device != NULL) {
288 if (__connman_device_connect(service->device) < 0)
289 return __connman_error_failed(msg);
291 service->state = CONNMAN_SERVICE_STATE_READY;
293 state_changed(service);
296 return __connman_error_not_supported(msg);
299 static DBusMessage *disconnect_service(DBusConnection *conn,
300 DBusMessage *msg, void *data)
302 struct connman_service *service = data;
304 if (service->device != NULL) {
305 if (__connman_device_connect(service->device) < 0)
306 return __connman_error_failed(msg);
308 service->state = CONNMAN_SERVICE_STATE_IDLE;
310 state_changed(service);
313 return __connman_error_not_supported(msg);
316 static DBusMessage *remove_service(DBusConnection *conn,
317 DBusMessage *msg, void *data)
319 struct connman_service *service = data;
321 if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
322 return __connman_error_not_supported(msg);
324 connman_service_set_favorite(service, FALSE);
326 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
329 static DBusMessage *move_before(DBusConnection *conn,
330 DBusMessage *msg, void *data)
332 struct connman_service *service = data;
334 if (service->favorite == FALSE)
335 return __connman_error_not_supported(msg);
337 return __connman_error_not_implemented(msg);
340 static DBusMessage *move_after(DBusConnection *conn,
341 DBusMessage *msg, void *data)
343 struct connman_service *service = data;
345 if (service->favorite == FALSE)
346 return __connman_error_not_supported(msg);
348 return __connman_error_not_implemented(msg);
351 static GDBusMethodTable service_methods[] = {
352 { "GetProperties", "", "a{sv}", get_properties },
353 { "SetProperty", "sv", "", set_property },
354 { "Connect", "", "", connect_service },
355 { "Disconnect", "", "", disconnect_service },
356 { "Remove", "", "", remove_service },
357 { "MoveBefore", "o", "", move_before },
358 { "MoveAfter", "o", "", move_after },
362 static GDBusSignalTable service_signals[] = {
363 { "PropertyChanged", "sv" },
367 static void service_free(gpointer data)
369 struct connman_service *service = data;
370 char *path = service->path;
372 DBG("service %p", service);
374 g_hash_table_remove(service_hash, service->identifier);
376 service->path = NULL;
379 __connman_profile_changed();
381 g_dbus_unregister_interface(connection, path,
382 CONNMAN_SERVICE_INTERFACE);
386 if (service->network != NULL)
387 connman_network_unref(service->network);
389 g_free(service->name);
390 g_free(service->passphrase);
391 g_free(service->identifier);
396 * connman_service_put:
397 * @service: service structure
399 * Release service if no longer needed
401 void connman_service_put(struct connman_service *service)
403 DBG("service %p", service);
405 if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
408 iter = g_hash_table_lookup(service_hash, service->identifier);
410 g_sequence_remove(iter);
412 service_free(service);
416 static void __connman_service_initialize(struct connman_service *service)
418 DBG("service %p", service);
420 service->refcount = 1;
422 service->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
423 service->mode = CONNMAN_SERVICE_MODE_UNKNOWN;
424 service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
425 service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
427 service->favorite = FALSE;
433 * connman_service_create:
435 * Allocate a new service.
437 * Returns: a newly-allocated #connman_service structure
439 struct connman_service *connman_service_create(void)
441 struct connman_service *service;
443 service = g_try_new0(struct connman_service, 1);
447 DBG("service %p", service);
449 __connman_service_initialize(service);
455 * connman_service_ref:
456 * @service: service structure
458 * Increase reference counter of service
460 struct connman_service *connman_service_ref(struct connman_service *service)
462 g_atomic_int_inc(&service->refcount);
468 * connman_service_unref:
469 * @service: service structure
471 * Decrease reference counter of service
473 void connman_service_unref(struct connman_service *service)
475 connman_service_put(service);
478 static gint service_compare(gconstpointer a, gconstpointer b,
481 struct connman_service *service_a = (void *) a;
482 struct connman_service *service_b = (void *) b;
484 if (service_a->order > service_b->order)
487 if (service_a->order < service_b->order)
490 if (service_a->favorite == TRUE && service_b->favorite == FALSE)
493 if (service_a->favorite == FALSE && service_b->favorite == TRUE)
496 return (gint) service_b->strength - (gint) service_a->strength;
500 * connman_service_set_favorite:
501 * @service: service structure
502 * @favorite: favorite value
504 * Change the favorite setting of service
506 int connman_service_set_favorite(struct connman_service *service,
507 connman_bool_t favorite)
511 iter = g_hash_table_lookup(service_hash, service->identifier);
515 if (service->favorite)
518 service->favorite = favorite;
520 g_sequence_sort_changed(iter, service_compare, NULL);
522 __connman_profile_changed();
527 int __connman_service_set_carrier(struct connman_service *service,
528 connman_bool_t carrier)
530 DBG("service %p carrier %d", service, carrier);
535 switch (service->type) {
536 case CONNMAN_SERVICE_TYPE_UNKNOWN:
537 case CONNMAN_SERVICE_TYPE_WIFI:
538 case CONNMAN_SERVICE_TYPE_WIMAX:
540 case CONNMAN_SERVICE_TYPE_ETHERNET:
545 service->state = CONNMAN_SERVICE_STATE_CARRIER;
547 service->state = CONNMAN_SERVICE_STATE_IDLE;
549 state_changed(service);
551 return connman_service_set_favorite(service, carrier);
554 int __connman_service_indicate_configuration(struct connman_service *service)
556 DBG("service %p", service);
561 service->state = CONNMAN_SERVICE_STATE_CONFIGURATION;
563 state_changed(service);
568 int __connman_service_ready(struct connman_service *service)
570 DBG("service %p", service);
575 service->state = CONNMAN_SERVICE_STATE_READY;
577 state_changed(service);
582 int __connman_service_disconnect(struct connman_service *service)
584 DBG("service %p", service);
589 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
591 state_changed(service);
597 * connman_service_lookup:
598 * @identifier: service identifier
600 * Look up a service by identifier (reference count will not be increased)
602 struct connman_service *connman_service_lookup(const char *identifier)
606 iter = g_hash_table_lookup(service_hash, identifier);
608 return g_sequence_get(iter);
614 * connman_service_get:
615 * @identifier: service identifier
617 * Look up a service by identifier or create a new one if not found
619 struct connman_service *connman_service_get(const char *identifier)
621 struct connman_service *service;
624 iter = g_hash_table_lookup(service_hash, identifier);
626 service = g_sequence_get(iter);
628 g_atomic_int_inc(&service->refcount);
632 service = g_try_new0(struct connman_service, 1);
636 DBG("service %p", service);
638 __connman_service_initialize(service);
640 service->identifier = g_strdup(identifier);
642 iter = g_sequence_insert_sorted(service_list, service,
643 service_compare, NULL);
645 g_hash_table_insert(service_hash, service->identifier, iter);
650 static int service_register(struct connman_service *service)
652 const char *path = __connman_profile_active();
654 DBG("service %p", service);
656 if (service->path != NULL)
659 service->path = g_strdup_printf("%s/%s", path, service->identifier);
661 DBG("path %s", service->path);
663 g_dbus_register_interface(connection, service->path,
664 CONNMAN_SERVICE_INTERFACE,
665 service_methods, service_signals,
666 NULL, service, NULL);
668 __connman_profile_changed();
674 * connman_service_lookup_from_device:
675 * @device: device structure
677 * Look up a service by device (reference count will not be increased)
679 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
681 struct connman_service *service;
684 name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
685 connman_device_get_index(device));
687 service = connman_service_lookup(name);
694 static enum connman_service_type convert_device_type(struct connman_device *device)
696 enum connman_device_type type = connman_device_get_type(device);
699 case CONNMAN_DEVICE_TYPE_UNKNOWN:
700 case CONNMAN_DEVICE_TYPE_VENDOR:
701 case CONNMAN_DEVICE_TYPE_WIFI:
702 case CONNMAN_DEVICE_TYPE_WIMAX:
703 case CONNMAN_DEVICE_TYPE_BLUETOOTH:
704 case CONNMAN_DEVICE_TYPE_GPS:
705 case CONNMAN_DEVICE_TYPE_HSO:
706 case CONNMAN_DEVICE_TYPE_NOZOMI:
707 case CONNMAN_DEVICE_TYPE_HUAWEI:
708 case CONNMAN_DEVICE_TYPE_NOVATEL:
710 case CONNMAN_DEVICE_TYPE_ETHERNET:
711 return CONNMAN_SERVICE_TYPE_ETHERNET;
714 return CONNMAN_SERVICE_TYPE_UNKNOWN;
718 * connman_service_create_from_device:
719 * @device: device structure
721 * Look up service by device and if not found, create one
723 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
725 struct connman_service *service;
728 name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
729 connman_device_get_index(device));
731 service = connman_service_get(name);
735 if (service->path != NULL) {
736 connman_service_put(service);
741 service->type = convert_device_type(device);
743 service->device = device;
745 service_register(service);
754 * connman_service_lookup_from_network:
755 * @network: network structure
757 * Look up a service by network (reference count will not be increased)
759 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
761 struct connman_service *service;
765 group = __connman_network_get_group(network);
769 name = g_strdup_printf("%s_%s",
770 __connman_network_get_type(network), group);
772 service = connman_service_lookup(name);
779 static enum connman_service_type convert_network_type(struct connman_network *network)
781 enum connman_network_type type = connman_network_get_type(network);
784 case CONNMAN_NETWORK_TYPE_UNKNOWN:
785 case CONNMAN_NETWORK_TYPE_VENDOR:
786 case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
787 case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
788 case CONNMAN_NETWORK_TYPE_HSO:
790 case CONNMAN_NETWORK_TYPE_WIFI:
791 return CONNMAN_SERVICE_TYPE_WIFI;
792 case CONNMAN_NETWORK_TYPE_WIMAX:
793 return CONNMAN_SERVICE_TYPE_WIMAX;
796 return CONNMAN_SERVICE_TYPE_UNKNOWN;
799 static enum connman_service_mode convert_wifi_mode(const char *mode)
802 return CONNMAN_SERVICE_MODE_UNKNOWN;
803 else if (g_str_equal(mode, "managed") == TRUE)
804 return CONNMAN_SERVICE_MODE_MANAGED;
805 else if (g_str_equal(mode, "adhoc") == TRUE)
806 return CONNMAN_SERVICE_MODE_ADHOC;
808 return CONNMAN_SERVICE_MODE_UNKNOWN;
811 static enum connman_service_mode convert_wifi_security(const char *security)
813 if (security == NULL)
814 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
815 else if (g_str_equal(security, "none") == TRUE)
816 return CONNMAN_SERVICE_SECURITY_NONE;
817 else if (g_str_equal(security, "wep") == TRUE)
818 return CONNMAN_SERVICE_SECURITY_WEP;
819 else if (g_str_equal(security, "wpa") == TRUE)
820 return CONNMAN_SERVICE_SECURITY_WPA;
821 else if (g_str_equal(security, "wpa2") == TRUE)
822 return CONNMAN_SERVICE_SECURITY_WPA2;
824 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
827 static void update_from_network(struct connman_service *service,
828 struct connman_network *network)
830 connman_uint8_t strength = service->strength;
834 str = connman_network_get_string(network, "Name");
836 g_free(service->name);
837 service->name = g_strdup(str);
840 service->strength = connman_network_get_uint8(network, "Strength");
842 str = connman_network_get_string(network, "WiFi.Mode");
843 service->mode = convert_wifi_mode(str);
845 str = connman_network_get_string(network, "WiFi.Security");
846 service->security = convert_wifi_security(str);
848 if (service->strength > strength && service->network != NULL) {
849 connman_network_unref(service->network);
850 service->network = NULL;
853 if (service->network == NULL) {
854 service->network = connman_network_ref(network);
856 str = connman_network_get_string(network, "WiFi.Passphrase");
858 g_free(service->passphrase);
859 service->passphrase = g_strdup(str);
863 iter = g_hash_table_lookup(service_hash, service->identifier);
865 g_sequence_sort_changed(iter, service_compare, NULL);
869 * connman_service_create_from_network:
870 * @network: network structure
872 * Look up service by network and if not found, create one
874 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
876 struct connman_service *service;
880 group = __connman_network_get_group(network);
884 name = g_strdup_printf("%s_%s",
885 __connman_network_get_type(network), group);
887 service = connman_service_get(name);
891 if (service->path != NULL) {
892 update_from_network(service, network);
894 __connman_profile_changed();
896 connman_service_put(service);
901 service->type = convert_network_type(network);
903 update_from_network(service, network);
905 service_register(service);
913 int __connman_service_init(void)
917 connection = connman_dbus_get_connection();
919 service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
922 service_list = g_sequence_new(service_free);
927 void __connman_service_cleanup(void)
931 g_sequence_free(service_list);
934 g_hash_table_destroy(service_hash);
937 dbus_connection_unref(connection);