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