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