technology: Remove the global device hash
[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 struct connman_rfkill {
38         unsigned int index;
39         enum connman_service_type type;
40         connman_bool_t softblock;
41         connman_bool_t hardblock;
42 };
43
44 enum connman_technology_state {
45         CONNMAN_TECHNOLOGY_STATE_UNKNOWN   = 0,
46         CONNMAN_TECHNOLOGY_STATE_OFFLINE   = 1,
47         CONNMAN_TECHNOLOGY_STATE_AVAILABLE = 2,
48         CONNMAN_TECHNOLOGY_STATE_ENABLED   = 3,
49         CONNMAN_TECHNOLOGY_STATE_CONNECTED = 4,
50 };
51
52 struct connman_technology {
53         gint refcount;
54         enum connman_service_type type;
55         enum connman_technology_state state;
56         char *path;
57         GHashTable *rfkill_list;
58         GSList *device_list;
59         gint enabled;
60         gint blocked;
61         char *regdom;
62
63         connman_bool_t tethering;
64         char *tethering_ident;
65         char *tethering_passphrase;
66
67         struct connman_technology_driver *driver;
68         void *driver_data;
69
70         DBusMessage *pending_reply;
71         guint pending_timeout;
72 };
73
74 static GSList *driver_list = NULL;
75
76 static gint compare_priority(gconstpointer a, gconstpointer b)
77 {
78         const struct connman_technology_driver *driver1 = a;
79         const struct connman_technology_driver *driver2 = b;
80
81         return driver2->priority - driver1->priority;
82 }
83
84 /**
85  * connman_technology_driver_register:
86  * @driver: Technology driver definition
87  *
88  * Register a new technology driver
89  *
90  * Returns: %0 on success
91  */
92 int connman_technology_driver_register(struct connman_technology_driver *driver)
93 {
94         GSList *list;
95         struct connman_technology *technology;
96
97         DBG("driver %p name %s", driver, driver->name);
98
99         driver_list = g_slist_insert_sorted(driver_list, driver,
100                                                         compare_priority);
101
102         for (list = technology_list; list; list = list->next) {
103                 technology = list->data;
104
105                 if (technology->driver != NULL)
106                         continue;
107
108                 if (technology->type == driver->type)
109                         technology->driver = driver;
110         }
111
112         return 0;
113 }
114
115 /**
116  * connman_technology_driver_unregister:
117  * @driver: Technology driver definition
118  *
119  * Remove a previously registered technology driver
120  */
121 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
122 {
123         GSList *list;
124         struct connman_technology *technology;
125
126         DBG("driver %p name %s", driver, driver->name);
127
128         for (list = technology_list; list; list = list->next) {
129                 technology = list->data;
130
131                 if (technology->driver == NULL)
132                         continue;
133
134                 if (technology->type == driver->type) {
135                         technology->driver->remove(technology);
136                         technology->driver = NULL;
137                 }
138         }
139
140         driver_list = g_slist_remove(driver_list, driver);
141 }
142
143 static void tethering_changed(struct connman_technology *technology)
144 {
145         connman_bool_t tethering = technology->tethering;
146
147         connman_dbus_property_changed_basic(technology->path,
148                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
149                                                 DBUS_TYPE_BOOLEAN, &tethering);
150 }
151
152 void connman_technology_tethering_notify(struct connman_technology *technology,
153                                                         connman_bool_t enabled)
154 {
155         DBG("technology %p enabled %u", technology, enabled);
156
157         if (technology->tethering == enabled)
158                 return;
159
160         technology->tethering = enabled;
161
162         tethering_changed(technology);
163
164         if (enabled == TRUE)
165                 __connman_tethering_set_enabled();
166         else
167                 __connman_tethering_set_disabled();
168 }
169
170 static int set_tethering(struct connman_technology *technology,
171                                 const char *bridge, connman_bool_t enabled)
172 {
173         const char *ident, *passphrase;
174
175         ident = technology->tethering_ident;
176         passphrase = technology->tethering_passphrase;
177
178         if (technology->driver == NULL ||
179                         technology->driver->set_tethering == NULL)
180                 return -EOPNOTSUPP;
181
182         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
183             (ident == NULL || passphrase == NULL))
184                 return -EINVAL;
185
186         return technology->driver->set_tethering(technology, ident, passphrase,
187                                                         bridge, enabled);
188 }
189
190 void connman_technology_regdom_notify(struct connman_technology *technology,
191                                                         const char *alpha2)
192 {
193         DBG("");
194
195         if (alpha2 == NULL)
196                 connman_error("Failed to set regulatory domain");
197         else
198                 DBG("Regulatory domain set to %s", alpha2);
199
200         g_free(technology->regdom);
201         technology->regdom = g_strdup(alpha2);
202 }
203
204 int connman_technology_set_regdom(const char *alpha2)
205 {
206         GSList *list;
207
208         for (list = technology_list; list; list = list->next) {
209                 struct connman_technology *technology = list->data;
210
211                 if (technology->driver == NULL)
212                         continue;
213
214                 if (technology->driver->set_regdom)
215                         technology->driver->set_regdom(technology, alpha2);
216         }
217
218         return 0;
219 }
220
221 static void free_rfkill(gpointer data)
222 {
223         struct connman_rfkill *rfkill = data;
224
225         g_free(rfkill);
226 }
227
228 void __connman_technology_list(DBusMessageIter *iter, void *user_data)
229 {
230         GSList *list;
231
232         for (list = technology_list; list; list = list->next) {
233                 struct connman_technology *technology = list->data;
234
235                 if (technology->path == NULL)
236                         continue;
237
238                 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
239                                                         &technology->path);
240         }
241 }
242
243 static void technologies_changed(void)
244 {
245         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
246                         CONNMAN_MANAGER_INTERFACE, "Technologies",
247                         DBUS_TYPE_OBJECT_PATH, __connman_technology_list, NULL);
248 }
249
250 static const char *state2string(enum connman_technology_state state)
251 {
252         switch (state) {
253         case CONNMAN_TECHNOLOGY_STATE_UNKNOWN:
254                 break;
255         case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
256                 return "offline";
257         case CONNMAN_TECHNOLOGY_STATE_AVAILABLE:
258                 return "available";
259         case CONNMAN_TECHNOLOGY_STATE_ENABLED:
260                 return "enabled";
261         case CONNMAN_TECHNOLOGY_STATE_CONNECTED:
262                 return "connected";
263         }
264
265         return NULL;
266 }
267
268 static void state_changed(struct connman_technology *technology)
269 {
270         const char *str;
271
272         str = state2string(technology->state);
273         if (str == NULL)
274                 return;
275
276         connman_dbus_property_changed_basic(technology->path,
277                                 CONNMAN_TECHNOLOGY_INTERFACE, "State",
278                                                 DBUS_TYPE_STRING, &str);
279 }
280
281 static const char *get_name(enum connman_service_type type)
282 {
283         switch (type) {
284         case CONNMAN_SERVICE_TYPE_UNKNOWN:
285         case CONNMAN_SERVICE_TYPE_SYSTEM:
286         case CONNMAN_SERVICE_TYPE_GPS:
287         case CONNMAN_SERVICE_TYPE_VPN:
288         case CONNMAN_SERVICE_TYPE_GADGET:
289                 break;
290         case CONNMAN_SERVICE_TYPE_ETHERNET:
291                 return "Wired";
292         case CONNMAN_SERVICE_TYPE_WIFI:
293                 return "WiFi";
294         case CONNMAN_SERVICE_TYPE_WIMAX:
295                 return "WiMAX";
296         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
297                 return "Bluetooth";
298         case CONNMAN_SERVICE_TYPE_CELLULAR:
299                 return "3G";
300         }
301
302         return NULL;
303 }
304
305 static DBusMessage *get_properties(DBusConnection *conn,
306                                         DBusMessage *message, void *user_data)
307 {
308         struct connman_technology *technology = user_data;
309         DBusMessage *reply;
310         DBusMessageIter array, dict;
311         const char *str;
312
313         reply = dbus_message_new_method_return(message);
314         if (reply == NULL)
315                 return NULL;
316
317         dbus_message_iter_init_append(reply, &array);
318
319         connman_dbus_dict_open(&array, &dict);
320
321         str = state2string(technology->state);
322         if (str != NULL)
323                 connman_dbus_dict_append_basic(&dict, "State",
324                                                 DBUS_TYPE_STRING, &str);
325
326         str = get_name(technology->type);
327         if (str != NULL)
328                 connman_dbus_dict_append_basic(&dict, "Name",
329                                                 DBUS_TYPE_STRING, &str);
330
331         str = __connman_service_type2string(technology->type);
332         if (str != NULL)
333                 connman_dbus_dict_append_basic(&dict, "Type",
334                                                 DBUS_TYPE_STRING, &str);
335
336         connman_dbus_dict_append_basic(&dict, "Tethering",
337                                         DBUS_TYPE_BOOLEAN,
338                                         &technology->tethering);
339
340         if (technology->tethering_ident != NULL)
341                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
342                                                 DBUS_TYPE_STRING,
343                                                 &technology->tethering_ident);
344
345         if (technology->tethering_passphrase != NULL)
346                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
347                                                 DBUS_TYPE_STRING,
348                                                 &technology->tethering_passphrase);
349
350         connman_dbus_dict_close(&array, &dict);
351
352         return reply;
353 }
354
355 static DBusMessage *set_property(DBusConnection *conn,
356                                         DBusMessage *msg, void *data)
357 {
358         struct connman_technology *technology = data;
359         DBusMessageIter iter, value;
360         const char *name;
361         int type;
362
363         DBG("conn %p", conn);
364
365         if (dbus_message_iter_init(msg, &iter) == FALSE)
366                 return __connman_error_invalid_arguments(msg);
367
368         dbus_message_iter_get_basic(&iter, &name);
369         dbus_message_iter_next(&iter);
370         dbus_message_iter_recurse(&iter, &value);
371
372         type = dbus_message_iter_get_arg_type(&value);
373
374         DBG("property %s", name);
375
376         if (g_str_equal(name, "Tethering") == TRUE) {
377                 int err;
378                 connman_bool_t tethering;
379                 const char *bridge;
380
381                 if (type != DBUS_TYPE_BOOLEAN)
382                         return __connman_error_invalid_arguments(msg);
383
384                 dbus_message_iter_get_basic(&value, &tethering);
385
386                 if (technology->tethering == tethering)
387                         return __connman_error_in_progress(msg);
388
389                 bridge = __connman_tethering_get_bridge();
390                 if (bridge == NULL)
391                         return __connman_error_not_supported(msg);
392
393                 err = set_tethering(technology, bridge, tethering);
394                 if (err < 0)
395                         return __connman_error_failed(msg, -err);
396
397         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
398                 const char *str;
399
400                 dbus_message_iter_get_basic(&value, &str);
401
402                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
403                         return __connman_error_not_supported(msg);
404
405                 technology->tethering_ident = g_strdup(str);
406         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
407                 const char *str;
408
409                 dbus_message_iter_get_basic(&value, &str);
410
411                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
412                         return __connman_error_not_supported(msg);
413
414                 if (strlen(str) < 8)
415                         return __connman_error_invalid_arguments(msg);
416
417                 technology->tethering_passphrase = g_strdup(str);
418         } else
419                 return __connman_error_invalid_property(msg);
420
421         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
422 }
423
424 static GDBusMethodTable technology_methods[] = {
425         { "GetProperties", "",   "a{sv}", get_properties },
426         { "SetProperty",   "sv", "",      set_property   },
427         { },
428 };
429
430 static GDBusSignalTable technology_signals[] = {
431         { "PropertyChanged", "sv" },
432         { },
433 };
434
435 static struct connman_technology *technology_find(enum connman_service_type type)
436 {
437         GSList *list;
438
439         DBG("type %d", type);
440
441         for (list = technology_list; list; list = list->next) {
442                 struct connman_technology *technology = list->data;
443
444                 if (technology->type == type)
445                         return technology;
446         }
447
448         return NULL;
449 }
450
451 static struct connman_technology *technology_get(enum connman_service_type type)
452 {
453         struct connman_technology *technology;
454         const char *str;
455         GSList *list;
456
457         DBG("type %d", type);
458
459         technology = technology_find(type);
460         if (technology != NULL) {
461                 g_atomic_int_inc(&technology->refcount);
462                 goto done;
463         }
464
465         str = __connman_service_type2string(type);
466         if (str == NULL)
467                 return NULL;
468
469         technology = g_try_new0(struct connman_technology, 1);
470         if (technology == NULL)
471                 return NULL;
472
473         technology->refcount = 1;
474
475         technology->type = type;
476         technology->path = g_strdup_printf("%s/technology/%s",
477                                                         CONNMAN_PATH, str);
478
479         technology->rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal,
480                                                         NULL, free_rfkill);
481         technology->device_list = NULL;
482
483         technology->pending_reply = NULL;
484         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
485
486         if (g_dbus_register_interface(connection, technology->path,
487                                         CONNMAN_TECHNOLOGY_INTERFACE,
488                                         technology_methods, technology_signals,
489                                         NULL, technology, NULL) == FALSE) {
490                 connman_error("Failed to register %s", technology->path);
491                 g_free(technology);
492                 return NULL;
493         }
494
495         technology_list = g_slist_append(technology_list, technology);
496
497         technologies_changed();
498
499         if (technology->driver != NULL)
500                 goto done;
501
502         for (list = driver_list; list; list = list->next) {
503                 struct connman_technology_driver *driver = list->data;
504
505                 DBG("driver %p name %s", driver, driver->name);
506
507                 if (driver->type != technology->type)
508                         continue;
509
510                 if (driver->probe(technology) == 0) {
511                         technology->driver = driver;
512                         break;
513                 }
514         }
515
516 done:
517         DBG("technology %p", technology);
518
519         return technology;
520 }
521
522 static void technology_put(struct connman_technology *technology)
523 {
524         DBG("technology %p", technology);
525
526         if (g_atomic_int_dec_and_test(&technology->refcount) == FALSE)
527                 return;
528
529         if (technology->driver) {
530                 technology->driver->remove(technology);
531                 technology->driver = NULL;
532         }
533
534         technology_list = g_slist_remove(technology_list, technology);
535
536         technologies_changed();
537
538         g_dbus_unregister_interface(connection, technology->path,
539                                                 CONNMAN_TECHNOLOGY_INTERFACE);
540
541         g_slist_free(technology->device_list);
542         g_hash_table_destroy(technology->rfkill_list);
543
544         g_free(technology->path);
545         g_free(technology->regdom);
546         g_free(technology);
547 }
548
549 void __connman_technology_add_interface(enum connman_service_type type,
550                                 int index, const char *name, const char *ident)
551 {
552         struct connman_technology *technology;
553
554         switch (type) {
555         case CONNMAN_SERVICE_TYPE_UNKNOWN:
556         case CONNMAN_SERVICE_TYPE_SYSTEM:
557                 return;
558         case CONNMAN_SERVICE_TYPE_ETHERNET:
559         case CONNMAN_SERVICE_TYPE_WIFI:
560         case CONNMAN_SERVICE_TYPE_WIMAX:
561         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
562         case CONNMAN_SERVICE_TYPE_CELLULAR:
563         case CONNMAN_SERVICE_TYPE_GPS:
564         case CONNMAN_SERVICE_TYPE_VPN:
565         case CONNMAN_SERVICE_TYPE_GADGET:
566                 break;
567         }
568
569         connman_info("Create interface %s [ %s ]", name,
570                                 __connman_service_type2string(type));
571
572         technology = technology_get(type);
573
574         if (technology == NULL || technology->driver == NULL
575                         || technology->driver->add_interface == NULL)
576                 return;
577
578         technology->driver->add_interface(technology,
579                                         index, name, ident);
580 }
581
582 void __connman_technology_remove_interface(enum connman_service_type type,
583                                 int index, const char *name, const char *ident)
584 {
585         struct connman_technology *technology;
586
587         switch (type) {
588         case CONNMAN_SERVICE_TYPE_UNKNOWN:
589         case CONNMAN_SERVICE_TYPE_SYSTEM:
590                 return;
591         case CONNMAN_SERVICE_TYPE_ETHERNET:
592         case CONNMAN_SERVICE_TYPE_WIFI:
593         case CONNMAN_SERVICE_TYPE_WIMAX:
594         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
595         case CONNMAN_SERVICE_TYPE_CELLULAR:
596         case CONNMAN_SERVICE_TYPE_GPS:
597         case CONNMAN_SERVICE_TYPE_VPN:
598         case CONNMAN_SERVICE_TYPE_GADGET:
599                 break;
600         }
601
602         connman_info("Remove interface %s [ %s ]", name,
603                                 __connman_service_type2string(type));
604
605         technology = technology_find(type);
606
607         if (technology == NULL || technology->driver == NULL)
608                 return;
609
610         if (technology->driver->remove_interface)
611                 technology->driver->remove_interface(technology, index);
612
613         technology_put(technology);
614 }
615
616 int __connman_technology_add_device(struct connman_device *device)
617 {
618         struct connman_technology *technology;
619         enum connman_service_type type;
620
621         DBG("device %p", device);
622
623         type = __connman_device_get_service_type(device);
624         __connman_notifier_register(type);
625
626         technology = technology_get(type);
627         if (technology == NULL)
628                 return -ENXIO;
629
630         if (g_atomic_int_get(&technology->blocked))
631                 goto done;
632
633         technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
634
635         state_changed(technology);
636
637 done:
638
639         technology->device_list = g_slist_append(technology->device_list,
640                                                                 device);
641
642         return 0;
643 }
644
645 int __connman_technology_remove_device(struct connman_device *device)
646 {
647         struct connman_technology *technology;
648         enum connman_service_type type;
649
650         DBG("device %p", device);
651
652         type = __connman_device_get_service_type(device);
653         __connman_notifier_unregister(type);
654
655         technology = technology_find(type);
656         if (technology == NULL)
657                 return -ENXIO;
658
659         technology->device_list = g_slist_remove(technology->device_list,
660                                                                 device);
661         if (technology->device_list == NULL) {
662                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
663                 state_changed(technology);
664         }
665
666         return 0;
667 }
668
669 static gboolean technology_pending_reply(gpointer user_data)
670 {
671         struct connman_technology *technology = user_data;
672         DBusMessage *reply;
673
674         /* Power request timedout, send ETIMEDOUT. */
675         if (technology->pending_reply != NULL) {
676                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
677                 if (reply != NULL)
678                         g_dbus_send_message(connection, reply);
679
680                 dbus_message_unref(technology->pending_reply);
681                 technology->pending_reply = NULL;
682                 technology->pending_timeout = 0;
683         }
684
685         return FALSE;
686 }
687
688 int __connman_technology_enabled(enum connman_service_type type)
689 {
690         struct connman_technology *technology;
691
692         technology = technology_find(type);
693         if (technology == NULL)
694                 return -ENXIO;
695
696         if (g_atomic_int_get(&technology->blocked))
697                 return -ERFKILL;
698
699         __connman_notifier_enable(type);
700
701         if (g_atomic_int_exchange_and_add(&technology->enabled, 1) == 0) {
702                 technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
703                 state_changed(technology);
704         }
705
706         if (__connman_profile_get_offlinemode() == TRUE) {
707                 __connman_profile_set_offlinemode(FALSE, FALSE);
708                 __connman_profile_save_default();
709         }
710
711         if (technology->pending_reply != NULL) {
712                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
713                 dbus_message_unref(technology->pending_reply);
714                 technology->pending_reply = NULL;
715                 technology->pending_timeout = 0;
716         }
717
718         return 0;
719 }
720
721 int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg)
722 {
723         struct connman_technology *technology;
724         GSList *list;
725         int err = 0;
726         int ret = -ENODEV;
727         DBusMessage *reply;
728
729         DBG("type %d enable", type);
730
731         technology = technology_find(type);
732         if (technology == NULL) {
733                 err = -ENXIO;
734                 goto done;
735         }
736
737         if (technology->pending_reply != NULL) {
738                 err = -EBUSY;
739                 goto done;
740         }
741
742         if (msg != NULL)
743                 technology->pending_reply = dbus_message_ref(msg);
744
745         for (list = technology->device_list; list; list = list->next) {
746                 struct connman_device *device = list->data;
747
748                 err = __connman_device_enable_persistent(device);
749                 /*
750                  * err = 0 : Device was enabled right away.
751                  * If atleast one device gets enabled, we consider
752                  * the technology to be enabled.
753                  */
754                 if (err == 0)
755                         ret = 0;
756         }
757
758 done:
759         if (ret == 0)
760                 return ret;
761
762         if (msg != NULL) {
763                 if (err == -EINPROGRESS)
764                         technology->pending_timeout = g_timeout_add_seconds(10,
765                                         technology_pending_reply, technology);
766                 else {
767                         reply = __connman_error_failed(msg, -err);
768                         if (reply != NULL)
769                                 g_dbus_send_message(connection, reply);
770                 }
771         }
772
773         return err;
774 }
775
776 int __connman_technology_disabled(enum connman_service_type type)
777 {
778         struct connman_technology *technology;
779         GSList *list;
780
781         technology = technology_find(type);
782         if (technology == NULL)
783                 return -ENXIO;
784
785         if (technology->pending_reply != NULL) {
786                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
787                 dbus_message_unref(technology->pending_reply);
788                 technology->pending_reply = NULL;
789         }
790
791         if (g_atomic_int_dec_and_test(&technology->enabled) == TRUE) {
792                 __connman_notifier_disable(type);
793
794                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
795                 state_changed(technology);
796         }
797
798         for (list = technology->device_list; list; list = list->next) {
799                 struct connman_device *device = list->data;
800
801                 if (__connman_device_get_blocked(device) == FALSE)
802                         return 0;
803         }
804
805         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
806         state_changed(technology);
807
808         return 0;
809 }
810
811 int __connman_technology_disable(enum connman_service_type type, DBusMessage *msg)
812 {
813         struct connman_technology *technology;
814         GSList *list;
815         int err = 0;
816         int ret = -ENODEV;
817         DBusMessage *reply;
818
819         DBG("type %d disable", type);
820
821         technology = technology_find(type);
822         if (technology == NULL) {
823                 err = -ENXIO;
824                 goto done;
825         }
826
827         if (technology->pending_reply != NULL) {
828                 err = -EBUSY;
829                 goto done;
830         }
831
832         if (msg != NULL)
833                 technology->pending_reply = dbus_message_ref(msg);
834
835         for (list = technology->device_list; list; list = list->next) {
836                 struct connman_device *device = list->data;
837
838                 err = __connman_device_disable_persistent(device);
839                 if (err == 0)
840                         ret = 0;
841         }
842
843 done:
844         if (ret == 0)
845                 return ret;
846
847         if (msg != NULL) {
848                 if (err == -EINPROGRESS)
849                         technology->pending_timeout = g_timeout_add_seconds(10,
850                                         technology_pending_reply, technology);
851                 else {
852                         reply = __connman_error_failed(msg, -err);
853                         if (reply != NULL)
854                                 g_dbus_send_message(connection, reply);
855                 }
856         }
857
858         return err;
859 }
860
861 static void technology_blocked(struct connman_technology *technology,
862                                 connman_bool_t blocked)
863 {
864         GSList *list;
865
866         for (list = technology->device_list; list; list = list->next) {
867                 struct connman_device *device = list->data;
868
869                 __connman_device_set_blocked(device, blocked);
870         }
871 }
872
873 int __connman_technology_add_rfkill(unsigned int index,
874                                         enum connman_service_type type,
875                                                 connman_bool_t softblock,
876                                                 connman_bool_t hardblock)
877 {
878         struct connman_technology *technology;
879         struct connman_rfkill *rfkill;
880         connman_bool_t blocked;
881
882         DBG("index %u type %d soft %u hard %u", index, type,
883                                                         softblock, hardblock);
884
885         technology = technology_get(type);
886         if (technology == NULL)
887                 return -ENXIO;
888
889         rfkill = g_try_new0(struct connman_rfkill, 1);
890         if (rfkill == NULL)
891                 return -ENOMEM;
892
893         rfkill->index = index;
894         rfkill->type = type;
895         rfkill->softblock = softblock;
896         rfkill->hardblock = hardblock;
897
898         g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
899
900         blocked = (softblock || hardblock) ? TRUE : FALSE;
901         if (blocked == FALSE)
902                 return 0;
903
904         if (g_atomic_int_exchange_and_add(&technology->blocked, 1) == 0) {
905                 technology_blocked(technology, TRUE);
906
907                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
908                 state_changed(technology);
909         }
910
911         return 0;
912 }
913
914 int __connman_technology_update_rfkill(unsigned int index,
915                                         enum connman_service_type type,
916                                                 connman_bool_t softblock,
917                                                 connman_bool_t hardblock)
918 {
919         struct connman_technology *technology;
920         struct connman_rfkill *rfkill;
921         connman_bool_t blocked, old_blocked;
922
923         DBG("index %u soft %u hard %u", index, softblock, hardblock);
924
925         technology = technology_find(type);
926         if (technology == NULL)
927                 return -ENXIO;
928
929         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
930         if (rfkill == NULL)
931                 return -ENXIO;
932
933         old_blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
934         blocked = (softblock || hardblock) ? TRUE : FALSE;
935
936         rfkill->softblock = softblock;
937         rfkill->hardblock = hardblock;
938
939         if (blocked == old_blocked)
940                 return 0;
941
942         if (blocked) {
943                 guint n_blocked;
944
945                 n_blocked =
946                         g_atomic_int_exchange_and_add(&technology->blocked, 1);
947                 if (n_blocked != g_hash_table_size(technology->rfkill_list) - 1)
948                         return 0;
949
950                 technology_blocked(technology, blocked);
951                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
952                 state_changed(technology);
953         } else {
954                 if (g_atomic_int_dec_and_test(&technology->blocked) == FALSE)
955                         return 0;
956
957                 technology_blocked(technology, blocked);
958                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
959                 state_changed(technology);
960         }
961
962         return 0;
963 }
964
965 int __connman_technology_remove_rfkill(unsigned int index,
966                                         enum connman_service_type type)
967 {
968         struct connman_technology *technology;
969         struct connman_rfkill *rfkill;
970         connman_bool_t blocked;
971
972         DBG("index %u", index);
973
974         technology = technology_find(type);
975         if (technology == NULL)
976                 return -ENXIO;
977
978         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
979         if (rfkill == NULL)
980                 return -ENXIO;
981
982         blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
983
984         g_hash_table_remove(technology->rfkill_list, &index);
985
986         if (blocked &&
987                 g_atomic_int_dec_and_test(&technology->blocked) == TRUE) {
988                 technology_blocked(technology, FALSE);
989                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
990                 state_changed(technology);
991         }
992
993         return 0;
994 }
995
996 connman_bool_t __connman_technology_get_blocked(enum connman_service_type type)
997 {
998         struct connman_technology *technology;
999
1000         technology = technology_find(type);
1001         if (technology == NULL)
1002                 return FALSE;
1003
1004         if (g_atomic_int_get(&technology->blocked))
1005                 return TRUE;
1006
1007         return FALSE;
1008 }
1009
1010 int __connman_technology_init(void)
1011 {
1012         DBG("");
1013
1014         connection = connman_dbus_get_connection();
1015
1016         return 0;
1017 }
1018
1019 void __connman_technology_cleanup(void)
1020 {
1021         DBG("");
1022
1023         dbus_connection_unref(connection);
1024 }