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