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