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->network != NULL) {
290 err = connman_network_connect(service->network);
291 if (err < 0 && err != -EINPROGRESS)
292 return __connman_error_failed(msg);
294 service->state = CONNMAN_SERVICE_STATE_ASSOCIATION;
296 state_changed(service);
298 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
301 if (service->device != NULL) {
302 if (service->favorite == FALSE)
303 return __connman_error_no_carrier(msg);
305 if (__connman_device_connect(service->device) < 0)
306 return __connman_error_failed(msg);
308 service->state = CONNMAN_SERVICE_STATE_READY;
310 state_changed(service);
312 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
315 return __connman_error_not_supported(msg);
318 static DBusMessage *disconnect_service(DBusConnection *conn,
319 DBusMessage *msg, void *data)
321 struct connman_service *service = data;
323 if (service->network != NULL) {
326 err = __connman_network_disconnect(service->network);
327 if (err < 0 && err != -EINPROGRESS)
328 return __connman_error_failed(msg);
330 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
332 state_changed(service);
334 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
337 if (service->device != NULL) {
338 if (service->favorite == FALSE)
339 return __connman_error_no_carrier(msg);
341 if (__connman_device_connect(service->device) < 0)
342 return __connman_error_failed(msg);
344 service->state = CONNMAN_SERVICE_STATE_IDLE;
346 state_changed(service);
348 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
351 return __connman_error_not_supported(msg);
354 static DBusMessage *remove_service(DBusConnection *conn,
355 DBusMessage *msg, void *data)
357 struct connman_service *service = data;
359 if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
360 return __connman_error_not_supported(msg);
362 if (service->network != NULL) {
365 err = __connman_network_disconnect(service->network);
366 if (err < 0 && err != -EINPROGRESS)
367 return __connman_error_failed(msg);
369 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
371 state_changed(service);
374 connman_service_set_favorite(service, FALSE);
376 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
379 static DBusMessage *move_before(DBusConnection *conn,
380 DBusMessage *msg, void *data)
382 struct connman_service *service = data;
384 if (service->favorite == FALSE)
385 return __connman_error_not_supported(msg);
387 return __connman_error_not_implemented(msg);
390 static DBusMessage *move_after(DBusConnection *conn,
391 DBusMessage *msg, void *data)
393 struct connman_service *service = data;
395 if (service->favorite == FALSE)
396 return __connman_error_not_supported(msg);
398 return __connman_error_not_implemented(msg);
401 static GDBusMethodTable service_methods[] = {
402 { "GetProperties", "", "a{sv}", get_properties },
403 { "SetProperty", "sv", "", set_property },
404 { "Connect", "", "", connect_service },
405 { "Disconnect", "", "", disconnect_service },
406 { "Remove", "", "", remove_service },
407 { "MoveBefore", "o", "", move_before },
408 { "MoveAfter", "o", "", move_after },
412 static GDBusSignalTable service_signals[] = {
413 { "PropertyChanged", "sv" },
417 static void service_free(gpointer data)
419 struct connman_service *service = data;
420 char *path = service->path;
422 DBG("service %p", service);
424 g_hash_table_remove(service_hash, service->identifier);
426 service->path = NULL;
429 __connman_profile_changed();
431 g_dbus_unregister_interface(connection, path,
432 CONNMAN_SERVICE_INTERFACE);
436 if (service->network != NULL)
437 connman_network_unref(service->network);
439 g_free(service->name);
440 g_free(service->passphrase);
441 g_free(service->identifier);
446 * connman_service_put:
447 * @service: service structure
449 * Release service if no longer needed
451 void connman_service_put(struct connman_service *service)
453 DBG("service %p", service);
455 if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
458 iter = g_hash_table_lookup(service_hash, service->identifier);
460 g_sequence_remove(iter);
462 service_free(service);
466 static void __connman_service_initialize(struct connman_service *service)
468 DBG("service %p", service);
470 service->refcount = 1;
472 service->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
473 service->mode = CONNMAN_SERVICE_MODE_UNKNOWN;
474 service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
475 service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
477 service->favorite = FALSE;
483 * connman_service_create:
485 * Allocate a new service.
487 * Returns: a newly-allocated #connman_service structure
489 struct connman_service *connman_service_create(void)
491 struct connman_service *service;
493 service = g_try_new0(struct connman_service, 1);
497 DBG("service %p", service);
499 __connman_service_initialize(service);
505 * connman_service_ref:
506 * @service: service structure
508 * Increase reference counter of service
510 struct connman_service *connman_service_ref(struct connman_service *service)
512 g_atomic_int_inc(&service->refcount);
518 * connman_service_unref:
519 * @service: service structure
521 * Decrease reference counter of service
523 void connman_service_unref(struct connman_service *service)
525 connman_service_put(service);
528 static gint service_compare(gconstpointer a, gconstpointer b,
531 struct connman_service *service_a = (void *) a;
532 struct connman_service *service_b = (void *) b;
534 if (service_a->order > service_b->order)
537 if (service_a->order < service_b->order)
540 if (service_a->favorite == TRUE && service_b->favorite == FALSE)
543 if (service_a->favorite == FALSE && service_b->favorite == TRUE)
546 return (gint) service_b->strength - (gint) service_a->strength;
550 * connman_service_set_favorite:
551 * @service: service structure
552 * @favorite: favorite value
554 * Change the favorite setting of service
556 int connman_service_set_favorite(struct connman_service *service,
557 connman_bool_t favorite)
561 iter = g_hash_table_lookup(service_hash, service->identifier);
565 if (service->favorite)
568 service->favorite = favorite;
570 g_sequence_sort_changed(iter, service_compare, NULL);
572 __connman_profile_changed();
577 int __connman_service_set_carrier(struct connman_service *service,
578 connman_bool_t carrier)
580 DBG("service %p carrier %d", service, carrier);
585 switch (service->type) {
586 case CONNMAN_SERVICE_TYPE_UNKNOWN:
587 case CONNMAN_SERVICE_TYPE_WIFI:
588 case CONNMAN_SERVICE_TYPE_WIMAX:
590 case CONNMAN_SERVICE_TYPE_ETHERNET:
595 service->state = CONNMAN_SERVICE_STATE_CARRIER;
597 service->state = CONNMAN_SERVICE_STATE_IDLE;
599 state_changed(service);
601 return connman_service_set_favorite(service, carrier);
604 int __connman_service_indicate_configuration(struct connman_service *service)
606 DBG("service %p", service);
611 service->state = CONNMAN_SERVICE_STATE_CONFIGURATION;
613 state_changed(service);
618 int __connman_service_ready(struct connman_service *service)
620 DBG("service %p", service);
625 service->state = CONNMAN_SERVICE_STATE_READY;
627 state_changed(service);
632 int __connman_service_disconnect(struct connman_service *service)
634 DBG("service %p", service);
639 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
641 state_changed(service);
647 * connman_service_lookup:
648 * @identifier: service identifier
650 * Look up a service by identifier (reference count will not be increased)
652 struct connman_service *connman_service_lookup(const char *identifier)
656 iter = g_hash_table_lookup(service_hash, identifier);
658 return g_sequence_get(iter);
664 * connman_service_get:
665 * @identifier: service identifier
667 * Look up a service by identifier or create a new one if not found
669 struct connman_service *connman_service_get(const char *identifier)
671 struct connman_service *service;
674 iter = g_hash_table_lookup(service_hash, identifier);
676 service = g_sequence_get(iter);
678 g_atomic_int_inc(&service->refcount);
682 service = g_try_new0(struct connman_service, 1);
686 DBG("service %p", service);
688 __connman_service_initialize(service);
690 service->identifier = g_strdup(identifier);
692 iter = g_sequence_insert_sorted(service_list, service,
693 service_compare, NULL);
695 g_hash_table_insert(service_hash, service->identifier, iter);
700 static int service_register(struct connman_service *service)
702 const char *path = __connman_profile_active();
704 DBG("service %p", service);
706 if (service->path != NULL)
709 service->path = g_strdup_printf("%s/%s", path, service->identifier);
711 DBG("path %s", service->path);
713 g_dbus_register_interface(connection, service->path,
714 CONNMAN_SERVICE_INTERFACE,
715 service_methods, service_signals,
716 NULL, service, NULL);
718 __connman_profile_changed();
724 * connman_service_lookup_from_device:
725 * @device: device structure
727 * Look up a service by device (reference count will not be increased)
729 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
731 struct connman_service *service;
735 ident = __connman_device_get_ident(device);
739 name = g_strdup_printf("%s_%s",
740 __connman_device_get_type(device), ident);
742 service = connman_service_lookup(name);
749 static enum connman_service_type convert_device_type(struct connman_device *device)
751 enum connman_device_type type = connman_device_get_type(device);
754 case CONNMAN_DEVICE_TYPE_UNKNOWN:
755 case CONNMAN_DEVICE_TYPE_VENDOR:
756 case CONNMAN_DEVICE_TYPE_WIFI:
757 case CONNMAN_DEVICE_TYPE_WIMAX:
758 case CONNMAN_DEVICE_TYPE_BLUETOOTH:
759 case CONNMAN_DEVICE_TYPE_GPS:
760 case CONNMAN_DEVICE_TYPE_HSO:
761 case CONNMAN_DEVICE_TYPE_NOZOMI:
762 case CONNMAN_DEVICE_TYPE_HUAWEI:
763 case CONNMAN_DEVICE_TYPE_NOVATEL:
765 case CONNMAN_DEVICE_TYPE_ETHERNET:
766 return CONNMAN_SERVICE_TYPE_ETHERNET;
769 return CONNMAN_SERVICE_TYPE_UNKNOWN;
773 * connman_service_create_from_device:
774 * @device: device structure
776 * Look up service by device and if not found, create one
778 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
780 struct connman_service *service;
784 ident = __connman_device_get_ident(device);
788 name = g_strdup_printf("%s_%s",
789 __connman_device_get_type(device), ident);
791 service = connman_service_get(name);
795 if (service->path != NULL) {
796 connman_service_put(service);
801 service->type = convert_device_type(device);
803 service->device = device;
805 service_register(service);
814 * connman_service_lookup_from_network:
815 * @network: network structure
817 * Look up a service by network (reference count will not be increased)
819 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
821 struct connman_service *service;
822 const char *ident, *group;
825 ident = __connman_network_get_ident(network);
829 group = __connman_network_get_group(network);
833 name = g_strdup_printf("%s_%s_%s",
834 __connman_network_get_type(network), ident, group);
836 service = connman_service_lookup(name);
843 static enum connman_service_type convert_network_type(struct connman_network *network)
845 enum connman_network_type type = connman_network_get_type(network);
848 case CONNMAN_NETWORK_TYPE_UNKNOWN:
849 case CONNMAN_NETWORK_TYPE_VENDOR:
850 case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
851 case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
852 case CONNMAN_NETWORK_TYPE_HSO:
854 case CONNMAN_NETWORK_TYPE_WIFI:
855 return CONNMAN_SERVICE_TYPE_WIFI;
856 case CONNMAN_NETWORK_TYPE_WIMAX:
857 return CONNMAN_SERVICE_TYPE_WIMAX;
860 return CONNMAN_SERVICE_TYPE_UNKNOWN;
863 static enum connman_service_mode convert_wifi_mode(const char *mode)
866 return CONNMAN_SERVICE_MODE_UNKNOWN;
867 else if (g_str_equal(mode, "managed") == TRUE)
868 return CONNMAN_SERVICE_MODE_MANAGED;
869 else if (g_str_equal(mode, "adhoc") == TRUE)
870 return CONNMAN_SERVICE_MODE_ADHOC;
872 return CONNMAN_SERVICE_MODE_UNKNOWN;
875 static enum connman_service_mode convert_wifi_security(const char *security)
877 if (security == NULL)
878 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
879 else if (g_str_equal(security, "none") == TRUE)
880 return CONNMAN_SERVICE_SECURITY_NONE;
881 else if (g_str_equal(security, "wep") == TRUE)
882 return CONNMAN_SERVICE_SECURITY_WEP;
883 else if (g_str_equal(security, "wpa") == TRUE)
884 return CONNMAN_SERVICE_SECURITY_WPA;
885 else if (g_str_equal(security, "wpa2") == TRUE)
886 return CONNMAN_SERVICE_SECURITY_WPA2;
888 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
891 static void update_from_network(struct connman_service *service,
892 struct connman_network *network)
894 connman_uint8_t strength = service->strength;
898 str = connman_network_get_string(network, "Name");
900 g_free(service->name);
901 service->name = g_strdup(str);
904 service->strength = connman_network_get_uint8(network, "Strength");
906 str = connman_network_get_string(network, "WiFi.Mode");
907 service->mode = convert_wifi_mode(str);
909 str = connman_network_get_string(network, "WiFi.Security");
910 service->security = convert_wifi_security(str);
912 if (service->strength > strength && service->network != NULL) {
913 connman_network_unref(service->network);
914 service->network = NULL;
917 if (service->network == NULL) {
918 service->network = connman_network_ref(network);
920 str = connman_network_get_string(network, "WiFi.Passphrase");
922 g_free(service->passphrase);
923 service->passphrase = g_strdup(str);
927 iter = g_hash_table_lookup(service_hash, service->identifier);
929 g_sequence_sort_changed(iter, service_compare, NULL);
933 * connman_service_create_from_network:
934 * @network: network structure
936 * Look up service by network and if not found, create one
938 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
940 struct connman_service *service;
941 const char *ident, *group;
944 ident = __connman_network_get_ident(network);
948 group = __connman_network_get_group(network);
952 name = g_strdup_printf("%s_%s_%s",
953 __connman_network_get_type(network), ident, group);
955 service = connman_service_get(name);
959 if (service->path != NULL) {
960 update_from_network(service, network);
962 __connman_profile_changed();
964 connman_service_put(service);
969 service->type = convert_network_type(network);
971 update_from_network(service, network);
973 service_register(service);
981 int __connman_service_init(void)
985 connection = connman_dbus_get_connection();
987 service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
990 service_list = g_sequence_new(service_free);
995 void __connman_service_cleanup(void)
999 g_sequence_free(service_list);
1000 service_list = NULL;
1002 g_hash_table_destroy(service_hash);
1003 service_hash = NULL;
1005 dbus_connection_unref(connection);