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