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