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