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