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