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