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