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