Updated connman to version 1.35
[platform/upstream/connman.git] / src / technology.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  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 bool global_offlinemode;
45
46 #if defined TIZEN_EXT
47 typedef enum {
48         CONNMAN_SCAN_TYPE_FULL_CHANNEL = 0x00,
49         CONNMAN_SCAN_TYPE_SPECIFIC_AP,
50         CONNMAN_SCAN_TYPE_MULTI_AP,
51 } connman_scan_type_e;
52
53 static connman_scan_type_e g_scan_type = -1;
54 #endif
55
56 struct connman_rfkill {
57         unsigned int index;
58         enum connman_service_type type;
59         bool softblock;
60         bool hardblock;
61 };
62
63 struct connman_technology {
64         int refcount;
65         enum connman_service_type type;
66         char *path;
67         GSList *device_list;
68         bool enabled;
69         char *regdom;
70         bool connected;
71
72         bool tethering;
73         bool tethering_persistent; /* Tells the save status, needed
74                                               * as offline mode might set
75                                               * tethering OFF.
76                                               */
77         char *tethering_ident;
78         char *tethering_passphrase;
79         bool tethering_hidden;
80
81         bool enable_persistent; /* Save the tech state */
82
83         GSList *driver_list;
84
85         DBusMessage *pending_reply;
86         guint pending_timeout;
87
88         GSList *scan_pending;
89
90         bool rfkill_driven;
91         bool softblocked;
92         bool hardblocked;
93         bool dbus_registered;
94 };
95
96 static GSList *driver_list = NULL;
97
98 static int technology_enabled(struct connman_technology *technology);
99 static int technology_disabled(struct connman_technology *technology);
100
101 static gint compare_priority(gconstpointer a, gconstpointer b)
102 {
103         const struct connman_technology_driver *driver1 = a;
104         const struct connman_technology_driver *driver2 = b;
105
106         return driver2->priority - driver1->priority;
107 }
108
109 static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
110 {
111         struct connman_rfkill *rfkill = value;
112         enum connman_service_type type = GPOINTER_TO_INT(user_data);
113
114         /* Calling _technology_rfkill_add will update the tech. */
115         if (rfkill->type == type)
116                 __connman_technology_add_rfkill(rfkill->index, type,
117                                 rfkill->softblock, rfkill->hardblock);
118 }
119
120 bool
121 connman_technology_is_tethering_allowed(enum connman_service_type type)
122 {
123         static char *allowed_default[] = { "wifi", "bluetooth", "gadget",
124                                            NULL };
125         const char *type_str = __connman_service_type2string(type);
126         char **allowed;
127         int i;
128
129         if (!type_str)
130                 return false;
131
132         allowed = connman_setting_get_string_list("TetheringTechnologies");
133         if (!allowed)
134                 allowed = allowed_default;
135
136         for (i = 0; allowed[i]; i++) {
137                 if (g_strcmp0(allowed[i], type_str) == 0)
138                         return true;
139         }
140
141         return false;
142 }
143
144 static const char *get_name(enum connman_service_type type)
145 {
146         switch (type) {
147         case CONNMAN_SERVICE_TYPE_UNKNOWN:
148         case CONNMAN_SERVICE_TYPE_SYSTEM:
149         case CONNMAN_SERVICE_TYPE_GPS:
150         case CONNMAN_SERVICE_TYPE_VPN:
151                 break;
152         case CONNMAN_SERVICE_TYPE_GADGET:
153                 return "Gadget";
154         case CONNMAN_SERVICE_TYPE_ETHERNET:
155                 return "Wired";
156         case CONNMAN_SERVICE_TYPE_WIFI:
157                 return "WiFi";
158         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
159                 return "Bluetooth";
160         case CONNMAN_SERVICE_TYPE_CELLULAR:
161                 return "Cellular";
162         case CONNMAN_SERVICE_TYPE_P2P:
163                 return "P2P";
164         }
165
166         return NULL;
167 }
168
169 static void technology_save(struct connman_technology *technology)
170 {
171         GKeyFile *keyfile;
172         gchar *identifier;
173         const char *name = get_name(technology->type);
174
175         DBG("technology %p type %d name %s", technology, technology->type,
176                                                                         name);
177         if (!name)
178                 return;
179
180         keyfile = __connman_storage_load_global();
181         if (!keyfile)
182                 keyfile = g_key_file_new();
183
184         identifier = g_strdup_printf("%s", name);
185         if (!identifier)
186                 goto done;
187
188         g_key_file_set_boolean(keyfile, identifier, "Enable",
189                                 technology->enable_persistent);
190
191         g_key_file_set_boolean(keyfile, identifier, "Tethering",
192                                 technology->tethering_persistent);
193
194         g_key_file_set_boolean(keyfile, identifier, "Hidden",
195                                 technology->tethering_hidden);
196
197         if (technology->tethering_ident)
198                 g_key_file_set_string(keyfile, identifier,
199                                         "Tethering.Identifier",
200                                         technology->tethering_ident);
201
202         if (technology->tethering_passphrase)
203                 g_key_file_set_string(keyfile, identifier,
204                                         "Tethering.Passphrase",
205                                         technology->tethering_passphrase);
206
207 done:
208         g_free(identifier);
209
210         __connman_storage_save_global(keyfile);
211
212         g_key_file_free(keyfile);
213
214         return;
215 }
216
217 static void tethering_changed(struct connman_technology *technology)
218 {
219         dbus_bool_t tethering = technology->tethering;
220
221         connman_dbus_property_changed_basic(technology->path,
222                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
223                                                 DBUS_TYPE_BOOLEAN, &tethering);
224
225         technology_save(technology);
226 }
227
228 int connman_technology_tethering_notify(struct connman_technology *technology,
229                                                         bool enabled)
230 {
231         int err;
232
233         DBG("technology %p enabled %u", technology, enabled);
234
235         if (technology->tethering == enabled)
236                 return -EALREADY;
237
238         if (enabled) {
239                 err = __connman_tethering_set_enabled();
240                 if (err < 0)
241                         return err;
242         } else
243                 __connman_tethering_set_disabled();
244
245         technology->tethering = enabled;
246         tethering_changed(technology);
247
248         return 0;
249 }
250
251 static int set_tethering(struct connman_technology *technology,
252                                 bool enabled)
253 {
254         int result = -EOPNOTSUPP;
255         int err;
256         const char *ident, *passphrase, *bridge;
257         GSList *tech_drivers;
258
259         ident = technology->tethering_ident;
260         passphrase = technology->tethering_passphrase;
261
262         __sync_synchronize();
263         if (!technology->enabled)
264                 return -EACCES;
265
266         bridge = __connman_tethering_get_bridge();
267         if (!bridge)
268                 return -EOPNOTSUPP;
269
270         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && (!ident))
271                 return -EINVAL;
272
273         for (tech_drivers = technology->driver_list; tech_drivers;
274              tech_drivers = g_slist_next(tech_drivers)) {
275                 struct connman_technology_driver *driver = tech_drivers->data;
276
277                 if (!driver || !driver->set_tethering)
278                         continue;
279
280                 err = driver->set_tethering(technology, ident, passphrase,
281                                 bridge, enabled);
282
283                 if (result == -EINPROGRESS)
284                         continue;
285
286                 if (err == -EINPROGRESS || err == 0)
287                         result = err;
288         }
289
290         return result;
291 }
292
293 void connman_technology_regdom_notify(struct connman_technology *technology,
294                                                         const char *alpha2)
295 {
296         DBG("");
297
298         if (!alpha2)
299                 connman_error("Failed to set regulatory domain");
300         else
301                 DBG("Regulatory domain set to %s", alpha2);
302
303         g_free(technology->regdom);
304         technology->regdom = g_strdup(alpha2);
305 }
306
307 static int set_regdom_by_device(struct connman_technology *technology,
308                                                         const char *alpha2)
309 {
310         GSList *list;
311
312         for (list = technology->device_list; list; list = list->next) {
313                 struct connman_device *device = list->data;
314
315                 if (connman_device_set_regdom(device, alpha2) != 0)
316                         return -ENOTSUP;
317         }
318
319         return 0;
320 }
321
322 int connman_technology_set_regdom(const char *alpha2)
323 {
324         GSList *list, *tech_drivers;
325
326         for (list = technology_list; list; list = list->next) {
327                 struct connman_technology *technology = list->data;
328
329                 if (set_regdom_by_device(technology, alpha2) != 0) {
330
331                         for (tech_drivers = technology->driver_list;
332                              tech_drivers;
333                              tech_drivers = g_slist_next(tech_drivers)) {
334
335                                 struct connman_technology_driver *driver =
336                                         tech_drivers->data;
337
338                                 if (driver->set_regdom)
339                                         driver->set_regdom(technology, alpha2);
340                         }
341                 }
342         }
343
344         return 0;
345 }
346
347 static struct connman_technology *technology_find(enum connman_service_type type)
348 {
349         GSList *list;
350
351         DBG("type %d", type);
352
353         for (list = technology_list; list; list = list->next) {
354                 struct connman_technology *technology = list->data;
355
356                 if (technology->type == type)
357                         return technology;
358         }
359
360         return NULL;
361 }
362
363 bool connman_technology_get_wifi_tethering(const char **ssid,
364                                                         const char **psk)
365 {
366         struct connman_technology *technology;
367
368         if (!ssid || !psk)
369                 return false;
370
371         *ssid = *psk = NULL;
372
373         technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
374         if (!technology)
375                 return false;
376
377         if (!technology->tethering)
378                 return false;
379
380         *ssid = technology->tethering_ident;
381         *psk = technology->tethering_passphrase;
382
383         return true;
384 }
385
386 static void free_rfkill(gpointer data)
387 {
388         struct connman_rfkill *rfkill = data;
389
390         g_free(rfkill);
391 }
392
393 static void technology_load(struct connman_technology *technology)
394 {
395         GKeyFile *keyfile;
396         gchar *identifier;
397         GError *error = NULL;
398         bool enable, need_saving = false;
399
400         DBG("technology %p", technology);
401
402         keyfile = __connman_storage_load_global();
403         /* Fallback on disabling technology if file not found. */
404         if (!keyfile) {
405                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
406                         /* We enable ethernet by default */
407                         technology->enable_persistent = true;
408                 else
409                         technology->enable_persistent = false;
410                 return;
411         }
412
413         identifier = g_strdup_printf("%s", get_name(technology->type));
414         if (!identifier)
415                 goto done;
416
417         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
418         if (!error)
419                 technology->enable_persistent = enable;
420         else {
421                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
422                         technology->enable_persistent = true;
423                 else
424                         technology->enable_persistent = false;
425
426                 need_saving = true;
427                 g_clear_error(&error);
428         }
429
430         enable = g_key_file_get_boolean(keyfile, identifier,
431                                         "Tethering", &error);
432         if (!error)
433                 technology->tethering_persistent = enable;
434         else {
435                 need_saving = true;
436                 g_clear_error(&error);
437         }
438
439         if (need_saving)
440                 technology_save(technology);
441
442         technology->tethering_ident = g_key_file_get_string(keyfile,
443                                 identifier, "Tethering.Identifier", NULL);
444
445         technology->tethering_passphrase = g_key_file_get_string(keyfile,
446                                 identifier, "Tethering.Passphrase", NULL);
447 done:
448         g_free(identifier);
449
450         g_key_file_free(keyfile);
451
452         return;
453 }
454
455 bool __connman_technology_get_offlinemode(void)
456 {
457         return global_offlinemode;
458 }
459
460 static void connman_technology_save_offlinemode(void)
461 {
462         GKeyFile *keyfile;
463         GError *error = NULL;
464         bool offlinemode;
465
466         keyfile = __connman_storage_load_global();
467
468         if (!keyfile) {
469                 keyfile = g_key_file_new();
470                 g_key_file_set_boolean(keyfile, "global",
471                                         "OfflineMode", global_offlinemode);
472
473                 __connman_storage_save_global(keyfile);
474         }
475         else {
476                 offlinemode = g_key_file_get_boolean(keyfile, "global",
477                                                 "OfflineMode", &error);
478
479                 if (error || offlinemode != global_offlinemode) {
480                         g_key_file_set_boolean(keyfile, "global",
481                                         "OfflineMode", global_offlinemode);
482                         if (error)
483                                 g_clear_error(&error);
484
485                         __connman_storage_save_global(keyfile);
486                 }
487         }
488
489         g_key_file_free(keyfile);
490
491         return;
492 }
493
494 static bool connman_technology_load_offlinemode(void)
495 {
496         GKeyFile *keyfile;
497         GError *error = NULL;
498         bool offlinemode;
499
500         /* If there is a error, we enable offlinemode */
501         keyfile = __connman_storage_load_global();
502         if (!keyfile)
503                 return false;
504
505         offlinemode = g_key_file_get_boolean(keyfile, "global",
506                                                 "OfflineMode", &error);
507         if (error) {
508                 offlinemode = false;
509                 g_clear_error(&error);
510         }
511
512         g_key_file_free(keyfile);
513
514         return offlinemode;
515 }
516
517 static void append_properties(DBusMessageIter *iter,
518                 struct connman_technology *technology)
519 {
520         DBusMessageIter dict;
521         dbus_bool_t val;
522         const char *str;
523
524         connman_dbus_dict_open(iter, &dict);
525
526         str = get_name(technology->type);
527         if (str)
528                 connman_dbus_dict_append_basic(&dict, "Name",
529                                                 DBUS_TYPE_STRING, &str);
530
531         str = __connman_service_type2string(technology->type);
532         if (str)
533                 connman_dbus_dict_append_basic(&dict, "Type",
534                                                 DBUS_TYPE_STRING, &str);
535
536         __sync_synchronize();
537         val = technology->enabled;
538         connman_dbus_dict_append_basic(&dict, "Powered",
539                                         DBUS_TYPE_BOOLEAN,
540                                         &val);
541
542         val = technology->connected;
543         connman_dbus_dict_append_basic(&dict, "Connected",
544                                         DBUS_TYPE_BOOLEAN,
545                                         &val);
546
547         val = technology->tethering;
548         connman_dbus_dict_append_basic(&dict, "Tethering",
549                                         DBUS_TYPE_BOOLEAN,
550                                         &val);
551
552         if (technology->tethering_ident)
553                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
554                                         DBUS_TYPE_STRING,
555                                         &technology->tethering_ident);
556
557         if (technology->tethering_passphrase)
558                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
559                                         DBUS_TYPE_STRING,
560                                         &technology->tethering_passphrase);
561
562         val = technology->tethering_hidden;
563         connman_dbus_dict_append_basic(&dict, "Hidden",
564                                         DBUS_TYPE_BOOLEAN,
565                                         &val);
566
567         connman_dbus_dict_close(iter, &dict);
568 }
569
570 static void technology_added_signal(struct connman_technology *technology)
571 {
572         DBusMessage *signal;
573         DBusMessageIter iter;
574
575         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
576                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
577         if (!signal)
578                 return;
579
580         dbus_message_iter_init_append(signal, &iter);
581         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
582                                                         &technology->path);
583         append_properties(&iter, technology);
584
585         dbus_connection_send(connection, signal, NULL);
586         dbus_message_unref(signal);
587 }
588
589 static void technology_removed_signal(struct connman_technology *technology)
590 {
591         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
592                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
593                         DBUS_TYPE_OBJECT_PATH, &technology->path,
594                         DBUS_TYPE_INVALID);
595 }
596
597 static DBusMessage *get_properties(DBusConnection *conn,
598                                         DBusMessage *message, void *user_data)
599 {
600         struct connman_technology *technology = user_data;
601         DBusMessage *reply;
602         DBusMessageIter iter;
603
604         reply = dbus_message_new_method_return(message);
605         if (!reply)
606                 return NULL;
607
608         dbus_message_iter_init_append(reply, &iter);
609         append_properties(&iter, technology);
610
611         return reply;
612 }
613
614 void __connman_technology_list_struct(DBusMessageIter *array)
615 {
616         GSList *list;
617         DBusMessageIter entry;
618
619         for (list = technology_list; list; list = list->next) {
620                 struct connman_technology *technology = list->data;
621
622                 if (!technology->path ||
623                                 (technology->rfkill_driven &&
624                                  technology->hardblocked))
625                         continue;
626
627                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
628                                 NULL, &entry);
629                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
630                                 &technology->path);
631                 append_properties(&entry, technology);
632                 dbus_message_iter_close_container(array, &entry);
633         }
634 }
635
636 static gboolean technology_pending_reply(gpointer user_data)
637 {
638         struct connman_technology *technology = user_data;
639         DBusMessage *reply;
640
641         /* Power request timedout, send ETIMEDOUT. */
642         if (technology->pending_reply) {
643                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
644                 if (reply)
645                         g_dbus_send_message(connection, reply);
646
647                 dbus_message_unref(technology->pending_reply);
648                 technology->pending_reply = NULL;
649                 technology->pending_timeout = 0;
650         }
651
652         return FALSE;
653 }
654
655 static int technology_affect_devices(struct connman_technology *technology,
656                                                 bool enable_device)
657 {
658         int err = 0, err_dev;
659         GSList *list;
660
661         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
662                 if (enable_device)
663                         __connman_technology_enabled(technology->type);
664                 else
665                         __connman_technology_disabled(technology->type);
666                 return 0;
667         }
668
669         for (list = technology->device_list; list; list = list->next) {
670                 struct connman_device *device = list->data;
671
672                 if (enable_device)
673                         err_dev = __connman_device_enable(device);
674                 else
675                         err_dev = __connman_device_disable(device);
676
677                 if (err_dev < 0 && err_dev != -EALREADY)
678                         err = err_dev;
679         }
680
681         return err;
682 }
683
684 static void powered_changed(struct connman_technology *technology)
685 {
686         dbus_bool_t enabled;
687
688         if (!technology->dbus_registered)
689                 return;
690
691         if (technology->pending_reply) {
692                 g_dbus_send_reply(connection,
693                                 technology->pending_reply, DBUS_TYPE_INVALID);
694                 dbus_message_unref(technology->pending_reply);
695                 technology->pending_reply = NULL;
696
697                 g_source_remove(technology->pending_timeout);
698                 technology->pending_timeout = 0;
699         }
700
701         __sync_synchronize();
702         enabled = technology->enabled;
703 #if defined TIZEN_EXT
704         DBG("ConnMan, Powered : %s, %s",
705                         enabled ? "TRUE" : "FALSE",technology->path);
706 #endif
707         connman_dbus_property_changed_basic(technology->path,
708                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
709                         DBUS_TYPE_BOOLEAN, &enabled);
710 }
711
712 static void enable_tethering(struct connman_technology *technology)
713 {
714         int ret;
715
716         if (!connman_setting_get_bool("PersistentTetheringMode"))
717                 return;
718
719         ret = set_tethering(technology, true);
720         if (ret < 0 && ret != -EALREADY)
721                 DBG("Cannot enable tethering yet for %s (%d/%s)",
722                         get_name(technology->type),
723                         -ret, strerror(-ret));
724 }
725
726 static int technology_enabled(struct connman_technology *technology)
727 {
728         __sync_synchronize();
729         if (technology->enabled)
730                 return -EALREADY;
731
732         technology->enabled = true;
733
734         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
735                 struct connman_technology *p2p;
736
737                 p2p = technology_find(CONNMAN_SERVICE_TYPE_P2P);
738                 if (p2p && !p2p->enabled && p2p->enable_persistent)
739                         technology_enabled(p2p);
740         }
741
742         if (technology->tethering_persistent)
743                 enable_tethering(technology);
744
745         powered_changed(technology);
746
747         return 0;
748 }
749
750 static int technology_enable(struct connman_technology *technology)
751 {
752         int err = 0;
753         int err_dev;
754
755         DBG("technology %p enable", technology);
756
757         __sync_synchronize();
758
759         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
760                 struct connman_technology *wifi;
761
762                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
763                 if (wifi && wifi->enabled)
764                         return technology_enabled(technology);
765                 return 0;
766         }
767
768         if (technology->enabled)
769                 return -EALREADY;
770
771         if (technology->pending_reply)
772                 return -EBUSY;
773
774         if (connman_setting_get_bool("PersistentTetheringMode") &&
775                                         technology->tethering)
776                 set_tethering(technology, true);
777
778         if (technology->rfkill_driven)
779                 err = __connman_rfkill_block(technology->type, false);
780
781         err_dev = technology_affect_devices(technology, true);
782
783         if (!technology->rfkill_driven)
784                 err = err_dev;
785
786         return err;
787 }
788
789 static int technology_disabled(struct connman_technology *technology)
790 {
791         __sync_synchronize();
792         if (!technology->enabled)
793                 return -EALREADY;
794
795         technology->enabled = false;
796
797         powered_changed(technology);
798
799         return 0;
800 }
801
802 static int technology_disable(struct connman_technology *technology)
803 {
804         int err;
805
806         DBG("technology %p disable", technology);
807
808         __sync_synchronize();
809
810         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
811                 technology->enable_persistent = false;
812                 return technology_disabled(technology);
813         } else if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
814                 struct connman_technology *p2p;
815
816                 p2p = technology_find(CONNMAN_SERVICE_TYPE_P2P);
817                 if (p2p && p2p->enabled) {
818                         p2p->enable_persistent = true;
819                         technology_disabled(p2p);
820                 }
821         }
822
823         if (!technology->enabled)
824                 return -EALREADY;
825
826         if (technology->pending_reply)
827                 return -EBUSY;
828
829         if (technology->tethering)
830                 set_tethering(technology, false);
831
832         err = technology_affect_devices(technology, false);
833
834         if (technology->rfkill_driven)
835                 err = __connman_rfkill_block(technology->type, true);
836
837         return err;
838 }
839
840 static DBusMessage *set_powered(struct connman_technology *technology,
841                                 DBusMessage *msg, bool powered)
842 {
843         DBusMessage *reply = NULL;
844         int err = 0;
845
846         if (technology->rfkill_driven && technology->hardblocked) {
847                 err = -EACCES;
848                 goto make_reply;
849         }
850
851         if (powered)
852                 err = technology_enable(technology);
853         else
854                 err = technology_disable(technology);
855
856         if (err != -EBUSY) {
857                 technology->enable_persistent = powered;
858                 technology_save(technology);
859         }
860
861 make_reply:
862         if (err == -EINPROGRESS) {
863                 technology->pending_reply = dbus_message_ref(msg);
864                 technology->pending_timeout = g_timeout_add_seconds(10,
865                                         technology_pending_reply, technology);
866         } else if (err == -EALREADY) {
867                 if (powered)
868                         reply = __connman_error_already_enabled(msg);
869                 else
870                         reply = __connman_error_already_disabled(msg);
871         } else if (err < 0)
872                 reply = __connman_error_failed(msg, -err);
873         else
874                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
875
876         return reply;
877 }
878
879 static DBusMessage *set_property(DBusConnection *conn,
880                                         DBusMessage *msg, void *data)
881 {
882         struct connman_technology *technology = data;
883         DBusMessageIter iter, value;
884         const char *name;
885         int type, err;
886
887         DBG("conn %p", conn);
888
889         if (!dbus_message_iter_init(msg, &iter))
890                 return __connman_error_invalid_arguments(msg);
891
892         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
893                 return __connman_error_invalid_arguments(msg);
894
895         dbus_message_iter_get_basic(&iter, &name);
896         dbus_message_iter_next(&iter);
897
898         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
899                 return __connman_error_invalid_arguments(msg);
900
901         dbus_message_iter_recurse(&iter, &value);
902
903         type = dbus_message_iter_get_arg_type(&value);
904
905         DBG("property %s", name);
906
907         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && technology->connected) {
908                 uid_t uid;
909                 if (connman_dbus_get_connection_unix_user_sync(conn,
910                                                 dbus_message_get_sender(msg),
911                                                 &uid) < 0) {
912                         DBG("Can not get unix user id!");
913                         return __connman_error_permission_denied(msg);
914                 }
915
916                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
917                         DBG("Not allow this user to operate wifi technology now!");
918                         return __connman_error_permission_denied(msg);
919                 }
920         }
921
922         if (g_str_equal(name, "Tethering")) {
923                 dbus_bool_t tethering;
924                 int err;
925
926                 if (type != DBUS_TYPE_BOOLEAN)
927                         return __connman_error_invalid_arguments(msg);
928
929                 if (!connman_technology_is_tethering_allowed(technology->type)) {
930                         DBG("%s tethering not allowed by config file",
931                                 __connman_service_type2string(technology->type));
932                         return __connman_error_not_supported(msg);
933                 }
934
935                 dbus_message_iter_get_basic(&value, &tethering);
936
937                 if (technology->tethering == tethering) {
938                         if (!tethering)
939                                 return __connman_error_already_disabled(msg);
940                         else
941                                 return __connman_error_already_enabled(msg);
942                 }
943
944                 err = set_tethering(technology, tethering);
945                 if (err < 0)
946                         return __connman_error_failed(msg, -err);
947
948                 technology->tethering_persistent = tethering;
949
950                 technology_save(technology);
951
952         } else if (g_str_equal(name, "TetheringIdentifier")) {
953                 const char *str;
954
955                 dbus_message_iter_get_basic(&value, &str);
956
957                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
958                         return __connman_error_not_supported(msg);
959
960                 if (strlen(str) < 1 || strlen(str) > 32)
961                         return __connman_error_invalid_arguments(msg);
962
963                 if (g_strcmp0(technology->tethering_ident, str) != 0) {
964                         g_free(technology->tethering_ident);
965                         technology->tethering_ident = g_strdup(str);
966                         technology_save(technology);
967
968                         connman_dbus_property_changed_basic(technology->path,
969                                                 CONNMAN_TECHNOLOGY_INTERFACE,
970                                                 "TetheringIdentifier",
971                                                 DBUS_TYPE_STRING,
972                                                 &technology->tethering_ident);
973                 }
974         } else if (g_str_equal(name, "TetheringPassphrase")) {
975                 const char *str;
976
977                 dbus_message_iter_get_basic(&value, &str);
978
979                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
980                         return __connman_error_not_supported(msg);
981
982                 err = __connman_service_check_passphrase(CONNMAN_SERVICE_SECURITY_PSK,
983                                                         str);
984                 if (err < 0)
985                         return __connman_error_passphrase_required(msg);
986
987                 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
988                         g_free(technology->tethering_passphrase);
989                         technology->tethering_passphrase = g_strdup(str);
990                         technology_save(technology);
991
992                         connman_dbus_property_changed_basic(technology->path,
993                                         CONNMAN_TECHNOLOGY_INTERFACE,
994                                         "TetheringPassphrase",
995                                         DBUS_TYPE_STRING,
996                                         &technology->tethering_passphrase);
997                 }
998         } else if (g_str_equal(name, "Hidden")) {
999                 dbus_bool_t hidden;
1000
1001                 if (type != DBUS_TYPE_BOOLEAN)
1002                         return __connman_error_invalid_arguments(msg);
1003
1004                 dbus_message_iter_get_basic(&value, &hidden);
1005
1006                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1007                         return __connman_error_not_supported(msg);
1008
1009                 technology->tethering_hidden = hidden;
1010                 technology_save(technology);
1011
1012                 connman_dbus_property_changed_basic(technology->path,
1013                                         CONNMAN_TECHNOLOGY_INTERFACE,
1014                                         "Hidden",
1015                                         DBUS_TYPE_BOOLEAN,
1016                                         &hidden);
1017         } else if (g_str_equal(name, "Powered")) {
1018                 dbus_bool_t enable;
1019
1020                 if (type != DBUS_TYPE_BOOLEAN)
1021                         return __connman_error_invalid_arguments(msg);
1022
1023                 dbus_message_iter_get_basic(&value, &enable);
1024
1025                 return set_powered(technology, msg, enable);
1026         } else
1027                 return __connman_error_invalid_property(msg);
1028
1029         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1030 }
1031
1032 static void reply_scan_pending(struct connman_technology *technology, int err)
1033 {
1034         DBusMessage *reply;
1035
1036         DBG("technology %p err %d", technology, err);
1037
1038         while (technology->scan_pending) {
1039                 DBusMessage *msg = technology->scan_pending->data;
1040
1041                 DBG("reply to %s", dbus_message_get_sender(msg));
1042
1043                 if (err == 0)
1044                         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1045                 else
1046                         reply = __connman_error_failed(msg, -err);
1047                 g_dbus_send_message(connection, reply);
1048                 dbus_message_unref(msg);
1049
1050                 technology->scan_pending =
1051                         g_slist_delete_link(technology->scan_pending,
1052                                         technology->scan_pending);
1053         }
1054 }
1055
1056 #if defined TIZEN_EXT
1057 dbus_bool_t __connman_technology_notify_scan_changed(const char *key, void *val)
1058 {
1059         DBG("key %s", key);
1060         DBusMessage *signal;
1061         DBusMessageIter iter;
1062         dbus_bool_t result = FALSE;
1063
1064         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1065                         CONNMAN_MANAGER_INTERFACE, "ScanChanged");
1066         if (!signal)
1067                 return result;
1068
1069         dbus_message_iter_init_append(signal, &iter);
1070         connman_dbus_property_append_basic(&iter, key, DBUS_TYPE_BOOLEAN, val);
1071
1072         result = dbus_connection_send(connection, signal, NULL);
1073         dbus_message_unref(signal);
1074
1075         DBG("Successfuly sent signal");
1076
1077         return result;
1078 }
1079 #endif
1080
1081 void __connman_technology_scan_started(struct connman_device *device)
1082 {
1083         DBG("device %p", device);
1084 #if defined TIZEN_EXT
1085         dbus_bool_t status = 1;
1086         __connman_technology_notify_scan_changed("scan_started", &status);
1087 #endif
1088 }
1089
1090 void __connman_technology_scan_stopped(struct connman_device *device,
1091                                         enum connman_service_type type)
1092 {
1093         int count = 0;
1094         struct connman_technology *technology;
1095         GSList *list;
1096
1097         technology = technology_find(type);
1098
1099         DBG("technology %p device %p", technology, device);
1100
1101         if (!technology)
1102                 return;
1103
1104         for (list = technology->device_list; list; list = list->next) {
1105                 struct connman_device *other_device = list->data;
1106
1107                 if (device == other_device)
1108                         continue;
1109
1110                 if (__connman_device_get_service_type(other_device) != type)
1111                         continue;
1112
1113                 if (connman_device_get_scanning(other_device))
1114                         count += 1;
1115         }
1116
1117 #if defined TIZEN_EXT
1118         if (count == 0) {
1119                 DBusMessage *signal;
1120                 DBusMessageIter iter;
1121                 dbus_bool_t status = 0;
1122                 __connman_technology_notify_scan_changed("scan_done", &status);
1123
1124                 signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1125                                 CONNMAN_MANAGER_INTERFACE, "ScanDone");
1126                 if (!signal)
1127                         return;
1128
1129                 dbus_message_iter_init_append(signal, &iter);
1130                 connman_dbus_property_append_basic(&iter, "Scantype",
1131                                 DBUS_TYPE_INT32, &g_scan_type);
1132
1133                 dbus_connection_send(connection, signal, NULL);
1134                 dbus_message_unref(signal);
1135                 reply_scan_pending(technology, 0);
1136
1137                 DBG("Successfuly sent ScanDone signal");
1138         }
1139 #else
1140         if (count == 0)
1141                 reply_scan_pending(technology, 0);
1142 #endif
1143 }
1144
1145 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
1146                                                 int result, const char *alpha2)
1147 {
1148         bool regdom_set = false;
1149         struct connman_technology *technology;
1150         enum connman_service_type type;
1151         GSList *tech_drivers;
1152
1153         type = __connman_device_get_service_type(device);
1154         technology = technology_find(type);
1155
1156         if (!technology)
1157                 return;
1158
1159         if (result < 0) {
1160
1161                 for (tech_drivers = technology->driver_list;
1162                      tech_drivers;
1163                      tech_drivers = g_slist_next(tech_drivers)) {
1164                         struct connman_technology_driver *driver =
1165                                 tech_drivers->data;
1166
1167                         if (driver->set_regdom) {
1168                                 driver->set_regdom(technology, alpha2);
1169                                 regdom_set = true;
1170                         }
1171
1172                 }
1173
1174                 if (!regdom_set)
1175                         alpha2 = NULL;
1176         }
1177
1178         connman_technology_regdom_notify(technology, alpha2);
1179 }
1180
1181 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
1182 {
1183         struct connman_technology *technology = data;
1184         int err;
1185
1186         DBG("technology %p request from %s", technology,
1187                         dbus_message_get_sender(msg));
1188
1189         if (technology->type == CONNMAN_SERVICE_TYPE_P2P &&
1190                                 !technology->enabled)
1191                 return __connman_error_permission_denied(msg);
1192
1193         dbus_message_ref(msg);
1194 #if !defined TIZEN_EXT
1195         technology->scan_pending =
1196                 g_slist_prepend(technology->scan_pending, msg);
1197 #endif
1198
1199         err = __connman_device_request_scan(technology->type);
1200 #if defined TIZEN_EXT
1201         if (err < 0)
1202                 return __connman_error_failed(msg, -err);
1203 #else
1204         if (err < 0)
1205                 reply_scan_pending(technology, err);
1206 #endif
1207
1208 #if defined TIZEN_EXT
1209         if (err == 0) {
1210                 g_scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1211                 DBG("g_scan_type %d", g_scan_type);
1212         }
1213         technology->scan_pending =
1214                 g_slist_prepend(technology->scan_pending, msg);
1215 #endif
1216         return NULL;
1217 }
1218
1219 #if defined TIZEN_EXT
1220 static DBusMessage *specific_scan(DBusConnection *conn, DBusMessage *msg, void *data)
1221 {
1222         struct connman_technology *technology = data;
1223         GSList *specific_scan_list = NULL;
1224         int scan_type = 0;
1225         const char *name = NULL;
1226         unsigned int freq = 0;
1227         DBusMessageIter iter, dict;
1228         int err;
1229
1230         DBG("technology %p request from %s", technology,
1231                         dbus_message_get_sender(msg));
1232
1233         if (!dbus_message_iter_init(msg, &iter))
1234                 return __connman_error_invalid_arguments(msg);
1235
1236         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1237                 return __connman_error_invalid_arguments(msg);
1238
1239         dbus_message_iter_recurse(&iter, &dict);
1240         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1241                 DBusMessageIter entry, value2;
1242                 const char *key;
1243                 int type;
1244
1245                 dbus_message_iter_recurse(&dict, &entry);
1246                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
1247                         g_slist_free_full(specific_scan_list, g_free);
1248                         return __connman_error_invalid_arguments(msg);
1249                 }
1250
1251                 dbus_message_iter_get_basic(&entry, &key);
1252                 dbus_message_iter_next(&entry);
1253
1254                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
1255                         g_slist_free_full(specific_scan_list, g_free);
1256                         return __connman_error_invalid_arguments(msg);
1257                 }
1258
1259                 dbus_message_iter_recurse(&entry, &value2);
1260                 type = dbus_message_iter_get_arg_type(&value2);
1261                 if (g_str_equal(key, "SSID")) {
1262                         if (type != DBUS_TYPE_STRING) {
1263                                 g_slist_free_full(specific_scan_list, g_free);
1264                                 return __connman_error_invalid_arguments(msg);
1265                         }
1266
1267                         scan_type = 1; /* SSID based scan */
1268                         dbus_message_iter_get_basic(&value2, &name);
1269                         DBG("name %s", name);
1270                         specific_scan_list = g_slist_append(specific_scan_list, g_strdup(name));
1271                 } else if (g_str_equal(key, "Frequency")) {
1272                         if (type != DBUS_TYPE_UINT16) {
1273                                 g_slist_free_full(specific_scan_list, g_free);
1274                                 return __connman_error_invalid_arguments(msg);
1275                         }
1276
1277                         scan_type = 2; /* Frequency based scan */
1278                         dbus_message_iter_get_basic(&value2, &freq);
1279                         DBG("freq %d", freq);
1280                         specific_scan_list = g_slist_append(specific_scan_list, GINT_TO_POINTER(freq));
1281                 }
1282                 dbus_message_iter_next(&dict);
1283         }
1284
1285         dbus_message_ref(msg);
1286
1287         err = __connman_device_request_specific_scan(technology->type, scan_type, specific_scan_list);
1288         if (err < 0)
1289                 return __connman_error_failed(msg, -err);
1290
1291         if (err == 0) {
1292                 guint list_size = g_slist_length(specific_scan_list);
1293                 if (list_size == 1)
1294                         g_scan_type = CONNMAN_SCAN_TYPE_SPECIFIC_AP;
1295                 else
1296                         g_scan_type = CONNMAN_SCAN_TYPE_MULTI_AP;
1297                 DBG("list_size %u g_scan_type %d", list_size, g_scan_type);
1298         }
1299         technology->scan_pending =
1300                 g_slist_prepend(technology->scan_pending, msg);
1301
1302         if (scan_type == 1) {
1303                 g_slist_free_full(specific_scan_list, g_free);
1304                 scan_type = 0;
1305         }
1306         return NULL;
1307 }
1308
1309 static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data)
1310 {
1311         DBusMessage *reply;
1312         DBusMessageIter iter, dict;
1313         GSList *list;
1314         struct connman_technology *technology = data;
1315         dbus_bool_t scanning = false;
1316
1317         DBG("technology %p", technology);
1318
1319         for (list = technology->device_list; list; list = list->next) {
1320                 struct connman_device *device = list->data;
1321                 scanning = connman_device_get_scanning(device);
1322                 if(scanning)
1323                         break;
1324         }
1325
1326         DBG("scanning : %d", scanning);
1327         reply = dbus_message_new_method_return(msg);
1328         if (!reply)
1329                 return NULL;
1330
1331         dbus_message_iter_init_append(reply, &iter);
1332
1333         connman_dbus_dict_open(&iter, &dict);
1334         connman_dbus_dict_append_basic(&dict, "Scanstate",
1335                                         DBUS_TYPE_BOOLEAN,
1336                                         &scanning);
1337
1338         connman_dbus_dict_close(&iter, &dict);
1339
1340         return reply;
1341 }
1342 #endif
1343
1344 static const GDBusMethodTable technology_methods[] = {
1345         { GDBUS_DEPRECATED_METHOD("GetProperties",
1346                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1347                         get_properties) },
1348         { GDBUS_ASYNC_METHOD("SetProperty",
1349                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1350                         NULL, set_property) },
1351         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
1352 #if defined TIZEN_EXT
1353         { GDBUS_ASYNC_METHOD("SpecificScan", GDBUS_ARGS({ "specificscan", "a{sv}" }),
1354                         NULL, specific_scan) },
1355         { GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }),
1356                         get_scan_state) },
1357 #endif
1358         { },
1359 };
1360
1361 static const GDBusSignalTable technology_signals[] = {
1362         { GDBUS_SIGNAL("PropertyChanged",
1363                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1364         { GDBUS_SIGNAL("DhcpConnected",
1365                         GDBUS_ARGS({ "aptype", "s" },
1366                                 { "ipaddr", "s" },
1367                                 { "macaddr", "s" },
1368                                 { "hostname", "s" })) },
1369         { GDBUS_SIGNAL("DhcpLeaseDeleted",
1370                         GDBUS_ARGS({ "aptype", "s" },
1371                                 { "ipaddr", "s" },
1372                                 { "macaddr", "s" },
1373                                 { "hostname", "s" })) },
1374         { },
1375 };
1376
1377 static bool technology_dbus_register(struct connman_technology *technology)
1378 {
1379         if (technology->dbus_registered ||
1380                                 (technology->rfkill_driven &&
1381                                  technology->hardblocked))
1382                 return true;
1383
1384         if (!g_dbus_register_interface(connection, technology->path,
1385                                         CONNMAN_TECHNOLOGY_INTERFACE,
1386                                         technology_methods, technology_signals,
1387                                         NULL, technology, NULL)) {
1388                 connman_error("Failed to register %s", technology->path);
1389                 return false;
1390         }
1391
1392         technology_added_signal(technology);
1393         technology->dbus_registered = true;
1394
1395         return true;
1396 }
1397
1398 static void technology_dbus_unregister(struct connman_technology *technology)
1399 {
1400         if (!technology->dbus_registered)
1401                 return;
1402
1403         technology_removed_signal(technology);
1404         g_dbus_unregister_interface(connection, technology->path,
1405                 CONNMAN_TECHNOLOGY_INTERFACE);
1406
1407         technology->dbus_registered = false;
1408 }
1409
1410 static void technology_put(struct connman_technology *technology)
1411 {
1412         DBG("technology %p", technology);
1413
1414         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
1415                 return;
1416
1417         reply_scan_pending(technology, -EINTR);
1418
1419         while (technology->driver_list) {
1420                 struct connman_technology_driver *driver;
1421
1422                 driver = technology->driver_list->data;
1423
1424                 if (driver->remove)
1425                         driver->remove(technology);
1426
1427                 technology->driver_list =
1428                         g_slist_delete_link(technology->driver_list,
1429                                         technology->driver_list);
1430         }
1431
1432         technology_list = g_slist_remove(technology_list, technology);
1433
1434         technology_dbus_unregister(technology);
1435
1436         g_slist_free(technology->device_list);
1437
1438     if (technology->pending_reply) {
1439         dbus_message_unref(technology->pending_reply);
1440         technology->pending_reply = NULL;
1441         g_source_remove(technology->pending_timeout);
1442         technology->pending_timeout = 0;
1443     }
1444
1445         g_free(technology->path);
1446         g_free(technology->regdom);
1447         g_free(technology->tethering_ident);
1448         g_free(technology->tethering_passphrase);
1449         g_free(technology);
1450 }
1451
1452 static struct connman_technology *technology_get(enum connman_service_type type)
1453 {
1454         GSList *tech_drivers = NULL;
1455         struct connman_technology_driver *driver;
1456         struct connman_technology *technology;
1457         const char *str;
1458         GSList *list;
1459
1460         DBG("type %d", type);
1461
1462         str = __connman_service_type2string(type);
1463         if (!str)
1464                 return NULL;
1465
1466         technology = technology_find(type);
1467         if (technology) {
1468                 if (type != CONNMAN_SERVICE_TYPE_P2P)
1469                         __sync_fetch_and_add(&technology->refcount, 1);
1470                 return technology;
1471         }
1472
1473         /* First check if we have a driver for this technology type */
1474         for (list = driver_list; list; list = list->next) {
1475                 driver = list->data;
1476
1477                 if (driver->type == type) {
1478                         DBG("technology %p driver %p", technology, driver);
1479                         tech_drivers = g_slist_append(tech_drivers, driver);
1480                 }
1481         }
1482
1483         if (!tech_drivers) {
1484                 DBG("No matching drivers found for %s.",
1485                                 __connman_service_type2string(type));
1486                 return NULL;
1487         }
1488
1489         technology = g_try_new0(struct connman_technology, 1);
1490         if (!technology)
1491                 return NULL;
1492
1493         technology->refcount = 1;
1494         technology->type = type;
1495         technology->tethering_hidden = FALSE;
1496         technology->path = g_strdup_printf("%s/technology/%s",
1497                                                         CONNMAN_PATH, str);
1498
1499         technology_load(technology);
1500         technology_list = g_slist_prepend(technology_list, technology);
1501         technology->driver_list = tech_drivers;
1502
1503         for (list = tech_drivers; list; list = list->next) {
1504                 driver = list->data;
1505
1506                 if (driver->probe && driver->probe(technology) < 0)
1507                         DBG("Driver probe failed for technology %p",
1508                                         technology);
1509         }
1510
1511         if (!technology_dbus_register(technology)) {
1512                 technology_put(technology);
1513                 return NULL;
1514         }
1515
1516         if (type == CONNMAN_SERVICE_TYPE_P2P) {
1517                 struct connman_technology *wifi;
1518                 bool enable;
1519
1520                 enable = technology->enable_persistent;
1521
1522                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
1523                 if (enable && wifi)
1524                         enable = wifi->enabled;
1525
1526                 technology_affect_devices(technology, enable);
1527         }
1528
1529         DBG("technology %p %s", technology, get_name(technology->type));
1530
1531         return technology;
1532 }
1533
1534 int connman_technology_driver_register(struct connman_technology_driver *driver)
1535 {
1536         GSList *list;
1537         struct connman_device *device;
1538         enum connman_service_type type;
1539
1540         for (list = driver_list; list; list = list->next) {
1541                 if (list->data == driver)
1542                         goto exist;
1543         }
1544
1545         DBG("Registering %s driver", driver->name);
1546
1547         driver_list = g_slist_insert_sorted(driver_list, driver,
1548                                                         compare_priority);
1549
1550         /*
1551          * Check for technology less devices if this driver
1552          * can service any of them.
1553         */
1554         for (list = techless_device_list; list; list = list->next) {
1555                 device = list->data;
1556
1557                 type = __connman_device_get_service_type(device);
1558                 if (type != driver->type)
1559                         continue;
1560
1561                 techless_device_list = g_slist_remove(techless_device_list,
1562                                                                 device);
1563
1564                 __connman_technology_add_device(device);
1565         }
1566
1567         /* Check for orphaned rfkill switches. */
1568         g_hash_table_foreach(rfkill_list, rfkill_check,
1569                                         GINT_TO_POINTER(driver->type));
1570
1571 exist:
1572         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
1573                 if (!technology_get(CONNMAN_SERVICE_TYPE_P2P))
1574                         return -ENOMEM;
1575         }
1576
1577         return 0;
1578 }
1579
1580 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
1581 {
1582         GSList *list, *tech_drivers;
1583         struct connman_technology *technology;
1584         struct connman_technology_driver *current;
1585
1586         DBG("Unregistering driver %p name %s", driver, driver->name);
1587
1588         for (list = technology_list; list; list = list->next) {
1589                 technology = list->data;
1590
1591                 for (tech_drivers = technology->driver_list; tech_drivers;
1592                                 tech_drivers = g_slist_next(tech_drivers)) {
1593                         current = tech_drivers->data;
1594                         if (driver != current)
1595                                 continue;
1596
1597                         if (driver->remove)
1598                                 driver->remove(technology);
1599
1600                         technology->driver_list =
1601                                 g_slist_remove(technology->driver_list,
1602                                                                 driver);
1603                         break;
1604                 }
1605         }
1606
1607         driver_list = g_slist_remove(driver_list, driver);
1608
1609         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
1610                 technology = technology_find(CONNMAN_SERVICE_TYPE_P2P);
1611                 if (technology)
1612                         technology_put(technology);
1613         }
1614 }
1615
1616 void __connman_technology_add_interface(enum connman_service_type type,
1617                                 int index, const char *ident)
1618 {
1619         struct connman_technology *technology;
1620         GSList *tech_drivers;
1621         struct connman_technology_driver *driver;
1622         char *name;
1623
1624         switch (type) {
1625         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1626         case CONNMAN_SERVICE_TYPE_SYSTEM:
1627                 return;
1628         case CONNMAN_SERVICE_TYPE_ETHERNET:
1629         case CONNMAN_SERVICE_TYPE_WIFI:
1630         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1631         case CONNMAN_SERVICE_TYPE_CELLULAR:
1632         case CONNMAN_SERVICE_TYPE_GPS:
1633         case CONNMAN_SERVICE_TYPE_VPN:
1634         case CONNMAN_SERVICE_TYPE_GADGET:
1635         case CONNMAN_SERVICE_TYPE_P2P:
1636                 break;
1637         }
1638
1639         name = connman_inet_ifname(index);
1640         connman_info("Adding interface %s [ %s ]", name,
1641                                 __connman_service_type2string(type));
1642
1643         technology = technology_find(type);
1644
1645         if (!technology)
1646                 goto out;
1647
1648         for (tech_drivers = technology->driver_list; tech_drivers;
1649              tech_drivers = g_slist_next(tech_drivers)) {
1650                 driver = tech_drivers->data;
1651
1652                 if (driver->add_interface)
1653                         driver->add_interface(technology, index, name, ident);
1654         }
1655
1656         /*
1657          * At this point we can try to enable tethering automatically as
1658          * now the interfaces are set properly.
1659          */
1660         if (technology->tethering_persistent)
1661                 enable_tethering(technology);
1662
1663 out:
1664         g_free(name);
1665 }
1666
1667 void __connman_technology_remove_interface(enum connman_service_type type,
1668                                 int index, const char *ident)
1669 {
1670         struct connman_technology *technology;
1671         GSList *tech_drivers;
1672         struct connman_technology_driver *driver;
1673         char *name;
1674
1675         switch (type) {
1676         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1677         case CONNMAN_SERVICE_TYPE_SYSTEM:
1678                 return;
1679         case CONNMAN_SERVICE_TYPE_ETHERNET:
1680         case CONNMAN_SERVICE_TYPE_WIFI:
1681         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1682         case CONNMAN_SERVICE_TYPE_CELLULAR:
1683         case CONNMAN_SERVICE_TYPE_GPS:
1684         case CONNMAN_SERVICE_TYPE_VPN:
1685         case CONNMAN_SERVICE_TYPE_GADGET:
1686         case CONNMAN_SERVICE_TYPE_P2P:
1687                 break;
1688         }
1689
1690         name = connman_inet_ifname(index);
1691         connman_info("Remove interface %s [ %s ]", name,
1692                                 __connman_service_type2string(type));
1693         g_free(name);
1694
1695         technology = technology_find(type);
1696
1697         if (!technology)
1698                 return;
1699
1700         for (tech_drivers = technology->driver_list; tech_drivers;
1701              tech_drivers = g_slist_next(tech_drivers)) {
1702                 driver = tech_drivers->data;
1703
1704                 if (driver->remove_interface)
1705                         driver->remove_interface(technology, index);
1706         }
1707 }
1708
1709 int __connman_technology_add_device(struct connman_device *device)
1710 {
1711         struct connman_technology *technology;
1712         enum connman_service_type type;
1713
1714         type = __connman_device_get_service_type(device);
1715
1716         DBG("device %p type %s", device, get_name(type));
1717
1718         technology = technology_get(type);
1719         if (!technology) {
1720                 /*
1721                  * Since no driver can be found for this device at the moment we
1722                  * add it to the techless device list.
1723                 */
1724                 techless_device_list = g_slist_prepend(techless_device_list,
1725                                                                 device);
1726
1727                 return -ENXIO;
1728         }
1729
1730         __sync_synchronize();
1731         if (technology->rfkill_driven) {
1732                 if (technology->enabled)
1733                         __connman_device_enable(device);
1734                 else
1735                         __connman_device_disable(device);
1736
1737                 goto done;
1738         }
1739
1740         if (technology->enable_persistent &&
1741                                         !global_offlinemode) {
1742                 int err = __connman_device_enable(device);
1743                 /*
1744                  * connman_technology_add_device() calls __connman_device_enable()
1745                  * but since the device is already enabled, the calls does not
1746                  * propagate through to connman_technology_enabled via
1747                  * connman_device_set_powered.
1748                  */
1749                 if (err == -EALREADY)
1750                         __connman_technology_enabled(type);
1751         }
1752         /* if technology persistent state is offline */
1753         if (!technology->enable_persistent)
1754                 __connman_device_disable(device);
1755
1756 done:
1757         technology->device_list = g_slist_prepend(technology->device_list,
1758                                                                 device);
1759
1760         return 0;
1761 }
1762
1763 int __connman_technology_remove_device(struct connman_device *device)
1764 {
1765         struct connman_technology *technology;
1766         enum connman_service_type type;
1767
1768         DBG("device %p", device);
1769
1770         type = __connman_device_get_service_type(device);
1771
1772         technology = technology_find(type);
1773         if (!technology) {
1774                 techless_device_list = g_slist_remove(techless_device_list,
1775                                                                 device);
1776                 return -ENXIO;
1777         }
1778
1779         technology->device_list = g_slist_remove(technology->device_list,
1780                                                                 device);
1781
1782         if (technology->tethering)
1783                 set_tethering(technology, false);
1784
1785         technology_put(technology);
1786
1787         return 0;
1788 }
1789
1790 int __connman_technology_enabled(enum connman_service_type type)
1791 {
1792         struct connman_technology *technology;
1793
1794         technology = technology_find(type);
1795         if (!technology)
1796                 return -ENXIO;
1797
1798         DBG("technology %p type %s rfkill %d enabled %d", technology,
1799                 get_name(type), technology->rfkill_driven,
1800                 technology->enabled);
1801 #if !defined TIZEN_EXT
1802         if (technology->rfkill_driven) {
1803                 if (technology->tethering_persistent)
1804                         enable_tethering(technology);
1805                 return 0;
1806         }
1807 #endif
1808
1809         return technology_enabled(technology);
1810 }
1811
1812 int __connman_technology_disabled(enum connman_service_type type)
1813 {
1814         struct connman_technology *technology;
1815         GSList *list;
1816
1817         technology = technology_find(type);
1818         if (!technology)
1819                 return -ENXIO;
1820 #if !defined TIZEN_EXT
1821         if (technology->rfkill_driven)
1822                 return 0;
1823 #endif
1824         for (list = technology->device_list; list; list = list->next) {
1825                 struct connman_device *device = list->data;
1826
1827                 if (connman_device_get_powered(device))
1828                         return 0;
1829         }
1830
1831         return technology_disabled(technology);
1832 }
1833
1834 int __connman_technology_set_offlinemode(bool offlinemode)
1835 {
1836         GSList *list;
1837         int err = -EINVAL, enabled_tech_count = 0;
1838
1839         if (global_offlinemode == offlinemode)
1840                 return 0;
1841
1842         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1843
1844         /*
1845          * This is a bit tricky. When you set offlinemode, there is no
1846          * way to differentiate between attempting offline mode and
1847          * resuming offlinemode from last saved profile. We need that
1848          * information in rfkill_update, otherwise it falls back on the
1849          * technology's persistent state. Hence we set the offline mode here
1850          * but save it & call the notifier only if its successful.
1851          */
1852
1853         global_offlinemode = offlinemode;
1854
1855         /* Traverse technology list, enable/disable each technology. */
1856         for (list = technology_list; list; list = list->next) {
1857                 struct connman_technology *technology = list->data;
1858
1859                 if (offlinemode)
1860                         err = technology_disable(technology);
1861                 else {
1862                         if (technology->hardblocked)
1863                                 continue;
1864
1865                         if (technology->enable_persistent) {
1866                                 err = technology_enable(technology);
1867                                 enabled_tech_count++;
1868                         }
1869                 }
1870         }
1871
1872         if (err == 0 || err == -EINPROGRESS || err == -EALREADY ||
1873                         (err == -EINVAL && enabled_tech_count == 0)) {
1874                 connman_technology_save_offlinemode();
1875                 __connman_notifier_offlinemode(offlinemode);
1876         } else
1877                 global_offlinemode = connman_technology_load_offlinemode();
1878
1879         return err;
1880 }
1881
1882 void __connman_technology_set_connected(enum connman_service_type type,
1883                 bool connected)
1884 {
1885         struct connman_technology *technology;
1886         dbus_bool_t val;
1887
1888         technology = technology_find(type);
1889         if (!technology)
1890                 return;
1891
1892         DBG("technology %p connected %d", technology, connected);
1893
1894         technology->connected = connected;
1895
1896         val = connected;
1897         connman_dbus_property_changed_basic(technology->path,
1898                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
1899                         DBUS_TYPE_BOOLEAN, &val);
1900 }
1901
1902 static bool technology_apply_rfkill_change(struct connman_technology *technology,
1903                                                 bool softblock,
1904                                                 bool hardblock,
1905                                                 bool new_rfkill)
1906 {
1907         bool hardblock_changed = false;
1908         bool apply = true;
1909         GList *start, *list;
1910
1911         DBG("technology %p --> %d/%d vs %d/%d",
1912                         technology, softblock, hardblock,
1913                         technology->softblocked, technology->hardblocked);
1914
1915         if (technology->hardblocked == hardblock)
1916                 goto softblock_change;
1917
1918         if (!(new_rfkill && !hardblock)) {
1919                 start = g_hash_table_get_values(rfkill_list);
1920
1921                 for (list = start; list; list = list->next) {
1922                         struct connman_rfkill *rfkill = list->data;
1923
1924                         if (rfkill->type != technology->type)
1925                                 continue;
1926
1927                         if (rfkill->hardblock != hardblock)
1928                                 apply = false;
1929                 }
1930
1931                 g_list_free(start);
1932         }
1933
1934         if (!apply)
1935                 goto softblock_change;
1936
1937         technology->hardblocked = hardblock;
1938         hardblock_changed = true;
1939
1940 softblock_change:
1941         if (!apply && technology->softblocked != softblock)
1942                 apply = true;
1943
1944         if (!apply)
1945                 return technology->hardblocked;
1946
1947         technology->softblocked = softblock;
1948
1949         if (technology->hardblocked ||
1950                                         technology->softblocked) {
1951                 if (technology_disabled(technology) != -EALREADY)
1952                         technology_affect_devices(technology, false);
1953         } else if (!technology->hardblocked &&
1954                                         !technology->softblocked) {
1955                 if (technology_enabled(technology) != -EALREADY)
1956                         technology_affect_devices(technology, true);
1957         }
1958
1959         if (hardblock_changed) {
1960                 if (technology->hardblocked) {
1961                         DBG("%s is switched off.", get_name(technology->type));
1962                         technology_dbus_unregister(technology);
1963                 } else {
1964                         DBG("%s is switched on.", get_name(technology->type));
1965                         technology_dbus_register(technology);
1966
1967                         if (global_offlinemode)
1968                                 __connman_rfkill_block(technology->type, true);
1969                 }
1970         }
1971
1972         return technology->hardblocked;
1973 }
1974
1975 int __connman_technology_add_rfkill(unsigned int index,
1976                                         enum connman_service_type type,
1977                                                 bool softblock,
1978                                                 bool hardblock)
1979 {
1980         struct connman_technology *technology;
1981         struct connman_rfkill *rfkill;
1982
1983         DBG("index %u type %d soft %u hard %u", index, type,
1984                                                         softblock, hardblock);
1985
1986         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1987         if (rfkill)
1988                 goto done;
1989
1990         rfkill = g_try_new0(struct connman_rfkill, 1);
1991         if (!rfkill)
1992                 return -ENOMEM;
1993
1994         rfkill->index = index;
1995         rfkill->type = type;
1996         rfkill->softblock = softblock;
1997         rfkill->hardblock = hardblock;
1998
1999         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
2000
2001 done:
2002 #if defined TIZEN_EXT
2003         /* Fix Svace Issue [WGID: 1348]. */
2004         g_free(rfkill);
2005 #endif
2006         technology = technology_get(type);
2007         /* If there is no driver for this type, ignore it. */
2008         if (!technology)
2009                 return -ENXIO;
2010
2011         technology->rfkill_driven = true;
2012
2013 #if !defined TIZEN_EXT
2014         /* If hardblocked, there is no need to handle softblocked state */
2015         if (technology_apply_rfkill_change(technology,
2016                                 softblock, hardblock, true))
2017                 return 0;
2018 #endif
2019         if (global_offlinemode)
2020                 return 0;
2021
2022         /*
2023          * Depending on softblocked state we unblock/block according to
2024          * offlinemode and persistente state.
2025          */
2026         if (technology->softblocked &&
2027                                 technology->enable_persistent)
2028                 return __connman_rfkill_block(type, false);
2029         else if (!technology->softblocked &&
2030                                 !technology->enable_persistent)
2031                 return __connman_rfkill_block(type, true);
2032
2033         return 0;
2034 }
2035
2036 int __connman_technology_update_rfkill(unsigned int index,
2037                                         enum connman_service_type type,
2038                                                 bool softblock,
2039                                                 bool hardblock)
2040 {
2041         struct connman_technology *technology;
2042         struct connman_rfkill *rfkill;
2043
2044         DBG("index %u soft %u hard %u", index, softblock, hardblock);
2045
2046         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2047         if (!rfkill)
2048                 return -ENXIO;
2049
2050         if (rfkill->softblock == softblock &&
2051                                 rfkill->hardblock == hardblock)
2052                 return 0;
2053
2054         rfkill->softblock = softblock;
2055         rfkill->hardblock = hardblock;
2056
2057         technology = technology_find(type);
2058         /* If there is no driver for this type, ignore it. */
2059         if (!technology)
2060                 return -ENXIO;
2061
2062         technology_apply_rfkill_change(technology, softblock, hardblock,
2063                                                                 false);
2064
2065         if (technology->hardblocked)
2066                 DBG("%s hardblocked", get_name(technology->type));
2067         else
2068                 DBG("%s is%s softblocked", get_name(technology->type),
2069                         technology->softblocked ? "" : " not");
2070
2071         return 0;
2072 }
2073
2074 int __connman_technology_remove_rfkill(unsigned int index,
2075                                         enum connman_service_type type)
2076 {
2077         struct connman_technology *technology;
2078         struct connman_rfkill *rfkill;
2079
2080         DBG("index %u", index);
2081
2082         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2083         if (!rfkill)
2084                 return -ENXIO;
2085
2086         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
2087
2088         technology = technology_find(type);
2089         if (!technology)
2090                 return -ENXIO;
2091
2092         technology_apply_rfkill_change(technology,
2093                 technology->softblocked, !technology->hardblocked, false);
2094
2095         technology_put(technology);
2096
2097         return 0;
2098 }
2099
2100 int __connman_technology_init(void)
2101 {
2102         DBG("");
2103
2104         connection = connman_dbus_get_connection();
2105
2106         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2107                                                         NULL, free_rfkill);
2108
2109         global_offlinemode = connman_technology_load_offlinemode();
2110
2111         /* This will create settings file if it is missing */
2112         connman_technology_save_offlinemode();
2113
2114         return 0;
2115 }
2116
2117 void __connman_technology_cleanup(void)
2118 {
2119         DBG("");
2120
2121         while (technology_list) {
2122                 struct connman_technology *technology = technology_list->data;
2123                 technology_list = g_slist_remove(technology_list, technology);
2124                 technology_put(technology);
2125         }
2126
2127         g_hash_table_destroy(rfkill_list);
2128
2129         dbus_connection_unref(connection);
2130 }