Add support for service connect and disconnect methods
[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->network != NULL) {
288                 int err;
289
290                 err = connman_network_connect(service->network);
291                 if (err < 0 && err != -EINPROGRESS)
292                         return __connman_error_failed(msg);
293
294                 service->state = CONNMAN_SERVICE_STATE_ASSOCIATION;
295
296                 state_changed(service);
297
298                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
299         }
300
301         if (service->device != NULL) {
302                 if (service->favorite == FALSE)
303                         return __connman_error_no_carrier(msg);
304
305                 if (__connman_device_connect(service->device) < 0)
306                         return __connman_error_failed(msg);
307
308                 service->state = CONNMAN_SERVICE_STATE_READY;
309
310                 state_changed(service);
311
312                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
313         }
314
315         return __connman_error_not_supported(msg);
316 }
317
318 static DBusMessage *disconnect_service(DBusConnection *conn,
319                                         DBusMessage *msg, void *data)
320 {
321         struct connman_service *service = data;
322
323         if (service->network != NULL) {
324                 int err;
325
326                 err = __connman_network_disconnect(service->network);
327                 if (err < 0 && err != -EINPROGRESS)
328                         return __connman_error_failed(msg);
329
330                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
331
332                 state_changed(service);
333
334                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
335         }
336
337         if (service->device != NULL) {
338                 if (service->favorite == FALSE)
339                         return __connman_error_no_carrier(msg);
340
341                 if (__connman_device_connect(service->device) < 0)
342                         return __connman_error_failed(msg);
343
344                 service->state = CONNMAN_SERVICE_STATE_IDLE;
345
346                 state_changed(service);
347
348                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
349         }
350
351         return __connman_error_not_supported(msg);
352 }
353
354 static DBusMessage *remove_service(DBusConnection *conn,
355                                         DBusMessage *msg, void *data)
356 {
357         struct connman_service *service = data;
358
359         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
360                 return __connman_error_not_supported(msg);
361
362         if (service->network != NULL) {
363                 int err;
364
365                 err = __connman_network_disconnect(service->network);
366                 if (err < 0 && err != -EINPROGRESS)
367                         return __connman_error_failed(msg);
368
369                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
370
371                 state_changed(service);
372         }
373
374         connman_service_set_favorite(service, FALSE);
375
376         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
377 }
378
379 static DBusMessage *move_before(DBusConnection *conn,
380                                         DBusMessage *msg, void *data)
381 {
382         struct connman_service *service = data;
383
384         if (service->favorite == FALSE)
385                 return __connman_error_not_supported(msg);
386
387         return __connman_error_not_implemented(msg);
388 }
389
390 static DBusMessage *move_after(DBusConnection *conn,
391                                         DBusMessage *msg, void *data)
392 {
393         struct connman_service *service = data;
394
395         if (service->favorite == FALSE)
396                 return __connman_error_not_supported(msg);
397
398         return __connman_error_not_implemented(msg);
399 }
400
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         },
409         { },
410 };
411
412 static GDBusSignalTable service_signals[] = {
413         { "PropertyChanged", "sv" },
414         { },
415 };
416
417 static void service_free(gpointer data)
418 {
419         struct connman_service *service = data;
420         char *path = service->path;
421
422         DBG("service %p", service);
423
424         g_hash_table_remove(service_hash, service->identifier);
425
426         service->path = NULL;
427
428         if (path != NULL) {
429                 __connman_profile_changed();
430
431                 g_dbus_unregister_interface(connection, path,
432                                                 CONNMAN_SERVICE_INTERFACE);
433                 g_free(path);
434         }
435
436         if (service->network != NULL)
437                 connman_network_unref(service->network);
438
439         g_free(service->name);
440         g_free(service->passphrase);
441         g_free(service->identifier);
442         g_free(service);
443 }
444
445 /**
446  * connman_service_put:
447  * @service: service structure
448  *
449  * Release service if no longer needed
450  */
451 void connman_service_put(struct connman_service *service)
452 {
453         DBG("service %p", service);
454
455         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
456                 GSequenceIter *iter;
457
458                 iter = g_hash_table_lookup(service_hash, service->identifier);
459                 if (iter != NULL)
460                         g_sequence_remove(iter);
461                 else
462                         service_free(service);
463         }
464 }
465
466 static void __connman_service_initialize(struct connman_service *service)
467 {
468         DBG("service %p", service);
469
470         service->refcount = 1;
471
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;
476
477         service->favorite = FALSE;
478
479         service->order = 0;
480 }
481
482 /**
483  * connman_service_create:
484  *
485  * Allocate a new service.
486  *
487  * Returns: a newly-allocated #connman_service structure
488  */
489 struct connman_service *connman_service_create(void)
490 {
491         struct connman_service *service;
492
493         service = g_try_new0(struct connman_service, 1);
494         if (service == NULL)
495                 return NULL;
496
497         DBG("service %p", service);
498
499         __connman_service_initialize(service);
500
501         return service;
502 }
503
504 /**
505  * connman_service_ref:
506  * @service: service structure
507  *
508  * Increase reference counter of service
509  */
510 struct connman_service *connman_service_ref(struct connman_service *service)
511 {
512         g_atomic_int_inc(&service->refcount);
513
514         return service;
515 }
516
517 /**
518  * connman_service_unref:
519  * @service: service structure
520  *
521  * Decrease reference counter of service
522  */
523 void connman_service_unref(struct connman_service *service)
524 {
525         connman_service_put(service);
526 }
527
528 static gint service_compare(gconstpointer a, gconstpointer b,
529                                                         gpointer user_data)
530 {
531         struct connman_service *service_a = (void *) a;
532         struct connman_service *service_b = (void *) b;
533
534         if (service_a->order > service_b->order)
535                 return -1;
536
537         if (service_a->order < service_b->order)
538                 return 1;
539
540         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
541                 return -1;
542
543         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
544                 return 1;
545
546         return (gint) service_b->strength - (gint) service_a->strength;
547 }
548
549 /**
550  * connman_service_set_favorite:
551  * @service: service structure
552  * @favorite: favorite value
553  *
554  * Change the favorite setting of service
555  */
556 int connman_service_set_favorite(struct connman_service *service,
557                                                 connman_bool_t favorite)
558 {
559         GSequenceIter *iter;
560
561         iter = g_hash_table_lookup(service_hash, service->identifier);
562         if (iter == NULL)
563                 return -ENOENT;
564
565         if (service->favorite)
566                 return -EALREADY;
567
568         service->favorite = favorite;
569
570         g_sequence_sort_changed(iter, service_compare, NULL);
571
572         __connman_profile_changed();
573
574         return 0;
575 }
576
577 int __connman_service_set_carrier(struct connman_service *service,
578                                                 connman_bool_t carrier)
579 {
580         DBG("service %p carrier %d", service, carrier);
581
582         if (service == NULL)
583                 return -EINVAL;
584
585         switch (service->type) {
586         case CONNMAN_SERVICE_TYPE_UNKNOWN:
587         case CONNMAN_SERVICE_TYPE_WIFI:
588         case CONNMAN_SERVICE_TYPE_WIMAX:
589                 return -EINVAL;
590         case CONNMAN_SERVICE_TYPE_ETHERNET:
591                 break;
592         }
593
594         if (carrier == TRUE)
595                 service->state = CONNMAN_SERVICE_STATE_CARRIER;
596         else
597                 service->state = CONNMAN_SERVICE_STATE_IDLE;
598
599         state_changed(service);
600
601         return connman_service_set_favorite(service, carrier);
602 }
603
604 int __connman_service_indicate_configuration(struct connman_service *service)
605 {
606         DBG("service %p", service);
607
608         if (service == NULL)
609                 return -EINVAL;
610
611         service->state = CONNMAN_SERVICE_STATE_CONFIGURATION;
612
613         state_changed(service);
614
615         return 0;
616 }
617
618 int __connman_service_ready(struct connman_service *service)
619 {
620         DBG("service %p", service);
621
622         if (service == NULL)
623                 return -EINVAL;
624
625         service->state = CONNMAN_SERVICE_STATE_READY;
626
627         state_changed(service);
628
629         return 0;
630 }
631
632 int __connman_service_disconnect(struct connman_service *service)
633 {
634         DBG("service %p", service);
635
636         if (service == NULL)
637                 return -EINVAL;
638
639         service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
640
641         state_changed(service);
642
643         return 0;
644 }
645
646 /**
647  * connman_service_lookup:
648  * @identifier: service identifier
649  *
650  * Look up a service by identifier (reference count will not be increased)
651  */
652 struct connman_service *connman_service_lookup(const char *identifier)
653 {
654         GSequenceIter *iter;
655
656         iter = g_hash_table_lookup(service_hash, identifier);
657         if (iter != NULL)
658                 return g_sequence_get(iter);
659
660         return NULL;
661 }
662
663 /**
664  * connman_service_get:
665  * @identifier: service identifier
666  *
667  * Look up a service by identifier or create a new one if not found
668  */
669 struct connman_service *connman_service_get(const char *identifier)
670 {
671         struct connman_service *service;
672         GSequenceIter *iter;
673
674         iter = g_hash_table_lookup(service_hash, identifier);
675         if (iter != NULL) {
676                 service = g_sequence_get(iter);
677                 if (service != NULL)
678                         g_atomic_int_inc(&service->refcount);
679                 return service;
680         }
681
682         service = g_try_new0(struct connman_service, 1);
683         if (service == NULL)
684                 return NULL;
685
686         DBG("service %p", service);
687
688         __connman_service_initialize(service);
689
690         service->identifier = g_strdup(identifier);
691
692         iter = g_sequence_insert_sorted(service_list, service,
693                                                 service_compare, NULL);
694
695         g_hash_table_insert(service_hash, service->identifier, iter);
696
697         return service;
698 }
699
700 static int service_register(struct connman_service *service)
701 {
702         const char *path = __connman_profile_active();
703
704         DBG("service %p", service);
705
706         if (service->path != NULL)
707                 return -EALREADY;
708
709         service->path = g_strdup_printf("%s/%s", path, service->identifier);
710
711         DBG("path %s", service->path);
712
713         g_dbus_register_interface(connection, service->path,
714                                         CONNMAN_SERVICE_INTERFACE,
715                                         service_methods, service_signals,
716                                                         NULL, service, NULL);
717
718         __connman_profile_changed();
719
720         return 0;
721 }
722
723 /**
724  * connman_service_lookup_from_device:
725  * @device: device structure
726  *
727  * Look up a service by device (reference count will not be increased)
728  */
729 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
730 {
731         struct connman_service *service;
732         char *name;
733
734         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
735                                         connman_device_get_index(device));
736
737         service = connman_service_lookup(name);
738
739         g_free(name);
740
741         return service;
742 }
743
744 static enum connman_service_type convert_device_type(struct connman_device *device)
745 {
746         enum connman_device_type type = connman_device_get_type(device);
747
748         switch (type) {
749         case CONNMAN_DEVICE_TYPE_UNKNOWN:
750         case CONNMAN_DEVICE_TYPE_VENDOR:
751         case CONNMAN_DEVICE_TYPE_WIFI:
752         case CONNMAN_DEVICE_TYPE_WIMAX:
753         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
754         case CONNMAN_DEVICE_TYPE_GPS:
755         case CONNMAN_DEVICE_TYPE_HSO:
756         case CONNMAN_DEVICE_TYPE_NOZOMI:
757         case CONNMAN_DEVICE_TYPE_HUAWEI:
758         case CONNMAN_DEVICE_TYPE_NOVATEL:
759                 break;
760         case CONNMAN_DEVICE_TYPE_ETHERNET:
761                 return CONNMAN_SERVICE_TYPE_ETHERNET;
762         }
763
764         return CONNMAN_SERVICE_TYPE_UNKNOWN;
765 }
766
767 /**
768  * connman_service_create_from_device:
769  * @device: device structure
770  *
771  * Look up service by device and if not found, create one
772  */
773 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
774 {
775         struct connman_service *service;
776         char *name;
777
778         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
779                                         connman_device_get_index(device));
780
781         service = connman_service_get(name);
782         if (service == NULL)
783                 goto done;
784
785         if (service->path != NULL) {
786                 connman_service_put(service);
787                 service = NULL;
788                 goto done;
789         }
790
791         service->type = convert_device_type(device);
792
793         service->device = device;
794
795         service_register(service);
796
797 done:
798         g_free(name);
799
800         return service;
801 }
802
803 /**
804  * connman_service_lookup_from_network:
805  * @network: network structure
806  *
807  * Look up a service by network (reference count will not be increased)
808  */
809 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
810 {
811         struct connman_service *service;
812         const char *group;
813         char *name;
814
815         group = __connman_network_get_group(network);
816         if (group == NULL)
817                 return NULL;
818
819         name = g_strdup_printf("%s_%s",
820                                 __connman_network_get_type(network), group);
821
822         service = connman_service_lookup(name);
823
824         g_free(name);
825
826         return service;
827 }
828
829 static enum connman_service_type convert_network_type(struct connman_network *network)
830 {
831         enum connman_network_type type = connman_network_get_type(network);
832
833         switch (type) {
834         case CONNMAN_NETWORK_TYPE_UNKNOWN:
835         case CONNMAN_NETWORK_TYPE_VENDOR:
836         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
837         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
838         case CONNMAN_NETWORK_TYPE_HSO:
839                 break;
840         case CONNMAN_NETWORK_TYPE_WIFI:
841                 return CONNMAN_SERVICE_TYPE_WIFI;
842         case CONNMAN_NETWORK_TYPE_WIMAX:
843                 return CONNMAN_SERVICE_TYPE_WIMAX;
844         }
845
846         return CONNMAN_SERVICE_TYPE_UNKNOWN;
847 }
848
849 static enum connman_service_mode convert_wifi_mode(const char *mode)
850 {
851         if (mode == NULL)
852                 return CONNMAN_SERVICE_MODE_UNKNOWN;
853         else if (g_str_equal(mode, "managed") == TRUE)
854                 return CONNMAN_SERVICE_MODE_MANAGED;
855         else if (g_str_equal(mode, "adhoc") == TRUE)
856                 return CONNMAN_SERVICE_MODE_ADHOC;
857         else
858                 return CONNMAN_SERVICE_MODE_UNKNOWN;
859 }
860
861 static enum connman_service_mode convert_wifi_security(const char *security)
862 {
863         if (security == NULL)
864                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
865         else if (g_str_equal(security, "none") == TRUE)
866                 return CONNMAN_SERVICE_SECURITY_NONE;
867         else if (g_str_equal(security, "wep") == TRUE)
868                 return CONNMAN_SERVICE_SECURITY_WEP;
869         else if (g_str_equal(security, "wpa") == TRUE)
870                 return CONNMAN_SERVICE_SECURITY_WPA;
871         else if (g_str_equal(security, "wpa2") == TRUE)
872                 return CONNMAN_SERVICE_SECURITY_WPA2;
873         else
874                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
875 }
876
877 static void update_from_network(struct connman_service *service,
878                                         struct connman_network *network)
879 {
880         connman_uint8_t strength = service->strength;
881         GSequenceIter *iter;
882         const char *str;
883
884         str = connman_network_get_string(network, "Name");
885         if (str != NULL) {
886                 g_free(service->name);
887                 service->name = g_strdup(str);
888         }
889
890         service->strength = connman_network_get_uint8(network, "Strength");
891
892         str = connman_network_get_string(network, "WiFi.Mode");
893         service->mode = convert_wifi_mode(str);
894
895         str = connman_network_get_string(network, "WiFi.Security");
896         service->security = convert_wifi_security(str);
897
898         if (service->strength > strength && service->network != NULL) {
899                 connman_network_unref(service->network);
900                 service->network = NULL;
901         }
902
903         if (service->network == NULL) {
904                 service->network = connman_network_ref(network);
905
906                 str = connman_network_get_string(network, "WiFi.Passphrase");
907                 if (str != NULL) {
908                         g_free(service->passphrase);
909                         service->passphrase = g_strdup(str);
910                 }
911         }
912
913         iter = g_hash_table_lookup(service_hash, service->identifier);
914         if (iter != NULL)
915                 g_sequence_sort_changed(iter, service_compare, NULL);
916 }
917
918 /**
919  * connman_service_create_from_network:
920  * @network: network structure
921  *
922  * Look up service by network and if not found, create one
923  */
924 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
925 {
926         struct connman_service *service;
927         const char *group;
928         char *name;
929
930         group = __connman_network_get_group(network);
931         if (group == NULL)
932                 return NULL;
933
934         name = g_strdup_printf("%s_%s",
935                                 __connman_network_get_type(network), group);
936
937         service = connman_service_get(name);
938         if (service == NULL)
939                 goto done;
940
941         if (service->path != NULL) {
942                 update_from_network(service, network);
943
944                 __connman_profile_changed();
945
946                 connman_service_put(service);
947                 service = NULL;
948                 goto done;
949         }
950
951         service->type = convert_network_type(network);
952
953         update_from_network(service, network);
954
955         service_register(service);
956
957 done:
958         g_free(name);
959
960         return service;
961 }
962
963 int __connman_service_init(void)
964 {
965         DBG("");
966
967         connection = connman_dbus_get_connection();
968
969         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
970                                                                 NULL, NULL);
971
972         service_list = g_sequence_new(service_free);
973
974         return 0;
975 }
976
977 void __connman_service_cleanup(void)
978 {
979         DBG("");
980
981         g_sequence_free(service_list);
982         service_list = NULL;
983
984         g_hash_table_destroy(service_hash);
985         service_hash = NULL;
986
987         dbus_connection_unref(connection);
988 }