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