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