technology: Add object path to TechnologyAdded signal
[framework/connectivity/connman.git] / src / technology.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 <errno.h>
27 #include <string.h>
28
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection;
34
35 static GSList *technology_list = NULL;
36
37 static connman_bool_t global_offlinemode;
38
39 struct connman_rfkill {
40         unsigned int index;
41         enum connman_service_type type;
42         connman_bool_t softblock;
43         connman_bool_t hardblock;
44 };
45
46 enum connman_technology_state {
47         CONNMAN_TECHNOLOGY_STATE_UNKNOWN   = 0,
48         CONNMAN_TECHNOLOGY_STATE_OFFLINE   = 1,
49         CONNMAN_TECHNOLOGY_STATE_ENABLED   = 2,
50         CONNMAN_TECHNOLOGY_STATE_CONNECTED = 3,
51 };
52
53 struct connman_technology {
54         int refcount;
55         enum connman_service_type type;
56         enum connman_technology_state state;
57         char *path;
58         GHashTable *rfkill_list;
59         GSList *device_list;
60         int enabled;
61         char *regdom;
62
63         connman_bool_t tethering;
64         char *tethering_ident;
65         char *tethering_passphrase;
66
67         connman_bool_t enable_persistent; /* Save the tech state */
68
69         struct connman_technology_driver *driver;
70         void *driver_data;
71
72         DBusMessage *pending_reply;
73         guint pending_timeout;
74 };
75
76 static GSList *driver_list = NULL;
77
78 static gint compare_priority(gconstpointer a, gconstpointer b)
79 {
80         const struct connman_technology_driver *driver1 = a;
81         const struct connman_technology_driver *driver2 = b;
82
83         return driver2->priority - driver1->priority;
84 }
85
86 /**
87  * connman_technology_driver_register:
88  * @driver: Technology driver definition
89  *
90  * Register a new technology driver
91  *
92  * Returns: %0 on success
93  */
94 int connman_technology_driver_register(struct connman_technology_driver *driver)
95 {
96         DBG("Registering %s driver", driver->name);
97
98         driver_list = g_slist_insert_sorted(driver_list, driver,
99                                                         compare_priority);
100
101         return 0;
102 }
103
104 /**
105  * connman_technology_driver_unregister:
106  * @driver: Technology driver definition
107  *
108  * Remove a previously registered technology driver
109  */
110 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
111 {
112         GSList *list;
113         struct connman_technology *technology;
114
115         DBG("Unregistering driver %p name %s", driver, driver->name);
116
117         for (list = technology_list; list; list = list->next) {
118                 technology = list->data;
119
120                 if (technology->driver == NULL)
121                         continue;
122
123                 if (technology->type == driver->type) {
124                         technology->driver->remove(technology);
125                         technology->driver = NULL;
126                 }
127         }
128
129         driver_list = g_slist_remove(driver_list, driver);
130 }
131
132 static void tethering_changed(struct connman_technology *technology)
133 {
134         connman_bool_t tethering = technology->tethering;
135
136         connman_dbus_property_changed_basic(technology->path,
137                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
138                                                 DBUS_TYPE_BOOLEAN, &tethering);
139 }
140
141 void connman_technology_tethering_notify(struct connman_technology *technology,
142                                                         connman_bool_t enabled)
143 {
144         GSList *list;
145
146         DBG("technology %p enabled %u", technology, enabled);
147
148         if (technology->tethering == enabled)
149                 return;
150
151         technology->tethering = enabled;
152
153         tethering_changed(technology);
154
155         if (enabled == TRUE)
156                 __connman_tethering_set_enabled();
157         else {
158                 for (list = technology_list; list; list = list->next) {
159                         struct connman_technology *other_tech = list->data;
160                         if (other_tech->tethering == TRUE)
161                                 break;
162                 }
163                 if (list == NULL)
164                         __connman_tethering_set_disabled();
165         }
166 }
167
168 static int set_tethering(struct connman_technology *technology,
169                                 connman_bool_t enabled)
170 {
171         const char *ident, *passphrase, *bridge;
172
173         ident = technology->tethering_ident;
174         passphrase = technology->tethering_passphrase;
175
176         if (technology->driver == NULL ||
177                         technology->driver->set_tethering == NULL)
178                 return -EOPNOTSUPP;
179
180         bridge = __connman_tethering_get_bridge();
181         if (bridge == NULL)
182                 return -EOPNOTSUPP;
183
184         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
185             (ident == NULL || passphrase == NULL))
186                 return -EINVAL;
187
188         return technology->driver->set_tethering(technology, ident, passphrase,
189                                                         bridge, enabled);
190 }
191
192 void connman_technology_regdom_notify(struct connman_technology *technology,
193                                                         const char *alpha2)
194 {
195         DBG("");
196
197         if (alpha2 == NULL)
198                 connman_error("Failed to set regulatory domain");
199         else
200                 DBG("Regulatory domain set to %s", alpha2);
201
202         g_free(technology->regdom);
203         technology->regdom = g_strdup(alpha2);
204 }
205
206 int connman_technology_set_regdom(const char *alpha2)
207 {
208         GSList *list;
209
210         for (list = technology_list; list; list = list->next) {
211                 struct connman_technology *technology = list->data;
212
213                 if (technology->driver == NULL)
214                         continue;
215
216                 if (technology->driver->set_regdom)
217                         technology->driver->set_regdom(technology, alpha2);
218         }
219
220         return 0;
221 }
222
223 static void free_rfkill(gpointer data)
224 {
225         struct connman_rfkill *rfkill = data;
226
227         g_free(rfkill);
228 }
229
230 static const char *state2string(enum connman_technology_state state)
231 {
232         switch (state) {
233         case CONNMAN_TECHNOLOGY_STATE_UNKNOWN:
234                 break;
235         case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
236                 return "offline";
237         case CONNMAN_TECHNOLOGY_STATE_ENABLED:
238                 return "enabled";
239         case CONNMAN_TECHNOLOGY_STATE_CONNECTED:
240                 return "connected";
241         }
242
243         return NULL;
244 }
245
246 static void state_changed(struct connman_technology *technology)
247 {
248         const char *str;
249
250         str = state2string(technology->state);
251         if (str == NULL)
252                 return;
253
254         connman_dbus_property_changed_basic(technology->path,
255                                 CONNMAN_TECHNOLOGY_INTERFACE, "State",
256                                                 DBUS_TYPE_STRING, &str);
257 }
258
259 static const char *get_name(enum connman_service_type type)
260 {
261         switch (type) {
262         case CONNMAN_SERVICE_TYPE_UNKNOWN:
263         case CONNMAN_SERVICE_TYPE_SYSTEM:
264         case CONNMAN_SERVICE_TYPE_GPS:
265         case CONNMAN_SERVICE_TYPE_VPN:
266         case CONNMAN_SERVICE_TYPE_GADGET:
267                 break;
268         case CONNMAN_SERVICE_TYPE_ETHERNET:
269                 return "Wired";
270         case CONNMAN_SERVICE_TYPE_WIFI:
271                 return "WiFi";
272         case CONNMAN_SERVICE_TYPE_WIMAX:
273                 return "WiMAX";
274         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
275                 return "Bluetooth";
276         case CONNMAN_SERVICE_TYPE_CELLULAR:
277                 return "Cellular";
278         }
279
280         return NULL;
281 }
282
283 static void load_state(struct connman_technology *technology)
284 {
285         GKeyFile *keyfile;
286         gchar *identifier;
287         GError *error = NULL;
288         connman_bool_t enable;
289
290         DBG("technology %p", technology);
291
292         keyfile = __connman_storage_load_global();
293         /* Fallback on disabling technology if file not found. */
294         if (keyfile == NULL) {
295                 technology->enable_persistent = FALSE;
296                 return;
297         }
298
299         identifier = g_strdup_printf("%s", get_name(technology->type));
300         if (identifier == NULL)
301                 goto done;
302
303         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
304         if (error == NULL)
305                 technology->enable_persistent = enable;
306         else {
307                 technology->enable_persistent = FALSE;
308                 g_clear_error(&error);
309         }
310 done:
311         g_free(identifier);
312
313         g_key_file_free(keyfile);
314
315         return;
316 }
317
318 static void save_state(struct connman_technology *technology)
319 {
320         GKeyFile *keyfile;
321         gchar *identifier;
322
323         DBG("technology %p", technology);
324
325         keyfile = __connman_storage_load_global();
326         if (keyfile == NULL)
327                 keyfile = g_key_file_new();
328
329         identifier = g_strdup_printf("%s", get_name(technology->type));
330         if (identifier == NULL)
331                 goto done;
332
333         g_key_file_set_boolean(keyfile, identifier, "Enable",
334                                 technology->enable_persistent);
335
336 done:
337         g_free(identifier);
338
339         __connman_storage_save_global(keyfile);
340
341         g_key_file_free(keyfile);
342
343         return;
344 }
345
346 connman_bool_t __connman_technology_get_offlinemode(void)
347 {
348         return global_offlinemode;
349 }
350
351 static void connman_technology_save_offlinemode()
352 {
353         GKeyFile *keyfile;
354
355         keyfile = __connman_storage_load_global();
356         if (keyfile == NULL)
357                 keyfile = g_key_file_new();
358
359         g_key_file_set_boolean(keyfile, "global",
360                                         "OfflineMode", global_offlinemode);
361
362         __connman_storage_save_global(keyfile);
363
364         g_key_file_free(keyfile);
365
366         return;
367 }
368
369 static connman_bool_t connman_technology_load_offlinemode()
370 {
371         GKeyFile *keyfile;
372         GError *error = NULL;
373         connman_bool_t offlinemode;
374
375         /* If there is a error, we enable offlinemode */
376         keyfile = __connman_storage_load_global();
377         if (keyfile == NULL)
378                 return TRUE;
379
380         offlinemode = g_key_file_get_boolean(keyfile, "global",
381                                                 "OfflineMode", &error);
382         if (error != NULL) {
383                 offlinemode = TRUE;
384                 g_clear_error(&error);
385         }
386
387         g_key_file_free(keyfile);
388
389         return offlinemode;
390 }
391
392 static void append_properties(DBusMessageIter *iter,
393                 struct connman_technology *technology)
394 {
395         DBusMessageIter dict;
396         const char *str;
397         connman_bool_t powered;
398
399         connman_dbus_dict_open(iter, &dict);
400
401         str = state2string(technology->state);
402         if (str != NULL)
403                 connman_dbus_dict_append_basic(&dict, "State",
404                                                 DBUS_TYPE_STRING, &str);
405
406         str = get_name(technology->type);
407         if (str != NULL)
408                 connman_dbus_dict_append_basic(&dict, "Name",
409                                                 DBUS_TYPE_STRING, &str);
410
411         str = __connman_service_type2string(technology->type);
412         if (str != NULL)
413                 connman_dbus_dict_append_basic(&dict, "Type",
414                                                 DBUS_TYPE_STRING, &str);
415
416         __sync_synchronize();
417         if (technology->enabled > 0)
418                 powered = TRUE;
419         else
420                 powered = FALSE;
421         connman_dbus_dict_append_basic(&dict, "Powered",
422                                         DBUS_TYPE_BOOLEAN, &powered);
423
424         connman_dbus_dict_append_basic(&dict, "Tethering",
425                                         DBUS_TYPE_BOOLEAN,
426                                         &technology->tethering);
427
428         if (technology->tethering_ident != NULL)
429                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
430                                                 DBUS_TYPE_STRING,
431                                                 &technology->tethering_ident);
432
433         if (technology->tethering_passphrase != NULL)
434                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
435                                                 DBUS_TYPE_STRING,
436                                                 &technology->tethering_passphrase);
437
438         connman_dbus_dict_close(iter, &dict);
439 }
440
441 static void technology_added_signal(struct connman_technology *technology)
442 {
443         DBusMessage *signal;
444         DBusMessageIter iter;
445
446         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
447                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
448         if (signal == NULL)
449                 return;
450
451         dbus_message_iter_init_append(signal, &iter);
452         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
453                                                         &technology->path);
454         append_properties(&iter, technology);
455
456         dbus_connection_send(connection, signal, NULL);
457         dbus_message_unref(signal);
458 }
459
460 static void technology_removed_signal(struct connman_technology *technology)
461 {
462         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
463                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
464                         DBUS_TYPE_OBJECT_PATH, &technology->path,
465                         DBUS_TYPE_INVALID);
466 }
467
468 static DBusMessage *get_properties(DBusConnection *conn,
469                                         DBusMessage *message, void *user_data)
470 {
471         struct connman_technology *technology = user_data;
472         DBusMessage *reply;
473         DBusMessageIter iter;
474
475         reply = dbus_message_new_method_return(message);
476         if (reply == NULL)
477                 return NULL;
478
479         dbus_message_iter_init_append(reply, &iter);
480         append_properties(&iter, technology);
481
482         return reply;
483 }
484
485 void __connman_technology_list_struct(DBusMessageIter *array)
486 {
487         GSList *list;
488         DBusMessageIter entry;
489
490         for (list = technology_list; list; list = list->next) {
491                 struct connman_technology *technology = list->data;
492
493                 if (technology->path == NULL)
494                         continue;
495
496                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
497                                 NULL, &entry);
498                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
499                                 &technology->path);
500                 append_properties(&entry, technology);
501                 dbus_message_iter_close_container(array, &entry);
502         }
503 }
504
505 static gboolean technology_pending_reply(gpointer user_data)
506 {
507         struct connman_technology *technology = user_data;
508         DBusMessage *reply;
509
510         /* Power request timedout, send ETIMEDOUT. */
511         if (technology->pending_reply != NULL) {
512                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
513                 if (reply != NULL)
514                         g_dbus_send_message(connection, reply);
515
516                 dbus_message_unref(technology->pending_reply);
517                 technology->pending_reply = NULL;
518                 technology->pending_timeout = 0;
519         }
520
521         return FALSE;
522 }
523
524 static int technology_enable(struct connman_technology *technology,
525                 DBusMessage *msg)
526 {
527         GSList *list;
528         int err = 0;
529         int ret = -ENODEV;
530         DBusMessage *reply;
531
532         DBG("technology %p enable", technology);
533
534         __sync_synchronize();
535         if (technology->enabled > 0) {
536                 err = -EALREADY;
537                 goto done;
538         }
539
540         if (technology->pending_reply != NULL) {
541                 err = -EBUSY;
542                 goto done;
543         }
544
545         if (msg != NULL) {
546                 /*
547                  * This is a bit of a trick. When msg is not NULL it means
548                  * thats technology_enable was invoked from the manager API.
549                  * Hence we save the state here.
550                  */
551                 technology->enable_persistent = TRUE;
552                 save_state(technology);
553         }
554
555         __connman_rfkill_block(technology->type, FALSE);
556
557         /*
558          * An empty device list means that devices in the technology
559          * were rfkill blocked. The unblock above will enable the devs.
560          */
561         if (technology->device_list == NULL) {
562                 ret = 0;
563                 goto done;
564         }
565
566         for (list = technology->device_list; list; list = list->next) {
567                 struct connman_device *device = list->data;
568
569                 err = __connman_device_enable(device);
570                 /*
571                  * err = 0 : Device was enabled right away.
572                  * If atleast one device gets enabled, we consider
573                  * the technology to be enabled.
574                  */
575                 if (err == 0)
576                         ret = 0;
577         }
578
579 done:
580         if (ret == 0) {
581                 if (msg != NULL)
582                         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
583                 return ret;
584         }
585
586         if (msg != NULL) {
587                 if (err == -EINPROGRESS) {
588                         technology->pending_reply = dbus_message_ref(msg);
589                         technology->pending_timeout = g_timeout_add_seconds(10,
590                                         technology_pending_reply, technology);
591                 } else {
592                         reply = __connman_error_failed(msg, -err);
593                         if (reply != NULL)
594                                 g_dbus_send_message(connection, reply);
595                 }
596         }
597
598         return err;
599 }
600
601 static int technology_disable(struct connman_technology *technology,
602                 DBusMessage *msg)
603 {
604         GSList *list;
605         int err = 0;
606         int ret = -ENODEV;
607         DBusMessage *reply;
608
609         DBG("technology %p disable", technology);
610
611         __sync_synchronize();
612         if (technology->enabled == 0) {
613                 err = -EALREADY;
614                 goto done;
615         }
616
617         if (technology->pending_reply != NULL) {
618                 err = -EBUSY;
619                 goto done;
620         }
621
622         if (technology->tethering == TRUE)
623                 set_tethering(technology, FALSE);
624
625         if (msg != NULL) {
626                 technology->enable_persistent = FALSE;
627                 save_state(technology);
628         }
629
630         __connman_rfkill_block(technology->type, TRUE);
631
632         for (list = technology->device_list; list; list = list->next) {
633                 struct connman_device *device = list->data;
634
635                 err = __connman_device_disable(device);
636                 if (err == 0)
637                         ret = 0;
638         }
639
640 done:
641         if (ret == 0) {
642                 if (msg != NULL)
643                         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
644                 return ret;
645         }
646
647         if (msg != NULL) {
648                 if (err == -EINPROGRESS) {
649                         technology->pending_reply = dbus_message_ref(msg);
650                         technology->pending_timeout = g_timeout_add_seconds(10,
651                                         technology_pending_reply, technology);
652                 } else {
653                         reply = __connman_error_failed(msg, -err);
654                         if (reply != NULL)
655                                 g_dbus_send_message(connection, reply);
656                 }
657         }
658
659         return err;
660 }
661
662 static DBusMessage *set_property(DBusConnection *conn,
663                                         DBusMessage *msg, void *data)
664 {
665         struct connman_technology *technology = data;
666         DBusMessageIter iter, value;
667         const char *name;
668         int type;
669
670         DBG("conn %p", conn);
671
672         if (dbus_message_iter_init(msg, &iter) == FALSE)
673                 return __connman_error_invalid_arguments(msg);
674
675         dbus_message_iter_get_basic(&iter, &name);
676         dbus_message_iter_next(&iter);
677         dbus_message_iter_recurse(&iter, &value);
678
679         type = dbus_message_iter_get_arg_type(&value);
680
681         DBG("property %s", name);
682
683         if (g_str_equal(name, "Tethering") == TRUE) {
684                 int err;
685                 connman_bool_t tethering;
686
687                 if (type != DBUS_TYPE_BOOLEAN)
688                         return __connman_error_invalid_arguments(msg);
689
690                 dbus_message_iter_get_basic(&value, &tethering);
691
692                 if (technology->tethering == tethering)
693                         return __connman_error_in_progress(msg);
694
695                 err = set_tethering(technology, tethering);
696                 if (err < 0)
697                         return __connman_error_failed(msg, -err);
698
699         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
700                 const char *str;
701
702                 dbus_message_iter_get_basic(&value, &str);
703
704                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
705                         return __connman_error_not_supported(msg);
706
707                 technology->tethering_ident = g_strdup(str);
708         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
709                 const char *str;
710
711                 dbus_message_iter_get_basic(&value, &str);
712
713                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
714                         return __connman_error_not_supported(msg);
715
716                 if (strlen(str) < 8)
717                         return __connman_error_invalid_arguments(msg);
718
719                 technology->tethering_passphrase = g_strdup(str);
720         } else if (g_str_equal(name, "Powered") == TRUE) {
721                 connman_bool_t enable;
722
723                 if (type != DBUS_TYPE_BOOLEAN)
724                         return __connman_error_invalid_arguments(msg);
725
726                 dbus_message_iter_get_basic(&value, &enable);
727                 if (enable == TRUE)
728                         technology_enable(technology, msg);
729                 else
730                         technology_disable(technology, msg);
731
732         } else
733                 return __connman_error_invalid_property(msg);
734
735         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
736 }
737
738 static GDBusMethodTable technology_methods[] = {
739         { "GetProperties", "",   "a{sv}", get_properties },
740         { "SetProperty",   "sv", "",      set_property   },
741         { },
742 };
743
744 static GDBusSignalTable technology_signals[] = {
745         { "PropertyChanged", "sv" },
746         { },
747 };
748
749 static struct connman_technology *technology_find(enum connman_service_type type)
750 {
751         GSList *list;
752
753         DBG("type %d", type);
754
755         for (list = technology_list; list; list = list->next) {
756                 struct connman_technology *technology = list->data;
757
758                 if (technology->type == type)
759                         return technology;
760         }
761
762         return NULL;
763 }
764
765 static struct connman_technology *technology_get(enum connman_service_type type)
766 {
767         struct connman_technology *technology;
768         struct connman_technology_driver *driver = NULL;
769         const char *str;
770         GSList *list;
771         int err;
772
773         DBG("type %d", type);
774
775         str = __connman_service_type2string(type);
776         if (str == NULL)
777                 return NULL;
778
779         technology = technology_find(type);
780         if (technology != NULL)
781                 return technology;
782
783         /* First check if we have a driver for this technology type */
784         for (list = driver_list; list; list = list->next) {
785                 driver = list->data;
786
787                 if (driver->type == type)
788                         break;
789                 else
790                         driver = NULL;
791         }
792
793         if (driver == NULL) {
794                 DBG("No matching driver found for %s.",
795                                 __connman_service_type2string(type));
796                 return NULL;
797         }
798
799         technology = g_try_new0(struct connman_technology, 1);
800         if (technology == NULL)
801                 return NULL;
802
803         technology->refcount = 1;
804
805         technology->type = type;
806         technology->path = g_strdup_printf("%s/technology/%s",
807                                                         CONNMAN_PATH, str);
808
809         technology->rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal,
810                                                         NULL, free_rfkill);
811         technology->device_list = NULL;
812
813         technology->pending_reply = NULL;
814         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
815
816         load_state(technology);
817
818         if (g_dbus_register_interface(connection, technology->path,
819                                         CONNMAN_TECHNOLOGY_INTERFACE,
820                                         technology_methods, technology_signals,
821                                         NULL, technology, NULL) == FALSE) {
822                 connman_error("Failed to register %s", technology->path);
823                 g_free(technology);
824                 return NULL;
825         }
826
827         technology_list = g_slist_append(technology_list, technology);
828
829         technology_added_signal(technology);
830
831         technology->driver = driver;
832         err = driver->probe(technology);
833         if (err != 0)
834                 DBG("Driver probe failed for technology %p", technology);
835
836         DBG("technology %p", technology);
837
838         return technology;
839 }
840
841 static void technology_put(struct connman_technology *technology)
842 {
843         DBG("technology %p", technology);
844
845         if (__sync_fetch_and_sub(&technology->refcount, 1) != 1)
846                 return;
847
848         if (technology->driver) {
849                 technology->driver->remove(technology);
850                 technology->driver = NULL;
851         }
852
853         technology_list = g_slist_remove(technology_list, technology);
854
855         technology_removed_signal(technology);
856
857         g_dbus_unregister_interface(connection, technology->path,
858                                                 CONNMAN_TECHNOLOGY_INTERFACE);
859
860         g_slist_free(technology->device_list);
861         g_hash_table_destroy(technology->rfkill_list);
862
863         g_free(technology->path);
864         g_free(technology->regdom);
865         g_free(technology);
866 }
867
868 void __connman_technology_add_interface(enum connman_service_type type,
869                                 int index, const char *name, const char *ident)
870 {
871         struct connman_technology *technology;
872
873         switch (type) {
874         case CONNMAN_SERVICE_TYPE_UNKNOWN:
875         case CONNMAN_SERVICE_TYPE_SYSTEM:
876                 return;
877         case CONNMAN_SERVICE_TYPE_ETHERNET:
878         case CONNMAN_SERVICE_TYPE_WIFI:
879         case CONNMAN_SERVICE_TYPE_WIMAX:
880         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
881         case CONNMAN_SERVICE_TYPE_CELLULAR:
882         case CONNMAN_SERVICE_TYPE_GPS:
883         case CONNMAN_SERVICE_TYPE_VPN:
884         case CONNMAN_SERVICE_TYPE_GADGET:
885                 break;
886         }
887
888         connman_info("Adding interface %s [ %s ]", name,
889                                 __connman_service_type2string(type));
890
891         technology = technology_find(type);
892
893         if (technology == NULL || technology->driver == NULL
894                         || technology->driver->add_interface == NULL)
895                 return;
896
897         technology->driver->add_interface(technology,
898                                         index, name, ident);
899 }
900
901 void __connman_technology_remove_interface(enum connman_service_type type,
902                                 int index, const char *name, const char *ident)
903 {
904         struct connman_technology *technology;
905
906         switch (type) {
907         case CONNMAN_SERVICE_TYPE_UNKNOWN:
908         case CONNMAN_SERVICE_TYPE_SYSTEM:
909                 return;
910         case CONNMAN_SERVICE_TYPE_ETHERNET:
911         case CONNMAN_SERVICE_TYPE_WIFI:
912         case CONNMAN_SERVICE_TYPE_WIMAX:
913         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
914         case CONNMAN_SERVICE_TYPE_CELLULAR:
915         case CONNMAN_SERVICE_TYPE_GPS:
916         case CONNMAN_SERVICE_TYPE_VPN:
917         case CONNMAN_SERVICE_TYPE_GADGET:
918                 break;
919         }
920
921         connman_info("Remove interface %s [ %s ]", name,
922                                 __connman_service_type2string(type));
923
924         technology = technology_find(type);
925
926         if (technology == NULL || technology->driver == NULL)
927                 return;
928
929         if (technology->driver->remove_interface)
930                 technology->driver->remove_interface(technology, index);
931 }
932
933 int __connman_technology_add_device(struct connman_device *device)
934 {
935         struct connman_technology *technology;
936         enum connman_service_type type;
937
938         DBG("device %p", device);
939
940         type = __connman_device_get_service_type(device);
941
942         technology = technology_get(type);
943         if (technology == NULL)
944                 return -ENXIO;
945
946         if (technology->enable_persistent && !global_offlinemode)
947                 __connman_device_enable(device);
948         /* if technology persistent state is offline */
949         if (!technology->enable_persistent)
950                 __connman_device_disable(device);
951
952         technology->device_list = g_slist_append(technology->device_list,
953                                                                 device);
954
955         return 0;
956 }
957
958 int __connman_technology_remove_device(struct connman_device *device)
959 {
960         struct connman_technology *technology;
961         enum connman_service_type type;
962
963         DBG("device %p", device);
964
965         type = __connman_device_get_service_type(device);
966
967         technology = technology_find(type);
968         if (technology == NULL)
969                 return -ENXIO;
970
971         technology->device_list = g_slist_remove(technology->device_list,
972                                                                 device);
973         if (technology->device_list == NULL) {
974                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
975                 state_changed(technology);
976         }
977
978         return 0;
979 }
980
981 static void powered_changed(struct connman_technology *technology)
982 {
983         connman_bool_t powered;
984
985         __sync_synchronize();
986         if (technology->enabled >0)
987                 powered = TRUE;
988         else
989                 powered = FALSE;
990
991         connman_dbus_property_changed_basic(technology->path,
992                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
993                         DBUS_TYPE_BOOLEAN, &powered);
994 }
995
996 int __connman_technology_enabled(enum connman_service_type type)
997 {
998         struct connman_technology *technology;
999
1000         technology = technology_find(type);
1001         if (technology == NULL)
1002                 return -ENXIO;
1003
1004         if (__sync_fetch_and_add(&technology->enabled, 1) == 0) {
1005                 technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
1006                 state_changed(technology);
1007                 powered_changed(technology);
1008         }
1009
1010         if (technology->pending_reply != NULL) {
1011                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
1012                 dbus_message_unref(technology->pending_reply);
1013                 g_source_remove(technology->pending_timeout);
1014                 technology->pending_reply = NULL;
1015                 technology->pending_timeout = 0;
1016         }
1017
1018         return 0;
1019 }
1020
1021 int __connman_technology_disabled(enum connman_service_type type)
1022 {
1023         struct connman_technology *technology;
1024
1025         technology = technology_find(type);
1026         if (technology == NULL)
1027                 return -ENXIO;
1028
1029         if (technology->pending_reply != NULL) {
1030                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
1031                 dbus_message_unref(technology->pending_reply);
1032                 g_source_remove(technology->pending_timeout);
1033                 technology->pending_reply = NULL;
1034                 technology->pending_timeout = 0;
1035         }
1036
1037         if (__sync_fetch_and_sub(&technology->enabled, 1) != 1)
1038                 return 0;
1039
1040         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
1041         state_changed(technology);
1042         powered_changed(technology);
1043
1044         return 0;
1045 }
1046
1047 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
1048 {
1049         GSList *list;
1050         int err = -EINVAL;
1051
1052         if (global_offlinemode == offlinemode)
1053                 return 0;
1054
1055         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1056
1057         /*
1058          * This is a bit tricky. When you set offlinemode, there is no
1059          * way to differentiate between attempting offline mode and
1060          * resuming offlinemode from last saved profile. We need that
1061          * information in rfkill_update, otherwise it falls back on the
1062          * technology's persistent state. Hence we set the offline mode here
1063          * but save it & call the notifier only if its successful.
1064          */
1065
1066         global_offlinemode = offlinemode;
1067
1068         /* Traverse technology list, enable/disable each technology. */
1069         for (list = technology_list; list; list = list->next) {
1070                 struct connman_technology *technology = list->data;
1071
1072                 if (offlinemode)
1073                         err = technology_disable(technology, NULL);
1074
1075                 if (!offlinemode && technology->enable_persistent)
1076                         err = technology_enable(technology, NULL);
1077         }
1078
1079         if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
1080                 connman_technology_save_offlinemode();
1081                 __connman_notifier_offlinemode(offlinemode);
1082         } else
1083                 global_offlinemode = connman_technology_load_offlinemode();
1084
1085         return err;
1086 }
1087
1088 int __connman_technology_add_rfkill(unsigned int index,
1089                                         enum connman_service_type type,
1090                                                 connman_bool_t softblock,
1091                                                 connman_bool_t hardblock)
1092 {
1093         struct connman_technology *technology;
1094         struct connman_rfkill *rfkill;
1095
1096         DBG("index %u type %d soft %u hard %u", index, type,
1097                                                         softblock, hardblock);
1098
1099         technology = technology_get(type);
1100         if (technology == NULL)
1101                 return -ENXIO;
1102
1103         rfkill = g_try_new0(struct connman_rfkill, 1);
1104         if (rfkill == NULL)
1105                 return -ENOMEM;
1106
1107         rfkill->index = index;
1108         rfkill->type = type;
1109         rfkill->softblock = softblock;
1110         rfkill->hardblock = hardblock;
1111
1112         g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
1113
1114         if (hardblock) {
1115                 DBG("%s is switched off.", get_name(type));
1116                 return 0;
1117         }
1118
1119         /*
1120          * If Offline mode is on, we softblock the device if it isnt already.
1121          * If Offline mode is off, we rely on the persistent state of tech.
1122          */
1123         if (global_offlinemode) {
1124                 if (!softblock)
1125                         return __connman_rfkill_block(type, TRUE);
1126         } else {
1127                 if (technology->enable_persistent && softblock)
1128                         return __connman_rfkill_block(type, FALSE);
1129                 /* if technology persistent state is offline */
1130                 if (!technology->enable_persistent && !softblock)
1131                         return __connman_rfkill_block(type, TRUE);
1132         }
1133
1134         return 0;
1135 }
1136
1137 int __connman_technology_update_rfkill(unsigned int index,
1138                                         enum connman_service_type type,
1139                                                 connman_bool_t softblock,
1140                                                 connman_bool_t hardblock)
1141 {
1142         struct connman_technology *technology;
1143         struct connman_rfkill *rfkill;
1144
1145         DBG("index %u soft %u hard %u", index, softblock, hardblock);
1146
1147         technology = technology_find(type);
1148         if (technology == NULL)
1149                 return -ENXIO;
1150
1151         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
1152         if (rfkill == NULL)
1153                 return -ENXIO;
1154
1155         if (rfkill->softblock == softblock &&
1156                 rfkill->hardblock == hardblock)
1157                 return 0;
1158
1159         rfkill->softblock = softblock;
1160         rfkill->hardblock = hardblock;
1161
1162         if (hardblock) {
1163                 DBG("%s is switched off.", get_name(type));
1164                 return 0;
1165         }
1166
1167         if (!global_offlinemode) {
1168                 if (technology->enable_persistent && softblock)
1169                         return __connman_rfkill_block(type, FALSE);
1170                 if (!technology->enable_persistent && !softblock)
1171                         return __connman_rfkill_block(type, TRUE);
1172         }
1173
1174         return 0;
1175 }
1176
1177 int __connman_technology_remove_rfkill(unsigned int index,
1178                                         enum connman_service_type type)
1179 {
1180         struct connman_technology *technology;
1181         struct connman_rfkill *rfkill;
1182
1183         DBG("index %u", index);
1184
1185         technology = technology_find(type);
1186         if (technology == NULL)
1187                 return -ENXIO;
1188
1189         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
1190         if (rfkill == NULL)
1191                 return -ENXIO;
1192
1193         g_hash_table_remove(technology->rfkill_list, &index);
1194
1195         technology_put(technology);
1196
1197         return 0;
1198 }
1199
1200 int __connman_technology_init(void)
1201 {
1202         DBG("");
1203
1204         connection = connman_dbus_get_connection();
1205
1206         global_offlinemode = connman_technology_load_offlinemode();
1207
1208         return 0;
1209 }
1210
1211 void __connman_technology_cleanup(void)
1212 {
1213         DBG("");
1214
1215         dbus_connection_unref(connection);
1216 }