2a48698888e3c232f809214efe262b000bdaf6f8
[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 <string.h>
27
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 static DBusConnection *connection;
33
34 static GHashTable *rfkill_table;
35 static GHashTable *device_table;
36 static GSList *technology_list = NULL;
37
38 struct connman_rfkill {
39         unsigned int index;
40         enum connman_service_type type;
41         connman_bool_t softblock;
42         connman_bool_t hardblock;
43 };
44
45 enum connman_technology_state {
46         CONNMAN_TECHNOLOGY_STATE_UNKNOWN   = 0,
47         CONNMAN_TECHNOLOGY_STATE_OFFLINE   = 1,
48         CONNMAN_TECHNOLOGY_STATE_AVAILABLE = 2,
49         CONNMAN_TECHNOLOGY_STATE_BLOCKED   = 3,
50         CONNMAN_TECHNOLOGY_STATE_ENABLED   = 4,
51         CONNMAN_TECHNOLOGY_STATE_CONNECTED = 5,
52 };
53
54 struct connman_technology {
55         gint refcount;
56         enum connman_service_type type;
57         enum connman_technology_state state;
58         char *path;
59         GHashTable *rfkill_list;
60         GSList *device_list;
61         gint enabled;
62         gint blocked;
63         char *regdom;
64
65         connman_bool_t tethering;
66         char *tethering_ident;
67         char *tethering_passphrase;
68
69         struct connman_technology_driver *driver;
70         void *driver_data;
71 };
72
73 static GSList *driver_list = NULL;
74
75 static gint compare_priority(gconstpointer a, gconstpointer b)
76 {
77         const struct connman_technology_driver *driver1 = a;
78         const struct connman_technology_driver *driver2 = b;
79
80         return driver2->priority - driver1->priority;
81 }
82
83 /**
84  * connman_technology_driver_register:
85  * @driver: Technology driver definition
86  *
87  * Register a new technology driver
88  *
89  * Returns: %0 on success
90  */
91 int connman_technology_driver_register(struct connman_technology_driver *driver)
92 {
93         GSList *list;
94         struct connman_technology *technology;
95
96         DBG("driver %p name %s", driver, driver->name);
97
98         driver_list = g_slist_insert_sorted(driver_list, driver,
99                                                         compare_priority);
100
101         for (list = technology_list; list; list = list->next) {
102                 technology = list->data;
103
104                 if (technology->driver != NULL)
105                         continue;
106
107                 if (technology->type == driver->type)
108                         technology->driver = driver;
109         }
110
111         return 0;
112 }
113
114 /**
115  * connman_technology_driver_unregister:
116  * @driver: Technology driver definition
117  *
118  * Remove a previously registered technology driver
119  */
120 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
121 {
122         GSList *list;
123         struct connman_technology *technology;
124
125         DBG("driver %p name %s", driver, driver->name);
126
127         for (list = technology_list; list; list = list->next) {
128                 technology = list->data;
129
130                 if (technology->driver == NULL)
131                         continue;
132
133                 if (technology->type == driver->type) {
134                         technology->driver->remove(technology);
135                         technology->driver = NULL;
136                 }
137         }
138
139         driver_list = g_slist_remove(driver_list, driver);
140 }
141
142 static void tethering_changed(struct connman_technology *technology)
143 {
144         connman_bool_t tethering = technology->tethering;
145
146         connman_dbus_property_changed_basic(technology->path,
147                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
148                                                 DBUS_TYPE_BOOLEAN, &tethering);
149 }
150
151 void connman_technology_tethering_notify(struct connman_technology *technology,
152                                                         connman_bool_t enabled)
153 {
154         DBG("technology %p enabled %u", technology, enabled);
155
156         if (technology->tethering == enabled)
157                 return;
158
159         technology->tethering = enabled;
160
161         tethering_changed(technology);
162
163         if (enabled == TRUE)
164                 __connman_tethering_set_enabled();
165         else
166                 __connman_tethering_set_disabled();
167 }
168
169 static int set_tethering(struct connman_technology *technology,
170                                 const char *bridge, connman_bool_t enabled)
171 {
172         const char *ident, *passphrase;
173
174         ident = technology->tethering_ident;
175         passphrase = technology->tethering_passphrase;
176
177         if (technology->driver == NULL ||
178                         technology->driver->set_tethering == NULL)
179                 return -EOPNOTSUPP;
180
181         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
182             (ident == NULL || passphrase == NULL))
183                 return -EINVAL;
184
185         return technology->driver->set_tethering(technology, ident, passphrase,
186                                                         bridge, enabled);
187 }
188
189 void connman_technology_regdom_notify(struct connman_technology *technology,
190                                                         const char *alpha2)
191 {
192         DBG("");
193
194         if (alpha2 == NULL)
195                 connman_error("Failed to set regulatory domain");
196         else
197                 DBG("Regulatory domain set to %s", alpha2);
198
199         g_free(technology->regdom);
200         technology->regdom = g_strdup(alpha2);
201 }
202
203 int connman_technology_set_regdom(const char *alpha2)
204 {
205         GSList *list;
206
207         for (list = technology_list; list; list = list->next) {
208                 struct connman_technology *technology = list->data;
209
210                 if (technology->driver == NULL)
211                         continue;
212
213                 if (technology->driver->set_regdom)
214                         technology->driver->set_regdom(technology, alpha2);
215         }
216
217         return 0;
218 }
219
220 static void free_rfkill(gpointer data)
221 {
222         struct connman_rfkill *rfkill = data;
223
224         g_free(rfkill);
225 }
226
227 void __connman_technology_list(DBusMessageIter *iter, void *user_data)
228 {
229         GSList *list;
230
231         for (list = technology_list; list; list = list->next) {
232                 struct connman_technology *technology = list->data;
233
234                 if (technology->path == NULL)
235                         continue;
236
237                 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
238                                                         &technology->path);
239         }
240 }
241
242 static void technologies_changed(void)
243 {
244         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
245                         CONNMAN_MANAGER_INTERFACE, "Technologies",
246                         DBUS_TYPE_OBJECT_PATH, __connman_technology_list, NULL);
247 }
248
249 static const char *state2string(enum connman_technology_state state)
250 {
251         switch (state) {
252         case CONNMAN_TECHNOLOGY_STATE_UNKNOWN:
253                 break;
254         case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
255                 return "offline";
256         case CONNMAN_TECHNOLOGY_STATE_AVAILABLE:
257                 return "available";
258         case CONNMAN_TECHNOLOGY_STATE_BLOCKED:
259                 return "blocked";
260         case CONNMAN_TECHNOLOGY_STATE_ENABLED:
261                 return "enabled";
262         case CONNMAN_TECHNOLOGY_STATE_CONNECTED:
263                 return "connected";
264         }
265
266         return NULL;
267 }
268
269 static void state_changed(struct connman_technology *technology)
270 {
271         const char *str;
272
273         str = state2string(technology->state);
274         if (str == NULL)
275                 return;
276
277         connman_dbus_property_changed_basic(technology->path,
278                                 CONNMAN_TECHNOLOGY_INTERFACE, "State",
279                                                 DBUS_TYPE_STRING, &str);
280 }
281
282 static const char *get_name(enum connman_service_type type)
283 {
284         switch (type) {
285         case CONNMAN_SERVICE_TYPE_UNKNOWN:
286         case CONNMAN_SERVICE_TYPE_SYSTEM:
287         case CONNMAN_SERVICE_TYPE_GPS:
288         case CONNMAN_SERVICE_TYPE_VPN:
289         case CONNMAN_SERVICE_TYPE_GADGET:
290                 break;
291         case CONNMAN_SERVICE_TYPE_ETHERNET:
292                 return "Wired";
293         case CONNMAN_SERVICE_TYPE_WIFI:
294                 return "WiFi";
295         case CONNMAN_SERVICE_TYPE_WIMAX:
296                 return "WiMAX";
297         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
298                 return "Bluetooth";
299         case CONNMAN_SERVICE_TYPE_CELLULAR:
300                 return "3G";
301         }
302
303         return NULL;
304 }
305
306 static DBusMessage *get_properties(DBusConnection *conn,
307                                         DBusMessage *message, void *user_data)
308 {
309         struct connman_technology *technology = user_data;
310         DBusMessage *reply;
311         DBusMessageIter array, dict;
312         const char *str;
313
314         reply = dbus_message_new_method_return(message);
315         if (reply == NULL)
316                 return NULL;
317
318         dbus_message_iter_init_append(reply, &array);
319
320         connman_dbus_dict_open(&array, &dict);
321
322         str = state2string(technology->state);
323         if (str != NULL)
324                 connman_dbus_dict_append_basic(&dict, "State",
325                                                 DBUS_TYPE_STRING, &str);
326
327         str = get_name(technology->type);
328         if (str != NULL)
329                 connman_dbus_dict_append_basic(&dict, "Name",
330                                                 DBUS_TYPE_STRING, &str);
331
332         str = __connman_service_type2string(technology->type);
333         if (str != NULL)
334                 connman_dbus_dict_append_basic(&dict, "Type",
335                                                 DBUS_TYPE_STRING, &str);
336
337         connman_dbus_dict_append_basic(&dict, "Tethering",
338                                         DBUS_TYPE_BOOLEAN,
339                                         &technology->tethering);
340
341         if (technology->tethering_ident != NULL)
342                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
343                                                 DBUS_TYPE_STRING,
344                                                 &technology->tethering_ident);
345
346         if (technology->tethering_passphrase != NULL)
347                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
348                                                 DBUS_TYPE_STRING,
349                                                 &technology->tethering_passphrase);
350
351         connman_dbus_dict_close(&array, &dict);
352
353         return reply;
354 }
355
356 static DBusMessage *set_property(DBusConnection *conn,
357                                         DBusMessage *msg, void *data)
358 {
359         struct connman_technology *technology = data;
360         DBusMessageIter iter, value;
361         const char *name;
362         int type;
363
364         DBG("conn %p", conn);
365
366         if (dbus_message_iter_init(msg, &iter) == FALSE)
367                 return __connman_error_invalid_arguments(msg);
368
369         dbus_message_iter_get_basic(&iter, &name);
370         dbus_message_iter_next(&iter);
371         dbus_message_iter_recurse(&iter, &value);
372
373         type = dbus_message_iter_get_arg_type(&value);
374
375         DBG("property %s", name);
376
377         if (g_str_equal(name, "Tethering") == TRUE) {
378                 int err;
379                 connman_bool_t tethering;
380                 const char *bridge;
381
382                 if (type != DBUS_TYPE_BOOLEAN)
383                         return __connman_error_invalid_arguments(msg);
384
385                 dbus_message_iter_get_basic(&value, &tethering);
386
387                 if (technology->tethering == tethering)
388                         return __connman_error_in_progress(msg);
389
390                 bridge = __connman_tethering_get_bridge();
391                 if (bridge == NULL)
392                         return __connman_error_not_supported(msg);
393
394                 err = set_tethering(technology, bridge, tethering);
395                 if (err < 0)
396                         return __connman_error_failed(msg, -err);
397
398         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
399                 const char *str;
400
401                 dbus_message_iter_get_basic(&value, &str);
402
403                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
404                         return __connman_error_not_supported(msg);
405
406                 technology->tethering_ident = g_strdup(str);
407         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
408                 const char *str;
409
410                 dbus_message_iter_get_basic(&value, &str);
411
412                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
413                         return __connman_error_not_supported(msg);
414
415                 if (strlen(str) < 8)
416                         return __connman_error_invalid_arguments(msg);
417
418                 technology->tethering_passphrase = g_strdup(str);
419         } else
420                 return __connman_error_invalid_property(msg);
421
422         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
423 }
424
425 static GDBusMethodTable technology_methods[] = {
426         { "GetProperties", "",   "a{sv}", get_properties },
427         { "SetProperty",   "sv", "",      set_property   },
428         { },
429 };
430
431 static GDBusSignalTable technology_signals[] = {
432         { "PropertyChanged", "sv" },
433         { },
434 };
435
436 static struct connman_technology *technology_find(enum connman_service_type type)
437 {
438         GSList *list;
439
440         DBG("type %d", type);
441
442         for (list = technology_list; list; list = list->next) {
443                 struct connman_technology *technology = list->data;
444
445                 if (technology->type == type)
446                         return technology;
447         }
448
449         return NULL;
450 }
451
452 static struct connman_technology *technology_get(enum connman_service_type type)
453 {
454         struct connman_technology *technology;
455         const char *str;
456         GSList *list;
457
458         DBG("type %d", type);
459
460         technology = technology_find(type);
461         if (technology != NULL) {
462                 g_atomic_int_inc(&technology->refcount);
463                 goto done;
464         }
465
466         str = __connman_service_type2string(type);
467         if (str == NULL)
468                 return NULL;
469
470         technology = g_try_new0(struct connman_technology, 1);
471         if (technology == NULL)
472                 return NULL;
473
474         technology->refcount = 1;
475
476         technology->type = type;
477         technology->path = g_strdup_printf("%s/technology/%s",
478                                                         CONNMAN_PATH, str);
479
480         technology->rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal,
481                                                         NULL, free_rfkill);
482         technology->device_list = NULL;
483
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 static void unregister_technology(gpointer data)
617 {
618         struct connman_technology *technology = data;
619
620         technology_put(technology);
621 }
622
623 int __connman_technology_add_device(struct connman_device *device)
624 {
625         struct connman_technology *technology;
626         enum connman_service_type type;
627
628         DBG("device %p", device);
629
630         type = __connman_device_get_service_type(device);
631         __connman_notifier_register(type);
632
633         technology = technology_get(type);
634         if (technology == NULL)
635                 return -ENXIO;
636
637         g_hash_table_insert(device_table, device, technology);
638
639         if (g_atomic_int_get(&technology->blocked))
640                 goto done;
641
642         technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
643
644         state_changed(technology);
645
646 done:
647
648         technology->device_list = g_slist_append(technology->device_list,
649                                                                 device);
650
651         return 0;
652 }
653
654 int __connman_technology_remove_device(struct connman_device *device)
655 {
656         struct connman_technology *technology;
657         enum connman_service_type type;
658
659         DBG("device %p", device);
660
661         type = __connman_device_get_service_type(device);
662         __connman_notifier_unregister(type);
663
664         technology = g_hash_table_lookup(device_table, device);
665         if (technology == NULL)
666                 return -ENXIO;
667
668         technology->device_list = g_slist_remove(technology->device_list,
669                                                                 device);
670         if (technology->device_list == NULL) {
671                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
672                 state_changed(technology);
673         }
674
675         g_hash_table_remove(device_table, device);
676
677         return 0;
678 }
679
680 int __connman_technology_enable_device(struct connman_device *device)
681 {
682         struct connman_technology *technology;
683         enum connman_service_type type;
684
685         DBG("device %p", device);
686
687         technology = g_hash_table_lookup(device_table, device);
688         if (technology == NULL)
689                 return -ENXIO;
690
691         if (g_atomic_int_get(&technology->blocked))
692                 return -ERFKILL;
693
694         type = __connman_device_get_service_type(device);
695         __connman_notifier_enable(type);
696
697         if (g_atomic_int_exchange_and_add(&technology->enabled, 1) == 0) {
698                 technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
699                 state_changed(technology);
700         }
701
702         return 0;
703 }
704
705 int __connman_technology_disable_device(struct connman_device *device)
706 {
707         struct connman_technology *technology;
708         enum connman_service_type type;
709         GSList *list;
710
711         DBG("device %p", device);
712
713         type = __connman_device_get_service_type(device);
714         __connman_notifier_disable(type);
715
716         technology = g_hash_table_lookup(device_table, device);
717         if (technology == NULL)
718                 return -ENXIO;
719
720         if (g_atomic_int_dec_and_test(&technology->enabled) == TRUE) {
721                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
722                 state_changed(technology);
723         }
724
725         for (list = technology->device_list; list; list = list->next) {
726                 struct connman_device *device = list->data;
727
728                 if (__connman_device_get_blocked(device) == FALSE)
729                         return 0;
730         }
731
732         technology->state = CONNMAN_TECHNOLOGY_STATE_BLOCKED;
733         state_changed(technology);
734
735         return 0;
736 }
737
738 static void technology_blocked(struct connman_technology *technology,
739                                 connman_bool_t blocked)
740 {
741         GSList *list;
742
743         for (list = technology->device_list; list; list = list->next) {
744                 struct connman_device *device = list->data;
745
746                 __connman_device_set_blocked(device, blocked);
747         }
748 }
749
750 int __connman_technology_add_rfkill(unsigned int index,
751                                         enum connman_service_type type,
752                                                 connman_bool_t softblock,
753                                                 connman_bool_t hardblock)
754 {
755         struct connman_technology *technology;
756         struct connman_rfkill *rfkill;
757         connman_bool_t blocked;
758
759         DBG("index %u type %d soft %u hard %u", index, type,
760                                                         softblock, hardblock);
761
762         technology = technology_get(type);
763         if (technology == NULL)
764                 return -ENXIO;
765
766         rfkill = g_try_new0(struct connman_rfkill, 1);
767         if (rfkill == NULL)
768                 return -ENOMEM;
769
770         rfkill->index = index;
771         rfkill->type = type;
772         rfkill->softblock = softblock;
773         rfkill->hardblock = hardblock;
774
775         g_hash_table_replace(rfkill_table, &rfkill->index, technology);
776
777         g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
778
779         blocked = (softblock || hardblock) ? TRUE : FALSE;
780         if (blocked == FALSE)
781                 return 0;
782
783         if (g_atomic_int_exchange_and_add(&technology->blocked, 1) == 0) {
784                 technology_blocked(technology, TRUE);
785
786                 technology->state = CONNMAN_TECHNOLOGY_STATE_BLOCKED;
787                 state_changed(technology);
788         }
789
790         return 0;
791 }
792
793 int __connman_technology_update_rfkill(unsigned int index,
794                                                 connman_bool_t softblock,
795                                                 connman_bool_t hardblock)
796 {
797         struct connman_technology *technology;
798         struct connman_rfkill *rfkill;
799         connman_bool_t blocked, old_blocked;
800
801         DBG("index %u soft %u hard %u", index, softblock, hardblock);
802
803         technology = g_hash_table_lookup(rfkill_table, &index);
804         if (technology == NULL)
805                 return -ENXIO;
806
807         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
808         if (rfkill == NULL)
809                 return -ENXIO;
810
811         old_blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
812         blocked = (softblock || hardblock) ? TRUE : FALSE;
813
814         rfkill->softblock = softblock;
815         rfkill->hardblock = hardblock;
816
817         if (blocked == old_blocked)
818                 return 0;
819
820         if (blocked) {
821                 guint n_blocked;
822
823                 n_blocked =
824                         g_atomic_int_exchange_and_add(&technology->blocked, 1);
825                 if (n_blocked != g_hash_table_size(technology->rfkill_list) - 1)
826                         return 0;
827
828                 technology_blocked(technology, blocked);
829                 technology->state = CONNMAN_TECHNOLOGY_STATE_BLOCKED;
830                 state_changed(technology);
831         } else {
832                 if (g_atomic_int_dec_and_test(&technology->blocked) == FALSE)
833                         return 0;
834
835                 technology_blocked(technology, blocked);
836                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
837                 state_changed(technology);
838         }
839
840         return 0;
841 }
842
843 int __connman_technology_remove_rfkill(unsigned int index)
844 {
845         struct connman_technology *technology;
846         struct connman_rfkill *rfkill;
847         connman_bool_t blocked;
848
849         DBG("index %u", index);
850
851         technology = g_hash_table_lookup(rfkill_table, &index);
852         if (technology == NULL)
853                 return -ENXIO;
854
855         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
856         if (rfkill == NULL)
857                 return -ENXIO;
858
859         blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
860
861         g_hash_table_remove(technology->rfkill_list, &index);
862
863         g_hash_table_remove(rfkill_table, &index);
864
865         if (blocked &&
866                 g_atomic_int_dec_and_test(&technology->blocked) == TRUE) {
867                 technology_blocked(technology, FALSE);
868                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
869                 state_changed(technology);
870         }
871
872         return 0;
873 }
874
875 connman_bool_t __connman_technology_get_blocked(enum connman_service_type type)
876 {
877         struct connman_technology *technology;
878
879         technology = technology_find(type);
880         if (technology == NULL)
881                 return FALSE;
882
883         if (g_atomic_int_get(&technology->blocked))
884                 return TRUE;
885
886         return FALSE;
887 }
888
889 int __connman_technology_init(void)
890 {
891         DBG("");
892
893         connection = connman_dbus_get_connection();
894
895         rfkill_table = g_hash_table_new_full(g_int_hash, g_int_equal,
896                                                 NULL, unregister_technology);
897         device_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
898                                                 NULL, unregister_technology);
899
900         return 0;
901 }
902
903 void __connman_technology_cleanup(void)
904 {
905         DBG("");
906
907         g_hash_table_destroy(device_table);
908         g_hash_table_destroy(rfkill_table);
909
910         dbus_connection_unref(connection);
911 }