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