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