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