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