Add support for service passphrase handling
[connman] / src / service.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gdbus.h>
27
28 #include "connman.h"
29
30 static DBusConnection *connection = NULL;
31
32 static GSequence *service_list = NULL;
33 static GHashTable *service_hash = NULL;
34
35 struct connman_service {
36         gint refcount;
37         char *identifier;
38         char *path;
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;
45         unsigned int order;
46         char *name;
47         char *passphrase;
48         struct connman_device *device;
49         struct connman_network *network;
50 };
51
52 static void append_path(gpointer value, gpointer user_data)
53 {
54         struct connman_service *service = value;
55         DBusMessageIter *iter = user_data;
56
57         if (service->path == NULL)
58                 return;
59
60         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
61                                                         &service->path);
62 }
63
64 void __connman_service_list(DBusMessageIter *iter)
65 {
66         DBG("");
67
68         g_sequence_foreach(service_list, append_path, iter);
69 }
70
71 static const char *type2string(enum connman_service_type type)
72 {
73         switch (type) {
74         case CONNMAN_SERVICE_TYPE_UNKNOWN:
75                 break;
76         case CONNMAN_SERVICE_TYPE_ETHERNET:
77                 return "ethernet";
78         case CONNMAN_SERVICE_TYPE_WIFI:
79                 return "wifi";
80         case CONNMAN_SERVICE_TYPE_WIMAX:
81                 return "wimax";
82         }
83
84         return NULL;
85 }
86
87 static const char *mode2string(enum connman_service_mode mode)
88 {
89         switch (mode) {
90         case CONNMAN_SERVICE_MODE_UNKNOWN:
91                 break;
92         case CONNMAN_SERVICE_MODE_MANAGED:
93                 return "managed";
94         case CONNMAN_SERVICE_MODE_ADHOC:
95                 return "adhoc";
96         }
97
98         return NULL;
99 }
100
101 static const char *security2string(enum connman_service_security security)
102 {
103         switch (security) {
104         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
105                 break;
106         case CONNMAN_SERVICE_SECURITY_NONE:
107                 return "none";
108         case CONNMAN_SERVICE_SECURITY_WEP:
109                 return "wep";
110         case CONNMAN_SERVICE_SECURITY_WPA:
111                 return "wpa";
112         case CONNMAN_SERVICE_SECURITY_WPA2:
113                 return "wpa2";
114         }
115
116         return NULL;
117 }
118
119 static const char *state2string(enum connman_service_state state)
120 {
121         switch (state) {
122         case CONNMAN_SERVICE_STATE_UNKNOWN:
123                 break;
124         case CONNMAN_SERVICE_STATE_IDLE:
125                 return "idle";
126         case CONNMAN_SERVICE_STATE_CARRIER:
127                 return "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:
133                 return "ready";
134         case CONNMAN_SERVICE_STATE_DISCONNECT:
135                 return "disconnect";
136         case CONNMAN_SERVICE_STATE_FAILURE:
137                 return "failure";
138         }
139
140         return NULL;
141 }
142
143 static void state_changed(struct connman_service *service)
144 {
145         DBusMessage *signal;
146         DBusMessageIter entry, value;
147         const char *str, *key = "State";
148
149         if (service->path == NULL)
150                 return;
151
152         str = state2string(service->state);
153         if (str == NULL)
154                 return;
155
156         signal = dbus_message_new_signal(service->path,
157                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
158         if (signal == NULL)
159                 return;
160
161         dbus_message_iter_init_append(signal, &entry);
162
163         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
164
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);
169
170         g_dbus_send_message(connection, signal);
171 }
172
173 static DBusMessage *get_properties(DBusConnection *conn,
174                                         DBusMessage *msg, void *data)
175 {
176         struct connman_service *service = data;
177         DBusMessage *reply;
178         DBusMessageIter array, dict;
179         const char *str;
180
181         DBG("conn %p", conn);
182
183         reply = dbus_message_new_method_return(msg);
184         if (reply == NULL)
185                 return NULL;
186
187         dbus_message_iter_init_append(reply, &array);
188
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);
193
194         str = type2string(service->type);
195         if (str != NULL)
196                 connman_dbus_dict_append_variant(&dict, "Type",
197                                                 DBUS_TYPE_STRING, &str);
198
199         str = mode2string(service->mode);
200         if (str != NULL)
201                 connman_dbus_dict_append_variant(&dict, "Mode",
202                                                 DBUS_TYPE_STRING, &str);
203
204         str = security2string(service->security);
205         if (str != NULL)
206                 connman_dbus_dict_append_variant(&dict, "Security",
207                                                 DBUS_TYPE_STRING, &str);
208
209         str = state2string(service->state);
210         if (str != NULL)
211                 connman_dbus_dict_append_variant(&dict, "State",
212                                                 DBUS_TYPE_STRING, &str);
213
214         if (service->strength > 0)
215                 connman_dbus_dict_append_variant(&dict, "Strength",
216                                         DBUS_TYPE_BYTE, &service->strength);
217
218         connman_dbus_dict_append_variant(&dict, "Favorite",
219                                         DBUS_TYPE_BOOLEAN, &service->favorite);
220
221         if (service->name != NULL)
222                 connman_dbus_dict_append_variant(&dict, "Name",
223                                         DBUS_TYPE_STRING, &service->name);
224
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);
230
231         dbus_message_iter_close_container(&array, &dict);
232
233         return reply;
234 }
235
236 static DBusMessage *set_property(DBusConnection *conn,
237                                         DBusMessage *msg, void *data)
238 {
239         struct connman_service *service = data;
240         DBusMessageIter iter, value;
241         const char *name;
242         int type;
243
244         DBG("conn %p", conn);
245
246         if (dbus_message_iter_init(msg, &iter) == FALSE)
247                 return __connman_error_invalid_arguments(msg);
248
249         dbus_message_iter_get_basic(&iter, &name);
250         dbus_message_iter_next(&iter);
251         dbus_message_iter_recurse(&iter, &value);
252
253         if (__connman_security_check_privilege(msg,
254                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
255                 return __connman_error_permission_denied(msg);
256
257         type = dbus_message_iter_get_arg_type(&value);
258
259         if (g_str_equal(name, "Passphrase") == TRUE) {
260                 const char *passphrase;
261
262                 if (type != DBUS_TYPE_STRING)
263                         return __connman_error_invalid_arguments(msg);
264
265                 if (__connman_security_check_privilege(msg,
266                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
267                         return __connman_error_permission_denied(msg);
268
269                 dbus_message_iter_get_basic(&value, &passphrase);
270
271                 g_free(service->passphrase);
272                 service->passphrase = g_strdup(passphrase);
273
274                 if (service->network != NULL)
275                         connman_network_set_string(service->network,
276                                 "WiFi.Passphrase", service->passphrase);
277         }
278
279         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
280 }
281
282 static DBusMessage *connect_service(DBusConnection *conn,
283                                         DBusMessage *msg, void *data)
284 {
285         struct connman_service *service = data;
286
287         if (service->device != NULL) {
288                 if (__connman_device_connect(service->device) < 0)
289                         return __connman_error_failed(msg);
290
291                 service->state = CONNMAN_SERVICE_STATE_READY;
292
293                 state_changed(service);
294         }
295
296         return __connman_error_not_supported(msg);
297 }
298
299 static DBusMessage *disconnect_service(DBusConnection *conn,
300                                         DBusMessage *msg, void *data)
301 {
302         struct connman_service *service = data;
303
304         if (service->device != NULL) {
305                 if (__connman_device_connect(service->device) < 0)
306                         return __connman_error_failed(msg);
307
308                 service->state = CONNMAN_SERVICE_STATE_IDLE;
309
310                 state_changed(service);
311         }
312
313         return __connman_error_not_supported(msg);
314 }
315
316 static DBusMessage *remove_service(DBusConnection *conn,
317                                         DBusMessage *msg, void *data)
318 {
319         struct connman_service *service = data;
320
321         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
322                 return __connman_error_not_supported(msg);
323
324         connman_service_set_favorite(service, FALSE);
325
326         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
327 }
328
329 static DBusMessage *move_before(DBusConnection *conn,
330                                         DBusMessage *msg, void *data)
331 {
332         struct connman_service *service = data;
333
334         if (service->favorite == FALSE)
335                 return __connman_error_not_supported(msg);
336
337         return __connman_error_not_implemented(msg);
338 }
339
340 static DBusMessage *move_after(DBusConnection *conn,
341                                         DBusMessage *msg, void *data)
342 {
343         struct connman_service *service = data;
344
345         if (service->favorite == FALSE)
346                 return __connman_error_not_supported(msg);
347
348         return __connman_error_not_implemented(msg);
349 }
350
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         },
359         { },
360 };
361
362 static GDBusSignalTable service_signals[] = {
363         { "PropertyChanged", "sv" },
364         { },
365 };
366
367 static void service_free(gpointer data)
368 {
369         struct connman_service *service = data;
370         char *path = service->path;
371
372         DBG("service %p", service);
373
374         g_hash_table_remove(service_hash, service->identifier);
375
376         service->path = NULL;
377
378         if (path != NULL) {
379                 __connman_profile_changed();
380
381                 g_dbus_unregister_interface(connection, path,
382                                                 CONNMAN_SERVICE_INTERFACE);
383                 g_free(path);
384         }
385
386         if (service->network != NULL)
387                 connman_network_unref(service->network);
388
389         g_free(service->name);
390         g_free(service->passphrase);
391         g_free(service->identifier);
392         g_free(service);
393 }
394
395 /**
396  * connman_service_put:
397  * @service: service structure
398  *
399  * Release service if no longer needed
400  */
401 void connman_service_put(struct connman_service *service)
402 {
403         DBG("service %p", service);
404
405         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
406                 GSequenceIter *iter;
407
408                 iter = g_hash_table_lookup(service_hash, service->identifier);
409                 if (iter != NULL)
410                         g_sequence_remove(iter);
411                 else
412                         service_free(service);
413         }
414 }
415
416 static void __connman_service_initialize(struct connman_service *service)
417 {
418         DBG("service %p", service);
419
420         service->refcount = 1;
421
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;
426
427         service->favorite = FALSE;
428
429         service->order = 0;
430 }
431
432 /**
433  * connman_service_create:
434  *
435  * Allocate a new service.
436  *
437  * Returns: a newly-allocated #connman_service structure
438  */
439 struct connman_service *connman_service_create(void)
440 {
441         struct connman_service *service;
442
443         service = g_try_new0(struct connman_service, 1);
444         if (service == NULL)
445                 return NULL;
446
447         DBG("service %p", service);
448
449         __connman_service_initialize(service);
450
451         return service;
452 }
453
454 /**
455  * connman_service_ref:
456  * @service: service structure
457  *
458  * Increase reference counter of service
459  */
460 struct connman_service *connman_service_ref(struct connman_service *service)
461 {
462         g_atomic_int_inc(&service->refcount);
463
464         return service;
465 }
466
467 /**
468  * connman_service_unref:
469  * @service: service structure
470  *
471  * Decrease reference counter of service
472  */
473 void connman_service_unref(struct connman_service *service)
474 {
475         connman_service_put(service);
476 }
477
478 static gint service_compare(gconstpointer a, gconstpointer b,
479                                                         gpointer user_data)
480 {
481         struct connman_service *service_a = (void *) a;
482         struct connman_service *service_b = (void *) b;
483
484         if (service_a->order > service_b->order)
485                 return -1;
486
487         if (service_a->order < service_b->order)
488                 return 1;
489
490         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
491                 return -1;
492
493         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
494                 return 1;
495
496         return (gint) service_b->strength - (gint) service_a->strength;
497 }
498
499 /**
500  * connman_service_set_favorite:
501  * @service: service structure
502  * @favorite: favorite value
503  *
504  * Change the favorite setting of service
505  */
506 int connman_service_set_favorite(struct connman_service *service,
507                                                 connman_bool_t favorite)
508 {
509         GSequenceIter *iter;
510
511         iter = g_hash_table_lookup(service_hash, service->identifier);
512         if (iter == NULL)
513                 return -ENOENT;
514
515         if (service->favorite)
516                 return -EALREADY;
517
518         service->favorite = favorite;
519
520         g_sequence_sort_changed(iter, service_compare, NULL);
521
522         __connman_profile_changed();
523
524         return 0;
525 }
526
527 int __connman_service_set_carrier(struct connman_service *service,
528                                                 connman_bool_t carrier)
529 {
530         DBG("service %p carrier %d", service, carrier);
531
532         if (service == NULL)
533                 return -EINVAL;
534
535         switch (service->type) {
536         case CONNMAN_SERVICE_TYPE_UNKNOWN:
537         case CONNMAN_SERVICE_TYPE_WIFI:
538         case CONNMAN_SERVICE_TYPE_WIMAX:
539                 return -EINVAL;
540         case CONNMAN_SERVICE_TYPE_ETHERNET:
541                 break;
542         }
543
544         if (carrier == TRUE)
545                 service->state = CONNMAN_SERVICE_STATE_CARRIER;
546         else
547                 service->state = CONNMAN_SERVICE_STATE_IDLE;
548
549         state_changed(service);
550
551         return connman_service_set_favorite(service, carrier);
552 }
553
554 int __connman_service_indicate_configuration(struct connman_service *service)
555 {
556         DBG("service %p", service);
557
558         if (service == NULL)
559                 return -EINVAL;
560
561         service->state = CONNMAN_SERVICE_STATE_CONFIGURATION;
562
563         state_changed(service);
564
565         return 0;
566 }
567
568 int __connman_service_ready(struct connman_service *service)
569 {
570         DBG("service %p", service);
571
572         if (service == NULL)
573                 return -EINVAL;
574
575         service->state = CONNMAN_SERVICE_STATE_READY;
576
577         state_changed(service);
578
579         return 0;
580 }
581
582 int __connman_service_disconnect(struct connman_service *service)
583 {
584         DBG("service %p", service);
585
586         if (service == NULL)
587                 return -EINVAL;
588
589         service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
590
591         state_changed(service);
592
593         return 0;
594 }
595
596 /**
597  * connman_service_lookup:
598  * @identifier: service identifier
599  *
600  * Look up a service by identifier (reference count will not be increased)
601  */
602 struct connman_service *connman_service_lookup(const char *identifier)
603 {
604         GSequenceIter *iter;
605
606         iter = g_hash_table_lookup(service_hash, identifier);
607         if (iter != NULL)
608                 return g_sequence_get(iter);
609
610         return NULL;
611 }
612
613 /**
614  * connman_service_get:
615  * @identifier: service identifier
616  *
617  * Look up a service by identifier or create a new one if not found
618  */
619 struct connman_service *connman_service_get(const char *identifier)
620 {
621         struct connman_service *service;
622         GSequenceIter *iter;
623
624         iter = g_hash_table_lookup(service_hash, identifier);
625         if (iter != NULL) {
626                 service = g_sequence_get(iter);
627                 if (service != NULL)
628                         g_atomic_int_inc(&service->refcount);
629                 return service;
630         }
631
632         service = g_try_new0(struct connman_service, 1);
633         if (service == NULL)
634                 return NULL;
635
636         DBG("service %p", service);
637
638         __connman_service_initialize(service);
639
640         service->identifier = g_strdup(identifier);
641
642         iter = g_sequence_insert_sorted(service_list, service,
643                                                 service_compare, NULL);
644
645         g_hash_table_insert(service_hash, service->identifier, iter);
646
647         return service;
648 }
649
650 static int service_register(struct connman_service *service)
651 {
652         const char *path = __connman_profile_active();
653
654         DBG("service %p", service);
655
656         if (service->path != NULL)
657                 return -EALREADY;
658
659         service->path = g_strdup_printf("%s/%s", path, service->identifier);
660
661         DBG("path %s", service->path);
662
663         g_dbus_register_interface(connection, service->path,
664                                         CONNMAN_SERVICE_INTERFACE,
665                                         service_methods, service_signals,
666                                                         NULL, service, NULL);
667
668         __connman_profile_changed();
669
670         return 0;
671 }
672
673 /**
674  * connman_service_lookup_from_device:
675  * @device: device structure
676  *
677  * Look up a service by device (reference count will not be increased)
678  */
679 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
680 {
681         struct connman_service *service;
682         char *name;
683
684         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
685                                         connman_device_get_index(device));
686
687         service = connman_service_lookup(name);
688
689         g_free(name);
690
691         return service;
692 }
693
694 static enum connman_service_type convert_device_type(struct connman_device *device)
695 {
696         enum connman_device_type type = connman_device_get_type(device);
697
698         switch (type) {
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:
709                 break;
710         case CONNMAN_DEVICE_TYPE_ETHERNET:
711                 return CONNMAN_SERVICE_TYPE_ETHERNET;
712         }
713
714         return CONNMAN_SERVICE_TYPE_UNKNOWN;
715 }
716
717 /**
718  * connman_service_create_from_device:
719  * @device: device structure
720  *
721  * Look up service by device and if not found, create one
722  */
723 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
724 {
725         struct connman_service *service;
726         char *name;
727
728         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
729                                         connman_device_get_index(device));
730
731         service = connman_service_get(name);
732         if (service == NULL)
733                 goto done;
734
735         if (service->path != NULL) {
736                 connman_service_put(service);
737                 service = NULL;
738                 goto done;
739         }
740
741         service->type = convert_device_type(device);
742
743         service->device = device;
744
745         service_register(service);
746
747 done:
748         g_free(name);
749
750         return service;
751 }
752
753 /**
754  * connman_service_lookup_from_network:
755  * @network: network structure
756  *
757  * Look up a service by network (reference count will not be increased)
758  */
759 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
760 {
761         struct connman_service *service;
762         const char *group;
763         char *name;
764
765         group = __connman_network_get_group(network);
766         if (group == NULL)
767                 return NULL;
768
769         name = g_strdup_printf("%s_%s",
770                                 __connman_network_get_type(network), group);
771
772         service = connman_service_lookup(name);
773
774         g_free(name);
775
776         return service;
777 }
778
779 static enum connman_service_type convert_network_type(struct connman_network *network)
780 {
781         enum connman_network_type type = connman_network_get_type(network);
782
783         switch (type) {
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:
789                 break;
790         case CONNMAN_NETWORK_TYPE_WIFI:
791                 return CONNMAN_SERVICE_TYPE_WIFI;
792         case CONNMAN_NETWORK_TYPE_WIMAX:
793                 return CONNMAN_SERVICE_TYPE_WIMAX;
794         }
795
796         return CONNMAN_SERVICE_TYPE_UNKNOWN;
797 }
798
799 static enum connman_service_mode convert_wifi_mode(const char *mode)
800 {
801         if (mode == NULL)
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;
807         else
808                 return CONNMAN_SERVICE_MODE_UNKNOWN;
809 }
810
811 static enum connman_service_mode convert_wifi_security(const char *security)
812 {
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;
823         else
824                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
825 }
826
827 static void update_from_network(struct connman_service *service,
828                                         struct connman_network *network)
829 {
830         connman_uint8_t strength = service->strength;
831         GSequenceIter *iter;
832         const char *str;
833
834         str = connman_network_get_string(network, "Name");
835         if (str != NULL) {
836                 g_free(service->name);
837                 service->name = g_strdup(str);
838         }
839
840         service->strength = connman_network_get_uint8(network, "Strength");
841
842         str = connman_network_get_string(network, "WiFi.Mode");
843         service->mode = convert_wifi_mode(str);
844
845         str = connman_network_get_string(network, "WiFi.Security");
846         service->security = convert_wifi_security(str);
847
848         if (service->strength > strength && service->network != NULL) {
849                 connman_network_unref(service->network);
850                 service->network = NULL;
851         }
852
853         if (service->network == NULL) {
854                 service->network = connman_network_ref(network);
855
856                 str = connman_network_get_string(network, "WiFi.Passphrase");
857                 if (str != NULL) {
858                         g_free(service->passphrase);
859                         service->passphrase = g_strdup(str);
860                 }
861         }
862
863         iter = g_hash_table_lookup(service_hash, service->identifier);
864         if (iter != NULL)
865                 g_sequence_sort_changed(iter, service_compare, NULL);
866 }
867
868 /**
869  * connman_service_create_from_network:
870  * @network: network structure
871  *
872  * Look up service by network and if not found, create one
873  */
874 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
875 {
876         struct connman_service *service;
877         const char *group;
878         char *name;
879
880         group = __connman_network_get_group(network);
881         if (group == NULL)
882                 return NULL;
883
884         name = g_strdup_printf("%s_%s",
885                                 __connman_network_get_type(network), group);
886
887         service = connman_service_get(name);
888         if (service == NULL)
889                 goto done;
890
891         if (service->path != NULL) {
892                 update_from_network(service, network);
893
894                 __connman_profile_changed();
895
896                 connman_service_put(service);
897                 service = NULL;
898                 goto done;
899         }
900
901         service->type = convert_network_type(network);
902
903         update_from_network(service, network);
904
905         service_register(service);
906
907 done:
908         g_free(name);
909
910         return service;
911 }
912
913 int __connman_service_init(void)
914 {
915         DBG("");
916
917         connection = connman_dbus_get_connection();
918
919         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
920                                                                 NULL, NULL);
921
922         service_list = g_sequence_new(service_free);
923
924         return 0;
925 }
926
927 void __connman_service_cleanup(void)
928 {
929         DBG("");
930
931         g_sequence_free(service_list);
932         service_list = NULL;
933
934         g_hash_table_destroy(service_hash);
935         service_hash = NULL;
936
937         dbus_connection_unref(connection);
938 }