a941f44d59bff81f67061e8677f201e5726a3366
[framework/connectivity/connman.git] / src / service.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 int __connman_service_connect(struct connman_service *service)
1634 {
1635         int err;
1636
1637         DBG("service %p", service);
1638
1639         if (service->state == CONNMAN_SERVICE_STATE_READY)
1640                 return -EISCONN;
1641
1642         if (is_connecting(service) == TRUE)
1643                 return -EALREADY;
1644
1645         switch (service->type) {
1646         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1647         case CONNMAN_SERVICE_TYPE_SYSTEM:
1648         case CONNMAN_SERVICE_TYPE_VPN:
1649                 return -EINVAL;
1650         case CONNMAN_SERVICE_TYPE_ETHERNET:
1651         case CONNMAN_SERVICE_TYPE_WIMAX:
1652         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1653                 break;
1654         case CONNMAN_SERVICE_TYPE_CELLULAR:
1655                 if (service->apn == NULL)
1656                         return -EINVAL;
1657                 break;
1658         case CONNMAN_SERVICE_TYPE_WIFI:
1659                 switch (service->security) {
1660                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
1661                 case CONNMAN_SERVICE_SECURITY_NONE:
1662                         break;
1663                 case CONNMAN_SERVICE_SECURITY_WEP:
1664                 case CONNMAN_SERVICE_SECURITY_PSK:
1665                 case CONNMAN_SERVICE_SECURITY_WPA:
1666                 case CONNMAN_SERVICE_SECURITY_RSN:
1667                 case CONNMAN_SERVICE_SECURITY_8021X:
1668                         if (service->passphrase == NULL)
1669                                 return -ENOKEY;
1670                         break;
1671                 }
1672                 break;
1673         }
1674
1675         if (service->network != NULL) {
1676                 if (prepare_network(service) == FALSE)
1677                         return -EINVAL;
1678
1679                 switch (service->security) {
1680                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
1681                 case CONNMAN_SERVICE_SECURITY_NONE:
1682                 case CONNMAN_SERVICE_SECURITY_WEP:
1683                 case CONNMAN_SERVICE_SECURITY_PSK:
1684                 case CONNMAN_SERVICE_SECURITY_WPA:
1685                 case CONNMAN_SERVICE_SECURITY_RSN:
1686                         break;
1687                 case CONNMAN_SERVICE_SECURITY_8021X:
1688                         prepare_8021x(service);
1689                         break;
1690                 }
1691
1692                 __connman_ipconfig_enable(service->ipconfig);
1693
1694                 err = __connman_network_connect(service->network);
1695         } else
1696                 return -EOPNOTSUPP;
1697
1698         if (err < 0) {
1699                 if (err != -EINPROGRESS) {
1700                         __connman_ipconfig_disable(service->ipconfig);
1701                         return err;
1702                 }
1703
1704                 service->timeout = g_timeout_add_seconds(CONNECT_TIMEOUT,
1705                                                 connect_timeout, service);
1706
1707                 return -EINPROGRESS;
1708         }
1709
1710         return 0;
1711 }
1712
1713 int __connman_service_disconnect(struct connman_service *service)
1714 {
1715         int err;
1716
1717         DBG("service %p", service);
1718
1719         if (service->network != NULL) {
1720                 err = __connman_network_disconnect(service->network);
1721         } else
1722                 return -EOPNOTSUPP;
1723
1724         __connman_ipconfig_disable(service->ipconfig);
1725
1726         if (err < 0) {
1727                 if (err != -EINPROGRESS)
1728                         return err;
1729
1730                 return -EINPROGRESS;
1731         }
1732
1733         return 0;
1734 }
1735
1736 /**
1737  * __connman_service_lookup:
1738  * @identifier: service identifier
1739  *
1740  * Look up a service by identifier (reference count will not be increased)
1741  */
1742 static struct connman_service *__connman_service_lookup(const char *identifier)
1743 {
1744         GSequenceIter *iter;
1745
1746         iter = g_hash_table_lookup(service_hash, identifier);
1747         if (iter != NULL)
1748                 return g_sequence_get(iter);
1749
1750         return NULL;
1751 }
1752
1753 static struct connman_network *create_hidden_wifi(struct connman_device *device,
1754                 const char *ssid, const char *mode, const char *security)
1755 {
1756         struct connman_network *network;
1757         char *name;
1758         int index;
1759         unsigned int i, ssid_len;
1760
1761         ssid_len = strlen(ssid);
1762         if (ssid_len < 1)
1763                 return NULL;
1764
1765         network = connman_network_create(NULL, CONNMAN_NETWORK_TYPE_WIFI);
1766         if (network == NULL)
1767                 return NULL;
1768
1769         connman_network_set_blob(network, "WiFi.SSID",
1770                                         (unsigned char *) ssid, ssid_len);
1771
1772         connman_network_set_string(network, "WiFi.Mode", mode);
1773         connman_network_set_string(network, "WiFi.Security", security);
1774
1775         name = g_try_malloc0(ssid_len + 1);
1776         if (name == NULL) {
1777                 connman_network_unref(network);
1778                 return NULL;
1779         }
1780
1781         for (i = 0; i < ssid_len; i++) {
1782                 if (g_ascii_isprint(ssid[i]))
1783                         name[i] = ssid[i];
1784                 else
1785                         name[i] = ' ';
1786         }
1787
1788         connman_network_set_name(network, name);
1789
1790         g_free(name);
1791
1792         index = connman_device_get_index(device);
1793         connman_network_set_index(network, index);
1794
1795         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
1796
1797         if (connman_device_add_network(device, network) < 0) {
1798                 connman_network_unref(network);
1799                 return NULL;
1800         }
1801
1802         connman_network_set_available(network, TRUE);
1803
1804         return network;
1805 }
1806
1807 int __connman_service_create_and_connect(DBusMessage *msg)
1808 {
1809         struct connman_service *service;
1810         struct connman_network *network;
1811         struct connman_device *device;
1812         DBusMessageIter iter, array;
1813         const char *mode = "managed", *security = "none";
1814         const char *type = NULL, *ssid = NULL, *passphrase = NULL;
1815         unsigned int ssid_len = 0;
1816         const char *ident;
1817         char *name, *group;
1818         gboolean created = FALSE;
1819         int err;
1820
1821         dbus_message_iter_init(msg, &iter);
1822         dbus_message_iter_recurse(&iter, &array);
1823
1824         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1825                 DBusMessageIter entry, value;
1826                 const char *key;
1827
1828                 dbus_message_iter_recurse(&array, &entry);
1829                 dbus_message_iter_get_basic(&entry, &key);
1830
1831                 dbus_message_iter_next(&entry);
1832                 dbus_message_iter_recurse(&entry, &value);
1833
1834                 switch (dbus_message_iter_get_arg_type(&value)) {
1835                 case DBUS_TYPE_STRING:
1836                         if (g_str_equal(key, "Type") == TRUE)
1837                                 dbus_message_iter_get_basic(&value, &type);
1838                         else if (g_str_equal(key, "WiFi.Mode") == TRUE ||
1839                                         g_str_equal(key, "Mode") == TRUE)
1840                                 dbus_message_iter_get_basic(&value, &mode);
1841                         else if (g_str_equal(key, "WiFi.Security") == TRUE ||
1842                                         g_str_equal(key, "Security") == TRUE)
1843                                 dbus_message_iter_get_basic(&value, &security);
1844                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE ||
1845                                         g_str_equal(key, "Passphrase") == TRUE)
1846                                 dbus_message_iter_get_basic(&value, &passphrase);
1847                         else if (g_str_equal(key, "WiFi.SSID") == TRUE ||
1848                                         g_str_equal(key, "SSID") == TRUE)
1849                                 dbus_message_iter_get_basic(&value, &ssid);
1850                 }
1851
1852                 dbus_message_iter_next(&array);
1853         }
1854
1855         if (type == NULL)
1856                 return -EINVAL;
1857
1858         if (g_strcmp0(type, "wifi") != 0 || g_strcmp0(mode, "managed") != 0)
1859                 return -EOPNOTSUPP;
1860
1861         if (ssid == NULL)
1862                 return -EINVAL;
1863
1864         ssid_len = strlen(ssid);
1865         if (ssid_len < 1)
1866                 return -EINVAL;
1867
1868         if (g_strcmp0(security, "none") != 0 &&
1869                                 g_strcmp0(security, "wep") != 0 &&
1870                                 g_strcmp0(security, "psk") != 0 &&
1871                                 g_strcmp0(security, "wpa") != 0 &&
1872                                 g_strcmp0(security, "rsn") != 0 &&
1873                                 g_strcmp0(security, "ieee8021x") != 0)
1874                 return -EINVAL;
1875
1876         device = __connman_element_find_device(CONNMAN_DEVICE_TYPE_WIFI);
1877         if (device == NULL)
1878                 return -EOPNOTSUPP;
1879
1880         ident = __connman_device_get_ident(device);
1881         if (ident == NULL)
1882                 return -EOPNOTSUPP;
1883
1884         group = connman_wifi_build_group_name((unsigned char *) ssid,
1885                                                 ssid_len, mode, security);
1886         if (group == NULL)
1887                 return -EINVAL;
1888
1889         name = g_strdup_printf("%s_%s_%s", type, ident, group);
1890
1891         service = __connman_service_lookup(name);
1892
1893         if (service != NULL)
1894                 goto done;
1895
1896         network = create_hidden_wifi(device, ssid, mode, security);
1897         if (network != NULL) {
1898                 connman_network_set_group(network, group);
1899                 created = TRUE;
1900         }
1901
1902         service = __connman_service_lookup(name);
1903
1904 done:
1905         g_free(name);
1906         g_free(group);
1907
1908         if (service == NULL) {
1909                 err = -EOPNOTSUPP;
1910                 goto failed;
1911         }
1912
1913         set_reconnect_state(service, FALSE);
1914
1915         __connman_device_disconnect(device);
1916
1917         if (passphrase != NULL) {
1918                 g_free(service->passphrase);
1919                 service->passphrase = g_strdup(passphrase);
1920         }
1921
1922         service->userconnect = TRUE;
1923
1924         err = __connman_service_connect(service);
1925         if (err < 0 && err != -EINPROGRESS)
1926                 goto failed;
1927
1928         g_dbus_send_reply(connection, msg,
1929                                 DBUS_TYPE_OBJECT_PATH, &service->path,
1930                                                         DBUS_TYPE_INVALID);
1931
1932         return 0;
1933
1934 failed:
1935         if (service != NULL && created == TRUE) {
1936                 struct connman_network *network = service->network;
1937
1938                 if (network != NULL) {
1939                         connman_network_set_available(network, FALSE);
1940                         __connman_device_cleanup_networks(device);
1941                 }
1942
1943                 __connman_service_put(service);
1944         }
1945
1946         return err;
1947 }
1948
1949 /**
1950  * __connman_service_get:
1951  * @identifier: service identifier
1952  *
1953  * Look up a service by identifier or create a new one if not found
1954  */
1955 static struct connman_service *__connman_service_get(const char *identifier)
1956 {
1957         struct connman_service *service;
1958         GSequenceIter *iter;
1959
1960         iter = g_hash_table_lookup(service_hash, identifier);
1961         if (iter != NULL) {
1962                 service = g_sequence_get(iter);
1963                 if (service != NULL)
1964                         g_atomic_int_inc(&service->refcount);
1965                 return service;
1966         }
1967
1968         service = connman_service_create();
1969         if (service == NULL)
1970                 return NULL;
1971
1972         DBG("service %p", service);
1973
1974         service->identifier = g_strdup(identifier);
1975
1976         service->profile = g_strdup(__connman_profile_active_ident());
1977
1978         iter = g_sequence_insert_sorted(service_list, service,
1979                                                 service_compare, NULL);
1980
1981         g_hash_table_insert(service_hash, service->identifier, iter);
1982
1983         return service;
1984 }
1985
1986 static int service_register(struct connman_service *service)
1987 {
1988         const char *path = __connman_profile_active_path();
1989         GSequenceIter *iter;
1990
1991         DBG("service %p", service);
1992
1993         if (service->path != NULL)
1994                 return -EALREADY;
1995
1996         service->path = g_strdup_printf("%s/%s", path, service->identifier);
1997
1998         DBG("path %s", service->path);
1999
2000         __connman_config_provision_service(service);
2001
2002         __connman_storage_load_service(service);
2003
2004         g_dbus_register_interface(connection, service->path,
2005                                         CONNMAN_SERVICE_INTERFACE,
2006                                         service_methods, service_signals,
2007                                                         NULL, service, NULL);
2008
2009         iter = g_hash_table_lookup(service_hash, service->identifier);
2010         if (iter != NULL)
2011                 g_sequence_sort_changed(iter, service_compare, NULL);
2012
2013         __connman_profile_changed(TRUE);
2014
2015         return 0;
2016 }
2017
2018 static void service_up(struct connman_ipconfig *ipconfig)
2019 {
2020         connman_info("%s up", connman_ipconfig_get_ifname(ipconfig));
2021 }
2022
2023 static void service_down(struct connman_ipconfig *ipconfig)
2024 {
2025         connman_info("%s down", connman_ipconfig_get_ifname(ipconfig));
2026 }
2027
2028 static void service_lower_up(struct connman_ipconfig *ipconfig)
2029 {
2030         connman_info("%s lower up", connman_ipconfig_get_ifname(ipconfig));
2031 }
2032
2033 static void service_lower_down(struct connman_ipconfig *ipconfig)
2034 {
2035         connman_info("%s lower down", connman_ipconfig_get_ifname(ipconfig));
2036 }
2037
2038 static void service_ip_bound(struct connman_ipconfig *ipconfig)
2039 {
2040         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
2041
2042         connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig));
2043
2044         settings_changed(service);
2045 }
2046
2047 static void service_ip_release(struct connman_ipconfig *ipconfig)
2048 {
2049         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
2050
2051         connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig));
2052
2053         settings_changed(service);
2054 }
2055
2056 static const struct connman_ipconfig_ops service_ops = {
2057         .up             = service_up,
2058         .down           = service_down,
2059         .lower_up       = service_lower_up,
2060         .lower_down     = service_lower_down,
2061         .ip_bound       = service_ip_bound,
2062         .ip_release     = service_ip_release,
2063 };
2064
2065 static void setup_ipconfig(struct connman_service *service, int index)
2066 {
2067         if (index < 0)
2068                 return;
2069
2070         service->ipconfig = connman_ipconfig_create(index);
2071         if (service->ipconfig == NULL)
2072                 return;
2073
2074         connman_ipconfig_set_method(service->ipconfig,
2075                                         CONNMAN_IPCONFIG_METHOD_DHCP);
2076
2077         connman_ipconfig_set_data(service->ipconfig, service);
2078
2079         connman_ipconfig_set_ops(service->ipconfig, &service_ops);
2080 }
2081
2082 /**
2083  * __connman_service_lookup_from_network:
2084  * @network: network structure
2085  *
2086  * Look up a service by network (reference count will not be increased)
2087  */
2088 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
2089 {
2090         struct connman_service *service;
2091         const char *ident, *group;
2092         char *name;
2093
2094         DBG("network %p", network);
2095
2096         ident = __connman_network_get_ident(network);
2097         if (ident == NULL)
2098                 return NULL;
2099
2100         group = connman_network_get_group(network);
2101         if (group == NULL)
2102                 return NULL;
2103
2104         name = g_strdup_printf("%s_%s_%s",
2105                         __connman_network_get_type(network), ident, group);
2106         service = __connman_service_lookup(name);
2107         g_free(name);
2108
2109         return service;
2110 }
2111
2112 const char *__connman_service_get_path(struct connman_service *service)
2113 {
2114         return service->path;
2115 }
2116
2117 unsigned int __connman_service_get_order(struct connman_service *service)
2118 {
2119         GSequenceIter *iter;
2120
2121         if (service == NULL)
2122                 return 0;
2123
2124         if (service->favorite == FALSE) {
2125                 service->order = 0;
2126                 goto done;
2127         }
2128
2129         iter = g_hash_table_lookup(service_hash, service->identifier);
2130         if (iter != NULL) {
2131                 if (g_sequence_iter_get_position(iter) == 0)
2132                         service->order = 1;
2133                 else
2134                         service->order = 0;
2135         }
2136
2137 done:
2138         return service->order;
2139 }
2140
2141 static enum connman_service_type convert_network_type(struct connman_network *network)
2142 {
2143         enum connman_network_type type = connman_network_get_type(network);
2144
2145         switch (type) {
2146         case CONNMAN_NETWORK_TYPE_UNKNOWN:
2147         case CONNMAN_NETWORK_TYPE_VENDOR:
2148                 break;
2149         case CONNMAN_NETWORK_TYPE_ETHERNET:
2150                 return CONNMAN_SERVICE_TYPE_ETHERNET;
2151         case CONNMAN_NETWORK_TYPE_WIFI:
2152                 return CONNMAN_SERVICE_TYPE_WIFI;
2153         case CONNMAN_NETWORK_TYPE_WIMAX:
2154                 return CONNMAN_SERVICE_TYPE_WIMAX;
2155         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
2156         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
2157                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
2158         case CONNMAN_NETWORK_TYPE_CELLULAR:
2159         case CONNMAN_NETWORK_TYPE_MBM:
2160         case CONNMAN_NETWORK_TYPE_HSO:
2161                 return CONNMAN_SERVICE_TYPE_CELLULAR;
2162         }
2163
2164         return CONNMAN_SERVICE_TYPE_UNKNOWN;
2165 }
2166
2167 static enum connman_service_mode convert_wifi_mode(const char *mode)
2168 {
2169         if (mode == NULL)
2170                 return CONNMAN_SERVICE_MODE_UNKNOWN;
2171         else if (g_str_equal(mode, "managed") == TRUE)
2172                 return CONNMAN_SERVICE_MODE_MANAGED;
2173         else if (g_str_equal(mode, "adhoc") == TRUE)
2174                 return CONNMAN_SERVICE_MODE_ADHOC;
2175         else
2176                 return CONNMAN_SERVICE_MODE_UNKNOWN;
2177 }
2178
2179 static enum connman_service_security convert_wifi_security(const char *security)
2180 {
2181         if (security == NULL)
2182                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
2183         else if (g_str_equal(security, "none") == TRUE)
2184                 return CONNMAN_SERVICE_SECURITY_NONE;
2185         else if (g_str_equal(security, "wep") == TRUE)
2186                 return CONNMAN_SERVICE_SECURITY_WEP;
2187         else if (g_str_equal(security, "wep") == TRUE)
2188                 return CONNMAN_SERVICE_SECURITY_PSK;
2189         else if (g_str_equal(security, "ieee8021x") == TRUE)
2190                 return CONNMAN_SERVICE_SECURITY_8021X;
2191         else if (g_str_equal(security, "wpa") == TRUE)
2192                 return CONNMAN_SERVICE_SECURITY_WPA;
2193         else if (g_str_equal(security, "rsn") == TRUE)
2194                 return CONNMAN_SERVICE_SECURITY_RSN;
2195         else
2196                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
2197 }
2198
2199 static enum connman_service_mode convert_cellular_mode(connman_uint8_t mode)
2200 {
2201         switch (mode) {
2202         case 0:
2203         case 1:
2204                 return CONNMAN_SERVICE_MODE_GPRS;
2205         case 3:
2206                 return CONNMAN_SERVICE_MODE_EDGE;
2207         case 2:
2208         case 4:
2209         case 5:
2210         case 6:
2211                 return CONNMAN_SERVICE_MODE_UMTS;
2212         }
2213
2214         return CONNMAN_SERVICE_MODE_UNKNOWN;
2215 }
2216
2217 static void update_from_network(struct connman_service *service,
2218                                         struct connman_network *network)
2219 {
2220         connman_uint8_t strength = service->strength;
2221         GSequenceIter *iter;
2222         const char *str;
2223
2224         DBG("service %p network %p", service, network);
2225
2226         if (service->state == CONNMAN_SERVICE_STATE_READY)
2227                 return;
2228
2229         if (is_connecting(service) == TRUE)
2230                 return;
2231
2232         str = connman_network_get_string(network, "Name");
2233         if (str != NULL) {
2234                 g_free(service->name);
2235                 service->name = g_strdup(str);
2236                 service->hidden = FALSE;
2237         } else {
2238                 g_free(service->name);
2239                 service->name = NULL;
2240                 service->hidden = TRUE;
2241         }
2242
2243         service->strength = connman_network_get_uint8(network, "Strength");
2244         service->roaming = connman_network_get_bool(network, "Roaming");
2245
2246         if (service->strength == 0) {
2247                 /*
2248                  * Filter out 0-values; it's unclear what they mean
2249                  * and they cause anomalous sorting of the priority list.
2250                  */
2251                 service->strength = strength;
2252         }
2253
2254         str = connman_network_get_string(network, "WiFi.Mode");
2255         service->mode = convert_wifi_mode(str);
2256
2257         str = connman_network_get_string(network, "WiFi.Security");
2258         service->security = convert_wifi_security(str);
2259
2260         str = connman_network_get_string(network, "Cellular.MCC");
2261         g_free(service->mcc);
2262         service->mcc = g_strdup(str);
2263
2264         str = connman_network_get_string(network, "Cellular.MNC");
2265         g_free(service->mnc);
2266         service->mnc = g_strdup(str);
2267
2268         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
2269                 connman_uint8_t value = connman_network_get_uint8(network,
2270                                                         "Cellular.Mode");
2271
2272                 service->mode = convert_cellular_mode(value);
2273         }
2274
2275         if (service->strength > strength && service->network != NULL) {
2276                 connman_network_unref(service->network);
2277                 service->network = connman_network_ref(network);
2278
2279                 strength_changed(service);
2280         }
2281
2282         if (service->network == NULL)
2283                 service->network = connman_network_ref(network);
2284
2285         iter = g_hash_table_lookup(service_hash, service->identifier);
2286         if (iter != NULL)
2287                 g_sequence_sort_changed(iter, service_compare, NULL);
2288 }
2289
2290 /**
2291  * __connman_service_create_from_network:
2292  * @network: network structure
2293  *
2294  * Look up service by network and if not found, create one
2295  */
2296 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
2297 {
2298         struct connman_service *service;
2299         const char *ident, *group;
2300         char *name;
2301
2302         DBG("network %p", network);
2303
2304         ident = __connman_network_get_ident(network);
2305         if (ident == NULL)
2306                 return NULL;
2307
2308         group = connman_network_get_group(network);
2309         if (group == NULL)
2310                 return NULL;
2311
2312         name = g_strdup_printf("%s_%s_%s",
2313                         __connman_network_get_type(network), ident, group);
2314         service = __connman_service_get(name);
2315         g_free(name);
2316
2317         if (service == NULL)
2318                 return NULL;
2319
2320         if (__connman_network_get_weakness(network) == TRUE)
2321                 return service;
2322
2323         if (service->path != NULL) {
2324                 update_from_network(service, network);
2325                 __connman_profile_changed(TRUE);
2326                 return service;
2327         }
2328
2329         service->type = convert_network_type(network);
2330
2331         switch (service->type) {
2332         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2333         case CONNMAN_SERVICE_TYPE_SYSTEM:
2334         case CONNMAN_SERVICE_TYPE_ETHERNET:
2335         case CONNMAN_SERVICE_TYPE_WIMAX:
2336         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2337         case CONNMAN_SERVICE_TYPE_VPN:
2338                 service->autoconnect = FALSE;
2339                 break;
2340         case CONNMAN_SERVICE_TYPE_WIFI:
2341         case CONNMAN_SERVICE_TYPE_CELLULAR:
2342                 service->autoconnect = TRUE;
2343                 break;
2344         }
2345
2346         service->state = CONNMAN_SERVICE_STATE_IDLE;
2347
2348         update_from_network(service, network);
2349
2350         setup_ipconfig(service, connman_network_get_index(network));
2351
2352         service_register(service);
2353
2354         if (service->favorite == TRUE)
2355                 __connman_service_auto_connect();
2356
2357         return service;
2358 }
2359
2360 void __connman_service_update_from_network(struct connman_network *network)
2361 {
2362         struct connman_service *service;
2363         enum connman_service_mode mode;
2364         connman_uint8_t strength, value;
2365         connman_bool_t roaming;
2366         GSequenceIter *iter;
2367
2368         DBG("network %p", network);
2369
2370         service = __connman_service_lookup_from_network(network);
2371         if (service == NULL)
2372                 return;
2373
2374         if (service->network == NULL)
2375                 return;
2376
2377         strength = connman_network_get_uint8(service->network, "Strength");
2378         if (strength == service->strength)
2379                 goto roaming;
2380
2381         service->strength = strength;
2382
2383         strength_changed(service);
2384
2385 roaming:
2386         roaming = connman_network_get_bool(service->network, "Roaming");
2387         if (roaming == service->roaming)
2388                 goto done;
2389
2390         service->roaming = roaming;
2391
2392         roaming_changed(service);
2393
2394         iter = g_hash_table_lookup(service_hash, service->identifier);
2395         if (iter != NULL)
2396                 g_sequence_sort_changed(iter, service_compare, NULL);
2397
2398 done:
2399         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
2400                 return;
2401
2402         value = connman_network_get_uint8(service->network, "Cellular.Mode");
2403         mode = convert_cellular_mode(value);
2404
2405         if (mode == service->mode)
2406                 return;
2407
2408         service->mode = mode;
2409
2410         mode_changed(service);
2411 }
2412
2413 void __connman_service_remove_from_network(struct connman_network *network)
2414 {
2415         struct connman_service *service;
2416
2417         DBG("network %p", network);
2418
2419         service = __connman_service_lookup_from_network(network);
2420         if (service == NULL)
2421                 return;
2422
2423         __connman_service_put(service);
2424 }
2425
2426 static int service_load(struct connman_service *service)
2427 {
2428         const char *ident = service->profile;
2429         GKeyFile *keyfile;
2430         GError *error = NULL;
2431         gchar *pathname, *data = NULL;
2432         gsize length;
2433         gchar *str;
2434         connman_bool_t autoconnect;
2435         unsigned int ssid_len;
2436         int err = 0;
2437
2438         DBG("service %p", service);
2439
2440         if (ident == NULL)
2441                 return -EINVAL;
2442
2443         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2444         if (pathname == NULL)
2445                 return -ENOMEM;
2446
2447         keyfile = g_key_file_new();
2448
2449         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
2450                 g_free(pathname);
2451                 return -ENOENT;
2452         }
2453
2454         g_free(pathname);
2455
2456         if (g_key_file_load_from_data(keyfile, data, length,
2457                                                         0, NULL) == FALSE) {
2458                 g_free(data);
2459                 return -EILSEQ;
2460         }
2461
2462         g_free(data);
2463
2464         switch (service->type) {
2465         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2466         case CONNMAN_SERVICE_TYPE_SYSTEM:
2467         case CONNMAN_SERVICE_TYPE_ETHERNET:
2468         case CONNMAN_SERVICE_TYPE_VPN:
2469                 break;
2470         case CONNMAN_SERVICE_TYPE_WIFI:
2471                 if (service->name == NULL) {
2472                         gchar *name;
2473
2474                         name = g_key_file_get_string(keyfile,
2475                                         service->identifier, "Name", NULL);
2476                         if (name != NULL) {
2477                                 g_free(service->name);
2478                                 service->name = name;
2479                         }
2480
2481                         if (service->network != NULL)
2482                                 connman_network_set_name(service->network,
2483                                                                         name);
2484                 }
2485
2486                 if (service->network &&
2487                                 connman_network_get_blob(service->network,
2488                                         "WiFi.SSID", &ssid_len) == NULL) {
2489                         gchar *hex_ssid;
2490
2491                         hex_ssid = g_key_file_get_string(keyfile,
2492                                                         service->identifier,
2493                                                                 "SSID", NULL);
2494
2495                         if (hex_ssid != NULL) {
2496                                 gchar *ssid;
2497                                 unsigned int i, j = 0, hex;
2498                                 size_t hex_ssid_len = strlen(hex_ssid);
2499
2500                                 ssid = g_try_malloc0(hex_ssid_len / 2);
2501                                 if (ssid == NULL) {
2502                                         g_free(hex_ssid);
2503                                         err = -ENOMEM;
2504                                         goto done;
2505                                 }
2506
2507                                 for (i = 0; i < hex_ssid_len; i += 2) {
2508                                         sscanf(hex_ssid + i, "%02x", &hex);
2509                                         ssid[j++] = hex;
2510                                 }
2511
2512                                 connman_network_set_blob(service->network,
2513                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
2514                         }
2515
2516                         g_free(hex_ssid);
2517                 }
2518                 /* fall through */
2519
2520         case CONNMAN_SERVICE_TYPE_WIMAX:
2521         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2522         case CONNMAN_SERVICE_TYPE_CELLULAR:
2523                 service->apn = g_key_file_get_string(keyfile,
2524                                         service->identifier, "APN", NULL);
2525
2526                 service->username = g_key_file_get_string(keyfile,
2527                                         service->identifier, "Username", NULL);
2528
2529                 service->username = g_key_file_get_string(keyfile,
2530                                         service->identifier, "Password", NULL);
2531
2532                 service->favorite = g_key_file_get_boolean(keyfile,
2533                                 service->identifier, "Favorite", NULL);
2534
2535                 autoconnect = g_key_file_get_boolean(keyfile,
2536                                 service->identifier, "AutoConnect", &error);
2537                 if (error == NULL)
2538                         service->autoconnect = autoconnect;
2539                 g_clear_error(&error);
2540
2541                 str = g_key_file_get_string(keyfile,
2542                                 service->identifier, "Failure", NULL);
2543                 if (str != NULL) {
2544                         service->state = CONNMAN_SERVICE_STATE_FAILURE;
2545                         service->error = string2error(str);
2546                 }
2547                 break;
2548         }
2549
2550         str = g_key_file_get_string(keyfile,
2551                                 service->identifier, "Modified", NULL);
2552         if (str != NULL) {
2553                 g_time_val_from_iso8601(str, &service->modified);
2554                 g_free(str);
2555         }
2556
2557         str = g_key_file_get_string(keyfile,
2558                                 service->identifier, "Passphrase", NULL);
2559         if (str != NULL) {
2560                 g_free(service->passphrase);
2561                 service->passphrase = str;
2562         }
2563
2564         if (service->ipconfig != NULL)
2565                 __connman_ipconfig_load(service->ipconfig, keyfile,
2566                                         service->identifier, "IPv4.");
2567
2568 done:
2569         g_key_file_free(keyfile);
2570
2571         return err;
2572 }
2573
2574 static int service_save(struct connman_service *service)
2575 {
2576         const char *ident = service->profile;
2577         GKeyFile *keyfile;
2578         gchar *pathname, *data = NULL;
2579         gsize length;
2580         gchar *str;
2581         int err = 0;
2582
2583         DBG("service %p", service);
2584
2585         if (ident == NULL)
2586                 return -EINVAL;
2587
2588         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2589         if (pathname == NULL)
2590                 return -ENOMEM;
2591
2592         keyfile = g_key_file_new();
2593
2594         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
2595                 goto update;
2596
2597         if (length > 0) {
2598                 if (g_key_file_load_from_data(keyfile, data, length,
2599                                                         0, NULL) == FALSE)
2600                         goto done;
2601         }
2602
2603         g_free(data);
2604
2605 update:
2606         if (service->name != NULL)
2607                 g_key_file_set_string(keyfile, service->identifier,
2608                                                 "Name", service->name);
2609
2610         switch (service->type) {
2611         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2612         case CONNMAN_SERVICE_TYPE_SYSTEM:
2613         case CONNMAN_SERVICE_TYPE_ETHERNET:
2614         case CONNMAN_SERVICE_TYPE_VPN:
2615                 break;
2616         case CONNMAN_SERVICE_TYPE_WIFI:
2617                 if (service->network) {
2618                         const unsigned char *ssid;
2619                         unsigned int ssid_len = 0;
2620
2621                         ssid = connman_network_get_blob(service->network,
2622                                                         "WiFi.SSID", &ssid_len);
2623
2624                         if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
2625                                 char *identifier = service->identifier;
2626                                 GString *str;
2627                                 unsigned int i;
2628
2629                                 str = g_string_sized_new(ssid_len * 2);
2630                                 if (str == NULL) {
2631                                         err = -ENOMEM;
2632                                         goto done;
2633                                 }
2634
2635                                 for (i = 0; i < ssid_len; i++)
2636                                         g_string_append_printf(str,
2637                                                         "%02x", ssid[i]);
2638
2639                                 g_key_file_set_string(keyfile, identifier,
2640                                                         "SSID", str->str);
2641
2642                                 g_string_free(str, TRUE);
2643                         }
2644                 }
2645                 /* fall through */
2646
2647         case CONNMAN_SERVICE_TYPE_WIMAX:
2648         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2649         case CONNMAN_SERVICE_TYPE_CELLULAR:
2650                 if (service->apn != NULL)
2651                         g_key_file_set_string(keyfile, service->identifier,
2652                                                         "APN", service->apn);
2653
2654                 if (service->username != NULL)
2655                         g_key_file_set_string(keyfile, service->identifier,
2656                                                 "Username", service->username);
2657
2658                 if (service->password != NULL)
2659                         g_key_file_set_string(keyfile, service->identifier,
2660                                                 "Password", service->password);
2661
2662                 g_key_file_set_boolean(keyfile, service->identifier,
2663                                         "Favorite", service->favorite);
2664
2665                 if (service->favorite == TRUE)
2666                         g_key_file_set_boolean(keyfile, service->identifier,
2667                                         "AutoConnect", service->autoconnect);
2668
2669                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
2670                         const char *failure = error2string(service->error);
2671                         if (failure != NULL)
2672                                 g_key_file_set_string(keyfile,
2673                                                         service->identifier,
2674                                                         "Failure", failure);
2675                 } else {
2676                         g_key_file_remove_key(keyfile, service->identifier,
2677                                                         "Failure", NULL);
2678                 }
2679                 break;
2680         }
2681
2682         str = g_time_val_to_iso8601(&service->modified);
2683         if (str != NULL) {
2684                 g_key_file_set_string(keyfile, service->identifier,
2685                                                         "Modified", str);
2686                 g_free(str);
2687         }
2688
2689         if (service->passphrase != NULL && strlen(service->passphrase) > 0)
2690                 g_key_file_set_string(keyfile, service->identifier,
2691                                         "Passphrase", service->passphrase);
2692         else
2693                 g_key_file_remove_key(keyfile, service->identifier,
2694                                                         "Passphrase", NULL);
2695
2696         if (service->ipconfig != NULL)
2697                 __connman_ipconfig_save(service->ipconfig, keyfile,
2698                                         service->identifier, "IPv4.");
2699
2700         data = g_key_file_to_data(keyfile, &length, NULL);
2701
2702         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
2703                 connman_error("Failed to store service information");
2704
2705 done:
2706         g_free(data);
2707
2708         g_key_file_free(keyfile);
2709
2710         g_free(pathname);
2711
2712         return err;
2713 }
2714
2715 static struct connman_storage service_storage = {
2716         .name           = "service",
2717         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
2718         .service_load   = service_load,
2719         .service_save   = service_save,
2720 };
2721
2722 int __connman_service_init(void)
2723 {
2724         DBG("");
2725
2726         connection = connman_dbus_get_connection();
2727
2728         if (connman_storage_register(&service_storage) < 0)
2729                 connman_error("Failed to register service storage");
2730
2731         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2732                                                                 NULL, NULL);
2733
2734         service_list = g_sequence_new(service_free);
2735
2736         return 0;
2737 }
2738
2739 void __connman_service_cleanup(void)
2740 {
2741         DBG("");
2742
2743         g_sequence_free(service_list);
2744         service_list = NULL;
2745
2746         g_hash_table_destroy(service_hash);
2747         service_hash = NULL;
2748
2749         connman_storage_unregister(&service_storage);
2750
2751         dbus_connection_unref(connection);
2752 }