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