technology: Do not apply Powered setting change if hardblock is on
[platform/upstream/connman.git] / src / technology.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  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 /*
38  * List of devices with no technology associated with them either because of
39  * no compiled in support or the driver is not yet loaded.
40 */
41 static GSList *techless_device_list = NULL;
42 static GHashTable *rfkill_list;
43
44 static connman_bool_t global_offlinemode;
45
46 struct connman_rfkill {
47         unsigned int index;
48         enum connman_service_type type;
49         connman_bool_t softblock;
50         connman_bool_t hardblock;
51 };
52
53 struct connman_technology {
54         int refcount;
55         enum connman_service_type type;
56         char *path;
57         GSList *device_list;
58         int enabled;
59         char *regdom;
60         connman_bool_t connected;
61
62         connman_bool_t tethering;
63         char *tethering_ident;
64         char *tethering_passphrase;
65
66         connman_bool_t enable_persistent; /* Save the tech state */
67
68         struct connman_technology_driver *driver;
69         void *driver_data;
70
71         DBusMessage *pending_reply;
72         guint pending_timeout;
73
74         GSList *scan_pending;
75
76         connman_bool_t hardblocked;
77 };
78
79 static GSList *driver_list = NULL;
80
81 static gint compare_priority(gconstpointer a, gconstpointer b)
82 {
83         const struct connman_technology_driver *driver1 = a;
84         const struct connman_technology_driver *driver2 = b;
85
86         return driver2->priority - driver1->priority;
87 }
88
89 static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
90 {
91         struct connman_rfkill *rfkill = value;
92         enum connman_service_type type = GPOINTER_TO_INT(user_data);
93
94         /* Calling _technology_rfkill_add will update the tech. */
95         if (rfkill->type == type)
96                 __connman_technology_add_rfkill(rfkill->index, type,
97                                 rfkill->softblock, rfkill->hardblock);
98 }
99
100 /**
101  * connman_technology_driver_register:
102  * @driver: Technology driver definition
103  *
104  * Register a new technology driver
105  *
106  * Returns: %0 on success
107  */
108 int connman_technology_driver_register(struct connman_technology_driver *driver)
109 {
110         GSList *list;
111         struct connman_device *device;
112         enum connman_service_type type;
113
114         DBG("Registering %s driver", driver->name);
115
116         driver_list = g_slist_insert_sorted(driver_list, driver,
117                                                         compare_priority);
118
119         if (techless_device_list == NULL)
120                 goto check_rfkill;
121
122         /*
123          * Check for technology less devices if this driver
124          * can service any of them.
125         */
126         for (list = techless_device_list; list; list = list->next) {
127                 device = list->data;
128
129                 type = __connman_device_get_service_type(device);
130                 if (type != driver->type)
131                         continue;
132
133                 techless_device_list = g_slist_remove(techless_device_list,
134                                                                 device);
135
136                 __connman_technology_add_device(device);
137         }
138
139 check_rfkill:
140         /* Check for orphaned rfkill switches. */
141         g_hash_table_foreach(rfkill_list, rfkill_check,
142                                         GINT_TO_POINTER(driver->type));
143
144         return 0;
145 }
146
147 /**
148  * connman_technology_driver_unregister:
149  * @driver: Technology driver definition
150  *
151  * Remove a previously registered technology driver
152  */
153 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
154 {
155         GSList *list;
156         struct connman_technology *technology;
157
158         DBG("Unregistering driver %p name %s", driver, driver->name);
159
160         for (list = technology_list; list; list = list->next) {
161                 technology = list->data;
162
163                 if (technology->driver == NULL)
164                         continue;
165
166                 if (technology->type == driver->type) {
167                         technology->driver->remove(technology);
168                         technology->driver = NULL;
169                 }
170         }
171
172         driver_list = g_slist_remove(driver_list, driver);
173 }
174
175 static void tethering_changed(struct connman_technology *technology)
176 {
177         connman_bool_t tethering = technology->tethering;
178
179         connman_dbus_property_changed_basic(technology->path,
180                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
181                                                 DBUS_TYPE_BOOLEAN, &tethering);
182 }
183
184 void connman_technology_tethering_notify(struct connman_technology *technology,
185                                                         connman_bool_t enabled)
186 {
187         GSList *list;
188
189         DBG("technology %p enabled %u", technology, enabled);
190
191         if (technology->tethering == enabled)
192                 return;
193
194         technology->tethering = enabled;
195
196         tethering_changed(technology);
197
198         if (enabled == TRUE)
199                 __connman_tethering_set_enabled();
200         else {
201                 for (list = technology_list; list; list = list->next) {
202                         struct connman_technology *other_tech = list->data;
203                         if (other_tech->tethering == TRUE)
204                                 break;
205                 }
206                 if (list == NULL)
207                         __connman_tethering_set_disabled();
208         }
209 }
210
211 static int set_tethering(struct connman_technology *technology,
212                                 connman_bool_t enabled)
213 {
214         const char *ident, *passphrase, *bridge;
215
216         ident = technology->tethering_ident;
217         passphrase = technology->tethering_passphrase;
218
219         if (technology->driver == NULL ||
220                         technology->driver->set_tethering == NULL)
221                 return -EOPNOTSUPP;
222
223         bridge = __connman_tethering_get_bridge();
224         if (bridge == NULL)
225                 return -EOPNOTSUPP;
226
227         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
228             (ident == NULL || passphrase == NULL))
229                 return -EINVAL;
230
231         return technology->driver->set_tethering(technology, ident, passphrase,
232                                                         bridge, enabled);
233 }
234
235 void connman_technology_regdom_notify(struct connman_technology *technology,
236                                                         const char *alpha2)
237 {
238         DBG("");
239
240         if (alpha2 == NULL)
241                 connman_error("Failed to set regulatory domain");
242         else
243                 DBG("Regulatory domain set to %s", alpha2);
244
245         g_free(technology->regdom);
246         technology->regdom = g_strdup(alpha2);
247 }
248
249 static int set_regdom_by_device(struct connman_technology *technology,
250                                                         const char *alpha2)
251 {
252         GSList *list;
253
254         for (list = technology->device_list; list; list = list->next) {
255                 struct connman_device *device = list->data;
256
257                 if (connman_device_set_regdom(device, alpha2) != 0)
258                         return -ENOTSUP;
259         }
260
261         return 0;
262 }
263
264 int connman_technology_set_regdom(const char *alpha2)
265 {
266         GSList *list;
267
268         for (list = technology_list; list; list = list->next) {
269                 struct connman_technology *technology = list->data;
270
271                 if (set_regdom_by_device(technology, alpha2) != 0) {
272                         if (technology->driver == NULL)
273                                 continue;
274
275                         if (technology->driver->set_regdom != NULL)
276                                 technology->driver->set_regdom(technology,
277                                                                 alpha2);
278                 }
279         }
280
281         return 0;
282 }
283
284 static void free_rfkill(gpointer data)
285 {
286         struct connman_rfkill *rfkill = data;
287
288         g_free(rfkill);
289 }
290
291 static const char *get_name(enum connman_service_type type)
292 {
293         switch (type) {
294         case CONNMAN_SERVICE_TYPE_UNKNOWN:
295         case CONNMAN_SERVICE_TYPE_SYSTEM:
296         case CONNMAN_SERVICE_TYPE_GPS:
297         case CONNMAN_SERVICE_TYPE_VPN:
298         case CONNMAN_SERVICE_TYPE_GADGET:
299                 break;
300         case CONNMAN_SERVICE_TYPE_ETHERNET:
301                 return "Wired";
302         case CONNMAN_SERVICE_TYPE_WIFI:
303                 return "WiFi";
304         case CONNMAN_SERVICE_TYPE_WIMAX:
305                 return "WiMAX";
306         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
307                 return "Bluetooth";
308         case CONNMAN_SERVICE_TYPE_CELLULAR:
309                 return "Cellular";
310         }
311
312         return NULL;
313 }
314
315 static void technology_save(struct connman_technology *technology)
316 {
317         GKeyFile *keyfile;
318         gchar *identifier;
319
320         DBG("technology %p", technology);
321
322         keyfile = __connman_storage_load_global();
323         if (keyfile == NULL)
324                 keyfile = g_key_file_new();
325
326         identifier = g_strdup_printf("%s", get_name(technology->type));
327         if (identifier == NULL)
328                 goto done;
329
330         g_key_file_set_boolean(keyfile, identifier, "Enable",
331                                 technology->enable_persistent);
332
333         if (technology->tethering_ident != NULL)
334                 g_key_file_set_string(keyfile, identifier,
335                                         "Tethering.Identifier",
336                                         technology->tethering_ident);
337
338         if (technology->tethering_passphrase != NULL)
339                 g_key_file_set_string(keyfile, identifier,
340                                         "Tethering.Passphrase",
341                                         technology->tethering_passphrase);
342
343 done:
344         g_free(identifier);
345
346         __connman_storage_save_global(keyfile);
347
348         g_key_file_free(keyfile);
349
350         return;
351 }
352
353 static void technology_load(struct connman_technology *technology)
354 {
355         GKeyFile *keyfile;
356         gchar *identifier;
357         GError *error = NULL;
358         connman_bool_t enable;
359
360         DBG("technology %p", technology);
361
362         keyfile = __connman_storage_load_global();
363         /* Fallback on disabling technology if file not found. */
364         if (keyfile == NULL) {
365                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
366                         /* We enable ethernet by default */
367                         technology->enable_persistent = TRUE;
368                 else
369                         technology->enable_persistent = FALSE;
370                 return;
371         }
372
373         identifier = g_strdup_printf("%s", get_name(technology->type));
374         if (identifier == NULL)
375                 goto done;
376
377         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
378         if (error == NULL)
379                 technology->enable_persistent = enable;
380         else {
381                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
382                         technology->enable_persistent = TRUE;
383                 else
384                         technology->enable_persistent = FALSE;
385
386                 technology_save(technology);
387                 g_clear_error(&error);
388         }
389
390         technology->tethering_ident = g_key_file_get_string(keyfile,
391                                 identifier, "Tethering.Identifier", NULL);
392
393         technology->tethering_passphrase = g_key_file_get_string(keyfile,
394                                 identifier, "Tethering.Passphrase", NULL);
395 done:
396         g_free(identifier);
397
398         g_key_file_free(keyfile);
399
400         return;
401 }
402
403 connman_bool_t __connman_technology_get_offlinemode(void)
404 {
405         return global_offlinemode;
406 }
407
408 static void connman_technology_save_offlinemode()
409 {
410         GKeyFile *keyfile;
411
412         keyfile = __connman_storage_load_global();
413         if (keyfile == NULL)
414                 keyfile = g_key_file_new();
415
416         g_key_file_set_boolean(keyfile, "global",
417                                         "OfflineMode", global_offlinemode);
418
419         __connman_storage_save_global(keyfile);
420
421         g_key_file_free(keyfile);
422
423         return;
424 }
425
426 static connman_bool_t connman_technology_load_offlinemode()
427 {
428         GKeyFile *keyfile;
429         GError *error = NULL;
430         connman_bool_t offlinemode;
431
432         /* If there is a error, we enable offlinemode */
433         keyfile = __connman_storage_load_global();
434         if (keyfile == NULL)
435                 return FALSE;
436
437         offlinemode = g_key_file_get_boolean(keyfile, "global",
438                                                 "OfflineMode", &error);
439         if (error != NULL) {
440                 offlinemode = FALSE;
441                 g_clear_error(&error);
442         }
443
444         g_key_file_free(keyfile);
445
446         return offlinemode;
447 }
448
449 static void append_properties(DBusMessageIter *iter,
450                 struct connman_technology *technology)
451 {
452         DBusMessageIter dict;
453         const char *str;
454         connman_bool_t powered;
455
456         connman_dbus_dict_open(iter, &dict);
457
458         str = get_name(technology->type);
459         if (str != NULL)
460                 connman_dbus_dict_append_basic(&dict, "Name",
461                                                 DBUS_TYPE_STRING, &str);
462
463         str = __connman_service_type2string(technology->type);
464         if (str != NULL)
465                 connman_dbus_dict_append_basic(&dict, "Type",
466                                                 DBUS_TYPE_STRING, &str);
467
468         __sync_synchronize();
469         if (technology->enabled > 0)
470                 powered = TRUE;
471         else
472                 powered = FALSE;
473         connman_dbus_dict_append_basic(&dict, "Powered",
474                                         DBUS_TYPE_BOOLEAN, &powered);
475
476         connman_dbus_dict_append_basic(&dict, "Connected",
477                                         DBUS_TYPE_BOOLEAN,
478                                         &technology->connected);
479
480         connman_dbus_dict_append_basic(&dict, "Tethering",
481                                         DBUS_TYPE_BOOLEAN,
482                                         &technology->tethering);
483
484         if (technology->tethering_ident != NULL)
485                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
486                                                 DBUS_TYPE_STRING,
487                                                 &technology->tethering_ident);
488
489         if (technology->tethering_passphrase != NULL)
490                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
491                                                 DBUS_TYPE_STRING,
492                                                 &technology->tethering_passphrase);
493
494         connman_dbus_dict_close(iter, &dict);
495 }
496
497 static void technology_added_signal(struct connman_technology *technology)
498 {
499         DBusMessage *signal;
500         DBusMessageIter iter;
501
502         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
503                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
504         if (signal == NULL)
505                 return;
506
507         dbus_message_iter_init_append(signal, &iter);
508         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
509                                                         &technology->path);
510         append_properties(&iter, technology);
511
512         dbus_connection_send(connection, signal, NULL);
513         dbus_message_unref(signal);
514 }
515
516 static void technology_removed_signal(struct connman_technology *technology)
517 {
518         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
519                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
520                         DBUS_TYPE_OBJECT_PATH, &technology->path,
521                         DBUS_TYPE_INVALID);
522 }
523
524 static DBusMessage *get_properties(DBusConnection *conn,
525                                         DBusMessage *message, void *user_data)
526 {
527         struct connman_technology *technology = user_data;
528         DBusMessage *reply;
529         DBusMessageIter iter;
530
531         reply = dbus_message_new_method_return(message);
532         if (reply == NULL)
533                 return NULL;
534
535         dbus_message_iter_init_append(reply, &iter);
536         append_properties(&iter, technology);
537
538         return reply;
539 }
540
541 void __connman_technology_list_struct(DBusMessageIter *array)
542 {
543         GSList *list;
544         DBusMessageIter entry;
545
546         for (list = technology_list; list; list = list->next) {
547                 struct connman_technology *technology = list->data;
548
549                 if (technology->path == NULL)
550                         continue;
551
552                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
553                                 NULL, &entry);
554                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
555                                 &technology->path);
556                 append_properties(&entry, technology);
557                 dbus_message_iter_close_container(array, &entry);
558         }
559 }
560
561 static gboolean technology_pending_reply(gpointer user_data)
562 {
563         struct connman_technology *technology = user_data;
564         DBusMessage *reply;
565
566         /* Power request timedout, send ETIMEDOUT. */
567         if (technology->pending_reply != NULL) {
568                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
569                 if (reply != NULL)
570                         g_dbus_send_message(connection, reply);
571
572                 dbus_message_unref(technology->pending_reply);
573                 technology->pending_reply = NULL;
574                 technology->pending_timeout = 0;
575         }
576
577         return FALSE;
578 }
579
580 static int technology_enable(struct connman_technology *technology,
581                                                 connman_bool_t hardblock)
582 {
583         GSList *list;
584         int err = 0;
585
586         DBG("technology %p enable", technology);
587
588         __sync_synchronize();
589         if (technology->enabled > 0) {
590                 err = -EALREADY;
591                 goto done;
592         }
593
594         if (technology->pending_reply != NULL) {
595                 err = -EBUSY;
596                 goto done;
597         }
598
599         if (hardblock == TRUE && technology->enable_persistent == FALSE)
600                 goto done;
601
602         __connman_rfkill_block(technology->type, FALSE);
603
604         for (list = technology->device_list; list; list = list->next) {
605                 struct connman_device *device = list->data;
606
607                 err = __connman_device_enable(device);
608         }
609
610 done:
611         return err;
612 }
613
614 static int technology_disable(struct connman_technology *technology,
615                                                 connman_bool_t hardblock)
616 {
617         GSList *list;
618         int err = 0;
619
620         DBG("technology %p disable", technology);
621
622         __sync_synchronize();
623         if (technology->enabled == 0) {
624                 err = -EALREADY;
625                 goto done;
626         }
627
628         if (technology->pending_reply != NULL) {
629                 err = -EBUSY;
630                 goto done;
631         }
632
633         if (technology->tethering == TRUE)
634                 set_tethering(technology, FALSE);
635
636         if (hardblock == FALSE)
637                 __connman_rfkill_block(technology->type, TRUE);
638
639         for (list = technology->device_list; list; list = list->next) {
640                 struct connman_device *device = list->data;
641
642                 err = __connman_device_disable(device);
643         }
644
645 done:
646         return err;
647 }
648
649 static DBusMessage *set_powered(struct connman_technology *technology,
650                                 DBusMessage *msg, connman_bool_t powered)
651 {
652         DBusMessage *reply = NULL;
653         int err = 0;
654
655         if (technology->hardblocked == TRUE) {
656                 err = -EACCES;
657                 goto make_reply;
658         }
659
660         if (powered == TRUE)
661                 err = technology_enable(technology, FALSE);
662         else
663                 err = technology_disable(technology, FALSE);
664
665         if (err != -EBUSY) {
666                 technology->enable_persistent = powered;
667                 technology_save(technology);
668         }
669
670 make_reply:
671         if (err == -EINPROGRESS) {
672                 technology->pending_reply = dbus_message_ref(msg);
673                 technology->pending_timeout = g_timeout_add_seconds(10,
674                                         technology_pending_reply, technology);
675         } else if (err == -EALREADY) {
676                 if (powered == TRUE)
677                         reply = __connman_error_already_enabled(msg);
678                 else
679                         reply = __connman_error_already_disabled(msg);
680         } else if (err < 0)
681                 reply = __connman_error_failed(msg, -err);
682         else
683                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
684
685         return reply;
686 }
687
688 static DBusMessage *set_property(DBusConnection *conn,
689                                         DBusMessage *msg, void *data)
690 {
691         struct connman_technology *technology = data;
692         DBusMessageIter iter, value;
693         const char *name;
694         int type;
695
696         DBG("conn %p", conn);
697
698         if (dbus_message_iter_init(msg, &iter) == FALSE)
699                 return __connman_error_invalid_arguments(msg);
700
701         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
702                 return __connman_error_invalid_arguments(msg);
703
704         dbus_message_iter_get_basic(&iter, &name);
705         dbus_message_iter_next(&iter);
706
707         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
708                 return __connman_error_invalid_arguments(msg);
709
710         dbus_message_iter_recurse(&iter, &value);
711
712         type = dbus_message_iter_get_arg_type(&value);
713
714         DBG("property %s", name);
715
716         if (g_str_equal(name, "Tethering") == TRUE) {
717                 int err;
718                 connman_bool_t tethering;
719
720                 if (type != DBUS_TYPE_BOOLEAN)
721                         return __connman_error_invalid_arguments(msg);
722
723                 dbus_message_iter_get_basic(&value, &tethering);
724
725                 if (technology->tethering == tethering) {
726                         if (tethering == FALSE)
727                                 return __connman_error_already_disabled(msg);
728                         else
729                                 return __connman_error_already_enabled(msg);
730                 }
731
732                 err = set_tethering(technology, tethering);
733                 if (err < 0)
734                         return __connman_error_failed(msg, -err);
735
736         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
737                 const char *str;
738
739                 dbus_message_iter_get_basic(&value, &str);
740
741                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
742                         return __connman_error_not_supported(msg);
743
744                 if (strlen(str) < 1 || strlen(str) > 32)
745                         return __connman_error_invalid_arguments(msg);
746
747                 if (g_strcmp0(technology->tethering_ident, str) != 0) {
748                         g_free(technology->tethering_ident);
749                         technology->tethering_ident = g_strdup(str);
750                         technology_save(technology);
751
752                         connman_dbus_property_changed_basic(technology->path,
753                                                 CONNMAN_TECHNOLOGY_INTERFACE,
754                                                 "TetheringIdentifier",
755                                                 DBUS_TYPE_STRING,
756                                                 &technology->tethering_ident);
757                 }
758         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
759                 const char *str;
760
761                 dbus_message_iter_get_basic(&value, &str);
762
763                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
764                         return __connman_error_not_supported(msg);
765
766                 if (strlen(str) < 8 || strlen(str) > 63)
767                         return __connman_error_passphrase_required(msg);
768
769                 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
770                         g_free(technology->tethering_passphrase);
771                         technology->tethering_passphrase = g_strdup(str);
772                         technology_save(technology);
773
774                         connman_dbus_property_changed_basic(technology->path,
775                                         CONNMAN_TECHNOLOGY_INTERFACE,
776                                         "TetheringPassphrase",
777                                         DBUS_TYPE_STRING,
778                                         &technology->tethering_passphrase);
779                 }
780         } else if (g_str_equal(name, "Powered") == TRUE) {
781                 connman_bool_t enable;
782
783                 if (type != DBUS_TYPE_BOOLEAN)
784                         return __connman_error_invalid_arguments(msg);
785
786                 dbus_message_iter_get_basic(&value, &enable);
787
788                 return set_powered(technology, msg, enable);
789         } else
790                 return __connman_error_invalid_property(msg);
791
792         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
793 }
794
795 static struct connman_technology *technology_find(enum connman_service_type type)
796 {
797         GSList *list;
798
799         DBG("type %d", type);
800
801         for (list = technology_list; list; list = list->next) {
802                 struct connman_technology *technology = list->data;
803
804                 if (technology->type == type)
805                         return technology;
806         }
807
808         return NULL;
809 }
810
811 static void reply_scan_pending(struct connman_technology *technology, int err)
812 {
813         DBusMessage *reply;
814
815         DBG("technology %p err %d", technology, err);
816
817         while (technology->scan_pending != NULL) {
818                 DBusMessage *msg = technology->scan_pending->data;
819
820                 DBG("reply to %s", dbus_message_get_sender(msg));
821
822                 if (err == 0)
823                         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
824                 else
825                         reply = __connman_error_failed(msg, -err);
826                 g_dbus_send_message(connection, reply);
827                 dbus_message_unref(msg);
828
829                 technology->scan_pending =
830                         g_slist_delete_link(technology->scan_pending,
831                                         technology->scan_pending);
832         }
833 }
834
835 void __connman_technology_scan_started(struct connman_device *device)
836 {
837         DBG("device %p", device);
838 }
839
840 void __connman_technology_scan_stopped(struct connman_device *device)
841 {
842         int count = 0;
843         struct connman_technology *technology;
844         enum connman_service_type type;
845         GSList *list;
846
847         type = __connman_device_get_service_type(device);
848         technology = technology_find(type);
849
850         DBG("technology %p device %p", technology, device);
851
852         if (technology == NULL)
853                 return;
854
855         for (list = technology->device_list; list != NULL; list = list->next) {
856                 struct connman_device *other_device = list->data;
857
858                 if (device == other_device)
859                         continue;
860
861                 if (__connman_device_get_service_type(other_device) != type)
862                         continue;
863
864                 if (connman_device_get_scanning(other_device) == TRUE)
865                         count += 1;
866         }
867
868         if (count == 0)
869                 reply_scan_pending(technology, 0);
870 }
871
872 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
873                                                 int result, const char *alpha2)
874 {
875         struct connman_technology *technology;
876         enum connman_service_type type;
877
878         type = __connman_device_get_service_type(device);
879         technology = technology_find(type);
880
881         if (technology == NULL)
882                 return;
883
884         if (result < 0) {
885                 if (technology->driver != NULL &&
886                                 technology->driver->set_regdom != NULL) {
887                         technology->driver->set_regdom(technology, alpha2);
888                         return;
889                 }
890
891                 alpha2 = NULL;
892         }
893
894         connman_technology_regdom_notify(technology, alpha2);
895 }
896
897 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
898 {
899         struct connman_technology *technology = data;
900         int err;
901
902         DBG ("technology %p request from %s", technology,
903                         dbus_message_get_sender(msg));
904
905         dbus_message_ref(msg);
906         technology->scan_pending =
907                 g_slist_prepend(technology->scan_pending, msg);
908
909         err = __connman_device_request_scan(technology->type);
910         if (err < 0)
911                 reply_scan_pending(technology, err);
912
913         return NULL;
914 }
915
916 static const GDBusMethodTable technology_methods[] = {
917         { GDBUS_DEPRECATED_METHOD("GetProperties",
918                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
919                         get_properties) },
920         { GDBUS_ASYNC_METHOD("SetProperty",
921                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
922                         NULL, set_property) },
923         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
924         { },
925 };
926
927 static const GDBusSignalTable technology_signals[] = {
928         { GDBUS_SIGNAL("PropertyChanged",
929                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
930         { },
931 };
932
933 static struct connman_technology *technology_get(enum connman_service_type type)
934 {
935         struct connman_technology *technology;
936         struct connman_technology_driver *driver = NULL;
937         const char *str;
938         GSList *list;
939         int err;
940
941         DBG("type %d", type);
942
943         str = __connman_service_type2string(type);
944         if (str == NULL)
945                 return NULL;
946
947         technology = technology_find(type);
948         if (technology != NULL) {
949                 __sync_fetch_and_add(&technology->refcount, 1);
950                 return technology;
951         }
952
953         /* First check if we have a driver for this technology type */
954         for (list = driver_list; list; list = list->next) {
955                 driver = list->data;
956
957                 if (driver->type == type)
958                         break;
959                 else
960                         driver = NULL;
961         }
962
963         if (driver == NULL) {
964                 DBG("No matching driver found for %s.",
965                                 __connman_service_type2string(type));
966                 return NULL;
967         }
968
969         technology = g_try_new0(struct connman_technology, 1);
970         if (technology == NULL)
971                 return NULL;
972
973         technology->refcount = 1;
974
975         if (type == CONNMAN_SERVICE_TYPE_ETHERNET)
976                 technology->hardblocked = FALSE;
977         else
978                 technology->hardblocked = TRUE;
979
980         technology->type = type;
981         technology->path = g_strdup_printf("%s/technology/%s",
982                                                         CONNMAN_PATH, str);
983
984         technology->device_list = NULL;
985
986         technology->pending_reply = NULL;
987
988         technology_load(technology);
989
990         if (g_dbus_register_interface(connection, technology->path,
991                                         CONNMAN_TECHNOLOGY_INTERFACE,
992                                         technology_methods, technology_signals,
993                                         NULL, technology, NULL) == FALSE) {
994                 connman_error("Failed to register %s", technology->path);
995                 g_free(technology);
996                 return NULL;
997         }
998
999         technology_list = g_slist_prepend(technology_list, technology);
1000
1001         technology_added_signal(technology);
1002
1003         technology->driver = driver;
1004         err = driver->probe(technology);
1005         if (err != 0)
1006                 DBG("Driver probe failed for technology %p", technology);
1007
1008         DBG("technology %p", technology);
1009
1010         return technology;
1011 }
1012
1013 static void technology_put(struct connman_technology *technology)
1014 {
1015         DBG("technology %p", technology);
1016
1017         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
1018                 return;
1019
1020         reply_scan_pending(technology, -EINTR);
1021
1022         if (technology->driver) {
1023                 technology->driver->remove(technology);
1024                 technology->driver = NULL;
1025         }
1026
1027         technology_list = g_slist_remove(technology_list, technology);
1028
1029         technology_removed_signal(technology);
1030
1031         g_dbus_unregister_interface(connection, technology->path,
1032                                                 CONNMAN_TECHNOLOGY_INTERFACE);
1033
1034         g_slist_free(technology->device_list);
1035
1036         g_free(technology->path);
1037         g_free(technology->regdom);
1038         g_free(technology->tethering_ident);
1039         g_free(technology->tethering_passphrase);
1040         g_free(technology);
1041 }
1042
1043 void __connman_technology_add_interface(enum connman_service_type type,
1044                                 int index, const char *name, const char *ident)
1045 {
1046         struct connman_technology *technology;
1047
1048         switch (type) {
1049         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1050         case CONNMAN_SERVICE_TYPE_SYSTEM:
1051                 return;
1052         case CONNMAN_SERVICE_TYPE_ETHERNET:
1053         case CONNMAN_SERVICE_TYPE_WIFI:
1054         case CONNMAN_SERVICE_TYPE_WIMAX:
1055         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1056         case CONNMAN_SERVICE_TYPE_CELLULAR:
1057         case CONNMAN_SERVICE_TYPE_GPS:
1058         case CONNMAN_SERVICE_TYPE_VPN:
1059         case CONNMAN_SERVICE_TYPE_GADGET:
1060                 break;
1061         }
1062
1063         connman_info("Adding interface %s [ %s ]", name,
1064                                 __connman_service_type2string(type));
1065
1066         technology = technology_find(type);
1067
1068         if (technology == NULL || technology->driver == NULL
1069                         || technology->driver->add_interface == NULL)
1070                 return;
1071
1072         technology->driver->add_interface(technology,
1073                                         index, name, ident);
1074 }
1075
1076 void __connman_technology_remove_interface(enum connman_service_type type,
1077                                 int index, const char *name, const char *ident)
1078 {
1079         struct connman_technology *technology;
1080
1081         switch (type) {
1082         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1083         case CONNMAN_SERVICE_TYPE_SYSTEM:
1084                 return;
1085         case CONNMAN_SERVICE_TYPE_ETHERNET:
1086         case CONNMAN_SERVICE_TYPE_WIFI:
1087         case CONNMAN_SERVICE_TYPE_WIMAX:
1088         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1089         case CONNMAN_SERVICE_TYPE_CELLULAR:
1090         case CONNMAN_SERVICE_TYPE_GPS:
1091         case CONNMAN_SERVICE_TYPE_VPN:
1092         case CONNMAN_SERVICE_TYPE_GADGET:
1093                 break;
1094         }
1095
1096         connman_info("Remove interface %s [ %s ]", name,
1097                                 __connman_service_type2string(type));
1098
1099         technology = technology_find(type);
1100
1101         if (technology == NULL || technology->driver == NULL)
1102                 return;
1103
1104         if (technology->driver->remove_interface)
1105                 technology->driver->remove_interface(technology, index);
1106 }
1107
1108 int __connman_technology_add_device(struct connman_device *device)
1109 {
1110         struct connman_technology *technology;
1111         enum connman_service_type type;
1112
1113         DBG("device %p", device);
1114
1115         type = __connman_device_get_service_type(device);
1116
1117         technology = technology_get(type);
1118         if (technology == NULL) {
1119                 /*
1120                  * Since no driver can be found for this device at the moment we
1121                  * add it to the techless device list.
1122                 */
1123                 techless_device_list = g_slist_prepend(techless_device_list,
1124                                                                 device);
1125
1126                 return -ENXIO;
1127         }
1128
1129         if (technology->enable_persistent &&
1130                                         global_offlinemode == FALSE &&
1131                                         technology->hardblocked == FALSE) {
1132                 int err = __connman_device_enable(device);
1133                 /*
1134                  * connman_technology_add_device() calls __connman_device_enable()
1135                  * but since the device is already enabled, the calls does not
1136                  * propagate through to connman_technology_enabled via
1137                  * connman_device_set_powered.
1138                  */
1139                 if (err == -EALREADY)
1140                         __connman_technology_enabled(type);
1141         }
1142         /* if technology persistent state is offline or hardblocked */
1143         if (technology->enable_persistent == FALSE ||
1144                                         technology->hardblocked == TRUE)
1145                 __connman_device_disable(device);
1146
1147         technology->device_list = g_slist_prepend(technology->device_list,
1148                                                                 device);
1149
1150         return 0;
1151 }
1152
1153 int __connman_technology_remove_device(struct connman_device *device)
1154 {
1155         struct connman_technology *technology;
1156         enum connman_service_type type;
1157
1158         DBG("device %p", device);
1159
1160         type = __connman_device_get_service_type(device);
1161
1162         technology = technology_find(type);
1163         if (technology == NULL) {
1164                 techless_device_list = g_slist_remove(techless_device_list,
1165                                                                 device);
1166                 return -ENXIO;
1167         }
1168
1169         technology->device_list = g_slist_remove(technology->device_list,
1170                                                                 device);
1171         technology_put(technology);
1172
1173         return 0;
1174 }
1175
1176 static void powered_changed(struct connman_technology *technology)
1177 {
1178         connman_bool_t powered;
1179
1180         __sync_synchronize();
1181         if (technology->enabled >0)
1182                 powered = TRUE;
1183         else
1184                 powered = FALSE;
1185
1186         connman_dbus_property_changed_basic(technology->path,
1187                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
1188                         DBUS_TYPE_BOOLEAN, &powered);
1189 }
1190
1191 int __connman_technology_enabled(enum connman_service_type type)
1192 {
1193         struct connman_technology *technology;
1194
1195         technology = technology_find(type);
1196         if (technology == NULL)
1197                 return -ENXIO;
1198
1199         if (__sync_fetch_and_add(&technology->enabled, 1) != 0)
1200                 return -EALREADY;
1201
1202         powered_changed(technology);
1203
1204         if (technology->pending_reply != NULL) {
1205                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
1206                 dbus_message_unref(technology->pending_reply);
1207                 g_source_remove(technology->pending_timeout);
1208                 technology->pending_reply = NULL;
1209                 technology->pending_timeout = 0;
1210         }
1211
1212         return 0;
1213 }
1214
1215 int __connman_technology_disabled(enum connman_service_type type)
1216 {
1217         struct connman_technology *technology;
1218
1219         technology = technology_find(type);
1220         if (technology == NULL)
1221                 return -ENXIO;
1222
1223         if (__sync_fetch_and_sub(&technology->enabled, 1) != 1)
1224                 return -EINPROGRESS;
1225
1226         if (technology->pending_reply != NULL) {
1227                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
1228                 dbus_message_unref(technology->pending_reply);
1229                 g_source_remove(technology->pending_timeout);
1230                 technology->pending_reply = NULL;
1231                 technology->pending_timeout = 0;
1232         }
1233
1234         powered_changed(technology);
1235
1236         return 0;
1237 }
1238
1239 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
1240 {
1241         GSList *list;
1242         int err = -EINVAL;
1243
1244         if (global_offlinemode == offlinemode)
1245                 return 0;
1246
1247         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1248
1249         /*
1250          * This is a bit tricky. When you set offlinemode, there is no
1251          * way to differentiate between attempting offline mode and
1252          * resuming offlinemode from last saved profile. We need that
1253          * information in rfkill_update, otherwise it falls back on the
1254          * technology's persistent state. Hence we set the offline mode here
1255          * but save it & call the notifier only if its successful.
1256          */
1257
1258         global_offlinemode = offlinemode;
1259
1260         /* Traverse technology list, enable/disable each technology. */
1261         for (list = technology_list; list; list = list->next) {
1262                 struct connman_technology *technology = list->data;
1263
1264                 if (offlinemode)
1265                         err = technology_disable(technology, FALSE);
1266
1267                 if (!offlinemode && technology->enable_persistent)
1268                         err = technology_enable(technology, FALSE);
1269         }
1270
1271         if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
1272                 connman_technology_save_offlinemode();
1273                 __connman_notifier_offlinemode(offlinemode);
1274         } else
1275                 global_offlinemode = connman_technology_load_offlinemode();
1276
1277         return err;
1278 }
1279
1280 void __connman_technology_set_connected(enum connman_service_type type,
1281                 connman_bool_t connected)
1282 {
1283         struct connman_technology *technology;
1284
1285         technology = technology_find(type);
1286         if (technology == NULL)
1287                 return;
1288
1289         DBG("technology %p connected %d", technology, connected);
1290
1291         technology->connected = connected;
1292
1293         connman_dbus_property_changed_basic(technology->path,
1294                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
1295                         DBUS_TYPE_BOOLEAN, &connected);
1296 }
1297
1298 static void technology_apply_hardblock_change(struct connman_technology *technology,
1299                                                 connman_bool_t hardblock)
1300 {
1301         gboolean apply = TRUE;
1302         GList *start, *list;
1303
1304         if (technology->hardblocked == hardblock)
1305                 return;
1306
1307         start = g_hash_table_get_values(rfkill_list);
1308         for (list = start; list != NULL; list = list->next) {
1309                 struct connman_rfkill *rfkill = list->data;
1310
1311                 if (rfkill->type != technology->type)
1312                         continue;
1313
1314                 if (rfkill->hardblock != hardblock)
1315                         apply = FALSE;
1316         }
1317
1318         g_list_free(start);
1319
1320         if (apply == FALSE)
1321                 return;
1322
1323         technology->hardblocked = hardblock;
1324
1325         if (hardblock == TRUE) {
1326                 DBG("%s is switched off.", get_name(technology->type));
1327                 technology_disable(technology, TRUE);
1328         } else
1329                 technology_enable(technology, TRUE);
1330
1331 }
1332
1333 int __connman_technology_add_rfkill(unsigned int index,
1334                                         enum connman_service_type type,
1335                                                 connman_bool_t softblock,
1336                                                 connman_bool_t hardblock)
1337 {
1338         struct connman_technology *technology;
1339         struct connman_rfkill *rfkill;
1340
1341         DBG("index %u type %d soft %u hard %u", index, type,
1342                                                         softblock, hardblock);
1343
1344         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1345         if (rfkill != NULL)
1346                 goto done;
1347
1348         rfkill = g_try_new0(struct connman_rfkill, 1);
1349         if (rfkill == NULL)
1350                 return -ENOMEM;
1351
1352         rfkill->index = index;
1353         rfkill->type = type;
1354         rfkill->softblock = softblock;
1355         rfkill->hardblock = hardblock;
1356
1357         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
1358
1359 done:
1360         technology = technology_get(type);
1361         /* If there is no driver for this type, ignore it. */
1362         if (technology == NULL)
1363                 return -ENXIO;
1364
1365         technology_apply_hardblock_change(technology, hardblock);
1366
1367         /*
1368          * If Offline mode is on, we softblock the device if it isnt already.
1369          * If Offline mode is off, we rely on the persistent state of tech.
1370          */
1371         if (global_offlinemode) {
1372                 if (!softblock)
1373                         return __connman_rfkill_block(type, TRUE);
1374         } else {
1375                 if (technology->enable_persistent && softblock)
1376                         return __connman_rfkill_block(type, FALSE);
1377                 /* if technology persistent state is offline */
1378                 if (!technology->enable_persistent && !softblock)
1379                         return __connman_rfkill_block(type, TRUE);
1380         }
1381
1382         return 0;
1383 }
1384
1385 int __connman_technology_update_rfkill(unsigned int index,
1386                                         enum connman_service_type type,
1387                                                 connman_bool_t softblock,
1388                                                 connman_bool_t hardblock)
1389 {
1390         struct connman_technology *technology;
1391         struct connman_rfkill *rfkill;
1392
1393         DBG("index %u soft %u hard %u", index, softblock, hardblock);
1394
1395         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1396         if (rfkill == NULL)
1397                 return -ENXIO;
1398
1399         if (rfkill->softblock == softblock &&
1400                 rfkill->hardblock == hardblock)
1401                 return 0;
1402
1403         rfkill->softblock = softblock;
1404         rfkill->hardblock = hardblock;
1405
1406         technology = technology_find(type);
1407         /* If there is no driver for this type, ignore it. */
1408         if (technology == NULL)
1409                 return -ENXIO;
1410
1411         technology_apply_hardblock_change(technology, hardblock);
1412
1413         if (!global_offlinemode) {
1414                 if (technology->enable_persistent && softblock)
1415                         return __connman_rfkill_block(type, FALSE);
1416                 if (!technology->enable_persistent && !softblock)
1417                         return __connman_rfkill_block(type, TRUE);
1418         }
1419
1420         return 0;
1421 }
1422
1423 int __connman_technology_remove_rfkill(unsigned int index,
1424                                         enum connman_service_type type)
1425 {
1426         struct connman_technology *technology;
1427         struct connman_rfkill *rfkill;
1428
1429         DBG("index %u", index);
1430
1431         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1432         if (rfkill == NULL)
1433                 return -ENXIO;
1434
1435         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
1436
1437         technology = technology_find(type);
1438         if (technology == NULL)
1439                 return -ENXIO;
1440
1441         technology_put(technology);
1442
1443         return 0;
1444 }
1445
1446 int __connman_technology_init(void)
1447 {
1448         DBG("");
1449
1450         connection = connman_dbus_get_connection();
1451
1452         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1453                                                         NULL, free_rfkill);
1454
1455         global_offlinemode = connman_technology_load_offlinemode();
1456
1457         /* This will create settings file if it is missing */
1458         connman_technology_save_offlinemode();
1459
1460         return 0;
1461 }
1462
1463 void __connman_technology_cleanup(void)
1464 {
1465         DBG("");
1466
1467         g_hash_table_destroy(rfkill_list);
1468
1469         dbus_connection_unref(connection);
1470 }