technology: Handle rfkill hardblock
[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 {
582         GSList *list;
583         int err = 0;
584
585         DBG("technology %p enable", technology);
586
587         __sync_synchronize();
588         if (technology->enabled > 0) {
589                 err = -EALREADY;
590                 goto done;
591         }
592
593         if (technology->pending_reply != NULL) {
594                 err = -EBUSY;
595                 goto done;
596         }
597
598         __connman_rfkill_block(technology->type, FALSE);
599
600         for (list = technology->device_list; list; list = list->next) {
601                 struct connman_device *device = list->data;
602
603                 err = __connman_device_enable(device);
604         }
605
606 done:
607         return err;
608 }
609
610 static int technology_disable(struct connman_technology *technology)
611 {
612         GSList *list;
613         int err = 0;
614
615         DBG("technology %p disable", technology);
616
617         __sync_synchronize();
618         if (technology->enabled == 0) {
619                 err = -EALREADY;
620                 goto done;
621         }
622
623         if (technology->pending_reply != NULL) {
624                 err = -EBUSY;
625                 goto done;
626         }
627
628         if (technology->tethering == TRUE)
629                 set_tethering(technology, FALSE);
630
631         __connman_rfkill_block(technology->type, TRUE);
632
633         for (list = technology->device_list; list; list = list->next) {
634                 struct connman_device *device = list->data;
635
636                 err = __connman_device_disable(device);
637         }
638
639 done:
640         return err;
641 }
642
643 static DBusMessage *set_powered(struct connman_technology *technology,
644                                 DBusMessage *msg, connman_bool_t powered)
645 {
646         DBusMessage *reply = NULL;
647         connman_bool_t persistent;
648         int err;
649
650         if (powered == TRUE) {
651                 err = technology_enable(technology);
652                 persistent = TRUE;
653         } else {
654                 err = technology_disable(technology);
655                 persistent = FALSE;
656         }
657
658         if (err != -EBUSY) {
659                 technology->enable_persistent = persistent;
660                 technology_save(technology);
661         }
662
663         if (err == -EINPROGRESS) {
664                 technology->pending_reply = dbus_message_ref(msg);
665                 technology->pending_timeout = g_timeout_add_seconds(10,
666                                         technology_pending_reply, technology);
667         } else if (err == -EALREADY) {
668                 if (powered == TRUE)
669                         reply = __connman_error_already_enabled(msg);
670                 else
671                         reply = __connman_error_already_disabled(msg);
672         } else if (err < 0)
673                 reply = __connman_error_failed(msg, -err);
674         else
675                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
676
677         return reply;
678 }
679
680 static DBusMessage *set_property(DBusConnection *conn,
681                                         DBusMessage *msg, void *data)
682 {
683         struct connman_technology *technology = data;
684         DBusMessageIter iter, value;
685         const char *name;
686         int type;
687
688         DBG("conn %p", conn);
689
690         if (dbus_message_iter_init(msg, &iter) == FALSE)
691                 return __connman_error_invalid_arguments(msg);
692
693         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
694                 return __connman_error_invalid_arguments(msg);
695
696         dbus_message_iter_get_basic(&iter, &name);
697         dbus_message_iter_next(&iter);
698
699         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
700                 return __connman_error_invalid_arguments(msg);
701
702         dbus_message_iter_recurse(&iter, &value);
703
704         type = dbus_message_iter_get_arg_type(&value);
705
706         DBG("property %s", name);
707
708         if (g_str_equal(name, "Tethering") == TRUE) {
709                 int err;
710                 connman_bool_t tethering;
711
712                 if (type != DBUS_TYPE_BOOLEAN)
713                         return __connman_error_invalid_arguments(msg);
714
715                 dbus_message_iter_get_basic(&value, &tethering);
716
717                 if (technology->tethering == tethering) {
718                         if (tethering == FALSE)
719                                 return __connman_error_already_disabled(msg);
720                         else
721                                 return __connman_error_already_enabled(msg);
722                 }
723
724                 err = set_tethering(technology, tethering);
725                 if (err < 0)
726                         return __connman_error_failed(msg, -err);
727
728         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
729                 const char *str;
730
731                 dbus_message_iter_get_basic(&value, &str);
732
733                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
734                         return __connman_error_not_supported(msg);
735
736                 if (strlen(str) < 1 || strlen(str) > 32)
737                         return __connman_error_invalid_arguments(msg);
738
739                 if (g_strcmp0(technology->tethering_ident, str) != 0) {
740                         g_free(technology->tethering_ident);
741                         technology->tethering_ident = g_strdup(str);
742                         technology_save(technology);
743
744                         connman_dbus_property_changed_basic(technology->path,
745                                                 CONNMAN_TECHNOLOGY_INTERFACE,
746                                                 "TetheringIdentifier",
747                                                 DBUS_TYPE_STRING,
748                                                 &technology->tethering_ident);
749                 }
750         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
751                 const char *str;
752
753                 dbus_message_iter_get_basic(&value, &str);
754
755                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
756                         return __connman_error_not_supported(msg);
757
758                 if (strlen(str) < 8 || strlen(str) > 63)
759                         return __connman_error_passphrase_required(msg);
760
761                 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
762                         g_free(technology->tethering_passphrase);
763                         technology->tethering_passphrase = g_strdup(str);
764                         technology_save(technology);
765
766                         connman_dbus_property_changed_basic(technology->path,
767                                         CONNMAN_TECHNOLOGY_INTERFACE,
768                                         "TetheringPassphrase",
769                                         DBUS_TYPE_STRING,
770                                         &technology->tethering_passphrase);
771                 }
772         } else if (g_str_equal(name, "Powered") == TRUE) {
773                 connman_bool_t enable;
774
775                 if (type != DBUS_TYPE_BOOLEAN)
776                         return __connman_error_invalid_arguments(msg);
777
778                 dbus_message_iter_get_basic(&value, &enable);
779
780                 return set_powered(technology, msg, enable);
781         } else
782                 return __connman_error_invalid_property(msg);
783
784         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
785 }
786
787 static struct connman_technology *technology_find(enum connman_service_type type)
788 {
789         GSList *list;
790
791         DBG("type %d", type);
792
793         for (list = technology_list; list; list = list->next) {
794                 struct connman_technology *technology = list->data;
795
796                 if (technology->type == type)
797                         return technology;
798         }
799
800         return NULL;
801 }
802
803 static void reply_scan_pending(struct connman_technology *technology, int err)
804 {
805         DBusMessage *reply;
806
807         DBG("technology %p err %d", technology, err);
808
809         while (technology->scan_pending != NULL) {
810                 DBusMessage *msg = technology->scan_pending->data;
811
812                 DBG("reply to %s", dbus_message_get_sender(msg));
813
814                 if (err == 0)
815                         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
816                 else
817                         reply = __connman_error_failed(msg, -err);
818                 g_dbus_send_message(connection, reply);
819                 dbus_message_unref(msg);
820
821                 technology->scan_pending =
822                         g_slist_delete_link(technology->scan_pending,
823                                         technology->scan_pending);
824         }
825 }
826
827 void __connman_technology_scan_started(struct connman_device *device)
828 {
829         DBG("device %p", device);
830 }
831
832 void __connman_technology_scan_stopped(struct connman_device *device)
833 {
834         int count = 0;
835         struct connman_technology *technology;
836         enum connman_service_type type;
837         GSList *list;
838
839         type = __connman_device_get_service_type(device);
840         technology = technology_find(type);
841
842         DBG("technology %p device %p", technology, device);
843
844         if (technology == NULL)
845                 return;
846
847         for (list = technology->device_list; list != NULL; list = list->next) {
848                 struct connman_device *other_device = list->data;
849
850                 if (device == other_device)
851                         continue;
852
853                 if (__connman_device_get_service_type(other_device) != type)
854                         continue;
855
856                 if (connman_device_get_scanning(other_device) == TRUE)
857                         count += 1;
858         }
859
860         if (count == 0)
861                 reply_scan_pending(technology, 0);
862 }
863
864 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
865                                                 int result, const char *alpha2)
866 {
867         struct connman_technology *technology;
868         enum connman_service_type type;
869
870         type = __connman_device_get_service_type(device);
871         technology = technology_find(type);
872
873         if (technology == NULL)
874                 return;
875
876         if (result < 0) {
877                 if (technology->driver != NULL &&
878                                 technology->driver->set_regdom != NULL) {
879                         technology->driver->set_regdom(technology, alpha2);
880                         return;
881                 }
882
883                 alpha2 = NULL;
884         }
885
886         connman_technology_regdom_notify(technology, alpha2);
887 }
888
889 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
890 {
891         struct connman_technology *technology = data;
892         int err;
893
894         DBG ("technology %p request from %s", technology,
895                         dbus_message_get_sender(msg));
896
897         dbus_message_ref(msg);
898         technology->scan_pending =
899                 g_slist_prepend(technology->scan_pending, msg);
900
901         err = __connman_device_request_scan(technology->type);
902         if (err < 0)
903                 reply_scan_pending(technology, err);
904
905         return NULL;
906 }
907
908 static const GDBusMethodTable technology_methods[] = {
909         { GDBUS_DEPRECATED_METHOD("GetProperties",
910                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
911                         get_properties) },
912         { GDBUS_ASYNC_METHOD("SetProperty",
913                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
914                         NULL, set_property) },
915         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
916         { },
917 };
918
919 static const GDBusSignalTable technology_signals[] = {
920         { GDBUS_SIGNAL("PropertyChanged",
921                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
922         { },
923 };
924
925 static struct connman_technology *technology_get(enum connman_service_type type)
926 {
927         struct connman_technology *technology;
928         struct connman_technology_driver *driver = NULL;
929         const char *str;
930         GSList *list;
931         int err;
932
933         DBG("type %d", type);
934
935         str = __connman_service_type2string(type);
936         if (str == NULL)
937                 return NULL;
938
939         technology = technology_find(type);
940         if (technology != NULL) {
941                 __sync_fetch_and_add(&technology->refcount, 1);
942                 return technology;
943         }
944
945         /* First check if we have a driver for this technology type */
946         for (list = driver_list; list; list = list->next) {
947                 driver = list->data;
948
949                 if (driver->type == type)
950                         break;
951                 else
952                         driver = NULL;
953         }
954
955         if (driver == NULL) {
956                 DBG("No matching driver found for %s.",
957                                 __connman_service_type2string(type));
958                 return NULL;
959         }
960
961         technology = g_try_new0(struct connman_technology, 1);
962         if (technology == NULL)
963                 return NULL;
964
965         technology->refcount = 1;
966
967         if (type == CONNMAN_SERVICE_TYPE_ETHERNET)
968                 technology->hardblocked = FALSE;
969         else
970                 technology->hardblocked = TRUE;
971
972         technology->type = type;
973         technology->path = g_strdup_printf("%s/technology/%s",
974                                                         CONNMAN_PATH, str);
975
976         technology->device_list = NULL;
977
978         technology->pending_reply = NULL;
979
980         technology_load(technology);
981
982         if (g_dbus_register_interface(connection, technology->path,
983                                         CONNMAN_TECHNOLOGY_INTERFACE,
984                                         technology_methods, technology_signals,
985                                         NULL, technology, NULL) == FALSE) {
986                 connman_error("Failed to register %s", technology->path);
987                 g_free(technology);
988                 return NULL;
989         }
990
991         technology_list = g_slist_prepend(technology_list, technology);
992
993         technology_added_signal(technology);
994
995         technology->driver = driver;
996         err = driver->probe(technology);
997         if (err != 0)
998                 DBG("Driver probe failed for technology %p", technology);
999
1000         DBG("technology %p", technology);
1001
1002         return technology;
1003 }
1004
1005 static void technology_put(struct connman_technology *technology)
1006 {
1007         DBG("technology %p", technology);
1008
1009         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
1010                 return;
1011
1012         reply_scan_pending(technology, -EINTR);
1013
1014         if (technology->driver) {
1015                 technology->driver->remove(technology);
1016                 technology->driver = NULL;
1017         }
1018
1019         technology_list = g_slist_remove(technology_list, technology);
1020
1021         technology_removed_signal(technology);
1022
1023         g_dbus_unregister_interface(connection, technology->path,
1024                                                 CONNMAN_TECHNOLOGY_INTERFACE);
1025
1026         g_slist_free(technology->device_list);
1027
1028         g_free(technology->path);
1029         g_free(technology->regdom);
1030         g_free(technology->tethering_ident);
1031         g_free(technology->tethering_passphrase);
1032         g_free(technology);
1033 }
1034
1035 void __connman_technology_add_interface(enum connman_service_type type,
1036                                 int index, const char *name, const char *ident)
1037 {
1038         struct connman_technology *technology;
1039
1040         switch (type) {
1041         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1042         case CONNMAN_SERVICE_TYPE_SYSTEM:
1043                 return;
1044         case CONNMAN_SERVICE_TYPE_ETHERNET:
1045         case CONNMAN_SERVICE_TYPE_WIFI:
1046         case CONNMAN_SERVICE_TYPE_WIMAX:
1047         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1048         case CONNMAN_SERVICE_TYPE_CELLULAR:
1049         case CONNMAN_SERVICE_TYPE_GPS:
1050         case CONNMAN_SERVICE_TYPE_VPN:
1051         case CONNMAN_SERVICE_TYPE_GADGET:
1052                 break;
1053         }
1054
1055         connman_info("Adding interface %s [ %s ]", name,
1056                                 __connman_service_type2string(type));
1057
1058         technology = technology_find(type);
1059
1060         if (technology == NULL || technology->driver == NULL
1061                         || technology->driver->add_interface == NULL)
1062                 return;
1063
1064         technology->driver->add_interface(technology,
1065                                         index, name, ident);
1066 }
1067
1068 void __connman_technology_remove_interface(enum connman_service_type type,
1069                                 int index, const char *name, const char *ident)
1070 {
1071         struct connman_technology *technology;
1072
1073         switch (type) {
1074         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1075         case CONNMAN_SERVICE_TYPE_SYSTEM:
1076                 return;
1077         case CONNMAN_SERVICE_TYPE_ETHERNET:
1078         case CONNMAN_SERVICE_TYPE_WIFI:
1079         case CONNMAN_SERVICE_TYPE_WIMAX:
1080         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1081         case CONNMAN_SERVICE_TYPE_CELLULAR:
1082         case CONNMAN_SERVICE_TYPE_GPS:
1083         case CONNMAN_SERVICE_TYPE_VPN:
1084         case CONNMAN_SERVICE_TYPE_GADGET:
1085                 break;
1086         }
1087
1088         connman_info("Remove interface %s [ %s ]", name,
1089                                 __connman_service_type2string(type));
1090
1091         technology = technology_find(type);
1092
1093         if (technology == NULL || technology->driver == NULL)
1094                 return;
1095
1096         if (technology->driver->remove_interface)
1097                 technology->driver->remove_interface(technology, index);
1098 }
1099
1100 int __connman_technology_add_device(struct connman_device *device)
1101 {
1102         struct connman_technology *technology;
1103         enum connman_service_type type;
1104
1105         DBG("device %p", device);
1106
1107         type = __connman_device_get_service_type(device);
1108
1109         technology = technology_get(type);
1110         if (technology == NULL) {
1111                 /*
1112                  * Since no driver can be found for this device at the moment we
1113                  * add it to the techless device list.
1114                 */
1115                 techless_device_list = g_slist_prepend(techless_device_list,
1116                                                                 device);
1117
1118                 return -ENXIO;
1119         }
1120
1121         if (technology->enable_persistent &&
1122                                         global_offlinemode == FALSE &&
1123                                         technology->hardblocked == FALSE) {
1124                 int err = __connman_device_enable(device);
1125                 /*
1126                  * connman_technology_add_device() calls __connman_device_enable()
1127                  * but since the device is already enabled, the calls does not
1128                  * propagate through to connman_technology_enabled via
1129                  * connman_device_set_powered.
1130                  */
1131                 if (err == -EALREADY)
1132                         __connman_technology_enabled(type);
1133         }
1134         /* if technology persistent state is offline or hardblocked */
1135         if (technology->enable_persistent == FALSE ||
1136                                         technology->hardblocked == TRUE)
1137                 __connman_device_disable(device);
1138
1139         technology->device_list = g_slist_prepend(technology->device_list,
1140                                                                 device);
1141
1142         return 0;
1143 }
1144
1145 int __connman_technology_remove_device(struct connman_device *device)
1146 {
1147         struct connman_technology *technology;
1148         enum connman_service_type type;
1149
1150         DBG("device %p", device);
1151
1152         type = __connman_device_get_service_type(device);
1153
1154         technology = technology_find(type);
1155         if (technology == NULL) {
1156                 techless_device_list = g_slist_remove(techless_device_list,
1157                                                                 device);
1158                 return -ENXIO;
1159         }
1160
1161         technology->device_list = g_slist_remove(technology->device_list,
1162                                                                 device);
1163         technology_put(technology);
1164
1165         return 0;
1166 }
1167
1168 static void powered_changed(struct connman_technology *technology)
1169 {
1170         connman_bool_t powered;
1171
1172         __sync_synchronize();
1173         if (technology->enabled >0)
1174                 powered = TRUE;
1175         else
1176                 powered = FALSE;
1177
1178         connman_dbus_property_changed_basic(technology->path,
1179                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
1180                         DBUS_TYPE_BOOLEAN, &powered);
1181 }
1182
1183 int __connman_technology_enabled(enum connman_service_type type)
1184 {
1185         struct connman_technology *technology;
1186
1187         technology = technology_find(type);
1188         if (technology == NULL)
1189                 return -ENXIO;
1190
1191         if (__sync_fetch_and_add(&technology->enabled, 1) != 0)
1192                 return -EALREADY;
1193
1194         powered_changed(technology);
1195
1196         if (technology->pending_reply != NULL) {
1197                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
1198                 dbus_message_unref(technology->pending_reply);
1199                 g_source_remove(technology->pending_timeout);
1200                 technology->pending_reply = NULL;
1201                 technology->pending_timeout = 0;
1202         }
1203
1204         return 0;
1205 }
1206
1207 int __connman_technology_disabled(enum connman_service_type type)
1208 {
1209         struct connman_technology *technology;
1210
1211         technology = technology_find(type);
1212         if (technology == NULL)
1213                 return -ENXIO;
1214
1215         if (__sync_fetch_and_sub(&technology->enabled, 1) != 1)
1216                 return -EINPROGRESS;
1217
1218         if (technology->pending_reply != NULL) {
1219                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
1220                 dbus_message_unref(technology->pending_reply);
1221                 g_source_remove(technology->pending_timeout);
1222                 technology->pending_reply = NULL;
1223                 technology->pending_timeout = 0;
1224         }
1225
1226         powered_changed(technology);
1227
1228         return 0;
1229 }
1230
1231 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
1232 {
1233         GSList *list;
1234         int err = -EINVAL;
1235
1236         if (global_offlinemode == offlinemode)
1237                 return 0;
1238
1239         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1240
1241         /*
1242          * This is a bit tricky. When you set offlinemode, there is no
1243          * way to differentiate between attempting offline mode and
1244          * resuming offlinemode from last saved profile. We need that
1245          * information in rfkill_update, otherwise it falls back on the
1246          * technology's persistent state. Hence we set the offline mode here
1247          * but save it & call the notifier only if its successful.
1248          */
1249
1250         global_offlinemode = offlinemode;
1251
1252         /* Traverse technology list, enable/disable each technology. */
1253         for (list = technology_list; list; list = list->next) {
1254                 struct connman_technology *technology = list->data;
1255
1256                 if (offlinemode)
1257                         err = technology_disable(technology);
1258
1259                 if (!offlinemode && technology->enable_persistent)
1260                         err = technology_enable(technology);
1261         }
1262
1263         if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
1264                 connman_technology_save_offlinemode();
1265                 __connman_notifier_offlinemode(offlinemode);
1266         } else
1267                 global_offlinemode = connman_technology_load_offlinemode();
1268
1269         return err;
1270 }
1271
1272 void __connman_technology_set_connected(enum connman_service_type type,
1273                 connman_bool_t connected)
1274 {
1275         struct connman_technology *technology;
1276
1277         technology = technology_find(type);
1278         if (technology == NULL)
1279                 return;
1280
1281         DBG("technology %p connected %d", technology, connected);
1282
1283         technology->connected = connected;
1284
1285         connman_dbus_property_changed_basic(technology->path,
1286                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
1287                         DBUS_TYPE_BOOLEAN, &connected);
1288 }
1289
1290 static void technology_apply_hardblock_change(struct connman_technology *technology,
1291                                                 connman_bool_t hardblock)
1292 {
1293         if (technology->hardblocked == hardblock)
1294                 return;
1295
1296         technology->hardblocked = hardblock;
1297
1298         if (hardblock == TRUE)
1299                 DBG("%s is switched off.", get_name(technology->type));
1300 }
1301
1302 int __connman_technology_add_rfkill(unsigned int index,
1303                                         enum connman_service_type type,
1304                                                 connman_bool_t softblock,
1305                                                 connman_bool_t hardblock)
1306 {
1307         struct connman_technology *technology;
1308         struct connman_rfkill *rfkill;
1309
1310         DBG("index %u type %d soft %u hard %u", index, type,
1311                                                         softblock, hardblock);
1312
1313         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1314         if (rfkill != NULL)
1315                 goto done;
1316
1317         rfkill = g_try_new0(struct connman_rfkill, 1);
1318         if (rfkill == NULL)
1319                 return -ENOMEM;
1320
1321         rfkill->index = index;
1322         rfkill->type = type;
1323         rfkill->softblock = softblock;
1324         rfkill->hardblock = hardblock;
1325
1326         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
1327
1328 done:
1329         technology = technology_get(type);
1330         /* If there is no driver for this type, ignore it. */
1331         if (technology == NULL)
1332                 return -ENXIO;
1333
1334         technology_apply_hardblock_change(technology, hardblock);
1335
1336         /*
1337          * If Offline mode is on, we softblock the device if it isnt already.
1338          * If Offline mode is off, we rely on the persistent state of tech.
1339          */
1340         if (global_offlinemode) {
1341                 if (!softblock)
1342                         return __connman_rfkill_block(type, TRUE);
1343         } else {
1344                 if (technology->enable_persistent && softblock)
1345                         return __connman_rfkill_block(type, FALSE);
1346                 /* if technology persistent state is offline */
1347                 if (!technology->enable_persistent && !softblock)
1348                         return __connman_rfkill_block(type, TRUE);
1349         }
1350
1351         return 0;
1352 }
1353
1354 int __connman_technology_update_rfkill(unsigned int index,
1355                                         enum connman_service_type type,
1356                                                 connman_bool_t softblock,
1357                                                 connman_bool_t hardblock)
1358 {
1359         struct connman_technology *technology;
1360         struct connman_rfkill *rfkill;
1361
1362         DBG("index %u soft %u hard %u", index, softblock, hardblock);
1363
1364         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1365         if (rfkill == NULL)
1366                 return -ENXIO;
1367
1368         if (rfkill->softblock == softblock &&
1369                 rfkill->hardblock == hardblock)
1370                 return 0;
1371
1372         rfkill->softblock = softblock;
1373         rfkill->hardblock = hardblock;
1374
1375         technology = technology_find(type);
1376         /* If there is no driver for this type, ignore it. */
1377         if (technology == NULL)
1378                 return -ENXIO;
1379
1380         technology_apply_hardblock_change(technology, hardblock);
1381
1382         if (!global_offlinemode) {
1383                 if (technology->enable_persistent && softblock)
1384                         return __connman_rfkill_block(type, FALSE);
1385                 if (!technology->enable_persistent && !softblock)
1386                         return __connman_rfkill_block(type, TRUE);
1387         }
1388
1389         return 0;
1390 }
1391
1392 int __connman_technology_remove_rfkill(unsigned int index,
1393                                         enum connman_service_type type)
1394 {
1395         struct connman_technology *technology;
1396         struct connman_rfkill *rfkill;
1397
1398         DBG("index %u", index);
1399
1400         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1401         if (rfkill == NULL)
1402                 return -ENXIO;
1403
1404         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
1405
1406         technology = technology_find(type);
1407         if (technology == NULL)
1408                 return -ENXIO;
1409
1410         technology_put(technology);
1411
1412         return 0;
1413 }
1414
1415 int __connman_technology_init(void)
1416 {
1417         DBG("");
1418
1419         connection = connman_dbus_get_connection();
1420
1421         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1422                                                         NULL, free_rfkill);
1423
1424         global_offlinemode = connman_technology_load_offlinemode();
1425
1426         /* This will create settings file if it is missing */
1427         connman_technology_save_offlinemode();
1428
1429         return 0;
1430 }
1431
1432 void __connman_technology_cleanup(void)
1433 {
1434         DBG("");
1435
1436         g_hash_table_destroy(rfkill_list);
1437
1438         dbus_connection_unref(connection);
1439 }