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