[connman] Notify 'ScanDone' signal with scan-type info.
[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         technology->scan_pending =
1183                 g_slist_prepend(technology->scan_pending, msg);
1184
1185         err = __connman_device_request_scan(technology->type);
1186         if (err < 0)
1187                 reply_scan_pending(technology, err);
1188
1189 #if defined TIZEN_EXT
1190         if (err == 0) {
1191                 g_scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1192                 DBG("g_scan_type %d", g_scan_type);
1193         }
1194 #endif
1195         return NULL;
1196 }
1197
1198 #if defined TIZEN_EXT
1199 static DBusMessage *specific_scan(DBusConnection *conn, DBusMessage *msg, void *data)
1200 {
1201         struct connman_technology *technology = data;
1202         GSList *specific_scan_list = NULL;
1203         int scan_type = 0;
1204         const char *name = NULL;
1205         unsigned int freq = 0;
1206         DBusMessageIter iter, dict;
1207         int err;
1208
1209         DBG("technology %p request from %s", technology,
1210                         dbus_message_get_sender(msg));
1211
1212         if (!dbus_message_iter_init(msg, &iter))
1213                 return __connman_error_invalid_arguments(msg);
1214
1215         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1216                 return __connman_error_invalid_arguments(msg);
1217
1218         dbus_message_iter_recurse(&iter, &dict);
1219         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1220                 DBusMessageIter entry, value2;
1221                 const char *key;
1222                 int type;
1223
1224                 dbus_message_iter_recurse(&dict, &entry);
1225                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1226                         return __connman_error_invalid_arguments(msg);
1227
1228                 dbus_message_iter_get_basic(&entry, &key);
1229                 dbus_message_iter_next(&entry);
1230
1231                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1232                         return __connman_error_invalid_arguments(msg);
1233
1234                 dbus_message_iter_recurse(&entry, &value2);
1235                 type = dbus_message_iter_get_arg_type(&value2);
1236                 if (g_str_equal(key, "SSID")) {
1237                         if (type != DBUS_TYPE_STRING)
1238                                 return __connman_error_invalid_arguments(msg);
1239
1240                         scan_type = 1; /* SSID based scan */
1241                         dbus_message_iter_get_basic(&value2, &name);
1242                         DBG("name %s", name);
1243                         specific_scan_list = g_slist_append(specific_scan_list, g_strdup(name));
1244                 } else if (g_str_equal(key, "Frequency")) {
1245                         if (type != DBUS_TYPE_UINT16) {
1246                                 g_slist_free_full(specific_scan_list, g_free);
1247                                 return __connman_error_invalid_arguments(msg);
1248                         }
1249
1250                         scan_type = 2; /* Frequency based scan */
1251                         dbus_message_iter_get_basic(&value2, &freq);
1252                         DBG("freq %d", freq);
1253                         specific_scan_list = g_slist_append(specific_scan_list, GINT_TO_POINTER(freq));
1254                 }
1255                 dbus_message_iter_next(&dict);
1256         }
1257
1258         dbus_message_ref(msg);
1259         technology->scan_pending =
1260                 g_slist_prepend(technology->scan_pending, msg);
1261
1262         err = __connman_device_request_specific_scan(technology->type, scan_type, specific_scan_list);
1263         if (err < 0)
1264                 reply_scan_pending(technology, err);
1265
1266         if (err == 0) {
1267                 guint list_size = g_slist_length(specific_scan_list);
1268                 if (list_size == 1)
1269                         g_scan_type = CONNMAN_SCAN_TYPE_SPECIFIC_AP;
1270                 else
1271                         g_scan_type = CONNMAN_SCAN_TYPE_MULTI_AP;
1272                 DBG("list_size %u g_scan_type %d", list_size, g_scan_type);
1273         }
1274
1275         if (scan_type == 1) {
1276                 g_slist_free_full(specific_scan_list, g_free);
1277                 scan_type = 0;
1278         }
1279         return NULL;
1280 }
1281
1282 static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data)
1283 {
1284         DBusMessage *reply;
1285         DBusMessageIter iter, dict;
1286         GSList *list;
1287         struct connman_technology *technology = data;
1288         dbus_bool_t scanning = false;
1289
1290         DBG("technology %p", technology);
1291
1292         for (list = technology->device_list; list; list = list->next) {
1293                 struct connman_device *device = list->data;
1294                 scanning = connman_device_get_scanning(device);
1295                 if(scanning)
1296                         break;
1297         }
1298
1299         DBG("scanning : %d", scanning);
1300         reply = dbus_message_new_method_return(msg);
1301         if (!reply)
1302                 return NULL;
1303
1304         dbus_message_iter_init_append(reply, &iter);
1305
1306         connman_dbus_dict_open(&iter, &dict);
1307         connman_dbus_dict_append_basic(&dict, "Scanstate",
1308                                         DBUS_TYPE_BOOLEAN,
1309                                         &scanning);
1310
1311         connman_dbus_dict_close(&iter, &dict);
1312
1313         return reply;
1314 }
1315 #endif
1316
1317 static const GDBusMethodTable technology_methods[] = {
1318         { GDBUS_DEPRECATED_METHOD("GetProperties",
1319                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1320                         get_properties) },
1321         { GDBUS_ASYNC_METHOD("SetProperty",
1322                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1323                         NULL, set_property) },
1324         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
1325 #if defined TIZEN_EXT
1326         { GDBUS_ASYNC_METHOD("SpecificScan", GDBUS_ARGS({ "specificscan", "a{sv}" }),
1327                         NULL, specific_scan) },
1328         { GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }),
1329                         get_scan_state) },
1330 #endif
1331         { },
1332 };
1333
1334 static const GDBusSignalTable technology_signals[] = {
1335         { GDBUS_SIGNAL("PropertyChanged",
1336                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1337         { GDBUS_SIGNAL("DhcpConnected",
1338                         GDBUS_ARGS({ "aptype", "s" },
1339                                 { "ipaddr", "s" },
1340                                 { "macaddr", "s" },
1341                                 { "hostname", "s" })) },
1342         { GDBUS_SIGNAL("DhcpLeaseDeleted",
1343                         GDBUS_ARGS({ "aptype", "s" },
1344                                 { "ipaddr", "s" },
1345                                 { "macaddr", "s" },
1346                                 { "hostname", "s" })) },
1347         { },
1348 };
1349
1350 static bool technology_dbus_register(struct connman_technology *technology)
1351 {
1352         if (technology->dbus_registered ||
1353                                 (technology->rfkill_driven &&
1354                                  technology->hardblocked))
1355                 return true;
1356
1357         if (!g_dbus_register_interface(connection, technology->path,
1358                                         CONNMAN_TECHNOLOGY_INTERFACE,
1359                                         technology_methods, technology_signals,
1360                                         NULL, technology, NULL)) {
1361                 connman_error("Failed to register %s", technology->path);
1362                 return false;
1363         }
1364
1365         technology_added_signal(technology);
1366         technology->dbus_registered = true;
1367
1368         return true;
1369 }
1370
1371 static void technology_dbus_unregister(struct connman_technology *technology)
1372 {
1373         if (!technology->dbus_registered)
1374                 return;
1375
1376         technology_removed_signal(technology);
1377         g_dbus_unregister_interface(connection, technology->path,
1378                 CONNMAN_TECHNOLOGY_INTERFACE);
1379
1380         technology->dbus_registered = false;
1381 }
1382
1383 static void technology_put(struct connman_technology *technology)
1384 {
1385         DBG("technology %p", technology);
1386
1387         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
1388                 return;
1389
1390         reply_scan_pending(technology, -EINTR);
1391
1392         while (technology->driver_list) {
1393                 struct connman_technology_driver *driver;
1394
1395                 driver = technology->driver_list->data;
1396
1397                 if (driver->remove)
1398                         driver->remove(technology);
1399
1400                 technology->driver_list =
1401                         g_slist_delete_link(technology->driver_list,
1402                                         technology->driver_list);
1403         }
1404
1405         technology_list = g_slist_remove(technology_list, technology);
1406
1407         technology_dbus_unregister(technology);
1408
1409         g_slist_free(technology->device_list);
1410
1411         g_free(technology->path);
1412         g_free(technology->regdom);
1413         g_free(technology->tethering_ident);
1414         g_free(technology->tethering_passphrase);
1415         g_free(technology);
1416 }
1417
1418 static struct connman_technology *technology_get(enum connman_service_type type)
1419 {
1420         GSList *tech_drivers = NULL;
1421         struct connman_technology_driver *driver;
1422         struct connman_technology *technology;
1423         const char *str;
1424         GSList *list;
1425
1426         DBG("type %d", type);
1427
1428         str = __connman_service_type2string(type);
1429         if (!str)
1430                 return NULL;
1431
1432         technology = technology_find(type);
1433         if (technology) {
1434                 if (type != CONNMAN_SERVICE_TYPE_P2P)
1435                         __sync_fetch_and_add(&technology->refcount, 1);
1436                 return technology;
1437         }
1438
1439         /* First check if we have a driver for this technology type */
1440         for (list = driver_list; list; list = list->next) {
1441                 driver = list->data;
1442
1443                 if (driver->type == type) {
1444                         DBG("technology %p driver %p", technology, driver);
1445                         tech_drivers = g_slist_append(tech_drivers, driver);
1446                 }
1447         }
1448
1449         if (!tech_drivers) {
1450                 DBG("No matching drivers found for %s.",
1451                                 __connman_service_type2string(type));
1452                 return NULL;
1453         }
1454
1455         technology = g_try_new0(struct connman_technology, 1);
1456         if (!technology)
1457                 return NULL;
1458
1459         technology->refcount = 1;
1460         technology->type = type;
1461         technology->tethering_hidden = FALSE;
1462         technology->path = g_strdup_printf("%s/technology/%s",
1463                                                         CONNMAN_PATH, str);
1464
1465         technology_load(technology);
1466         technology_list = g_slist_prepend(technology_list, technology);
1467         technology->driver_list = tech_drivers;
1468
1469         for (list = tech_drivers; list; list = list->next) {
1470                 driver = list->data;
1471
1472                 if (driver->probe && driver->probe(technology) < 0)
1473                         DBG("Driver probe failed for technology %p",
1474                                         technology);
1475         }
1476
1477         if (!technology_dbus_register(technology)) {
1478                 technology_put(technology);
1479                 return NULL;
1480         }
1481
1482         if (type == CONNMAN_SERVICE_TYPE_P2P) {
1483                 struct connman_technology *wifi;
1484                 bool enable;
1485
1486                 enable = technology->enable_persistent;
1487
1488                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
1489                 if (enable && wifi)
1490                         enable = wifi->enabled;
1491
1492                 technology_affect_devices(technology, enable);
1493         }
1494
1495         DBG("technology %p %s", technology, get_name(technology->type));
1496
1497         return technology;
1498 }
1499
1500 int connman_technology_driver_register(struct connman_technology_driver *driver)
1501 {
1502         GSList *list;
1503         struct connman_device *device;
1504         enum connman_service_type type;
1505
1506         for (list = driver_list; list; list = list->next) {
1507                 if (list->data == driver)
1508                         goto exist;
1509         }
1510
1511         DBG("Registering %s driver", driver->name);
1512
1513         driver_list = g_slist_insert_sorted(driver_list, driver,
1514                                                         compare_priority);
1515
1516         /*
1517          * Check for technology less devices if this driver
1518          * can service any of them.
1519         */
1520         for (list = techless_device_list; list; list = list->next) {
1521                 device = list->data;
1522
1523                 type = __connman_device_get_service_type(device);
1524                 if (type != driver->type)
1525                         continue;
1526
1527                 techless_device_list = g_slist_remove(techless_device_list,
1528                                                                 device);
1529
1530                 __connman_technology_add_device(device);
1531         }
1532
1533         /* Check for orphaned rfkill switches. */
1534         g_hash_table_foreach(rfkill_list, rfkill_check,
1535                                         GINT_TO_POINTER(driver->type));
1536
1537 exist:
1538         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
1539                 if (!technology_get(CONNMAN_SERVICE_TYPE_P2P))
1540                         return -ENOMEM;
1541         }
1542
1543         return 0;
1544 }
1545
1546 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
1547 {
1548         GSList *list, *tech_drivers;
1549         struct connman_technology *technology;
1550         struct connman_technology_driver *current;
1551
1552         DBG("Unregistering driver %p name %s", driver, driver->name);
1553
1554         for (list = technology_list; list; list = list->next) {
1555                 technology = list->data;
1556
1557                 for (tech_drivers = technology->driver_list; tech_drivers;
1558                                 tech_drivers = g_slist_next(tech_drivers)) {
1559                         current = tech_drivers->data;
1560                         if (driver != current)
1561                                 continue;
1562
1563                         if (driver->remove)
1564                                 driver->remove(technology);
1565
1566                         technology->driver_list =
1567                                 g_slist_remove(technology->driver_list,
1568                                                                 driver);
1569                         break;
1570                 }
1571         }
1572
1573         driver_list = g_slist_remove(driver_list, driver);
1574
1575         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
1576                 technology = technology_find(CONNMAN_SERVICE_TYPE_P2P);
1577                 if (technology)
1578                         technology_put(technology);
1579         }
1580 }
1581
1582 void __connman_technology_add_interface(enum connman_service_type type,
1583                                 int index, const char *ident)
1584 {
1585         struct connman_technology *technology;
1586         GSList *tech_drivers;
1587         struct connman_technology_driver *driver;
1588         char *name;
1589
1590         switch (type) {
1591         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1592         case CONNMAN_SERVICE_TYPE_SYSTEM:
1593                 return;
1594         case CONNMAN_SERVICE_TYPE_ETHERNET:
1595         case CONNMAN_SERVICE_TYPE_WIFI:
1596         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1597         case CONNMAN_SERVICE_TYPE_CELLULAR:
1598         case CONNMAN_SERVICE_TYPE_GPS:
1599         case CONNMAN_SERVICE_TYPE_VPN:
1600         case CONNMAN_SERVICE_TYPE_GADGET:
1601         case CONNMAN_SERVICE_TYPE_P2P:
1602                 break;
1603         }
1604
1605         name = connman_inet_ifname(index);
1606         connman_info("Adding interface %s [ %s ]", name,
1607                                 __connman_service_type2string(type));
1608
1609         technology = technology_find(type);
1610
1611         if (!technology)
1612                 goto out;
1613
1614         for (tech_drivers = technology->driver_list; tech_drivers;
1615              tech_drivers = g_slist_next(tech_drivers)) {
1616                 driver = tech_drivers->data;
1617
1618                 if (driver->add_interface)
1619                         driver->add_interface(technology, index, name, ident);
1620         }
1621
1622         /*
1623          * At this point we can try to enable tethering automatically as
1624          * now the interfaces are set properly.
1625          */
1626         if (technology->tethering_persistent)
1627                 enable_tethering(technology);
1628
1629 out:
1630         g_free(name);
1631 }
1632
1633 void __connman_technology_remove_interface(enum connman_service_type type,
1634                                 int index, const char *ident)
1635 {
1636         struct connman_technology *technology;
1637         GSList *tech_drivers;
1638         struct connman_technology_driver *driver;
1639         char *name;
1640
1641         switch (type) {
1642         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1643         case CONNMAN_SERVICE_TYPE_SYSTEM:
1644                 return;
1645         case CONNMAN_SERVICE_TYPE_ETHERNET:
1646         case CONNMAN_SERVICE_TYPE_WIFI:
1647         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1648         case CONNMAN_SERVICE_TYPE_CELLULAR:
1649         case CONNMAN_SERVICE_TYPE_GPS:
1650         case CONNMAN_SERVICE_TYPE_VPN:
1651         case CONNMAN_SERVICE_TYPE_GADGET:
1652         case CONNMAN_SERVICE_TYPE_P2P:
1653                 break;
1654         }
1655
1656         name = connman_inet_ifname(index);
1657         connman_info("Remove interface %s [ %s ]", name,
1658                                 __connman_service_type2string(type));
1659         g_free(name);
1660
1661         technology = technology_find(type);
1662
1663         if (!technology)
1664                 return;
1665
1666         for (tech_drivers = technology->driver_list; tech_drivers;
1667              tech_drivers = g_slist_next(tech_drivers)) {
1668                 driver = tech_drivers->data;
1669
1670                 if (driver->remove_interface)
1671                         driver->remove_interface(technology, index);
1672         }
1673 }
1674
1675 int __connman_technology_add_device(struct connman_device *device)
1676 {
1677         struct connman_technology *technology;
1678         enum connman_service_type type;
1679
1680         type = __connman_device_get_service_type(device);
1681
1682         DBG("device %p type %s", device, get_name(type));
1683
1684         technology = technology_get(type);
1685         if (!technology) {
1686                 /*
1687                  * Since no driver can be found for this device at the moment we
1688                  * add it to the techless device list.
1689                 */
1690                 techless_device_list = g_slist_prepend(techless_device_list,
1691                                                                 device);
1692
1693                 return -ENXIO;
1694         }
1695
1696         __sync_synchronize();
1697         if (technology->rfkill_driven) {
1698                 if (technology->enabled)
1699                         __connman_device_enable(device);
1700                 else
1701                         __connman_device_disable(device);
1702
1703                 goto done;
1704         }
1705
1706         if (technology->enable_persistent &&
1707                                         !global_offlinemode) {
1708                 int err = __connman_device_enable(device);
1709                 /*
1710                  * connman_technology_add_device() calls __connman_device_enable()
1711                  * but since the device is already enabled, the calls does not
1712                  * propagate through to connman_technology_enabled via
1713                  * connman_device_set_powered.
1714                  */
1715                 if (err == -EALREADY)
1716                         __connman_technology_enabled(type);
1717         }
1718         /* if technology persistent state is offline */
1719         if (!technology->enable_persistent)
1720                 __connman_device_disable(device);
1721
1722 done:
1723         technology->device_list = g_slist_prepend(technology->device_list,
1724                                                                 device);
1725
1726         return 0;
1727 }
1728
1729 int __connman_technology_remove_device(struct connman_device *device)
1730 {
1731         struct connman_technology *technology;
1732         enum connman_service_type type;
1733
1734         DBG("device %p", device);
1735
1736         type = __connman_device_get_service_type(device);
1737
1738         technology = technology_find(type);
1739         if (!technology) {
1740                 techless_device_list = g_slist_remove(techless_device_list,
1741                                                                 device);
1742                 return -ENXIO;
1743         }
1744
1745         technology->device_list = g_slist_remove(technology->device_list,
1746                                                                 device);
1747
1748         if (technology->tethering)
1749                 set_tethering(technology, false);
1750
1751         technology_put(technology);
1752
1753         return 0;
1754 }
1755
1756 int __connman_technology_enabled(enum connman_service_type type)
1757 {
1758         struct connman_technology *technology;
1759
1760         technology = technology_find(type);
1761         if (!technology)
1762                 return -ENXIO;
1763
1764         DBG("technology %p type %s rfkill %d enabled %d", technology,
1765                 get_name(type), technology->rfkill_driven,
1766                 technology->enabled);
1767 #if !defined TIZEN_EXT
1768         if (technology->rfkill_driven) {
1769                 if (technology->tethering_persistent)
1770                         enable_tethering(technology);
1771                 return 0;
1772         }
1773 #endif
1774
1775         return technology_enabled(technology);
1776 }
1777
1778 int __connman_technology_disabled(enum connman_service_type type)
1779 {
1780         struct connman_technology *technology;
1781         GSList *list;
1782
1783         technology = technology_find(type);
1784         if (!technology)
1785                 return -ENXIO;
1786 #if !defined TIZEN_EXT
1787         if (technology->rfkill_driven)
1788                 return 0;
1789 #endif
1790         for (list = technology->device_list; list; list = list->next) {
1791                 struct connman_device *device = list->data;
1792
1793                 if (connman_device_get_powered(device))
1794                         return 0;
1795         }
1796
1797         return technology_disabled(technology);
1798 }
1799
1800 int __connman_technology_set_offlinemode(bool offlinemode)
1801 {
1802         GSList *list;
1803         int err = -EINVAL, enabled_tech_count = 0;
1804
1805         if (global_offlinemode == offlinemode)
1806                 return 0;
1807
1808         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1809
1810         /*
1811          * This is a bit tricky. When you set offlinemode, there is no
1812          * way to differentiate between attempting offline mode and
1813          * resuming offlinemode from last saved profile. We need that
1814          * information in rfkill_update, otherwise it falls back on the
1815          * technology's persistent state. Hence we set the offline mode here
1816          * but save it & call the notifier only if its successful.
1817          */
1818
1819         global_offlinemode = offlinemode;
1820
1821         /* Traverse technology list, enable/disable each technology. */
1822         for (list = technology_list; list; list = list->next) {
1823                 struct connman_technology *technology = list->data;
1824
1825                 if (offlinemode)
1826                         err = technology_disable(technology);
1827                 else {
1828                         if (technology->hardblocked)
1829                                 continue;
1830
1831                         if (technology->enable_persistent) {
1832                                 err = technology_enable(technology);
1833                                 enabled_tech_count++;
1834                         }
1835                 }
1836         }
1837
1838         if (err == 0 || err == -EINPROGRESS || err == -EALREADY ||
1839                         (err == -EINVAL && enabled_tech_count == 0)) {
1840                 connman_technology_save_offlinemode();
1841                 __connman_notifier_offlinemode(offlinemode);
1842         } else
1843                 global_offlinemode = connman_technology_load_offlinemode();
1844
1845         return err;
1846 }
1847
1848 void __connman_technology_set_connected(enum connman_service_type type,
1849                 bool connected)
1850 {
1851         struct connman_technology *technology;
1852         dbus_bool_t val;
1853
1854         technology = technology_find(type);
1855         if (!technology)
1856                 return;
1857
1858         DBG("technology %p connected %d", technology, connected);
1859
1860         technology->connected = connected;
1861
1862         val = connected;
1863         connman_dbus_property_changed_basic(technology->path,
1864                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
1865                         DBUS_TYPE_BOOLEAN, &val);
1866 }
1867
1868 static bool technology_apply_rfkill_change(struct connman_technology *technology,
1869                                                 bool softblock,
1870                                                 bool hardblock,
1871                                                 bool new_rfkill)
1872 {
1873         bool hardblock_changed = false;
1874         bool apply = true;
1875         GList *start, *list;
1876
1877         DBG("technology %p --> %d/%d vs %d/%d",
1878                         technology, softblock, hardblock,
1879                         technology->softblocked, technology->hardblocked);
1880
1881         if (technology->hardblocked == hardblock)
1882                 goto softblock_change;
1883
1884         if (!(new_rfkill && !hardblock)) {
1885                 start = g_hash_table_get_values(rfkill_list);
1886
1887                 for (list = start; list; list = list->next) {
1888                         struct connman_rfkill *rfkill = list->data;
1889
1890                         if (rfkill->type != technology->type)
1891                                 continue;
1892
1893                         if (rfkill->hardblock != hardblock)
1894                                 apply = false;
1895                 }
1896
1897                 g_list_free(start);
1898         }
1899
1900         if (!apply)
1901                 goto softblock_change;
1902
1903         technology->hardblocked = hardblock;
1904         hardblock_changed = true;
1905
1906 softblock_change:
1907         if (!apply && technology->softblocked != softblock)
1908                 apply = true;
1909
1910         if (!apply)
1911                 return technology->hardblocked;
1912
1913         technology->softblocked = softblock;
1914
1915         if (technology->hardblocked ||
1916                                         technology->softblocked) {
1917                 if (technology_disabled(technology) != -EALREADY)
1918                         technology_affect_devices(technology, false);
1919         } else if (!technology->hardblocked &&
1920                                         !technology->softblocked) {
1921                 if (technology_enabled(technology) != -EALREADY)
1922                         technology_affect_devices(technology, true);
1923         }
1924
1925         if (hardblock_changed) {
1926                 if (technology->hardblocked) {
1927                         DBG("%s is switched off.", get_name(technology->type));
1928                         technology_dbus_unregister(technology);
1929                 } else {
1930                         DBG("%s is switched on.", get_name(technology->type));
1931                         technology_dbus_register(technology);
1932
1933                         if (global_offlinemode)
1934                                 __connman_rfkill_block(technology->type, true);
1935                 }
1936         }
1937
1938         return technology->hardblocked;
1939 }
1940
1941 int __connman_technology_add_rfkill(unsigned int index,
1942                                         enum connman_service_type type,
1943                                                 bool softblock,
1944                                                 bool hardblock)
1945 {
1946         struct connman_technology *technology;
1947         struct connman_rfkill *rfkill;
1948
1949         DBG("index %u type %d soft %u hard %u", index, type,
1950                                                         softblock, hardblock);
1951
1952         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1953         if (rfkill)
1954                 goto done;
1955
1956         rfkill = g_try_new0(struct connman_rfkill, 1);
1957         if (!rfkill)
1958                 return -ENOMEM;
1959
1960         rfkill->index = index;
1961         rfkill->type = type;
1962         rfkill->softblock = softblock;
1963         rfkill->hardblock = hardblock;
1964
1965         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
1966
1967 done:
1968 #if defined TIZEN_EXT
1969         /* Fix Svace Issue [WGID: 1348]. */
1970         g_free(rfkill);
1971 #endif
1972         technology = technology_get(type);
1973         /* If there is no driver for this type, ignore it. */
1974         if (!technology)
1975                 return -ENXIO;
1976
1977         technology->rfkill_driven = true;
1978
1979 #if !defined TIZEN_EXT
1980         /* If hardblocked, there is no need to handle softblocked state */
1981         if (technology_apply_rfkill_change(technology,
1982                                 softblock, hardblock, true))
1983                 return 0;
1984 #endif
1985         if (global_offlinemode)
1986                 return 0;
1987
1988         /*
1989          * Depending on softblocked state we unblock/block according to
1990          * offlinemode and persistente state.
1991          */
1992         if (technology->softblocked &&
1993                                 technology->enable_persistent)
1994                 return __connman_rfkill_block(type, false);
1995         else if (!technology->softblocked &&
1996                                 !technology->enable_persistent)
1997                 return __connman_rfkill_block(type, true);
1998
1999         return 0;
2000 }
2001
2002 int __connman_technology_update_rfkill(unsigned int index,
2003                                         enum connman_service_type type,
2004                                                 bool softblock,
2005                                                 bool hardblock)
2006 {
2007         struct connman_technology *technology;
2008         struct connman_rfkill *rfkill;
2009
2010         DBG("index %u soft %u hard %u", index, softblock, hardblock);
2011
2012         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2013         if (!rfkill)
2014                 return -ENXIO;
2015
2016         if (rfkill->softblock == softblock &&
2017                                 rfkill->hardblock == hardblock)
2018                 return 0;
2019
2020         rfkill->softblock = softblock;
2021         rfkill->hardblock = hardblock;
2022
2023         technology = technology_find(type);
2024         /* If there is no driver for this type, ignore it. */
2025         if (!technology)
2026                 return -ENXIO;
2027
2028         technology_apply_rfkill_change(technology, softblock, hardblock,
2029                                                                 false);
2030
2031         if (technology->hardblocked)
2032                 DBG("%s hardblocked", get_name(technology->type));
2033         else
2034                 DBG("%s is%s softblocked", get_name(technology->type),
2035                         technology->softblocked ? "" : " not");
2036
2037         return 0;
2038 }
2039
2040 int __connman_technology_remove_rfkill(unsigned int index,
2041                                         enum connman_service_type type)
2042 {
2043         struct connman_technology *technology;
2044         struct connman_rfkill *rfkill;
2045
2046         DBG("index %u", index);
2047
2048         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2049         if (!rfkill)
2050                 return -ENXIO;
2051
2052         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
2053
2054         technology = technology_find(type);
2055         if (!technology)
2056                 return -ENXIO;
2057
2058         technology_apply_rfkill_change(technology,
2059                 technology->softblocked, !technology->hardblocked, false);
2060
2061         technology_put(technology);
2062
2063         return 0;
2064 }
2065
2066 int __connman_technology_init(void)
2067 {
2068         DBG("");
2069
2070         connection = connman_dbus_get_connection();
2071
2072         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2073                                                         NULL, free_rfkill);
2074
2075         global_offlinemode = connman_technology_load_offlinemode();
2076
2077         /* This will create settings file if it is missing */
2078         connman_technology_save_offlinemode();
2079
2080         return 0;
2081 }
2082
2083 void __connman_technology_cleanup(void)
2084 {
2085         DBG("");
2086
2087         while (technology_list) {
2088                 struct connman_technology *technology = technology_list->data;
2089                 technology_list = g_slist_remove(technology_list, technology);
2090                 technology_put(technology);
2091         }
2092
2093         g_hash_table_destroy(rfkill_list);
2094
2095         dbus_connection_unref(connection);
2096 }