technology: Remove global rfkill table
[framework/connectivity/connman.git] / src / technology.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection;
34
35 static 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_ENABLED   = 3,
50         CONNMAN_TECHNOLOGY_STATE_CONNECTED = 4,
51 };
52
53 struct connman_technology {
54         gint refcount;
55         enum connman_service_type type;
56         enum connman_technology_state state;
57         char *path;
58         GHashTable *rfkill_list;
59         GSList *device_list;
60         gint enabled;
61         gint blocked;
62         char *regdom;
63
64         connman_bool_t tethering;
65         char *tethering_ident;
66         char *tethering_passphrase;
67
68         struct connman_technology_driver *driver;
69         void *driver_data;
70
71         DBusMessage *pending_reply;
72         guint pending_timeout;
73 };
74
75 static GSList *driver_list = NULL;
76
77 static gint compare_priority(gconstpointer a, gconstpointer b)
78 {
79         const struct connman_technology_driver *driver1 = a;
80         const struct connman_technology_driver *driver2 = b;
81
82         return driver2->priority - driver1->priority;
83 }
84
85 /**
86  * connman_technology_driver_register:
87  * @driver: Technology driver definition
88  *
89  * Register a new technology driver
90  *
91  * Returns: %0 on success
92  */
93 int connman_technology_driver_register(struct connman_technology_driver *driver)
94 {
95         GSList *list;
96         struct connman_technology *technology;
97
98         DBG("driver %p name %s", driver, driver->name);
99
100         driver_list = g_slist_insert_sorted(driver_list, driver,
101                                                         compare_priority);
102
103         for (list = technology_list; list; list = list->next) {
104                 technology = list->data;
105
106                 if (technology->driver != NULL)
107                         continue;
108
109                 if (technology->type == driver->type)
110                         technology->driver = driver;
111         }
112
113         return 0;
114 }
115
116 /**
117  * connman_technology_driver_unregister:
118  * @driver: Technology driver definition
119  *
120  * Remove a previously registered technology driver
121  */
122 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
123 {
124         GSList *list;
125         struct connman_technology *technology;
126
127         DBG("driver %p name %s", driver, driver->name);
128
129         for (list = technology_list; list; list = list->next) {
130                 technology = list->data;
131
132                 if (technology->driver == NULL)
133                         continue;
134
135                 if (technology->type == driver->type) {
136                         technology->driver->remove(technology);
137                         technology->driver = NULL;
138                 }
139         }
140
141         driver_list = g_slist_remove(driver_list, driver);
142 }
143
144 static void tethering_changed(struct connman_technology *technology)
145 {
146         connman_bool_t tethering = technology->tethering;
147
148         connman_dbus_property_changed_basic(technology->path,
149                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
150                                                 DBUS_TYPE_BOOLEAN, &tethering);
151 }
152
153 void connman_technology_tethering_notify(struct connman_technology *technology,
154                                                         connman_bool_t enabled)
155 {
156         DBG("technology %p enabled %u", technology, enabled);
157
158         if (technology->tethering == enabled)
159                 return;
160
161         technology->tethering = enabled;
162
163         tethering_changed(technology);
164
165         if (enabled == TRUE)
166                 __connman_tethering_set_enabled();
167         else
168                 __connman_tethering_set_disabled();
169 }
170
171 static int set_tethering(struct connman_technology *technology,
172                                 const char *bridge, connman_bool_t enabled)
173 {
174         const char *ident, *passphrase;
175
176         ident = technology->tethering_ident;
177         passphrase = technology->tethering_passphrase;
178
179         if (technology->driver == NULL ||
180                         technology->driver->set_tethering == NULL)
181                 return -EOPNOTSUPP;
182
183         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
184             (ident == NULL || passphrase == NULL))
185                 return -EINVAL;
186
187         return technology->driver->set_tethering(technology, ident, passphrase,
188                                                         bridge, enabled);
189 }
190
191 void connman_technology_regdom_notify(struct connman_technology *technology,
192                                                         const char *alpha2)
193 {
194         DBG("");
195
196         if (alpha2 == NULL)
197                 connman_error("Failed to set regulatory domain");
198         else
199                 DBG("Regulatory domain set to %s", alpha2);
200
201         g_free(technology->regdom);
202         technology->regdom = g_strdup(alpha2);
203 }
204
205 int connman_technology_set_regdom(const char *alpha2)
206 {
207         GSList *list;
208
209         for (list = technology_list; list; list = list->next) {
210                 struct connman_technology *technology = list->data;
211
212                 if (technology->driver == NULL)
213                         continue;
214
215                 if (technology->driver->set_regdom)
216                         technology->driver->set_regdom(technology, alpha2);
217         }
218
219         return 0;
220 }
221
222 static void free_rfkill(gpointer data)
223 {
224         struct connman_rfkill *rfkill = data;
225
226         g_free(rfkill);
227 }
228
229 void __connman_technology_list(DBusMessageIter *iter, void *user_data)
230 {
231         GSList *list;
232
233         for (list = technology_list; list; list = list->next) {
234                 struct connman_technology *technology = list->data;
235
236                 if (technology->path == NULL)
237                         continue;
238
239                 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
240                                                         &technology->path);
241         }
242 }
243
244 static void technologies_changed(void)
245 {
246         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
247                         CONNMAN_MANAGER_INTERFACE, "Technologies",
248                         DBUS_TYPE_OBJECT_PATH, __connman_technology_list, NULL);
249 }
250
251 static const char *state2string(enum connman_technology_state state)
252 {
253         switch (state) {
254         case CONNMAN_TECHNOLOGY_STATE_UNKNOWN:
255                 break;
256         case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
257                 return "offline";
258         case CONNMAN_TECHNOLOGY_STATE_AVAILABLE:
259                 return "available";
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->pending_reply = NULL;
485         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
486
487         if (g_dbus_register_interface(connection, technology->path,
488                                         CONNMAN_TECHNOLOGY_INTERFACE,
489                                         technology_methods, technology_signals,
490                                         NULL, technology, NULL) == FALSE) {
491                 connman_error("Failed to register %s", technology->path);
492                 g_free(technology);
493                 return NULL;
494         }
495
496         technology_list = g_slist_append(technology_list, technology);
497
498         technologies_changed();
499
500         if (technology->driver != NULL)
501                 goto done;
502
503         for (list = driver_list; list; list = list->next) {
504                 struct connman_technology_driver *driver = list->data;
505
506                 DBG("driver %p name %s", driver, driver->name);
507
508                 if (driver->type != technology->type)
509                         continue;
510
511                 if (driver->probe(technology) == 0) {
512                         technology->driver = driver;
513                         break;
514                 }
515         }
516
517 done:
518         DBG("technology %p", technology);
519
520         return technology;
521 }
522
523 static void technology_put(struct connman_technology *technology)
524 {
525         DBG("technology %p", technology);
526
527         if (g_atomic_int_dec_and_test(&technology->refcount) == FALSE)
528                 return;
529
530         if (technology->driver) {
531                 technology->driver->remove(technology);
532                 technology->driver = NULL;
533         }
534
535         technology_list = g_slist_remove(technology_list, technology);
536
537         technologies_changed();
538
539         g_dbus_unregister_interface(connection, technology->path,
540                                                 CONNMAN_TECHNOLOGY_INTERFACE);
541
542         g_slist_free(technology->device_list);
543         g_hash_table_destroy(technology->rfkill_list);
544
545         g_free(technology->path);
546         g_free(technology->regdom);
547         g_free(technology);
548 }
549
550 void __connman_technology_add_interface(enum connman_service_type type,
551                                 int index, const char *name, const char *ident)
552 {
553         struct connman_technology *technology;
554
555         switch (type) {
556         case CONNMAN_SERVICE_TYPE_UNKNOWN:
557         case CONNMAN_SERVICE_TYPE_SYSTEM:
558                 return;
559         case CONNMAN_SERVICE_TYPE_ETHERNET:
560         case CONNMAN_SERVICE_TYPE_WIFI:
561         case CONNMAN_SERVICE_TYPE_WIMAX:
562         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
563         case CONNMAN_SERVICE_TYPE_CELLULAR:
564         case CONNMAN_SERVICE_TYPE_GPS:
565         case CONNMAN_SERVICE_TYPE_VPN:
566         case CONNMAN_SERVICE_TYPE_GADGET:
567                 break;
568         }
569
570         connman_info("Create interface %s [ %s ]", name,
571                                 __connman_service_type2string(type));
572
573         technology = technology_get(type);
574
575         if (technology == NULL || technology->driver == NULL
576                         || technology->driver->add_interface == NULL)
577                 return;
578
579         technology->driver->add_interface(technology,
580                                         index, name, ident);
581 }
582
583 void __connman_technology_remove_interface(enum connman_service_type type,
584                                 int index, const char *name, const char *ident)
585 {
586         struct connman_technology *technology;
587
588         switch (type) {
589         case CONNMAN_SERVICE_TYPE_UNKNOWN:
590         case CONNMAN_SERVICE_TYPE_SYSTEM:
591                 return;
592         case CONNMAN_SERVICE_TYPE_ETHERNET:
593         case CONNMAN_SERVICE_TYPE_WIFI:
594         case CONNMAN_SERVICE_TYPE_WIMAX:
595         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
596         case CONNMAN_SERVICE_TYPE_CELLULAR:
597         case CONNMAN_SERVICE_TYPE_GPS:
598         case CONNMAN_SERVICE_TYPE_VPN:
599         case CONNMAN_SERVICE_TYPE_GADGET:
600                 break;
601         }
602
603         connman_info("Remove interface %s [ %s ]", name,
604                                 __connman_service_type2string(type));
605
606         technology = technology_find(type);
607
608         if (technology == NULL || technology->driver == NULL)
609                 return;
610
611         if (technology->driver->remove_interface)
612                 technology->driver->remove_interface(technology, index);
613
614         technology_put(technology);
615 }
616
617 static void unregister_technology(gpointer data)
618 {
619         struct connman_technology *technology = data;
620
621         technology_put(technology);
622 }
623
624 int __connman_technology_add_device(struct connman_device *device)
625 {
626         struct connman_technology *technology;
627         enum connman_service_type type;
628
629         DBG("device %p", device);
630
631         type = __connman_device_get_service_type(device);
632         __connman_notifier_register(type);
633
634         technology = technology_get(type);
635         if (technology == NULL)
636                 return -ENXIO;
637
638         g_hash_table_insert(device_table, device, technology);
639
640         if (g_atomic_int_get(&technology->blocked))
641                 goto done;
642
643         technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
644
645         state_changed(technology);
646
647 done:
648
649         technology->device_list = g_slist_append(technology->device_list,
650                                                                 device);
651
652         return 0;
653 }
654
655 int __connman_technology_remove_device(struct connman_device *device)
656 {
657         struct connman_technology *technology;
658         enum connman_service_type type;
659
660         DBG("device %p", device);
661
662         type = __connman_device_get_service_type(device);
663         __connman_notifier_unregister(type);
664
665         technology = g_hash_table_lookup(device_table, device);
666         if (technology == NULL)
667                 return -ENXIO;
668
669         technology->device_list = g_slist_remove(technology->device_list,
670                                                                 device);
671         if (technology->device_list == NULL) {
672                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
673                 state_changed(technology);
674         }
675
676         g_hash_table_remove(device_table, device);
677
678         return 0;
679 }
680
681 static gboolean technology_pending_reply(gpointer user_data)
682 {
683         struct connman_technology *technology = user_data;
684         DBusMessage *reply;
685
686         /* Power request timedout, send ETIMEDOUT. */
687         if (technology->pending_reply != NULL) {
688                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
689                 if (reply != NULL)
690                         g_dbus_send_message(connection, reply);
691
692                 dbus_message_unref(technology->pending_reply);
693                 technology->pending_reply = NULL;
694                 technology->pending_timeout = 0;
695         }
696
697         return FALSE;
698 }
699
700 int __connman_technology_enabled(enum connman_service_type type)
701 {
702         struct connman_technology *technology;
703
704         technology = technology_find(type);
705         if (technology == NULL)
706                 return -ENXIO;
707
708         if (g_atomic_int_get(&technology->blocked))
709                 return -ERFKILL;
710
711         __connman_notifier_enable(type);
712
713         if (g_atomic_int_exchange_and_add(&technology->enabled, 1) == 0) {
714                 technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
715                 state_changed(technology);
716         }
717
718         if (__connman_profile_get_offlinemode() == TRUE) {
719                 __connman_profile_set_offlinemode(FALSE, FALSE);
720                 __connman_profile_save_default();
721         }
722
723         if (technology->pending_reply != NULL) {
724                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
725                 dbus_message_unref(technology->pending_reply);
726                 technology->pending_reply = NULL;
727                 technology->pending_timeout = 0;
728         }
729
730         return 0;
731 }
732
733 int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg)
734 {
735         struct connman_technology *technology;
736         GSList *list;
737         int err = 0;
738         int ret = -ENODEV;
739         DBusMessage *reply;
740
741         DBG("type %d enable", type);
742
743         technology = technology_find(type);
744         if (technology == NULL) {
745                 err = -ENXIO;
746                 goto done;
747         }
748
749         if (technology->pending_reply != NULL) {
750                 err = -EBUSY;
751                 goto done;
752         }
753
754         if (msg != NULL)
755                 technology->pending_reply = dbus_message_ref(msg);
756
757         for (list = technology->device_list; list; list = list->next) {
758                 struct connman_device *device = list->data;
759
760                 err = __connman_device_enable_persistent(device);
761                 /*
762                  * err = 0 : Device was enabled right away.
763                  * If atleast one device gets enabled, we consider
764                  * the technology to be enabled.
765                  */
766                 if (err == 0)
767                         ret = 0;
768         }
769
770 done:
771         if (ret == 0)
772                 return ret;
773
774         if (msg != NULL) {
775                 if (err == -EINPROGRESS)
776                         technology->pending_timeout = g_timeout_add_seconds(10,
777                                         technology_pending_reply, technology);
778                 else {
779                         reply = __connman_error_failed(msg, -err);
780                         if (reply != NULL)
781                                 g_dbus_send_message(connection, reply);
782                 }
783         }
784
785         return err;
786 }
787
788 int __connman_technology_disabled(enum connman_service_type type)
789 {
790         struct connman_technology *technology;
791         GSList *list;
792
793         technology = technology_find(type);
794         if (technology == NULL)
795                 return -ENXIO;
796
797         if (technology->pending_reply != NULL) {
798                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
799                 dbus_message_unref(technology->pending_reply);
800                 technology->pending_reply = NULL;
801         }
802
803         if (g_atomic_int_dec_and_test(&technology->enabled) == TRUE) {
804                 __connman_notifier_disable(type);
805
806                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
807                 state_changed(technology);
808         }
809
810         for (list = technology->device_list; list; list = list->next) {
811                 struct connman_device *device = list->data;
812
813                 if (__connman_device_get_blocked(device) == FALSE)
814                         return 0;
815         }
816
817         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
818         state_changed(technology);
819
820         return 0;
821 }
822
823 int __connman_technology_disable(enum connman_service_type type, DBusMessage *msg)
824 {
825         struct connman_technology *technology;
826         GSList *list;
827         int err = 0;
828         int ret = -ENODEV;
829         DBusMessage *reply;
830
831         DBG("type %d disable", type);
832
833         technology = technology_find(type);
834         if (technology == NULL) {
835                 err = -ENXIO;
836                 goto done;
837         }
838
839         if (technology->pending_reply != NULL) {
840                 err = -EBUSY;
841                 goto done;
842         }
843
844         if (msg != NULL)
845                 technology->pending_reply = dbus_message_ref(msg);
846
847         for (list = technology->device_list; list; list = list->next) {
848                 struct connman_device *device = list->data;
849
850                 err = __connman_device_disable_persistent(device);
851                 if (err == 0)
852                         ret = 0;
853         }
854
855 done:
856         if (ret == 0)
857                 return ret;
858
859         if (msg != NULL) {
860                 if (err == -EINPROGRESS)
861                         technology->pending_timeout = g_timeout_add_seconds(10,
862                                         technology_pending_reply, technology);
863                 else {
864                         reply = __connman_error_failed(msg, -err);
865                         if (reply != NULL)
866                                 g_dbus_send_message(connection, reply);
867                 }
868         }
869
870         return err;
871 }
872
873 static void technology_blocked(struct connman_technology *technology,
874                                 connman_bool_t blocked)
875 {
876         GSList *list;
877
878         for (list = technology->device_list; list; list = list->next) {
879                 struct connman_device *device = list->data;
880
881                 __connman_device_set_blocked(device, blocked);
882         }
883 }
884
885 int __connman_technology_add_rfkill(unsigned int index,
886                                         enum connman_service_type type,
887                                                 connman_bool_t softblock,
888                                                 connman_bool_t hardblock)
889 {
890         struct connman_technology *technology;
891         struct connman_rfkill *rfkill;
892         connman_bool_t blocked;
893
894         DBG("index %u type %d soft %u hard %u", index, type,
895                                                         softblock, hardblock);
896
897         technology = technology_get(type);
898         if (technology == NULL)
899                 return -ENXIO;
900
901         rfkill = g_try_new0(struct connman_rfkill, 1);
902         if (rfkill == NULL)
903                 return -ENOMEM;
904
905         rfkill->index = index;
906         rfkill->type = type;
907         rfkill->softblock = softblock;
908         rfkill->hardblock = hardblock;
909
910         g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
911
912         blocked = (softblock || hardblock) ? TRUE : FALSE;
913         if (blocked == FALSE)
914                 return 0;
915
916         if (g_atomic_int_exchange_and_add(&technology->blocked, 1) == 0) {
917                 technology_blocked(technology, TRUE);
918
919                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
920                 state_changed(technology);
921         }
922
923         return 0;
924 }
925
926 int __connman_technology_update_rfkill(unsigned int index,
927                                         enum connman_service_type type,
928                                                 connman_bool_t softblock,
929                                                 connman_bool_t hardblock)
930 {
931         struct connman_technology *technology;
932         struct connman_rfkill *rfkill;
933         connman_bool_t blocked, old_blocked;
934
935         DBG("index %u soft %u hard %u", index, softblock, hardblock);
936
937         technology = technology_find(type);
938         if (technology == NULL)
939                 return -ENXIO;
940
941         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
942         if (rfkill == NULL)
943                 return -ENXIO;
944
945         old_blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
946         blocked = (softblock || hardblock) ? TRUE : FALSE;
947
948         rfkill->softblock = softblock;
949         rfkill->hardblock = hardblock;
950
951         if (blocked == old_blocked)
952                 return 0;
953
954         if (blocked) {
955                 guint n_blocked;
956
957                 n_blocked =
958                         g_atomic_int_exchange_and_add(&technology->blocked, 1);
959                 if (n_blocked != g_hash_table_size(technology->rfkill_list) - 1)
960                         return 0;
961
962                 technology_blocked(technology, blocked);
963                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
964                 state_changed(technology);
965         } else {
966                 if (g_atomic_int_dec_and_test(&technology->blocked) == FALSE)
967                         return 0;
968
969                 technology_blocked(technology, blocked);
970                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
971                 state_changed(technology);
972         }
973
974         return 0;
975 }
976
977 int __connman_technology_remove_rfkill(unsigned int index,
978                                         enum connman_service_type type)
979 {
980         struct connman_technology *technology;
981         struct connman_rfkill *rfkill;
982         connman_bool_t blocked;
983
984         DBG("index %u", index);
985
986         technology = technology_find(type);
987         if (technology == NULL)
988                 return -ENXIO;
989
990         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
991         if (rfkill == NULL)
992                 return -ENXIO;
993
994         blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
995
996         g_hash_table_remove(technology->rfkill_list, &index);
997
998         if (blocked &&
999                 g_atomic_int_dec_and_test(&technology->blocked) == TRUE) {
1000                 technology_blocked(technology, FALSE);
1001                 technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
1002                 state_changed(technology);
1003         }
1004
1005         return 0;
1006 }
1007
1008 connman_bool_t __connman_technology_get_blocked(enum connman_service_type type)
1009 {
1010         struct connman_technology *technology;
1011
1012         technology = technology_find(type);
1013         if (technology == NULL)
1014                 return FALSE;
1015
1016         if (g_atomic_int_get(&technology->blocked))
1017                 return TRUE;
1018
1019         return FALSE;
1020 }
1021
1022 int __connman_technology_init(void)
1023 {
1024         DBG("");
1025
1026         connection = connman_dbus_get_connection();
1027
1028         device_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1029                                                 NULL, unregister_technology);
1030
1031         return 0;
1032 }
1033
1034 void __connman_technology_cleanup(void)
1035 {
1036         DBG("");
1037
1038         g_hash_table_destroy(device_table);
1039
1040         dbus_connection_unref(connection);
1041 }