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