Add another D-Bus helper for properties with arrays
[platform/upstream/connman.git] / 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 <stdio.h>
27 #include <string.h>
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 #define CONNECT_TIMEOUT         120
33
34 static DBusConnection *connection = NULL;
35
36 static GSequence *service_list = NULL;
37 static GHashTable *service_hash = NULL;
38
39 struct connman_service {
40         gint refcount;
41         char *identifier;
42         char *path;
43         enum connman_service_type type;
44         enum connman_service_mode mode;
45         enum connman_service_security security;
46         enum connman_service_state state;
47         enum connman_service_error error;
48         connman_uint8_t strength;
49         connman_bool_t favorite;
50         connman_bool_t hidden;
51         connman_bool_t ignore;
52         connman_bool_t autoconnect;
53         connman_bool_t userconnect;
54         GTimeVal modified;
55         unsigned int order;
56         char *name;
57         char *passphrase;
58         char *profile;
59         char *apn;
60         char *username;
61         char *password;
62         char *mcc;
63         char *mnc;
64         connman_bool_t roaming;
65         struct connman_ipconfig *ipconfig;
66         struct connman_network *network;
67         DBusMessage *pending;
68         guint timeout;
69 };
70
71 static void append_path(gpointer value, gpointer user_data)
72 {
73         struct connman_service *service = value;
74         DBusMessageIter *iter = user_data;
75
76         if (service->path == NULL || service->hidden == TRUE)
77                 return;
78
79         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
80                                                         &service->path);
81 }
82
83 void __connman_service_list(DBusMessageIter *iter)
84 {
85         DBG("");
86
87         g_sequence_foreach(service_list, append_path, iter);
88 }
89
90 struct find_data {
91         const char *path;
92         struct connman_service *service;
93 };
94
95 static void compare_path(gpointer value, gpointer user_data)
96 {
97         struct connman_service *service = value;
98         struct find_data *data = user_data;
99
100         if (data->service != NULL)
101                 return;
102
103         if (g_strcmp0(service->path, data->path) == 0)
104                 data->service = service;
105 }
106
107 static struct connman_service *find_service(const char *path)
108 {
109         struct find_data data = { .path = path, .service = NULL };
110
111         DBG("path %s", path);
112
113         g_sequence_foreach(service_list, compare_path, &data);
114
115         return data.service;
116 }
117
118 const char *__connman_service_type2string(enum connman_service_type type)
119 {
120         switch (type) {
121         case CONNMAN_SERVICE_TYPE_UNKNOWN:
122                 break;
123         case CONNMAN_SERVICE_TYPE_SYSTEM:
124                 return "system";
125         case CONNMAN_SERVICE_TYPE_ETHERNET:
126                 return "ethernet";
127         case CONNMAN_SERVICE_TYPE_WIFI:
128                 return "wifi";
129         case CONNMAN_SERVICE_TYPE_WIMAX:
130                 return "wimax";
131         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
132                 return "bluetooth";
133         case CONNMAN_SERVICE_TYPE_CELLULAR:
134                 return "cellular";
135         case CONNMAN_SERVICE_TYPE_VPN:
136                 return "vpn";
137         }
138
139         return NULL;
140 }
141
142 static const char *mode2string(enum connman_service_mode mode)
143 {
144         switch (mode) {
145         case CONNMAN_SERVICE_MODE_UNKNOWN:
146                 break;
147         case CONNMAN_SERVICE_MODE_MANAGED:
148                 return "managed";
149         case CONNMAN_SERVICE_MODE_ADHOC:
150                 return "adhoc";
151         case CONNMAN_SERVICE_MODE_GPRS:
152                 return "gprs";
153         case CONNMAN_SERVICE_MODE_EDGE:
154                 return "edge";
155         case CONNMAN_SERVICE_MODE_UMTS:
156                 return "umts";
157         }
158
159         return NULL;
160 }
161
162 static const char *security2string(enum connman_service_security security)
163 {
164         switch (security) {
165         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
166                 break;
167         case CONNMAN_SERVICE_SECURITY_NONE:
168                 return "none";
169         case CONNMAN_SERVICE_SECURITY_WEP:
170                 return "wep";
171         case CONNMAN_SERVICE_SECURITY_PSK:
172                 return "psk";
173         case CONNMAN_SERVICE_SECURITY_8021X:
174                 return "ieee8021x";
175         case CONNMAN_SERVICE_SECURITY_WPA:
176                 return "wpa";
177         case CONNMAN_SERVICE_SECURITY_RSN:
178                 return "rsn";
179         }
180
181         return NULL;
182 }
183
184 static const char *state2string(enum connman_service_state state)
185 {
186         switch (state) {
187         case CONNMAN_SERVICE_STATE_UNKNOWN:
188                 break;
189         case CONNMAN_SERVICE_STATE_IDLE:
190                 return "idle";
191         case CONNMAN_SERVICE_STATE_ASSOCIATION:
192                 return "association";
193         case CONNMAN_SERVICE_STATE_CONFIGURATION:
194                 return "configuration";
195         case CONNMAN_SERVICE_STATE_READY:
196                 return "ready";
197         case CONNMAN_SERVICE_STATE_DISCONNECT:
198                 return "disconnect";
199         case CONNMAN_SERVICE_STATE_FAILURE:
200                 return "failure";
201         }
202
203         return NULL;
204 }
205
206 static const char *error2string(enum connman_service_error error)
207 {
208         switch (error) {
209         case CONNMAN_SERVICE_ERROR_UNKNOWN:
210                 break;
211         case CONNMAN_SERVICE_ERROR_OUT_OF_RANGE:
212                 return "out-of-range";
213         case CONNMAN_SERVICE_ERROR_PIN_MISSING:
214                 return "pin-missing";
215         case CONNMAN_SERVICE_ERROR_DHCP_FAILED:
216                 return "dhcp-failed";
217         case CONNMAN_SERVICE_ERROR_CONNECT_FAILED:
218                 return "connect-failed";
219         }
220
221         return NULL;
222 }
223
224 static enum connman_service_error string2error(const char *error)
225 {
226         if (g_strcmp0(error, "dhcp-failed") == 0)
227                 return CONNMAN_SERVICE_ERROR_DHCP_FAILED;
228         else if (g_strcmp0(error, "pin-missing") == 0)
229                 return CONNMAN_SERVICE_ERROR_PIN_MISSING;
230
231         return CONNMAN_SERVICE_ERROR_UNKNOWN;
232 }
233
234 static struct connman_service *get_default(void)
235 {
236         struct connman_service *service;
237         GSequenceIter *iter;
238
239         iter = g_sequence_get_begin_iter(service_list);
240
241         if (g_sequence_iter_is_end(iter) == TRUE)
242                 return NULL;
243
244         service = g_sequence_get(iter);
245
246         if (service->state != CONNMAN_SERVICE_STATE_READY)
247                 return NULL;
248
249         return service;
250 }
251
252 static void default_changed(void)
253 {
254         struct connman_service *service = get_default();
255
256         __connman_notifier_default_changed(service);
257 }
258
259 const char *__connman_service_default(void)
260 {
261         struct connman_service *service;
262
263         service = get_default();
264         if (service == NULL)
265                 return "";
266
267         return __connman_service_type2string(service->type);
268 }
269
270 static void mode_changed(struct connman_service *service)
271 {
272         DBusMessage *signal;
273         DBusMessageIter iter;
274         const char *str;
275
276         if (service->path == NULL)
277                 return;
278
279         str = mode2string(service->mode);
280         if (str == NULL)
281                 return;
282
283         signal = dbus_message_new_signal(service->path,
284                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
285         if (signal == NULL)
286                 return;
287
288         dbus_message_iter_init_append(signal, &iter);
289
290         connman_dbus_property_append_variant(&iter,
291                                         "Mode", DBUS_TYPE_STRING, &str);
292
293         g_dbus_send_message(connection, signal);
294 }
295
296 static void state_changed(struct connman_service *service)
297 {
298         DBusMessage *signal;
299         DBusMessageIter iter;
300         const char *str;
301
302         if (service->path == NULL)
303                 return;
304
305         str = state2string(service->state);
306         if (str == NULL)
307                 return;
308
309         signal = dbus_message_new_signal(service->path,
310                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
311         if (signal == NULL)
312                 return;
313
314         dbus_message_iter_init_append(signal, &iter);
315
316         connman_dbus_property_append_variant(&iter,
317                                         "State", DBUS_TYPE_STRING, &str);
318
319         g_dbus_send_message(connection, signal);
320 }
321
322 static void strength_changed(struct connman_service *service)
323 {
324         DBusMessage *signal;
325         DBusMessageIter iter;
326
327         if (service->path == NULL)
328                 return;
329
330         if (service->strength == 0)
331                 return;
332
333         signal = dbus_message_new_signal(service->path,
334                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
335         if (signal == NULL)
336                 return;
337
338         dbus_message_iter_init_append(signal, &iter);
339
340         connman_dbus_property_append_variant(&iter,
341                         "Strength", DBUS_TYPE_BYTE, &service->strength);
342
343         g_dbus_send_message(connection, signal);
344 }
345
346 static void roaming_changed(struct connman_service *service)
347 {
348         DBusMessage *signal;
349         DBusMessageIter iter;
350
351         if (service->path == NULL)
352                 return;
353
354         signal = dbus_message_new_signal(service->path,
355                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
356         if (signal == NULL)
357                 return;
358
359         dbus_message_iter_init_append(signal, &iter);
360
361         connman_dbus_property_append_variant(&iter,
362                         "Roaming", DBUS_TYPE_BOOLEAN, &service->roaming);
363
364         g_dbus_send_message(connection, signal);
365 }
366
367 static void autoconnect_changed(struct connman_service *service)
368 {
369         DBusMessage *signal;
370         DBusMessageIter iter;
371
372         if (service->path == NULL)
373                 return;
374
375         signal = dbus_message_new_signal(service->path,
376                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
377         if (signal == NULL)
378                 return;
379
380         dbus_message_iter_init_append(signal, &iter);
381
382         connman_dbus_property_append_variant(&iter,
383                 "AutoConnect", DBUS_TYPE_BOOLEAN, &service->autoconnect);
384
385         g_dbus_send_message(connection, signal);
386 }
387
388 static void passphrase_changed(struct connman_service *service)
389 {
390         DBusMessage *signal;
391         DBusMessageIter iter;
392         dbus_bool_t required;
393
394         if (service->path == NULL)
395                 return;
396
397         switch (service->type) {
398         case CONNMAN_SERVICE_TYPE_UNKNOWN:
399         case CONNMAN_SERVICE_TYPE_SYSTEM:
400         case CONNMAN_SERVICE_TYPE_ETHERNET:
401         case CONNMAN_SERVICE_TYPE_WIMAX:
402         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
403         case CONNMAN_SERVICE_TYPE_CELLULAR:
404         case CONNMAN_SERVICE_TYPE_VPN:
405                 return;
406         case CONNMAN_SERVICE_TYPE_WIFI:
407                 required = FALSE;
408
409                 switch (service->security) {
410                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
411                 case CONNMAN_SERVICE_SECURITY_NONE:
412                 case CONNMAN_SERVICE_SECURITY_8021X:
413                         break;
414                 case CONNMAN_SERVICE_SECURITY_WEP:
415                 case CONNMAN_SERVICE_SECURITY_PSK:
416                 case CONNMAN_SERVICE_SECURITY_WPA:
417                 case CONNMAN_SERVICE_SECURITY_RSN:
418                         if (service->passphrase == NULL)
419                                 required = TRUE;
420                         break;
421                 }
422                 break;
423         }
424
425         signal = dbus_message_new_signal(service->path,
426                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
427         if (signal == NULL)
428                 return;
429
430         dbus_message_iter_init_append(signal, &iter);
431
432         connman_dbus_property_append_variant(&iter,
433                         "PassphraseRequired", DBUS_TYPE_BOOLEAN, &required);
434
435         g_dbus_send_message(connection, signal);
436 }
437
438 static void apn_changed(struct connman_service *service)
439 {
440         DBusMessage *signal;
441         DBusMessageIter iter;
442         dbus_bool_t required;
443
444         if (service->path == NULL)
445                 return;
446
447         switch (service->type) {
448         case CONNMAN_SERVICE_TYPE_UNKNOWN:
449         case CONNMAN_SERVICE_TYPE_SYSTEM:
450         case CONNMAN_SERVICE_TYPE_ETHERNET:
451         case CONNMAN_SERVICE_TYPE_WIMAX:
452         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
453         case CONNMAN_SERVICE_TYPE_WIFI:
454         case CONNMAN_SERVICE_TYPE_VPN:
455                 return;
456         case CONNMAN_SERVICE_TYPE_CELLULAR:
457                 break;
458         }
459
460         required = (service->apn == NULL) ? TRUE : FALSE;
461
462         signal = dbus_message_new_signal(service->path,
463                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
464         if (signal == NULL)
465                 return;
466
467         dbus_message_iter_init_append(signal, &iter);
468
469         connman_dbus_property_append_variant(&iter,
470                         "SetupRequired", DBUS_TYPE_BOOLEAN, &required);
471
472         g_dbus_send_message(connection, signal);
473 }
474
475 static DBusMessage *get_properties(DBusConnection *conn,
476                                         DBusMessage *msg, void *user_data)
477 {
478         struct connman_service *service = user_data;
479         DBusMessage *reply;
480         DBusMessageIter array, dict;
481         dbus_bool_t required;
482         const char *str;
483
484         DBG("service %p", service);
485
486         reply = dbus_message_new_method_return(msg);
487         if (reply == NULL)
488                 return NULL;
489
490         dbus_message_iter_init_append(reply, &array);
491
492         connman_dbus_dict_open(&array, &dict);
493
494         str = __connman_service_type2string(service->type);
495         if (str != NULL)
496                 connman_dbus_dict_append_variant(&dict, "Type",
497                                                 DBUS_TYPE_STRING, &str);
498
499         str = mode2string(service->mode);
500         if (str != NULL)
501                 connman_dbus_dict_append_variant(&dict, "Mode",
502                                                 DBUS_TYPE_STRING, &str);
503
504         str = security2string(service->security);
505         if (str != NULL)
506                 connman_dbus_dict_append_variant(&dict, "Security",
507                                                 DBUS_TYPE_STRING, &str);
508
509         str = state2string(service->state);
510         if (str != NULL)
511                 connman_dbus_dict_append_variant(&dict, "State",
512                                                 DBUS_TYPE_STRING, &str);
513
514         str = error2string(service->error);
515         if (str != NULL)
516                 connman_dbus_dict_append_variant(&dict, "Error",
517                                                 DBUS_TYPE_STRING, &str);
518
519         if (service->strength > 0)
520                 connman_dbus_dict_append_variant(&dict, "Strength",
521                                         DBUS_TYPE_BYTE, &service->strength);
522
523         connman_dbus_dict_append_variant(&dict, "Favorite",
524                                         DBUS_TYPE_BOOLEAN, &service->favorite);
525
526         if (service->favorite == TRUE)
527                 connman_dbus_dict_append_variant(&dict, "AutoConnect",
528                                 DBUS_TYPE_BOOLEAN, &service->autoconnect);
529         else
530                 connman_dbus_dict_append_variant(&dict, "AutoConnect",
531                                         DBUS_TYPE_BOOLEAN, &service->favorite);
532
533         if (service->name != NULL)
534                 connman_dbus_dict_append_variant(&dict, "Name",
535                                         DBUS_TYPE_STRING, &service->name);
536
537         switch (service->type) {
538         case CONNMAN_SERVICE_TYPE_UNKNOWN:
539         case CONNMAN_SERVICE_TYPE_SYSTEM:
540         case CONNMAN_SERVICE_TYPE_ETHERNET:
541         case CONNMAN_SERVICE_TYPE_WIMAX:
542         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
543         case CONNMAN_SERVICE_TYPE_VPN:
544                 break;
545         case CONNMAN_SERVICE_TYPE_CELLULAR:
546                 connman_dbus_dict_append_variant(&dict, "Roaming",
547                                         DBUS_TYPE_BOOLEAN, &service->roaming);
548
549                 if (service->mcc != NULL && service->mnc != NULL) {
550                         connman_dbus_dict_append_variant(&dict, "MCC",
551                                         DBUS_TYPE_STRING, &service->mcc);
552                         connman_dbus_dict_append_variant(&dict, "MNC",
553                                         DBUS_TYPE_STRING, &service->mnc);
554                 }
555
556                 if (service->apn != NULL) {
557                         connman_dbus_dict_append_variant(&dict, "APN",
558                                         DBUS_TYPE_STRING, &service->apn);
559
560                         if (service->username != NULL)
561                                 connman_dbus_dict_append_variant(&dict,
562                                         "Username", DBUS_TYPE_STRING,
563                                                         &service->username);
564
565                         if (service->password != NULL)
566                                 connman_dbus_dict_append_variant(&dict,
567                                         "Password", DBUS_TYPE_STRING,
568                                                         &service->password);
569
570                         required = FALSE;
571                 } else
572                         required = TRUE;
573
574                 connman_dbus_dict_append_variant(&dict, "SetupRequired",
575                                                 DBUS_TYPE_BOOLEAN, &required);
576                 break;
577         case CONNMAN_SERVICE_TYPE_WIFI:
578                 if (service->passphrase != NULL &&
579                                 __connman_security_check_privilege(msg,
580                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
581                         connman_dbus_dict_append_variant(&dict, "Passphrase",
582                                 DBUS_TYPE_STRING, &service->passphrase);
583
584                 required = FALSE;
585
586                 switch (service->security) {
587                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
588                 case CONNMAN_SERVICE_SECURITY_NONE:
589                 case CONNMAN_SERVICE_SECURITY_8021X:
590                         break;
591                 case CONNMAN_SERVICE_SECURITY_WEP:
592                 case CONNMAN_SERVICE_SECURITY_PSK:
593                 case CONNMAN_SERVICE_SECURITY_WPA:
594                 case CONNMAN_SERVICE_SECURITY_RSN:
595                         if (service->passphrase == NULL)
596                                 required = TRUE;
597                         break;
598                 }
599
600                 connman_dbus_dict_append_variant(&dict, "PassphraseRequired",
601                                                 DBUS_TYPE_BOOLEAN, &required);
602                 break;
603         }
604
605         if (service->ipconfig != NULL)
606                 __connman_ipconfig_append_ipv4(service->ipconfig,
607                                                         &dict, "IPv4.");
608
609         connman_dbus_dict_close(&array, &dict);
610
611         return reply;
612 }
613
614 static DBusMessage *set_property(DBusConnection *conn,
615                                         DBusMessage *msg, void *user_data)
616 {
617         struct connman_service *service = user_data;
618         DBusMessageIter iter, value;
619         const char *name;
620         int type;
621
622         DBG("service %p", service);
623
624         if (dbus_message_iter_init(msg, &iter) == FALSE)
625                 return __connman_error_invalid_arguments(msg);
626
627         dbus_message_iter_get_basic(&iter, &name);
628         dbus_message_iter_next(&iter);
629         dbus_message_iter_recurse(&iter, &value);
630
631         if (__connman_security_check_privilege(msg,
632                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
633                 return __connman_error_permission_denied(msg);
634
635         type = dbus_message_iter_get_arg_type(&value);
636
637         if (g_str_has_prefix(name, "AutoConnect") == TRUE) {
638                 connman_bool_t autoconnect;
639
640                 if (type != DBUS_TYPE_BOOLEAN)
641                         return __connman_error_invalid_arguments(msg);
642
643                 if (service->favorite == FALSE)
644                         return __connman_error_invalid_service(msg);
645
646                 dbus_message_iter_get_basic(&value, &autoconnect);
647
648                 if (service->autoconnect == autoconnect)
649                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
650
651                 service->autoconnect = autoconnect;
652
653                 autoconnect_changed(service);
654
655                 __connman_storage_save_service(service);
656         } else if (g_str_equal(name, "Passphrase") == TRUE) {
657                 const char *passphrase;
658
659                 if (type != DBUS_TYPE_STRING)
660                         return __connman_error_invalid_arguments(msg);
661
662                 if (__connman_security_check_privilege(msg,
663                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
664                         return __connman_error_permission_denied(msg);
665
666                 dbus_message_iter_get_basic(&value, &passphrase);
667
668                 g_free(service->passphrase);
669                 service->passphrase = g_strdup(passphrase);
670
671                 passphrase_changed(service);
672
673                 if (service->network != NULL)
674                         connman_network_set_string(service->network,
675                                 "WiFi.Passphrase", service->passphrase);
676
677                 __connman_storage_save_service(service);
678         } else if (g_str_equal(name, "APN") == TRUE) {
679                 const char *apn;
680
681                 if (type != DBUS_TYPE_STRING)
682                         return __connman_error_invalid_arguments(msg);
683
684                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
685                         return __connman_error_invalid_service(msg);
686
687                 dbus_message_iter_get_basic(&value, &apn);
688
689                 g_free(service->apn);
690                 service->apn = g_strdup(apn);
691
692                 apn_changed(service);
693
694                 if (service->network != NULL)
695                         connman_network_set_string(service->network,
696                                                 "Cellular.APN", service->apn);
697
698                 __connman_storage_save_service(service);
699         } else if (g_str_equal(name, "Username") == TRUE) {
700                 const char *username;
701
702                 if (type != DBUS_TYPE_STRING)
703                         return __connman_error_invalid_arguments(msg);
704
705                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
706                         return __connman_error_invalid_service(msg);
707
708                 dbus_message_iter_get_basic(&value, &username);
709
710                 g_free(service->username);
711                 service->username = g_strdup(username);
712
713                 if (service->network != NULL)
714                         connman_network_set_string(service->network,
715                                         "Cellular.Username", service->username);
716
717                 __connman_storage_save_service(service);
718         } else if (g_str_equal(name, "Password") == TRUE) {
719                 const char *password;
720
721                 if (type != DBUS_TYPE_STRING)
722                         return __connman_error_invalid_arguments(msg);
723
724                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
725                         return __connman_error_invalid_service(msg);
726
727                 dbus_message_iter_get_basic(&value, &password);
728
729                 g_free(service->password);
730                 service->password = g_strdup(password);
731
732                 if (service->network != NULL)
733                         connman_network_set_string(service->network,
734                                         "Cellular.Password", service->password);
735
736                 __connman_storage_save_service(service);
737         } else if (g_str_has_prefix(name, "IPv4.") == TRUE) {
738                 int err;
739
740                 if (service->ipconfig == NULL)
741                         return __connman_error_invalid_property(msg);
742
743                 err = __connman_ipconfig_set_ipv4(service->ipconfig,
744                                                         name + 5, &value);
745                 if (err < 0)
746                         return __connman_error_failed(msg, -err);
747         } else
748                 return __connman_error_invalid_property(msg);
749
750         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
751 }
752
753 static void set_idle(struct connman_service *service)
754 {
755         service->state = CONNMAN_SERVICE_STATE_IDLE;
756         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
757         state_changed(service);
758 }
759
760 static DBusMessage *clear_property(DBusConnection *conn,
761                                         DBusMessage *msg, void *user_data)
762 {
763         struct connman_service *service = user_data;
764         const char *name;
765
766         DBG("service %p", service);
767
768         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
769                                                         DBUS_TYPE_INVALID);
770
771         if (__connman_security_check_privilege(msg,
772                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
773                 return __connman_error_permission_denied(msg);
774
775         if (g_str_equal(name, "Error") == TRUE) {
776                 set_idle(service);
777
778                 g_get_current_time(&service->modified);
779                 __connman_storage_save_service(service);
780         } else if (g_str_equal(name, "Passphrase") == TRUE) {
781                 g_free(service->passphrase);
782                 service->passphrase = NULL;
783
784                 passphrase_changed(service);
785
786                 __connman_storage_save_service(service);
787         } else
788                 return __connman_error_invalid_property(msg);
789
790         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
791 }
792
793 static connman_bool_t is_connecting(struct connman_service *service)
794 {
795         switch (service->state) {
796         case CONNMAN_SERVICE_STATE_UNKNOWN:
797         case CONNMAN_SERVICE_STATE_IDLE:
798         case CONNMAN_SERVICE_STATE_FAILURE:
799         case CONNMAN_SERVICE_STATE_DISCONNECT:
800         case CONNMAN_SERVICE_STATE_READY:
801                 break;
802         case CONNMAN_SERVICE_STATE_ASSOCIATION:
803         case CONNMAN_SERVICE_STATE_CONFIGURATION:
804                 return TRUE;
805         }
806
807         return FALSE;
808 }
809
810 static connman_bool_t is_ignore(struct connman_service *service)
811 {
812         if (service->autoconnect == FALSE)
813                 return TRUE;
814
815         if (service->roaming == TRUE)
816                 return TRUE;
817
818         if (service->ignore == TRUE)
819                 return TRUE;
820
821         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
822                 return TRUE;
823
824         return FALSE;
825 }
826
827 void __connman_service_auto_connect(void)
828 {
829         struct connman_service *service = NULL;
830         GSequenceIter *iter;
831
832         DBG("");
833
834         iter = g_sequence_get_begin_iter(service_list);
835
836         while (g_sequence_iter_is_end(iter) == FALSE) {
837                 service = g_sequence_get(iter);
838
839                 if (service->pending != NULL)
840                         return;
841
842                 if (is_connecting(service) == TRUE)
843                         return;
844
845                 if (service->favorite == FALSE)
846                         return;
847
848                 if (service->state == CONNMAN_SERVICE_STATE_READY)
849                         return;
850
851                 if (is_ignore(service) == FALSE &&
852                                 service->state == CONNMAN_SERVICE_STATE_IDLE)
853                         break;
854
855                 service = NULL;
856
857                 iter = g_sequence_iter_next(iter);
858         }
859
860         if (service != NULL) {
861                 service->userconnect = FALSE;
862                 __connman_service_connect(service);
863         }
864 }
865
866 static void remove_timeout(struct connman_service *service)
867 {
868         if (service->timeout > 0) {
869                 g_source_remove(service->timeout);
870                 service->timeout = 0;
871         }
872 }
873
874 static void reply_pending(struct connman_service *service, int error)
875 {
876         remove_timeout(service);
877
878         if (service->pending != NULL) {
879                 if (error > 0) {
880                         DBusMessage *reply;
881
882                         reply = __connman_error_failed(service->pending,
883                                                                 error);
884                         if (reply != NULL)
885                                 g_dbus_send_message(connection, reply);
886                 } else
887                         g_dbus_send_reply(connection, service->pending,
888                                                         DBUS_TYPE_INVALID);
889
890                 dbus_message_unref(service->pending);
891                 service->pending = NULL;
892         }
893 }
894
895 static gboolean connect_timeout(gpointer user_data)
896 {
897         struct connman_service *service = user_data;
898         connman_bool_t autoconnect = FALSE;
899
900         DBG("service %p", service);
901
902         service->timeout = 0;
903
904         if (service->network != NULL)
905                 __connman_network_disconnect(service->network);
906
907         __connman_ipconfig_disable(service->ipconfig);
908
909         if (service->pending != NULL) {
910                 DBusMessage *reply;
911
912                 reply = __connman_error_operation_timeout(service->pending);
913                 if (reply != NULL)
914                         g_dbus_send_message(connection, reply);
915
916                 dbus_message_unref(service->pending);
917                 service->pending = NULL;
918         } else
919                 autoconnect = TRUE;
920
921         __connman_service_indicate_state(service,
922                                         CONNMAN_SERVICE_STATE_FAILURE);
923
924         if (autoconnect == TRUE && service->userconnect == FALSE)
925                 __connman_service_auto_connect();
926
927         return FALSE;
928 }
929
930 static void set_reconnect_state(struct connman_service *service,
931                                                 connman_bool_t reconnect)
932 {
933         struct connman_device *device;
934
935         if (service->network == NULL)
936                 return;
937
938         device = connman_network_get_device(service->network);
939         if (device == NULL)
940                 return;
941
942         __connman_device_set_reconnect(device, reconnect);
943 }
944
945 static connman_bool_t get_reconnect_state(struct connman_service *service)
946 {
947         struct connman_device *device;
948
949         if (service->network == NULL)
950                 return FALSE;
951
952         device = connman_network_get_device(service->network);
953         if (device == NULL)
954                 return FALSE;
955
956         return __connman_device_get_reconnect(device);
957 }
958
959 static DBusMessage *connect_service(DBusConnection *conn,
960                                         DBusMessage *msg, void *user_data)
961 {
962         struct connman_service *service = user_data;
963         GSequenceIter *iter;
964         int err;
965
966         DBG("service %p", service);
967
968         if (service->pending != NULL)
969                 return __connman_error_in_progress(msg);
970
971         iter = g_sequence_get_begin_iter(service_list);
972
973         while (g_sequence_iter_is_end(iter) == FALSE) {
974                 struct connman_service *temp = g_sequence_get(iter);
975
976                 if (service->type == temp->type &&
977                                         is_connecting(temp) == TRUE)
978                         return __connman_error_in_progress(msg);
979
980                 iter = g_sequence_iter_next(iter);
981         }
982
983         service->ignore = FALSE;
984
985         service->userconnect = TRUE;
986
987         service->pending = dbus_message_ref(msg);
988
989         set_reconnect_state(service, FALSE);
990
991         err = __connman_service_connect(service);
992         if (err < 0) {
993                 if (err == -ENOKEY) {
994                         if (__connman_agent_request_passphrase(service,
995                                                         NULL, NULL) == 0)
996                                 return NULL;
997                 }
998
999                 if (err != -EINPROGRESS) {
1000                         dbus_message_unref(service->pending);
1001                         service->pending = NULL;
1002
1003                         return __connman_error_failed(msg, -err);
1004                 }
1005
1006                 return NULL;
1007         }
1008
1009         dbus_message_unref(service->pending);
1010         service->pending = NULL;
1011
1012         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1013 }
1014
1015 static DBusMessage *disconnect_service(DBusConnection *conn,
1016                                         DBusMessage *msg, void *user_data)
1017 {
1018         struct connman_service *service = user_data;
1019         int err;
1020
1021         DBG("service %p", service);
1022
1023         reply_pending(service, ECONNABORTED);
1024
1025         service->ignore = TRUE;
1026
1027         set_reconnect_state(service, FALSE);
1028
1029         err = __connman_service_disconnect(service);
1030         if (err < 0) {
1031                 if (err != -EINPROGRESS)
1032                         return __connman_error_failed(msg, -err);
1033
1034                 return NULL;
1035         }
1036
1037         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1038 }
1039
1040 static DBusMessage *remove_service(DBusConnection *conn,
1041                                         DBusMessage *msg, void *user_data)
1042 {
1043         struct connman_service *service = user_data;
1044
1045         DBG("service %p", service);
1046
1047         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
1048                 return __connman_error_not_supported(msg);
1049
1050         if (service->favorite == FALSE &&
1051                         service->state != CONNMAN_SERVICE_STATE_FAILURE)
1052                 return __connman_error_not_supported(msg);
1053
1054         if (service->network != NULL) {
1055                 set_reconnect_state(service, FALSE);
1056
1057                 __connman_network_disconnect(service->network);
1058         }
1059
1060         g_free(service->passphrase);
1061         service->passphrase = NULL;
1062
1063         passphrase_changed(service);
1064
1065         g_free(service->apn);
1066         service->apn = NULL;
1067
1068         g_free(service->username);
1069         service->username = NULL;
1070
1071         g_free(service->password);
1072         service->password = NULL;
1073
1074         apn_changed(service);
1075
1076         set_idle(service);
1077
1078         connman_service_set_favorite(service, FALSE);
1079         __connman_storage_save_service(service);
1080
1081         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1082 }
1083
1084 static DBusMessage *move_before(DBusConnection *conn,
1085                                         DBusMessage *msg, void *user_data)
1086 {
1087         struct connman_service *service = user_data;
1088         struct connman_service *target;
1089         const char *path;
1090         GSequenceIter *src, *dst;
1091
1092         DBG("service %p", service);
1093
1094         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
1095                                                         DBUS_TYPE_INVALID);
1096
1097         if (service->favorite == FALSE)
1098                 return __connman_error_not_supported(msg);
1099
1100         target = find_service(path);
1101         if (target == NULL || target->favorite == FALSE || target == service)
1102                 return __connman_error_invalid_service(msg);
1103
1104         DBG("target %s", target->identifier);
1105
1106         if (target->state != service->state)
1107                 return __connman_error_invalid_service(msg);
1108
1109         g_get_current_time(&service->modified);
1110         __connman_storage_save_service(service);
1111
1112         src = g_hash_table_lookup(service_hash, service->identifier);
1113         dst = g_hash_table_lookup(service_hash, target->identifier);
1114
1115         g_sequence_move(src, dst);
1116
1117         __connman_profile_changed(FALSE);
1118
1119         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1120 }
1121
1122 static DBusMessage *move_after(DBusConnection *conn,
1123                                         DBusMessage *msg, void *user_data)
1124 {
1125         struct connman_service *service = user_data;
1126         struct connman_service *target;
1127         const char *path;
1128
1129         DBG("service %p", service);
1130
1131         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
1132                                                         DBUS_TYPE_INVALID);
1133
1134         if (service->favorite == FALSE)
1135                 return __connman_error_not_supported(msg);
1136
1137         target = find_service(path);
1138         if (target == NULL || target->favorite == FALSE || target == service)
1139                 return __connman_error_invalid_service(msg);
1140
1141         DBG("target %s", target->identifier);
1142
1143         if (target->state != service->state)
1144                 return __connman_error_invalid_service(msg);
1145
1146         g_get_current_time(&service->modified);
1147         __connman_storage_save_service(service);
1148
1149         return __connman_error_not_implemented(msg);
1150 }
1151
1152 static GDBusMethodTable service_methods[] = {
1153         { "GetProperties", "",   "a{sv}", get_properties     },
1154         { "SetProperty",   "sv", "",      set_property       },
1155         { "ClearProperty", "s",  "",      clear_property     },
1156         { "Connect",       "",   "",      connect_service,
1157                                                 G_DBUS_METHOD_FLAG_ASYNC },
1158         { "Disconnect",    "",   "",      disconnect_service },
1159         { "Remove",        "",   "",      remove_service     },
1160         { "MoveBefore",    "o",  "",      move_before        },
1161         { "MoveAfter",     "o",  "",      move_after         },
1162         { },
1163 };
1164
1165 static GDBusSignalTable service_signals[] = {
1166         { "PropertyChanged", "sv" },
1167         { },
1168 };
1169
1170 static void service_free(gpointer user_data)
1171 {
1172         struct connman_service *service = user_data;
1173         char *path = service->path;
1174
1175         DBG("service %p", service);
1176
1177         reply_pending(service, ENOENT);
1178
1179         g_hash_table_remove(service_hash, service->identifier);
1180
1181         service->path = NULL;
1182
1183         if (path != NULL) {
1184                 __connman_profile_changed(FALSE);
1185
1186                 g_dbus_unregister_interface(connection, path,
1187                                                 CONNMAN_SERVICE_INTERFACE);
1188                 g_free(path);
1189         }
1190
1191         if (service->network != NULL)
1192                 connman_network_unref(service->network);
1193
1194         if (service->ipconfig != NULL) {
1195                 connman_ipconfig_unref(service->ipconfig);
1196                 service->ipconfig = NULL;
1197         }
1198
1199         g_free(service->mcc);
1200         g_free(service->mnc);
1201         g_free(service->apn);
1202         g_free(service->username);
1203         g_free(service->password);
1204         g_free(service->profile);
1205         g_free(service->name);
1206         g_free(service->passphrase);
1207         g_free(service->identifier);
1208         g_free(service);
1209 }
1210
1211 /**
1212  * __connman_service_put:
1213  * @service: service structure
1214  *
1215  * Release service if no longer needed
1216  */
1217 void __connman_service_put(struct connman_service *service)
1218 {
1219         DBG("service %p", service);
1220
1221         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
1222                 GSequenceIter *iter;
1223
1224                 iter = g_hash_table_lookup(service_hash, service->identifier);
1225                 if (iter != NULL) {
1226                         reply_pending(service, ECONNABORTED);
1227
1228                         __connman_service_disconnect(service);
1229
1230                         g_sequence_remove(iter);
1231                 } else
1232                         service_free(service);
1233         }
1234 }
1235
1236 static void __connman_service_initialize(struct connman_service *service)
1237 {
1238         DBG("service %p", service);
1239
1240         service->refcount = 1;
1241
1242         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
1243         service->mode     = CONNMAN_SERVICE_MODE_UNKNOWN;
1244         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
1245         service->state    = CONNMAN_SERVICE_STATE_UNKNOWN;
1246
1247         service->favorite = FALSE;
1248         service->hidden = FALSE;
1249
1250         service->ignore = FALSE;
1251
1252         service->userconnect = FALSE;
1253
1254         service->order = 0;
1255 }
1256
1257 /**
1258  * connman_service_create:
1259  *
1260  * Allocate a new service.
1261  *
1262  * Returns: a newly-allocated #connman_service structure
1263  */
1264 struct connman_service *connman_service_create(void)
1265 {
1266         struct connman_service *service;
1267
1268         service = g_try_new0(struct connman_service, 1);
1269         if (service == NULL)
1270                 return NULL;
1271
1272         DBG("service %p", service);
1273
1274         __connman_service_initialize(service);
1275
1276         return service;
1277 }
1278
1279 /**
1280  * connman_service_ref:
1281  * @service: service structure
1282  *
1283  * Increase reference counter of service
1284  */
1285 struct connman_service *connman_service_ref(struct connman_service *service)
1286 {
1287         g_atomic_int_inc(&service->refcount);
1288
1289         return service;
1290 }
1291
1292 /**
1293  * connman_service_unref:
1294  * @service: service structure
1295  *
1296  * Decrease reference counter of service
1297  */
1298 void connman_service_unref(struct connman_service *service)
1299 {
1300         __connman_service_put(service);
1301 }
1302
1303 static gint service_compare(gconstpointer a, gconstpointer b,
1304                                                         gpointer user_data)
1305 {
1306         struct connman_service *service_a = (void *) a;
1307         struct connman_service *service_b = (void *) b;
1308
1309         if (service_a->state != service_b->state) {
1310                 if (service_a->state == CONNMAN_SERVICE_STATE_READY)
1311                         return -1;
1312                 if (service_b->state == CONNMAN_SERVICE_STATE_READY)
1313                         return 1;
1314         }
1315
1316         if (service_a->order > service_b->order)
1317                 return -1;
1318
1319         if (service_a->order < service_b->order)
1320                 return 1;
1321
1322         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
1323                 return -1;
1324
1325         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
1326                 return 1;
1327
1328         if (service_a->type != service_b->type) {
1329                 switch (service_a->type) {
1330                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
1331                 case CONNMAN_SERVICE_TYPE_SYSTEM:
1332                 case CONNMAN_SERVICE_TYPE_ETHERNET:
1333                 case CONNMAN_SERVICE_TYPE_VPN:
1334                         break;
1335                 case CONNMAN_SERVICE_TYPE_WIFI:
1336                         return 1;
1337                 case CONNMAN_SERVICE_TYPE_WIMAX:
1338                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1339                 case CONNMAN_SERVICE_TYPE_CELLULAR:
1340                         return -1;
1341                 }
1342         }
1343
1344         return (gint) service_b->strength - (gint) service_a->strength;
1345 }
1346
1347 static void favorite_changed(struct connman_service *service)
1348 {
1349         DBusMessage *signal;
1350         DBusMessageIter iter;
1351
1352         if (service->path == NULL)
1353                 return;
1354
1355         signal = dbus_message_new_signal(service->path,
1356                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
1357         if (signal == NULL)
1358                 return;
1359
1360         dbus_message_iter_init_append(signal, &iter);
1361
1362         connman_dbus_property_append_variant(&iter,
1363                         "Favorite", DBUS_TYPE_BOOLEAN, &service->favorite);
1364
1365         g_dbus_send_message(connection, signal);
1366 }
1367
1368 /**
1369  * connman_service_get_type:
1370  * @service: service structure
1371  *
1372  * Get the type of service
1373  */
1374 enum connman_service_type connman_service_get_type(struct connman_service *service)
1375 {
1376         if (service == NULL)
1377                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
1378
1379         return service->type;
1380 }
1381
1382 /**
1383  * connman_service_get_interface:
1384  * @service: service structure
1385  *
1386  * Get network interface of service
1387  */
1388 char *connman_service_get_interface(struct connman_service *service)
1389 {
1390         int index;
1391
1392         if (service == NULL)
1393                 return NULL;
1394
1395         if (service->network == NULL)
1396                 return NULL;
1397
1398         index = connman_network_get_index(service->network);
1399
1400         return connman_inet_ifname(index);
1401 }
1402
1403 /**
1404  * connman_service_set_favorite:
1405  * @service: service structure
1406  * @favorite: favorite value
1407  *
1408  * Change the favorite setting of service
1409  */
1410 int connman_service_set_favorite(struct connman_service *service,
1411                                                 connman_bool_t favorite)
1412 {
1413         GSequenceIter *iter;
1414
1415         iter = g_hash_table_lookup(service_hash, service->identifier);
1416         if (iter == NULL)
1417                 return -ENOENT;
1418
1419         if (service->favorite == favorite)
1420                 return -EALREADY;
1421
1422         service->favorite = favorite;
1423
1424         favorite_changed(service);
1425
1426         g_sequence_sort_changed(iter, service_compare, NULL);
1427
1428         __connman_profile_changed(FALSE);
1429
1430         return 0;
1431 }
1432
1433
1434 int __connman_service_indicate_state(struct connman_service *service,
1435                                         enum connman_service_state state)
1436 {
1437         GSequenceIter *iter;
1438
1439         DBG("service %p state %d", service, state);
1440
1441         if (service == NULL)
1442                 return -EINVAL;
1443
1444         if (service->state == state)
1445                 return -EALREADY;
1446
1447         if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
1448                                 state == CONNMAN_SERVICE_STATE_IDLE)
1449                 return -EINVAL;
1450
1451         if (service->state == CONNMAN_SERVICE_STATE_IDLE &&
1452                                 state == CONNMAN_SERVICE_STATE_DISCONNECT)
1453                 return -EINVAL;
1454
1455         if (state == CONNMAN_SERVICE_STATE_IDLE &&
1456                         service->state != CONNMAN_SERVICE_STATE_DISCONNECT) {
1457                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
1458                 state_changed(service);
1459
1460                 reply_pending(service, ECONNABORTED);
1461
1462                 __connman_service_disconnect(service);
1463         }
1464
1465         service->state = state;
1466         state_changed(service);
1467
1468         if (state == CONNMAN_SERVICE_STATE_IDLE) {
1469                 connman_bool_t reconnect;
1470
1471                 reconnect = get_reconnect_state(service);
1472                 if (reconnect == TRUE)
1473                         __connman_service_auto_connect();
1474         }
1475
1476         if (state == CONNMAN_SERVICE_STATE_READY) {
1477                 set_reconnect_state(service, TRUE);
1478
1479                 connman_service_set_favorite(service, TRUE);
1480
1481                 reply_pending(service, 0);
1482
1483                 service->userconnect = FALSE;
1484
1485                 g_get_current_time(&service->modified);
1486                 __connman_storage_save_service(service);
1487
1488                 __connman_notifier_connect(service->type);
1489
1490                 default_changed();
1491         } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) {
1492                 default_changed();
1493
1494                 __connman_notifier_disconnect(service->type);
1495         }
1496
1497         if (state == CONNMAN_SERVICE_STATE_FAILURE) {
1498                 reply_pending(service, EIO);
1499
1500                 if (service->userconnect == FALSE)
1501                         __connman_service_auto_connect();
1502
1503                 g_get_current_time(&service->modified);
1504                 __connman_storage_save_service(service);
1505         } else
1506                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
1507
1508         iter = g_hash_table_lookup(service_hash, service->identifier);
1509         if (iter != NULL)
1510                 g_sequence_sort_changed(iter, service_compare, NULL);
1511
1512         __connman_profile_changed(FALSE);
1513
1514         if (service->state == CONNMAN_SERVICE_STATE_IDLE ||
1515                         service->state == CONNMAN_SERVICE_STATE_FAILURE)
1516                 __connman_element_request_scan(CONNMAN_ELEMENT_TYPE_UNKNOWN);
1517
1518         return 0;
1519 }
1520
1521 int __connman_service_indicate_error(struct connman_service *service,
1522                                         enum connman_service_error error)
1523 {
1524         DBG("service %p error %d", service, error);
1525
1526         if (service == NULL)
1527                 return -EINVAL;
1528
1529         service->error = error;
1530
1531         return __connman_service_indicate_state(service,
1532                                         CONNMAN_SERVICE_STATE_FAILURE);
1533 }
1534
1535 int __connman_service_indicate_default(struct connman_service *service)
1536 {
1537         DBG("service %p", service);
1538
1539         default_changed();
1540
1541         return 0;
1542 }
1543
1544 static connman_bool_t prepare_network(struct connman_service *service)
1545 {
1546         enum connman_network_type type;
1547         unsigned int ssid_len;
1548
1549         type = connman_network_get_type(service->network);
1550
1551         switch (type) {
1552         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1553         case CONNMAN_NETWORK_TYPE_VENDOR:
1554                 return FALSE;
1555         case CONNMAN_NETWORK_TYPE_WIFI:
1556                 if (connman_network_get_blob(service->network, "WiFi.SSID",
1557                                                         &ssid_len) == NULL)
1558                         return FALSE;
1559
1560                 connman_network_set_string(service->network,
1561                                 "WiFi.Passphrase", service->passphrase);
1562                 break;
1563         case CONNMAN_NETWORK_TYPE_ETHERNET:
1564         case CONNMAN_NETWORK_TYPE_WIMAX:
1565         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1566         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1567         case CONNMAN_NETWORK_TYPE_CELLULAR:
1568                 break;
1569         case CONNMAN_NETWORK_TYPE_MBM:
1570         case CONNMAN_NETWORK_TYPE_HSO:
1571                 connman_network_set_string(service->network,
1572                                                 "Cellular.APN", service->apn);
1573
1574                 connman_network_set_string(service->network,
1575                                         "Cellular.Username", service->username);
1576                 connman_network_set_string(service->network,
1577                                         "Cellular.Password", service->password);
1578                 break;
1579         }
1580
1581         return TRUE;
1582 }
1583
1584 int __connman_service_connect(struct connman_service *service)
1585 {
1586         int err;
1587
1588         DBG("service %p", service);
1589
1590         if (service->state == CONNMAN_SERVICE_STATE_READY)
1591                 return -EISCONN;
1592
1593         if (is_connecting(service) == TRUE)
1594                 return -EALREADY;
1595
1596         switch (service->type) {
1597         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1598         case CONNMAN_SERVICE_TYPE_SYSTEM:
1599         case CONNMAN_SERVICE_TYPE_VPN:
1600                 return -EINVAL;
1601         case CONNMAN_SERVICE_TYPE_ETHERNET:
1602         case CONNMAN_SERVICE_TYPE_WIMAX:
1603         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1604                 break;
1605         case CONNMAN_SERVICE_TYPE_CELLULAR:
1606                 if (service->apn == NULL)
1607                         return -EINVAL;
1608                 break;
1609         case CONNMAN_SERVICE_TYPE_WIFI:
1610                 switch (service->security) {
1611                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
1612                 case CONNMAN_SERVICE_SECURITY_NONE:
1613                 case CONNMAN_SERVICE_SECURITY_8021X:
1614                         break;
1615                 case CONNMAN_SERVICE_SECURITY_WEP:
1616                 case CONNMAN_SERVICE_SECURITY_PSK:
1617                 case CONNMAN_SERVICE_SECURITY_WPA:
1618                 case CONNMAN_SERVICE_SECURITY_RSN:
1619                         if (service->passphrase == NULL)
1620                                 return -ENOKEY;
1621                         break;
1622                 }
1623                 break;
1624         }
1625
1626         if (service->network != NULL) {
1627                 if (prepare_network(service) == FALSE)
1628                         return -EINVAL;
1629
1630                 __connman_ipconfig_enable(service->ipconfig);
1631
1632                 err = __connman_network_connect(service->network);
1633         } else
1634                 return -EOPNOTSUPP;
1635
1636         if (err < 0) {
1637                 if (err != -EINPROGRESS) {
1638                         __connman_ipconfig_disable(service->ipconfig);
1639                         return err;
1640                 }
1641
1642                 service->timeout = g_timeout_add_seconds(CONNECT_TIMEOUT,
1643                                                 connect_timeout, service);
1644
1645                 return -EINPROGRESS;
1646         }
1647
1648         return 0;
1649 }
1650
1651 int __connman_service_disconnect(struct connman_service *service)
1652 {
1653         int err;
1654
1655         DBG("service %p", service);
1656
1657         if (service->network != NULL) {
1658                 err = __connman_network_disconnect(service->network);
1659         } else
1660                 return -EOPNOTSUPP;
1661
1662         __connman_ipconfig_disable(service->ipconfig);
1663
1664         if (err < 0) {
1665                 if (err != -EINPROGRESS)
1666                         return err;
1667
1668                 return -EINPROGRESS;
1669         }
1670
1671         return 0;
1672 }
1673
1674 /**
1675  * __connman_service_lookup:
1676  * @identifier: service identifier
1677  *
1678  * Look up a service by identifier (reference count will not be increased)
1679  */
1680 static struct connman_service *__connman_service_lookup(const char *identifier)
1681 {
1682         GSequenceIter *iter;
1683
1684         iter = g_hash_table_lookup(service_hash, identifier);
1685         if (iter != NULL)
1686                 return g_sequence_get(iter);
1687
1688         return NULL;
1689 }
1690
1691 static struct connman_network *create_hidden_wifi(struct connman_device *device,
1692                 const char *ssid, const char *mode, const char *security)
1693 {
1694         struct connman_network *network;
1695         char *name;
1696         int index;
1697         unsigned int i, ssid_len;
1698
1699         ssid_len = strlen(ssid);
1700         if (ssid_len < 1)
1701                 return NULL;
1702
1703         network = connman_network_create(NULL, CONNMAN_NETWORK_TYPE_WIFI);
1704         if (network == NULL)
1705                 return NULL;
1706
1707         connman_network_set_blob(network, "WiFi.SSID",
1708                                         (unsigned char *) ssid, ssid_len);
1709
1710         connman_network_set_string(network, "WiFi.Mode", mode);
1711         connman_network_set_string(network, "WiFi.Security", security);
1712
1713         name = g_try_malloc0(ssid_len + 1);
1714         if (name == NULL) {
1715                 connman_network_unref(network);
1716                 return NULL;
1717         }
1718
1719         for (i = 0; i < ssid_len; i++) {
1720                 if (g_ascii_isprint(ssid[i]))
1721                         name[i] = ssid[i];
1722                 else
1723                         name[i] = ' ';
1724         }
1725
1726         connman_network_set_name(network, name);
1727
1728         g_free(name);
1729
1730         index = connman_device_get_index(device);
1731         connman_network_set_index(network, index);
1732
1733         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
1734
1735         if (connman_device_add_network(device, network) < 0) {
1736                 connman_network_unref(network);
1737                 return NULL;
1738         }
1739
1740         connman_network_set_available(network, TRUE);
1741
1742         return network;
1743 }
1744
1745 int __connman_service_create_and_connect(DBusMessage *msg)
1746 {
1747         struct connman_service *service;
1748         struct connman_network *network;
1749         struct connman_device *device;
1750         DBusMessageIter iter, array;
1751         const char *mode = "managed", *security = "none";
1752         const char *type = NULL, *ssid = NULL, *passphrase = NULL;
1753         unsigned int ssid_len = 0;
1754         const char *ident;
1755         char *name, *group;
1756         gboolean created = FALSE;
1757         int err;
1758
1759         dbus_message_iter_init(msg, &iter);
1760         dbus_message_iter_recurse(&iter, &array);
1761
1762         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1763                 DBusMessageIter entry, value;
1764                 const char *key;
1765
1766                 dbus_message_iter_recurse(&array, &entry);
1767                 dbus_message_iter_get_basic(&entry, &key);
1768
1769                 dbus_message_iter_next(&entry);
1770                 dbus_message_iter_recurse(&entry, &value);
1771
1772                 switch (dbus_message_iter_get_arg_type(&value)) {
1773                 case DBUS_TYPE_STRING:
1774                         if (g_str_equal(key, "Type") == TRUE)
1775                                 dbus_message_iter_get_basic(&value, &type);
1776                         else if (g_str_equal(key, "WiFi.Mode") == TRUE ||
1777                                         g_str_equal(key, "Mode") == TRUE)
1778                                 dbus_message_iter_get_basic(&value, &mode);
1779                         else if (g_str_equal(key, "WiFi.Security") == TRUE ||
1780                                         g_str_equal(key, "Security") == TRUE)
1781                                 dbus_message_iter_get_basic(&value, &security);
1782                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE ||
1783                                         g_str_equal(key, "Passphrase") == TRUE)
1784                                 dbus_message_iter_get_basic(&value, &passphrase);
1785                         else if (g_str_equal(key, "WiFi.SSID") == TRUE ||
1786                                         g_str_equal(key, "SSID") == TRUE)
1787                                 dbus_message_iter_get_basic(&value, &ssid);
1788                 }
1789
1790                 dbus_message_iter_next(&array);
1791         }
1792
1793         if (type == NULL)
1794                 return -EINVAL;
1795
1796         if (g_strcmp0(type, "wifi") != 0 || g_strcmp0(mode, "managed") != 0)
1797                 return -EOPNOTSUPP;
1798
1799         if (ssid == NULL)
1800                 return -EINVAL;
1801
1802         ssid_len = strlen(ssid);
1803         if (ssid_len < 1)
1804                 return -EINVAL;
1805
1806         if (g_strcmp0(security, "none") != 0 &&
1807                                 g_strcmp0(security, "wep") != 0 &&
1808                                 g_strcmp0(security, "psk") != 0 &&
1809                                 g_strcmp0(security, "wpa") != 0 &&
1810                                 g_strcmp0(security, "rsn") != 0)
1811                 return -EINVAL;
1812
1813         device = __connman_element_find_device(CONNMAN_DEVICE_TYPE_WIFI);
1814         if (device == NULL)
1815                 return -EOPNOTSUPP;
1816
1817         ident = __connman_device_get_ident(device);
1818         if (ident == NULL)
1819                 return -EOPNOTSUPP;
1820
1821         group = connman_wifi_build_group_name((unsigned char *) ssid,
1822                                                 ssid_len, mode, security);
1823         if (group == NULL)
1824                 return -EINVAL;
1825
1826         name = g_strdup_printf("%s_%s_%s", type, ident, group);
1827
1828         service = __connman_service_lookup(name);
1829
1830         if (service != NULL)
1831                 goto done;
1832
1833         network = create_hidden_wifi(device, ssid, mode, security);
1834         if (network != NULL) {
1835                 connman_network_set_group(network, group);
1836                 created = TRUE;
1837         }
1838
1839         service = __connman_service_lookup(name);
1840
1841 done:
1842         g_free(name);
1843         g_free(group);
1844
1845         if (service == NULL) {
1846                 err = -EOPNOTSUPP;
1847                 goto failed;
1848         }
1849
1850         set_reconnect_state(service, FALSE);
1851
1852         __connman_device_disconnect(device);
1853
1854         if (passphrase != NULL) {
1855                 g_free(service->passphrase);
1856                 service->passphrase = g_strdup(passphrase);
1857         }
1858
1859         service->userconnect = TRUE;
1860
1861         err = __connman_service_connect(service);
1862         if (err < 0 && err != -EINPROGRESS)
1863                 goto failed;
1864
1865         g_dbus_send_reply(connection, msg,
1866                                 DBUS_TYPE_OBJECT_PATH, &service->path,
1867                                                         DBUS_TYPE_INVALID);
1868
1869         return 0;
1870
1871 failed:
1872         if (service != NULL && created == TRUE) {
1873                 struct connman_network *network = service->network;
1874
1875                 if (network != NULL) {
1876                         connman_network_set_available(network, FALSE);
1877                         __connman_device_cleanup_networks(device);
1878                 }
1879
1880                 __connman_service_put(service);
1881         }
1882
1883         return err;
1884 }
1885
1886 /**
1887  * __connman_service_get:
1888  * @identifier: service identifier
1889  *
1890  * Look up a service by identifier or create a new one if not found
1891  */
1892 static struct connman_service *__connman_service_get(const char *identifier)
1893 {
1894         struct connman_service *service;
1895         GSequenceIter *iter;
1896
1897         iter = g_hash_table_lookup(service_hash, identifier);
1898         if (iter != NULL) {
1899                 service = g_sequence_get(iter);
1900                 if (service != NULL)
1901                         g_atomic_int_inc(&service->refcount);
1902                 return service;
1903         }
1904
1905         service = connman_service_create();
1906         if (service == NULL)
1907                 return NULL;
1908
1909         DBG("service %p", service);
1910
1911         service->identifier = g_strdup(identifier);
1912
1913         service->profile = g_strdup(__connman_profile_active_ident());
1914
1915         __connman_storage_load_service(service);
1916
1917         iter = g_sequence_insert_sorted(service_list, service,
1918                                                 service_compare, NULL);
1919
1920         g_hash_table_insert(service_hash, service->identifier, iter);
1921
1922         return service;
1923 }
1924
1925 static int service_register(struct connman_service *service)
1926 {
1927         const char *path = __connman_profile_active_path();
1928         GSequenceIter *iter;
1929
1930         DBG("service %p", service);
1931
1932         if (service->path != NULL)
1933                 return -EALREADY;
1934
1935         service->path = g_strdup_printf("%s/%s", path, service->identifier);
1936
1937         DBG("path %s", service->path);
1938
1939         g_dbus_register_interface(connection, service->path,
1940                                         CONNMAN_SERVICE_INTERFACE,
1941                                         service_methods, service_signals,
1942                                                         NULL, service, NULL);
1943
1944         __connman_storage_load_service(service);
1945
1946         iter = g_hash_table_lookup(service_hash, service->identifier);
1947         if (iter != NULL)
1948                 g_sequence_sort_changed(iter, service_compare, NULL);
1949
1950         __connman_profile_changed(TRUE);
1951
1952         return 0;
1953 }
1954
1955 static void service_up(struct connman_ipconfig *ipconfig)
1956 {
1957         connman_info("%s up", connman_ipconfig_get_ifname(ipconfig));
1958 }
1959
1960 static void service_down(struct connman_ipconfig *ipconfig)
1961 {
1962         connman_info("%s down", connman_ipconfig_get_ifname(ipconfig));
1963 }
1964
1965 static void service_lower_up(struct connman_ipconfig *ipconfig)
1966 {
1967         connman_info("%s lower up", connman_ipconfig_get_ifname(ipconfig));
1968 }
1969
1970 static void service_lower_down(struct connman_ipconfig *ipconfig)
1971 {
1972         connman_info("%s lower down", connman_ipconfig_get_ifname(ipconfig));
1973 }
1974
1975 static void service_ip_bound(struct connman_ipconfig *ipconfig)
1976 {
1977         connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig));
1978 }
1979
1980 static void service_ip_release(struct connman_ipconfig *ipconfig)
1981 {
1982         connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig));
1983 }
1984
1985 static const struct connman_ipconfig_ops service_ops = {
1986         .up             = service_up,
1987         .down           = service_down,
1988         .lower_up       = service_lower_up,
1989         .lower_down     = service_lower_down,
1990         .ip_bound       = service_ip_bound,
1991         .ip_release     = service_ip_release,
1992 };
1993
1994 static void setup_ipconfig(struct connman_service *service, int index)
1995 {
1996         if (index < 0)
1997                 return;
1998
1999         service->ipconfig = connman_ipconfig_create(index);
2000         if (service->ipconfig == NULL)
2001                 return;
2002
2003         connman_ipconfig_set_method(service->ipconfig,
2004                                         CONNMAN_IPCONFIG_METHOD_DHCP);
2005
2006         __connman_storage_load_service(service);
2007
2008         connman_ipconfig_set_data(service->ipconfig, service);
2009
2010         connman_ipconfig_set_ops(service->ipconfig, &service_ops);
2011         connman_ipconfig_set_ops(service->ipconfig, NULL);
2012 }
2013
2014 /**
2015  * __connman_service_lookup_from_network:
2016  * @network: network structure
2017  *
2018  * Look up a service by network (reference count will not be increased)
2019  */
2020 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
2021 {
2022         struct connman_service *service;
2023         const char *ident, *group;
2024         char *name;
2025
2026         DBG("network %p", network);
2027
2028         ident = __connman_network_get_ident(network);
2029         if (ident == NULL)
2030                 return NULL;
2031
2032         group = connman_network_get_group(network);
2033         if (group == NULL)
2034                 return NULL;
2035
2036         name = g_strdup_printf("%s_%s_%s",
2037                         __connman_network_get_type(network), ident, group);
2038         service = __connman_service_lookup(name);
2039         g_free(name);
2040
2041         return service;
2042 }
2043
2044 const char *__connman_service_get_path(struct connman_service *service)
2045 {
2046         return service->path;
2047 }
2048
2049 unsigned int __connman_service_get_order(struct connman_service *service)
2050 {
2051         GSequenceIter *iter;
2052
2053         if (service == NULL)
2054                 return 0;
2055
2056         if (service->favorite == FALSE) {
2057                 service->order = 0;
2058                 goto done;
2059         }
2060
2061         iter = g_hash_table_lookup(service_hash, service->identifier);
2062         if (iter != NULL) {
2063                 if (g_sequence_iter_get_position(iter) == 0)
2064                         service->order = 1;
2065                 else
2066                         service->order = 0;
2067         }
2068
2069 done:
2070         return service->order;
2071 }
2072
2073 static enum connman_service_type convert_network_type(struct connman_network *network)
2074 {
2075         enum connman_network_type type = connman_network_get_type(network);
2076
2077         switch (type) {
2078         case CONNMAN_NETWORK_TYPE_UNKNOWN:
2079         case CONNMAN_NETWORK_TYPE_VENDOR:
2080                 break;
2081         case CONNMAN_NETWORK_TYPE_ETHERNET:
2082                 return CONNMAN_SERVICE_TYPE_ETHERNET;
2083         case CONNMAN_NETWORK_TYPE_WIFI:
2084                 return CONNMAN_SERVICE_TYPE_WIFI;
2085         case CONNMAN_NETWORK_TYPE_WIMAX:
2086                 return CONNMAN_SERVICE_TYPE_WIMAX;
2087         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
2088         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
2089                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
2090         case CONNMAN_NETWORK_TYPE_CELLULAR:
2091         case CONNMAN_NETWORK_TYPE_MBM:
2092         case CONNMAN_NETWORK_TYPE_HSO:
2093                 return CONNMAN_SERVICE_TYPE_CELLULAR;
2094         }
2095
2096         return CONNMAN_SERVICE_TYPE_UNKNOWN;
2097 }
2098
2099 static enum connman_service_mode convert_wifi_mode(const char *mode)
2100 {
2101         if (mode == NULL)
2102                 return CONNMAN_SERVICE_MODE_UNKNOWN;
2103         else if (g_str_equal(mode, "managed") == TRUE)
2104                 return CONNMAN_SERVICE_MODE_MANAGED;
2105         else if (g_str_equal(mode, "adhoc") == TRUE)
2106                 return CONNMAN_SERVICE_MODE_ADHOC;
2107         else
2108                 return CONNMAN_SERVICE_MODE_UNKNOWN;
2109 }
2110
2111 static enum connman_service_security convert_wifi_security(const char *security)
2112 {
2113         if (security == NULL)
2114                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
2115         else if (g_str_equal(security, "none") == TRUE)
2116                 return CONNMAN_SERVICE_SECURITY_NONE;
2117         else if (g_str_equal(security, "wep") == TRUE)
2118                 return CONNMAN_SERVICE_SECURITY_WEP;
2119         else if (g_str_equal(security, "wep") == TRUE)
2120                 return CONNMAN_SERVICE_SECURITY_PSK;
2121         else if (g_str_equal(security, "ieee8021x") == TRUE)
2122                 return CONNMAN_SERVICE_SECURITY_8021X;
2123         else if (g_str_equal(security, "wpa") == TRUE)
2124                 return CONNMAN_SERVICE_SECURITY_WPA;
2125         else if (g_str_equal(security, "rsn") == TRUE)
2126                 return CONNMAN_SERVICE_SECURITY_RSN;
2127         else
2128                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
2129 }
2130
2131 static enum connman_service_mode convert_cellular_mode(connman_uint8_t mode)
2132 {
2133         switch (mode) {
2134         case 0:
2135         case 1:
2136                 return CONNMAN_SERVICE_MODE_GPRS;
2137         case 3:
2138                 return CONNMAN_SERVICE_MODE_EDGE;
2139         case 2:
2140         case 4:
2141         case 5:
2142         case 6:
2143                 return CONNMAN_SERVICE_MODE_UMTS;
2144         }
2145
2146         return CONNMAN_SERVICE_MODE_UNKNOWN;
2147 }
2148
2149 static void update_from_network(struct connman_service *service,
2150                                         struct connman_network *network)
2151 {
2152         connman_uint8_t strength = service->strength;
2153         GSequenceIter *iter;
2154         const char *str;
2155
2156         DBG("service %p network %p", service, network);
2157
2158         if (service->state == CONNMAN_SERVICE_STATE_READY)
2159                 return;
2160
2161         if (is_connecting(service) == TRUE)
2162                 return;
2163
2164         str = connman_network_get_string(network, "Name");
2165         if (str != NULL) {
2166                 g_free(service->name);
2167                 service->name = g_strdup(str);
2168                 service->hidden = FALSE;
2169         } else {
2170                 g_free(service->name);
2171                 service->name = NULL;
2172                 service->hidden = TRUE;
2173         }
2174
2175         service->strength = connman_network_get_uint8(network, "Strength");
2176         service->roaming = connman_network_get_bool(network, "Roaming");
2177
2178         if (service->strength == 0) {
2179                 /*
2180                  * Filter out 0-values; it's unclear what they mean
2181                  * and they cause anomalous sorting of the priority list.
2182                  */
2183                 service->strength = strength;
2184         }
2185
2186         str = connman_network_get_string(network, "WiFi.Mode");
2187         service->mode = convert_wifi_mode(str);
2188
2189         str = connman_network_get_string(network, "WiFi.Security");
2190         service->security = convert_wifi_security(str);
2191
2192         str = connman_network_get_string(network, "Cellular.MCC");
2193         g_free(service->mcc);
2194         service->mcc = g_strdup(str);
2195
2196         str = connman_network_get_string(network, "Cellular.MNC");
2197         g_free(service->mnc);
2198         service->mnc = g_strdup(str);
2199
2200         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
2201                 connman_uint8_t value = connman_network_get_uint8(network,
2202                                                         "Cellular.Mode");
2203
2204                 service->mode = convert_cellular_mode(value);
2205         }
2206
2207         if (service->strength > strength && service->network != NULL) {
2208                 connman_network_unref(service->network);
2209                 service->network = connman_network_ref(network);
2210
2211                 strength_changed(service);
2212         }
2213
2214         if (service->network == NULL)
2215                 service->network = connman_network_ref(network);
2216
2217         iter = g_hash_table_lookup(service_hash, service->identifier);
2218         if (iter != NULL)
2219                 g_sequence_sort_changed(iter, service_compare, NULL);
2220 }
2221
2222 /**
2223  * __connman_service_create_from_network:
2224  * @network: network structure
2225  *
2226  * Look up service by network and if not found, create one
2227  */
2228 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
2229 {
2230         struct connman_service *service;
2231         const char *ident, *group;
2232         char *name;
2233
2234         DBG("network %p", network);
2235
2236         ident = __connman_network_get_ident(network);
2237         if (ident == NULL)
2238                 return NULL;
2239
2240         group = connman_network_get_group(network);
2241         if (group == NULL)
2242                 return NULL;
2243
2244         name = g_strdup_printf("%s_%s_%s",
2245                         __connman_network_get_type(network), ident, group);
2246         service = __connman_service_get(name);
2247         g_free(name);
2248
2249         if (service == NULL)
2250                 return NULL;
2251
2252         if (__connman_network_get_weakness(network) == TRUE)
2253                 return service;
2254
2255         if (service->path != NULL) {
2256                 update_from_network(service, network);
2257                 __connman_profile_changed(TRUE);
2258                 return service;
2259         }
2260
2261         service->type = convert_network_type(network);
2262
2263         switch (service->type) {
2264         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2265         case CONNMAN_SERVICE_TYPE_SYSTEM:
2266         case CONNMAN_SERVICE_TYPE_ETHERNET:
2267         case CONNMAN_SERVICE_TYPE_WIMAX:
2268         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2269         case CONNMAN_SERVICE_TYPE_VPN:
2270                 service->autoconnect = FALSE;
2271                 break;
2272         case CONNMAN_SERVICE_TYPE_WIFI:
2273         case CONNMAN_SERVICE_TYPE_CELLULAR:
2274                 service->autoconnect = TRUE;
2275                 break;
2276         }
2277
2278         service->state = CONNMAN_SERVICE_STATE_IDLE;
2279
2280         update_from_network(service, network);
2281
2282         setup_ipconfig(service, connman_network_get_index(network));
2283
2284         service_register(service);
2285
2286         __connman_profile_changed(TRUE);
2287
2288         if (service->favorite == TRUE)
2289                 __connman_service_auto_connect();
2290
2291         return service;
2292 }
2293
2294 void __connman_service_update_from_network(struct connman_network *network)
2295 {
2296         struct connman_service *service;
2297         enum connman_service_mode mode;
2298         connman_uint8_t strength, value;
2299         connman_bool_t roaming;
2300         GSequenceIter *iter;
2301
2302         DBG("network %p", network);
2303
2304         service = __connman_service_lookup_from_network(network);
2305         if (service == NULL)
2306                 return;
2307
2308         if (service->network == NULL)
2309                 return;
2310
2311         strength = connman_network_get_uint8(service->network, "Strength");
2312         if (strength == service->strength)
2313                 goto roaming;
2314
2315         service->strength = strength;
2316
2317         strength_changed(service);
2318
2319 roaming:
2320         roaming = connman_network_get_bool(service->network, "Roaming");
2321         if (roaming == service->roaming)
2322                 goto done;
2323
2324         service->roaming = roaming;
2325
2326         roaming_changed(service);
2327
2328         iter = g_hash_table_lookup(service_hash, service->identifier);
2329         if (iter != NULL)
2330                 g_sequence_sort_changed(iter, service_compare, NULL);
2331
2332 done:
2333         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
2334                 return;
2335
2336         value = connman_network_get_uint8(service->network, "Cellular.Mode");
2337         mode = convert_cellular_mode(value);
2338
2339         if (mode == service->mode)
2340                 return;
2341
2342         service->mode = mode;
2343
2344         mode_changed(service);
2345 }
2346
2347 void __connman_service_remove_from_network(struct connman_network *network)
2348 {
2349         struct connman_service *service;
2350
2351         DBG("network %p", network);
2352
2353         service = __connman_service_lookup_from_network(network);
2354         if (service == NULL)
2355                 return;
2356
2357         __connman_service_put(service);
2358 }
2359
2360 static int service_load(struct connman_service *service)
2361 {
2362         const char *ident = service->profile;
2363         GKeyFile *keyfile;
2364         GError *error = NULL;
2365         gchar *pathname, *data = NULL;
2366         gsize length;
2367         gchar *str;
2368         connman_bool_t autoconnect;
2369         unsigned int ssid_len;
2370         int err = 0;
2371
2372         DBG("service %p", service);
2373
2374         if (ident == NULL)
2375                 return -EINVAL;
2376
2377         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2378         if (pathname == NULL)
2379                 return -ENOMEM;
2380
2381         keyfile = g_key_file_new();
2382
2383         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
2384                 g_free(pathname);
2385                 return -ENOENT;
2386         }
2387
2388         g_free(pathname);
2389
2390         if (g_key_file_load_from_data(keyfile, data, length,
2391                                                         0, NULL) == FALSE) {
2392                 g_free(data);
2393                 return -EILSEQ;
2394         }
2395
2396         g_free(data);
2397
2398         switch (service->type) {
2399         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2400         case CONNMAN_SERVICE_TYPE_SYSTEM:
2401         case CONNMAN_SERVICE_TYPE_ETHERNET:
2402         case CONNMAN_SERVICE_TYPE_VPN:
2403                 break;
2404         case CONNMAN_SERVICE_TYPE_WIFI:
2405                 if (service->name == NULL) {
2406                         gchar *name;
2407
2408                         name = g_key_file_get_string(keyfile,
2409                                         service->identifier, "Name", NULL);
2410                         if (name != NULL) {
2411                                 g_free(service->name);
2412                                 service->name = name;
2413                         }
2414
2415                         if (service->network != NULL)
2416                                 connman_network_set_name(service->network,
2417                                                                         name);
2418                 }
2419
2420                 if (service->network &&
2421                                 connman_network_get_blob(service->network,
2422                                         "WiFi.SSID", &ssid_len) == NULL) {
2423                         gchar *hex_ssid;
2424
2425                         hex_ssid = g_key_file_get_string(keyfile,
2426                                                         service->identifier,
2427                                                                 "SSID", NULL);
2428
2429                         if (hex_ssid != NULL) {
2430                                 gchar *ssid;
2431                                 unsigned int i, j = 0, hex;
2432                                 size_t hex_ssid_len = strlen(hex_ssid);
2433
2434                                 ssid = g_try_malloc0(hex_ssid_len / 2);
2435                                 if (ssid == NULL) {
2436                                         g_free(hex_ssid);
2437                                         err = -ENOMEM;
2438                                         goto done;
2439                                 }
2440
2441                                 for (i = 0; i < hex_ssid_len; i += 2) {
2442                                         sscanf(hex_ssid + i, "%02x", &hex);
2443                                         ssid[j++] = hex;
2444                                 }
2445
2446                                 connman_network_set_blob(service->network,
2447                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
2448                         }
2449
2450                         g_free(hex_ssid);
2451                 }
2452                 /* fall through */
2453
2454         case CONNMAN_SERVICE_TYPE_WIMAX:
2455         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2456         case CONNMAN_SERVICE_TYPE_CELLULAR:
2457                 service->apn = g_key_file_get_string(keyfile,
2458                                         service->identifier, "APN", NULL);
2459
2460                 service->username = g_key_file_get_string(keyfile,
2461                                         service->identifier, "Username", NULL);
2462
2463                 service->username = g_key_file_get_string(keyfile,
2464                                         service->identifier, "Password", NULL);
2465
2466                 service->favorite = g_key_file_get_boolean(keyfile,
2467                                 service->identifier, "Favorite", NULL);
2468
2469                 autoconnect = g_key_file_get_boolean(keyfile,
2470                                 service->identifier, "AutoConnect", &error);
2471                 if (error == NULL)
2472                         service->autoconnect = autoconnect;
2473                 g_clear_error(&error);
2474
2475                 str = g_key_file_get_string(keyfile,
2476                                 service->identifier, "Failure", NULL);
2477                 if (str != NULL) {
2478                         service->state = CONNMAN_SERVICE_STATE_FAILURE;
2479                         service->error = string2error(str);
2480                 }
2481                 break;
2482         }
2483
2484         str = g_key_file_get_string(keyfile,
2485                                 service->identifier, "Modified", NULL);
2486         if (str != NULL) {
2487                 g_time_val_from_iso8601(str, &service->modified);
2488                 g_free(str);
2489         }
2490
2491         str = g_key_file_get_string(keyfile,
2492                                 service->identifier, "Passphrase", NULL);
2493         if (str != NULL) {
2494                 g_free(service->passphrase);
2495                 service->passphrase = str;
2496         }
2497
2498         if (service->ipconfig != NULL)
2499                 __connman_ipconfig_load(service->ipconfig, keyfile,
2500                                         service->identifier, "IPv4.");
2501
2502 done:
2503         g_key_file_free(keyfile);
2504
2505         return err;
2506 }
2507
2508 static int service_save(struct connman_service *service)
2509 {
2510         const char *ident = service->profile;
2511         GKeyFile *keyfile;
2512         gchar *pathname, *data = NULL;
2513         gsize length;
2514         gchar *str;
2515         int err = 0;
2516
2517         DBG("service %p", service);
2518
2519         if (ident == NULL)
2520                 return -EINVAL;
2521
2522         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2523         if (pathname == NULL)
2524                 return -ENOMEM;
2525
2526         keyfile = g_key_file_new();
2527
2528         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
2529                 goto update;
2530
2531         if (length > 0) {
2532                 if (g_key_file_load_from_data(keyfile, data, length,
2533                                                         0, NULL) == FALSE)
2534                         goto done;
2535         }
2536
2537         g_free(data);
2538
2539 update:
2540         if (service->name != NULL)
2541                 g_key_file_set_string(keyfile, service->identifier,
2542                                                 "Name", service->name);
2543
2544         switch (service->type) {
2545         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2546         case CONNMAN_SERVICE_TYPE_SYSTEM:
2547         case CONNMAN_SERVICE_TYPE_ETHERNET:
2548         case CONNMAN_SERVICE_TYPE_VPN:
2549                 break;
2550         case CONNMAN_SERVICE_TYPE_WIFI:
2551                 if (service->network) {
2552                         const unsigned char *ssid;
2553                         unsigned int ssid_len = 0;
2554
2555                         ssid = connman_network_get_blob(service->network,
2556                                                         "WiFi.SSID", &ssid_len);
2557
2558                         if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
2559                                 char *identifier = service->identifier;
2560                                 GString *str;
2561                                 unsigned int i;
2562
2563                                 str = g_string_sized_new(ssid_len * 2);
2564                                 if (str == NULL) {
2565                                         err = -ENOMEM;
2566                                         goto done;
2567                                 }
2568
2569                                 for (i = 0; i < ssid_len; i++)
2570                                         g_string_append_printf(str,
2571                                                         "%02x", ssid[i]);
2572
2573                                 g_key_file_set_string(keyfile, identifier,
2574                                                         "SSID", str->str);
2575
2576                                 g_string_free(str, TRUE);
2577                         }
2578                 }
2579                 /* fall through */
2580
2581         case CONNMAN_SERVICE_TYPE_WIMAX:
2582         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2583         case CONNMAN_SERVICE_TYPE_CELLULAR:
2584                 if (service->apn != NULL)
2585                         g_key_file_set_string(keyfile, service->identifier,
2586                                                         "APN", service->apn);
2587
2588                 if (service->username != NULL)
2589                         g_key_file_set_string(keyfile, service->identifier,
2590                                                 "Username", service->username);
2591
2592                 if (service->password != NULL)
2593                         g_key_file_set_string(keyfile, service->identifier,
2594                                                 "Password", service->password);
2595
2596                 g_key_file_set_boolean(keyfile, service->identifier,
2597                                         "Favorite", service->favorite);
2598
2599                 if (service->favorite == TRUE)
2600                         g_key_file_set_boolean(keyfile, service->identifier,
2601                                         "AutoConnect", service->autoconnect);
2602
2603                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
2604                         const char *failure = error2string(service->error);
2605                         if (failure != NULL)
2606                                 g_key_file_set_string(keyfile,
2607                                                         service->identifier,
2608                                                         "Failure", failure);
2609                 } else {
2610                         g_key_file_remove_key(keyfile, service->identifier,
2611                                                         "Failure", NULL);
2612                 }
2613                 break;
2614         }
2615
2616         str = g_time_val_to_iso8601(&service->modified);
2617         if (str != NULL) {
2618                 g_key_file_set_string(keyfile, service->identifier,
2619                                                         "Modified", str);
2620                 g_free(str);
2621         }
2622
2623         if (service->passphrase != NULL && strlen(service->passphrase) > 0)
2624                 g_key_file_set_string(keyfile, service->identifier,
2625                                         "Passphrase", service->passphrase);
2626         else
2627                 g_key_file_remove_key(keyfile, service->identifier,
2628                                                         "Passphrase", NULL);
2629
2630         if (service->ipconfig != NULL)
2631                 __connman_ipconfig_save(service->ipconfig, keyfile,
2632                                         service->identifier, "IPv4.");
2633
2634         data = g_key_file_to_data(keyfile, &length, NULL);
2635
2636         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
2637                 connman_error("Failed to store service information");
2638
2639 done:
2640         g_free(data);
2641
2642         g_key_file_free(keyfile);
2643
2644         g_free(pathname);
2645
2646         return err;
2647 }
2648
2649 static struct connman_storage service_storage = {
2650         .name           = "service",
2651         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
2652         .service_load   = service_load,
2653         .service_save   = service_save,
2654 };
2655
2656 int __connman_service_init(void)
2657 {
2658         DBG("");
2659
2660         connection = connman_dbus_get_connection();
2661
2662         if (connman_storage_register(&service_storage) < 0)
2663                 connman_error("Failed to register service storage");
2664
2665         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2666                                                                 NULL, NULL);
2667
2668         service_list = g_sequence_new(service_free);
2669
2670         return 0;
2671 }
2672
2673 void __connman_service_cleanup(void)
2674 {
2675         DBG("");
2676
2677         g_sequence_free(service_list);
2678         service_list = NULL;
2679
2680         g_hash_table_destroy(service_hash);
2681         service_hash = NULL;
2682
2683         connman_storage_unregister(&service_storage);
2684
2685         dbus_connection_unref(connection);
2686 }